diff options
184 files changed, 5197 insertions, 2467 deletions
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java index e57359fbf50e..5fd45eadbda9 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java @@ -141,6 +141,25 @@ public class AppSearchManager { } /** + * Creates a new {@link GlobalSearchSession}. + * + * <p>This process requires an AppSearch native indexing file system for each user. If it's not + * created for this user, the initialization process will create one under user's directory. + * + * @param executor Executor on which to invoke the callback. + * @param callback The {@link AppSearchResult}<{@link GlobalSearchSession}> of + * performing this operation. Or a {@link AppSearchResult} with failure + * reason code and error information. + */ + public void createGlobalSearchSession( + @NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + GlobalSearchSession.createGlobalSearchSession(mService, executor, callback); + } + + /** * Sets the schema being used by documents provided to the {@link #putDocuments} method. * * <p>The schema provided here is compared to the stored copy of the schema previously supplied @@ -383,22 +402,26 @@ public class AppSearchManager { @NonNull String queryExpression, @NonNull SearchSpec searchSpec) { // TODO(b/146386470): Transmit the result documents as a RemoteStream instead of sending // them in one big list. - AndroidFuture<AppSearchResult> searchResultsFuture = new AndroidFuture<>(); + AndroidFuture<AppSearchResult> future = new AndroidFuture<>(); try { - mService.query(DEFAULT_DATABASE_NAME, queryExpression, - searchSpec.getBundle(), searchResultsFuture); + mService.query(DEFAULT_DATABASE_NAME, queryExpression, searchSpec.getBundle(), + new IAppSearchResultCallback.Stub() { + public void onResult(AppSearchResult result) { + future.complete(result); + } + }); + AppSearchResult<Bundle> bundleResult = getFutureOrThrow(future); + if (!bundleResult.isSuccess()) { + return AppSearchResult.newFailedResult(bundleResult.getResultCode(), + bundleResult.getErrorMessage()); + } + SearchResultPage searchResultPage = new SearchResultPage(bundleResult.getResultValue()); + return AppSearchResult.newSuccessfulResult(searchResultPage.getResults()); } catch (RemoteException e) { - searchResultsFuture.completeExceptionally(e); - } - - // Translate the Bundle into a searchResultPage. - AppSearchResult<Bundle> bundleResult = getFutureOrThrow(searchResultsFuture); - if (!bundleResult.isSuccess()) { - return AppSearchResult.newFailedResult(bundleResult.getResultCode(), - bundleResult.getErrorMessage()); + throw e.rethrowFromSystemServer(); + } catch (Throwable t) { + return AppSearchResult.throwableToFailedResult(t); } - SearchResultPage searchResultPage = new SearchResultPage(bundleResult.getResultValue()); - return AppSearchResult.newSuccessfulResult(searchResultPage.getResults()); } /** diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl index f0b29964b895..37ce990b97c4 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl @@ -16,4 +16,4 @@ package android.app.appsearch; /** {@hide} */ -parcelable AppSearchResult;
\ No newline at end of file +parcelable AppSearchResult<ValueType>;
\ No newline at end of file diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java index fd4b1060bcd1..9c7ccea4c43b 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java @@ -270,6 +270,61 @@ public final class AppSearchSession { } /** + * Searches a document based on a given query string. + * + * <p>Currently we support following features in the raw query format: + * <ul> + * <li>AND + * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and + * ‘cat’”). + * Example: hello world matches documents that have both ‘hello’ and ‘world’ + * <li>OR + * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or + * ‘cat’”). + * Example: dog OR puppy + * <li>Exclusion + * <p>Exclude a term (e.g. “match documents that do + * not have the term ‘dog’”). + * Example: -dog excludes the term ‘dog’ + * <li>Grouping terms + * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g. + * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”). + * Example: (dog puppy) (cat kitten) two one group containing two terms. + * <li>Property restricts + * <p> Specifies which properties of a document to specifically match terms in (e.g. + * “match documents where the ‘subject’ property contains ‘important’”). + * Example: subject:important matches documents with the term ‘important’ in the + * ‘subject’ property + * <li>Schema type restricts + * <p>This is similar to property restricts, but allows for restricts on top-level document + * fields, such as schema_type. Clients should be able to limit their query to documents of + * a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”). + * Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents + * that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the + * ‘Video’ schema type. + * </ul> + * + * <p> This method is lightweight. The heavy work will be done in + * {@link SearchResults#getNextPage}. + * + * @param queryExpression Query String to search. + * @param searchSpec Spec for setting filters, raw query etc. + * @param executor Executor on which to invoke the callback of the following request + * {@link SearchResults#getNextPage}. + * @return The search result of performing this operation. + */ + @NonNull + public SearchResults query( + @NonNull String queryExpression, + @NonNull SearchSpec searchSpec, + @NonNull @CallbackExecutor Executor executor) { + Objects.requireNonNull(queryExpression); + Objects.requireNonNull(searchSpec); + Objects.requireNonNull(executor); + return new SearchResults(mService, mDatabaseName, queryExpression, searchSpec, executor); + } + + /** * Removes {@link GenericDocument}s from the index by URI. * * @param request Request containing URIs to be removed. @@ -342,6 +397,4 @@ public final class AppSearchSession { throw e.rethrowFromSystemServer(); } } - - // TODO(b/162450968) port query() and SearchResults.java to platform. } diff --git a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java new file mode 100644 index 000000000000..d2aa8eab4708 --- /dev/null +++ b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.appsearch; + + +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.os.RemoteException; + +import java.util.Objects; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * This class provides global access to the centralized AppSearch index maintained by the system. + * + * <p>Apps can retrieve indexed documents through the query API. + * @hide + */ +public class GlobalSearchSession { + + private final IAppSearchManager mService; + + static void createGlobalSearchSession( + @NonNull IAppSearchManager service, + @NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) { + GlobalSearchSession globalSearchSession = new GlobalSearchSession(service); + globalSearchSession.initialize(executor, callback); + } + + // NOTE: No instance of this class should be created or returned except via initialize(). + // Once the callback.accept has been called here, the class is ready to use. + private void initialize( + @NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) { + try { + mService.initialize(new IAppSearchResultCallback.Stub() { + public void onResult(AppSearchResult result) { + executor.execute(() -> { + if (result.isSuccess()) { + callback.accept( + AppSearchResult.newSuccessfulResult(GlobalSearchSession.this)); + } else { + callback.accept(result); + } + }); + } + }); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private GlobalSearchSession(@NonNull IAppSearchManager service) { + mService = service; + } + + /** + * Searches across all documents in the storage based on a given query string. + * + * <p>Currently we support following features in the raw query format: + * <ul> + * <li>AND + * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and + * ‘cat’”). + * Example: hello world matches documents that have both ‘hello’ and ‘world’ + * <li>OR + * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or + * ‘cat’”). + * Example: dog OR puppy + * <li>Exclusion + * <p>Exclude a term (e.g. “match documents that do + * not have the term ‘dog’”). + * Example: -dog excludes the term ‘dog’ + * <li>Grouping terms + * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g. + * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”). + * Example: (dog puppy) (cat kitten) two one group containing two terms. + * <li>Property restricts + * <p> Specifies which properties of a document to specifically match terms in (e.g. + * “match documents where the ‘subject’ property contains ‘important’”). + * Example: subject:important matches documents with the term ‘important’ in the + * ‘subject’ property + * <li>Schema type restricts + * <p>This is similar to property restricts, but allows for restricts on top-level document + * fields, such as schema_type. Clients should be able to limit their query to documents of + * a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”). + * Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents + * that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the + * ‘Video’ schema type. + * </ul> + * + * <p> This method is lightweight. The heavy work will be done in + * {@link SearchResults#getNextPage}. + * + * @param queryExpression Query String to search. + * @param searchSpec Spec for setting filters, raw query etc. + * @param executor Executor on which to invoke the callback of the following request + * {@link SearchResults#getNextPage}. + * @return The search result of performing this operation. + */ + @NonNull + public SearchResults globalQuery( + @NonNull String queryExpression, + @NonNull SearchSpec searchSpec, + @NonNull @CallbackExecutor Executor executor) { + Objects.requireNonNull(queryExpression); + Objects.requireNonNull(searchSpec); + Objects.requireNonNull(executor); + return new SearchResults(mService, /*databaseName=*/null, queryExpression, + searchSpec, executor); + } +} diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl index 62e60d7f4ab5..22e00f2cdfdc 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl +++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl @@ -85,13 +85,46 @@ interface IAppSearchManager { * @param databaseName The databaseName this query for. * @param queryExpression String to search for * @param searchSpecBundle SearchSpec bundle - * @param callback {@link AndroidFuture}<{@link AppSearchResult}<{@link SearchResults}>> + * @param callback {@link AppSearchResult}<{@link Bundle}> of performing this + * operation. */ void query( in String databaseName, in String queryExpression, in Bundle searchSpecBundle, - in AndroidFuture<AppSearchResult> callback); + in IAppSearchResultCallback callback); + + /** + * Executes a global query, i.e. over all permitted databases, against the AppSearch index and + * returns results. + * + * @param queryExpression String to search for + * @param searchSpecBundle SearchSpec bundle + * @param callback {@link AppSearchResult}<{@link Bundle}> of performing this + * operation. + */ + void globalQuery( + in String queryExpression, + in Bundle searchSpecBundle, + in IAppSearchResultCallback callback); + + /** + * Fetches the next page of results of a previously executed query. Results can be empty if + * next-page token is invalid or all pages have been returned. + * + * @param nextPageToken The token of pre-loaded results of previously executed query. + * @param callback {@link AppSearchResult}<{@link Bundle}> of performing this + * operation. + */ + void getNextPage(in long nextPageToken, in IAppSearchResultCallback callback); + + /** + * Invalidates the next-page token so that no more results of the related query can be returned. + * + * @param nextPageToken The token of pre-loaded results of previously executed query to be + * Invalidated. + */ + void invalidateNextPageToken(in long nextPageToken); /** * Removes documents by URI. diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java index 9f376250f1a6..8548d209c787 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java +++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,63 +16,123 @@ package android.app.appsearch; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; +import android.os.RemoteException; +import android.util.Log; -import java.util.ArrayList; +import com.android.internal.util.Preconditions; + +import java.io.Closeable; import java.util.List; +import java.util.concurrent.Executor; +import java.util.function.Consumer; /** - * Structure for transmitting a page of search results across binder. + * SearchResults are a returned object from a query API. + * + * <p>Each {@link SearchResult} contains a document and may contain other fields like snippets + * based on request. + * + * <p>Should close this object after finish fetching results. + * + * <p>This class is not thread safe. * @hide */ -public final class SearchResults implements Parcelable { - final List<SearchResult> mResults; - final long mNextPageToken; +public class SearchResults implements Closeable { + private static final String TAG = "SearchResults"; + + private final IAppSearchManager mService; + + @Nullable + private final String mDatabaseName; + + private final String mQueryExpression; + + private final SearchSpec mSearchSpec; + + private final Executor mExecutor; - public SearchResults(@NonNull List<SearchResult> results, long nextPageToken) { - mResults = results; - mNextPageToken = nextPageToken; + private long mNextPageToken; + + private boolean mIsFirstLoad = true; + + SearchResults(@NonNull IAppSearchManager service, + @Nullable String databaseName, + @NonNull String queryExpression, + @NonNull SearchSpec searchSpec, + @NonNull @CallbackExecutor Executor executor) { + mService = Preconditions.checkNotNull(service); + mExecutor = Preconditions.checkNotNull(executor); + mDatabaseName = databaseName; + mQueryExpression = Preconditions.checkNotNull(queryExpression); + mSearchSpec = Preconditions.checkNotNull(searchSpec); } - private SearchResults(@NonNull Parcel in) { - List<Bundle> resultBundles = in.readArrayList(/*loader=*/ null); - mResults = new ArrayList<>(resultBundles.size()); - for (int i = 0; i < resultBundles.size(); i++) { - SearchResult searchResult = new SearchResult(resultBundles.get(i)); - mResults.add(searchResult); + /** + * Gets a whole page of {@link SearchResult}s. + * + * <p>Re-call this method to get next page of {@link SearchResult}, until it returns an + * empty list. + * + * <p>The page size is set by {@link SearchSpec.Builder#setNumPerPage}. + * + * @param callback Callback to receive the pending result of performing this operation. + */ + public void getNextPage(@NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) { + try { + if (mIsFirstLoad) { + mIsFirstLoad = false; + if (mDatabaseName == null) { + mService.globalQuery(mQueryExpression, mSearchSpec.getBundle(), + wrapCallback(callback)); + } else { + mService.query(mDatabaseName, mQueryExpression, mSearchSpec.getBundle(), + wrapCallback(callback)); + } + } else { + mService.getNextPage(mNextPageToken, wrapCallback(callback)); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } - mNextPageToken = in.readLong(); } - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - List<Bundle> resultBundles = new ArrayList<>(mResults.size()); - for (int i = 0; i < mResults.size(); i++) { - resultBundles.add(mResults.get(i).getBundle()); + private void invokeCallback(AppSearchResult result, + @NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) { + if (result.isSuccess()) { + try { + SearchResultPage searchResultPage = + new SearchResultPage((Bundle) result.getResultValue()); + mNextPageToken = searchResultPage.getNextPageToken(); + callback.accept(AppSearchResult.newSuccessfulResult( + searchResultPage.getResults())); + } catch (Throwable t) { + callback.accept(AppSearchResult.throwableToFailedResult(t)); + } + } else { + callback.accept(result); } - dest.writeList(resultBundles); - dest.writeLong(mNextPageToken); } - @Override - public int describeContents() { - return 0; + public void close() { + mExecutor.execute(() -> { + try { + mService.invalidateNextPageToken(mNextPageToken); + } catch (RemoteException e) { + Log.d(TAG, "Unable to close the SearchResults", e); + } + }); } - public static final Creator<SearchResults> CREATOR = new Creator<SearchResults>() { - @NonNull - @Override - public SearchResults createFromParcel(@NonNull Parcel in) { - return new SearchResults(in); - } - - @NonNull - @Override - public SearchResults[] newArray(int size) { - return new SearchResults[size]; - } - }; + private IAppSearchResultCallback wrapCallback( + @NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) { + return new IAppSearchResultCallback.Stub() { + public void onResult(AppSearchResult result) { + mExecutor.execute(() -> invokeCallback(result, callback)); + } + }; + } } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java index c9dd89c3b6d1..d5146dd75c3b 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -36,7 +36,6 @@ import android.os.UserHandle; import android.util.ArraySet; import android.util.Log; -import com.android.internal.infra.AndroidFuture; import com.android.internal.util.Preconditions; import com.android.server.SystemService; import com.android.server.appsearch.external.localstorage.AppSearchImpl; @@ -69,6 +68,7 @@ public class AppSearchManagerService extends SystemService { @NonNull IAppSearchResultCallback callback) { Preconditions.checkNotNull(databaseName); Preconditions.checkNotNull(schemaBundles); + Preconditions.checkNotNull(callback); int callingUid = Binder.getCallingUidOrThrow(); int callingUserId = UserHandle.getUserId(callingUid); final long callingIdentity = Binder.clearCallingIdentity(); @@ -158,13 +158,12 @@ public class AppSearchManagerService extends SystemService { } // TODO(sidchhabra): Do this in a threadpool. - // TODO(b/162450968) handle pagination after getNextPage and SearchResults is ready. @Override public void query( @NonNull String databaseName, @NonNull String queryExpression, @NonNull Bundle searchSpecBundle, - @NonNull AndroidFuture<AppSearchResult> callback) { + @NonNull IAppSearchResultCallback callback) { Preconditions.checkNotNull(databaseName); Preconditions.checkNotNull(queryExpression); Preconditions.checkNotNull(searchSpecBundle); @@ -179,10 +178,70 @@ public class AppSearchManagerService extends SystemService { databaseName, queryExpression, new SearchSpec(searchSpecBundle)); - callback.complete( + invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(searchResultPage.getBundle())); } catch (Throwable t) { - callback.complete(throwableToFailedResult(t)); + invokeCallbackOnError(callback, t); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + + public void globalQuery( + @NonNull String queryExpression, + @NonNull Bundle searchSpecBundle, + @NonNull IAppSearchResultCallback callback) { + Preconditions.checkNotNull(queryExpression); + Preconditions.checkNotNull(searchSpecBundle); + Preconditions.checkNotNull(callback); + int callingUid = Binder.getCallingUidOrThrow(); + int callingUserId = UserHandle.getUserId(callingUid); + final long callingIdentity = Binder.clearCallingIdentity(); + try { + AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); + SearchResultPage searchResultPage = impl.globalQuery( + queryExpression, + new SearchSpec(searchSpecBundle)); + invokeCallbackOnResult(callback, + AppSearchResult.newSuccessfulResult(searchResultPage.getBundle())); + } catch (Throwable t) { + invokeCallbackOnError(callback, t); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + + @Override + public void getNextPage(long nextPageToken, + @NonNull IAppSearchResultCallback callback) { + Preconditions.checkNotNull(callback); + int callingUid = Binder.getCallingUidOrThrow(); + int callingUserId = UserHandle.getUserId(callingUid); + final long callingIdentity = Binder.clearCallingIdentity(); + // TODO(b/162450968) check nextPageToken is being advanced by the same uid as originally + // opened it + try { + AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); + SearchResultPage searchResultPage = impl.getNextPage(nextPageToken); + invokeCallbackOnResult(callback, + AppSearchResult.newSuccessfulResult(searchResultPage.getBundle())); + } catch (Throwable t) { + invokeCallbackOnError(callback, t); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + + @Override + public void invalidateNextPageToken(long nextPageToken) { + int callingUid = Binder.getCallingUidOrThrow(); + int callingUserId = UserHandle.getUserId(callingUid); + final long callingIdentity = Binder.clearCallingIdentity(); + try { + AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); + impl.invalidateNextPageToken(nextPageToken); + } catch (Throwable t) { + Log.d(TAG, "Unable to invalidate the query page token", t); } finally { Binder.restoreCallingIdentity(callingIdentity); } @@ -229,6 +288,7 @@ public class AppSearchManagerService extends SystemService { Preconditions.checkNotNull(databaseName); Preconditions.checkNotNull(queryExpression); Preconditions.checkNotNull(searchSpecBundle); + Preconditions.checkNotNull(callback); int callingUid = Binder.getCallingUidOrThrow(); int callingUserId = UserHandle.getUserId(callingUid); final long callingIdentity = Binder.clearCallingIdentity(); @@ -247,6 +307,7 @@ public class AppSearchManagerService extends SystemService { @Override public void initialize(@NonNull IAppSearchResultCallback callback) { + Preconditions.checkNotNull(callback); int callingUid = Binder.getCallingUidOrThrow(); int callingUserId = UserHandle.getUserId(callingUid); final long callingIdentity = Binder.clearCallingIdentity(); diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS index a61babf32e58..4e4e11988b62 100644 --- a/cmds/statsd/OWNERS +++ b/cmds/statsd/OWNERS @@ -1,9 +1 @@ -jeffreyhuang@google.com -joeo@google.com -jtnguyen@google.com -muhammadq@google.com -ruchirr@google.com -singhtejinder@google.com -tsaichristine@google.com -yaochen@google.com -yro@google.com +baligh@google.com diff --git a/core/api/current.txt b/core/api/current.txt index 49ebc385c965..b61bc2fde0e9 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -9098,6 +9098,15 @@ package android.bluetooth { field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppSdpSettings> CREATOR; } + public final class BluetoothLeAudio implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile { + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void close(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) protected void finalize(); + method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice); + method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]); + field public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED"; + } + public final class BluetoothManager { method public android.bluetooth.BluetoothAdapter getAdapter(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int); @@ -45403,6 +45412,7 @@ package android.telephony { } public static final class CarrierConfigManager.Ims { + field public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL = "ims.enable_presence_publish_bool"; field public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL = "ims.ims_single_registration_required_bool"; field public static final String KEY_PREFIX = "ims."; field public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = "ims.wifi_off_deferring_time_millis_int"; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 8ba5a94179ea..a5f2b6ac3af8 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -248,7 +248,9 @@ package android { field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK"; field public static final String WHITELIST_AUTO_REVOKE_PERMISSIONS = "android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS"; field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS"; + field public static final String WIFI_ACCESS_COEX_UNSAFE_CHANNELS = "android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS"; field public static final String WIFI_SET_DEVICE_MOBILITY_STATE = "android.permission.WIFI_SET_DEVICE_MOBILITY_STATE"; + field public static final String WIFI_UPDATE_COEX_UNSAFE_CHANNELS = "android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS"; field public static final String WIFI_UPDATE_USABILITY_STATS_SCORE = "android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"; field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG"; field public static final String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE"; @@ -6504,6 +6506,7 @@ package android.net { field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0 field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb field public static final int TYPE_NONE = -1; // 0xffffffff + field @Deprecated public static final int TYPE_PROXY = 16; // 0x10 field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd } @@ -10829,6 +10832,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean isIccLockEnabled(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isInEmergencySmsMode(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isLteCdmaEvdoGsmWcdmaEnabled(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isMobileDataPolicyEnabled(int); method public boolean isNrDualConnectivityEnabled(); @@ -11525,6 +11529,7 @@ package android.telephony.ims { method public boolean getCallExtraBoolean(String, boolean); method public int getCallExtraInt(String); method public int getCallExtraInt(String, int); + method @Nullable public <T extends android.os.Parcelable> T getCallExtraParcelable(@Nullable String); method public android.os.Bundle getCallExtras(); method public int getCallType(); method public static int getCallTypeFromVideoState(int); @@ -11547,6 +11552,7 @@ package android.telephony.ims { method public void setCallExtra(String, String); method public void setCallExtraBoolean(String, boolean); method public void setCallExtraInt(String, int); + method public void setCallExtraParcelable(@NonNull String, @NonNull android.os.Parcelable); method public void setCallRestrictCause(int); method public void setCallerNumberVerificationStatus(int); method public void setEmergencyCallRouting(int); @@ -11581,6 +11587,7 @@ package android.telephony.ims { field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telephony.ims.extra.CALL_DISCONNECT_CAUSE"; field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telephony.ims.extra.CALL_NETWORK_TYPE"; field @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech"; + field public static final String EXTRA_CALL_SUBJECT = "android.telephony.ims.extra.CALL_SUBJECT"; field public static final String EXTRA_CHILD_NUMBER = "ChildNum"; field public static final String EXTRA_CNA = "cna"; field public static final String EXTRA_CNAP = "cnap"; @@ -11590,8 +11597,11 @@ package android.telephony.ims { field public static final String EXTRA_EMERGENCY_CALL = "e_call"; field public static final String EXTRA_FORWARDED_NUMBER = "android.telephony.ims.extra.FORWARDED_NUMBER"; field public static final String EXTRA_IS_CALL_PULL = "CallPull"; + field public static final String EXTRA_LOCATION = "android.telephony.ims.extra.LOCATION"; field public static final String EXTRA_OI = "oi"; field public static final String EXTRA_OIR = "oir"; + field public static final String EXTRA_PICTURE_URL = "android.telephony.ims.extra.PICTURE_URL"; + field public static final String EXTRA_PRIORITY = "android.telephony.ims.extra.PRIORITY"; field public static final String EXTRA_REMOTE_URI = "remote_uri"; field public static final String EXTRA_USSD = "ussd"; field public static final int OIR_DEFAULT = 0; // 0x0 @@ -11599,6 +11609,8 @@ package android.telephony.ims { field public static final int OIR_PRESENTATION_PAYPHONE = 4; // 0x4 field public static final int OIR_PRESENTATION_RESTRICTED = 1; // 0x1 field public static final int OIR_PRESENTATION_UNKNOWN = 3; // 0x3 + field public static final int PRIORITY_NORMAL = 0; // 0x0 + field public static final int PRIORITY_URGENT = 1; // 0x1 field public static final int SERVICE_TYPE_EMERGENCY = 2; // 0x2 field public static final int SERVICE_TYPE_NONE = 0; // 0x0 field public static final int SERVICE_TYPE_NORMAL = 1; // 0x1 diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 2211807a422b..d9c0c71d44ae 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -85,6 +85,7 @@ import android.database.sqlite.SQLiteDebug.DbStats; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.HardwareRenderer; +import android.graphics.Typeface; import android.hardware.display.DisplayManagerGlobal; import android.inputmethodservice.InputMethodService; import android.media.MediaFrameworkInitializer; @@ -117,6 +118,7 @@ import android.os.Process; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SharedMemory; import android.os.StatsFrameworkInitializer; import android.os.StatsServiceManager; import android.os.StrictMode; @@ -844,6 +846,8 @@ public final class ActivityThread extends ClientTransactionHandler { long[] disabledCompatChanges; + SharedMemory mSerializedSystemFontMap; + @Override public String toString() { return "AppBindData{appInfo=" + appInfo + "}"; @@ -1054,7 +1058,8 @@ public final class ActivityThread extends ClientTransactionHandler { boolean isRestrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map services, Bundle coreSettings, String buildSerial, AutofillOptions autofillOptions, - ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) { + ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges, + SharedMemory serializedSystemFontMap) { if (services != null) { if (false) { // Test code to make sure the app could see the passed-in services. @@ -1103,6 +1108,7 @@ public final class ActivityThread extends ClientTransactionHandler { data.autofillOptions = autofillOptions; data.contentCaptureOptions = contentCaptureOptions; data.disabledCompatChanges = disabledCompatChanges; + data.mSerializedSystemFontMap = serializedSystemFontMap; sendMessage(H.BIND_APPLICATION, data); } @@ -6411,6 +6417,13 @@ public final class ActivityThread extends ClientTransactionHandler { */ LocaleList.setDefault(data.config.getLocales()); + try { + Typeface.setSystemFontMap(data.mSerializedSystemFontMap); + } catch (IOException | ErrnoException e) { + Slog.e(TAG, "Failed to parse serialized system font map"); + Typeface.loadPreinstalledSystemFontMap(); + } + synchronized (mResourcesManager) { /* * Update the system configuration since its preloaded and might not diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index 22ca42eb9cf4..890e957bdff4 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -43,6 +43,7 @@ import android.os.IInterface; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.RemoteCallback; +import android.os.SharedMemory; import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.ReferrerIntent; @@ -75,7 +76,8 @@ oneway interface IApplicationThread { boolean restrictedBackupMode, boolean persistent, in Configuration config, in CompatibilityInfo compatInfo, in Map services, in Bundle coreSettings, in String buildSerial, in AutofillOptions autofillOptions, - in ContentCaptureOptions contentCaptureOptions, in long[] disabledCompatChanges); + in ContentCaptureOptions contentCaptureOptions, in long[] disabledCompatChanges, + in SharedMemory serializedSystemFontMap); void runIsolatedEntryPoint(in String entryPoint, in String[] entryPointArgs); void scheduleExit(); void scheduleServiceArgs(IBinder token, in ParceledListSlice args); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 8e305e0b9784..5eb1922a163c 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -5240,9 +5240,22 @@ public class DevicePolicyManager { } /** - * Called by a device or profile owner, or delegated certificate installer, to install a - * certificate and corresponding private key. All apps within the profile will be able to access - * the certificate and use the private key, given direct user approval. + * This API can be called by the following to install a certificate and corresponding + * private key: + * <ul> + * <li>Device owner</li> + * <li>Profile owner</li> + * <li>Delegated certificate installer</li> + * <li>Credential management app</li> + * </ul> + * All apps within the profile will be able to access the certificate and use the private key, + * given direct user approval. + * + * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app + * can call this API. However, this API sets the key pair as user selectable by default, + * which is not permitted when called by the credential management app. Instead, + * {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)} should be + * called with {@link #INSTALLKEY_SET_USER_SELECTABLE} not set as a flag. * * <p>Access to the installed credentials will not be granted to the caller of this API without * direct user approval. This is for security - should a certificate installer become @@ -5273,10 +5286,23 @@ public class DevicePolicyManager { } /** - * Called by a device or profile owner, or delegated certificate installer, to install a - * certificate chain and corresponding private key for the leaf certificate. All apps within the - * profile will be able to access the certificate chain and use the private key, given direct - * user approval. + * This API can be called by the following to install a certificate chain and corresponding + * private key for the leaf certificate: + * <ul> + * <li>Device owner</li> + * <li>Profile owner</li> + * <li>Delegated certificate installer</li> + * <li>Credential management app</li> + * </ul> + * All apps within the profile will be able to access the certificate chain and use the private + * key, given direct user approval. + * + * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app + * can call this API. However, this API sets the key pair as user selectable by default, + * which is not permitted when called by the credential management app. Instead, + * {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)} should be + * called with {@link #INSTALLKEY_SET_USER_SELECTABLE} not set as a flag. + * Note, there can only be a credential management app on an unmanaged device. * * <p>The caller of this API may grant itself access to the certificate and private key * immediately, without user approval. It is a best practice not to request this unless strictly @@ -5314,10 +5340,26 @@ public class DevicePolicyManager { } /** - * Called by a device or profile owner, or delegated certificate installer, to install a - * certificate chain and corresponding private key for the leaf certificate. All apps within the - * profile will be able to access the certificate chain and use the private key, given direct - * user approval (if the user is allowed to select the private key). + * This API can be called by the following to install a certificate chain and corresponding + * private key for the leaf certificate: + * <ul> + * <li>Device owner</li> + * <li>Profile owner</li> + * <li>Delegated certificate installer</li> + * <li>Credential management app</li> + * </ul> + * All apps within the profile will be able to access the certificate chain and use the + * private key, given direct user approval (if the user is allowed to select the private key). + * + * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app + * can call this API. If called by the credential management app: + * <ul> + * <li>The componentName must be {@code null}r</li> + * <li>The alias must exist in the credential management app's + * {@link android.security.AppUriAuthenticationPolicy}</li> + * <li>The key pair must not be user selectable</li> + * </ul> + * Note, there can only be a credential management app on an unmanaged device. * * <p>The caller of this API may grant itself access to the certificate and private key * immediately, without user approval. It is a best practice not to request this unless strictly @@ -5343,7 +5385,8 @@ public class DevicePolicyManager { * {@link #INSTALLKEY_REQUEST_CREDENTIALS_ACCESS}. * @return {@code true} if the keys were installed, {@code false} otherwise. * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile - * owner. + * owner, or {@code admin} is null but the calling application is not a delegated + * certificate installer or credential management app. * @see android.security.KeyChain#getCertificateChain * @see #setDelegatedScopes * @see #DELEGATION_CERT_INSTALL @@ -5376,15 +5419,26 @@ public class DevicePolicyManager { } /** - * Called by a device or profile owner, or delegated certificate installer, to remove a - * certificate and private key pair installed under a given alias. + * This API can be called by the following to remove a certificate and private key pair + * installed under a given alias: + * <ul> + * <li>Device owner</li> + * <li>Profile owner</li> + * <li>Delegated certificate installer</li> + * <li>Credential management app</li> + * </ul> + * + * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app + * can call this API. If called by the credential management app, the componentName must be + * {@code null}. Note, there can only be a credential management app on an unmanaged device. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or * {@code null} if calling from a delegated certificate installer. * @param alias The private key alias under which the certificate is installed. * @return {@code true} if the private key alias no longer exists, {@code false} otherwise. * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile - * owner. + * owner, or {@code admin} is null but the calling application is not a delegated + * certificate installer or credential management app. * @see #setDelegatedScopes * @see #DELEGATION_CERT_INSTALL */ @@ -5419,10 +5473,20 @@ public class DevicePolicyManager { } /** - * Called by a device or profile owner, or delegated certificate installer, to generate a - * new private/public key pair. If the device supports key generation via secure hardware, - * this method is useful for creating a key in KeyChain that never left the secure hardware. - * Access to the key is controlled the same way as in {@link #installKeyPair}. + * This API can be called by the following to generate a new private/public key pair: + * <ul> + * <li>Device owner</li> + * <li>Profile owner</li> + * <li>Delegated certificate installer</li> + * <li>Credential management app</li> + * </ul> + * If the device supports key generation via secure hardware, this method is useful for + * creating a key in KeyChain that never left the secure hardware. Access to the key is + * controlled the same way as in {@link #installKeyPair}. + * + * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app + * can call this API. If called by the credential management app, the componentName must be + * {@code null}. Note, there can only be a credential management app on an unmanaged device. * * <p>Because this method might take several seconds to complete, it should only be called from * a worker thread. This method returns {@code null} when called from the main thread. @@ -5445,9 +5509,10 @@ public class DevicePolicyManager { * supports these features, refer to {@link #isDeviceIdAttestationSupported()} and * {@link #isUniqueDeviceAttestationSupported()}. * - * <p>Device owner, profile owner and their delegated certificate installer can use - * {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device information - * including manufacturer, model, brand, device and product in the attestation record. + * <p>Device owner, profile owner, their delegated certificate installer and the credential + * management app can use {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device + * information including manufacturer, model, brand, device and product in the attestation + * record. * Only device owner, profile owner on an organization-owned device and their delegated * certificate installers can use {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and * {@link #ID_TYPE_MEID} to request unique device identifiers to be attested (the serial number, @@ -5482,9 +5547,11 @@ public class DevicePolicyManager { * {@code keySpec}. * @return A non-null {@code AttestedKeyPair} if the key generation succeeded, null otherwise. * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile - * owner. If Device ID attestation is requested (using {@link #ID_TYPE_SERIAL}, - * {@link #ID_TYPE_IMEI} or {@link #ID_TYPE_MEID}), the caller must be the Device Owner - * or the Certificate Installer delegate. + * owner, or {@code admin} is null but the calling application is not a delegated + * certificate installer or credential management app. If Device ID attestation is + * requested (using {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} or + * {@link #ID_TYPE_MEID}), the caller must be the Device Owner or the Certificate + * Installer delegate. * @throws IllegalArgumentException in the following cases: * <p> * <ul> @@ -5647,10 +5714,19 @@ public class DevicePolicyManager { } /** - * Called by a device or profile owner, or delegated certificate installer, to associate - * certificates with a key pair that was generated using {@link #generateKeyPair}, and - * set whether the key is available for the user to choose in the certificate selection - * prompt. + * This API can be called by the following to associate certificates with a key pair that was + * generated using {@link #generateKeyPair}, and set whether the key is available for the user + * to choose in the certificate selection prompt: + * <ul> + * <li>Device owner</li> + * <li>Profile owner</li> + * <li>Delegated certificate installer</li> + * <li>Credential management app</li> + * </ul> + * + * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app + * can call this API. If called by the credential management app, the componentName must be + * {@code null}. Note, there can only be a credential management app on an unmanaged device. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or * {@code null} if calling from a delegated certificate installer. @@ -5668,7 +5744,7 @@ public class DevicePolicyManager { * successfully associated with it, {@code false} otherwise. * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile * owner, or {@code admin} is null but the calling application is not a delegated - * certificate installer. + * certificate installer or credential management app. */ public boolean setKeyPairCertificate(@Nullable ComponentName admin, @NonNull String alias, @NonNull List<Certificate> certs, boolean isUserSelectable) { diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java new file mode 100644 index 000000000000..3f00fa6f4181 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothLeAudio.java @@ -0,0 +1,451 @@ +/* + * Copyright 2020 HIMSA II K/S - www.himsa.com. + * Represented by EHIMA - www.ehima.com + * + * 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.bluetooth; + +import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.CloseGuard; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class provides the public APIs to control the LeAudio profile. + * + * <p>BluetoothLeAudio is a proxy object for controlling the Bluetooth LE Audio + * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get + * the BluetoothLeAudio proxy object. + * + * <p> Android only supports one set of connected Bluetooth LeAudio device at a time. Each + * method is protected with its appropriate permission. + */ +public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { + private static final String TAG = "BluetoothLeAudio"; + private static final boolean DBG = false; + private static final boolean VDBG = false; + + private CloseGuard mCloseGuard; + + /** + * Intent used to broadcast the change in connection state of the LeAudio + * profile. Please note that in the binaural case, there will be two different LE devices for + * the left and right side and each device will have their own connection state changes. + * + * <p>This intent will have 3 extras: + * <ul> + * <li> {@link #EXTRA_STATE} - The current state of the profile. </li> + * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li> + * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> + * </ul> + * + * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of + * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, + * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to + * receive. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = + "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED"; + + /** + * Intent used to broadcast the selection of a connected device as active. + * + * <p>This intent will have one extra: + * <ul> + * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can + * be null if no device is active. </li> + * </ul> + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to + * receive. + * + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED = + "android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED"; + + /** + * This represents an invalid group ID. + * + * @hide + */ + public static final int GROUP_ID_INVALID = IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID; + + private BluetoothAdapter mAdapter; + private final BluetoothProfileConnector<IBluetoothLeAudio> mProfileConnector = + new BluetoothProfileConnector(this, BluetoothProfile.LE_AUDIO, "BluetoothLeAudio", + IBluetoothLeAudio.class.getName()) { + @Override + public IBluetoothLeAudio getServiceInterface(IBinder service) { + return IBluetoothLeAudio.Stub.asInterface(Binder.allowBlocking(service)); + } + }; + + /** + * Create a BluetoothLeAudio proxy object for interacting with the local + * Bluetooth LeAudio service. + */ + /*package*/ BluetoothLeAudio(Context context, ServiceListener listener) { + mAdapter = BluetoothAdapter.getDefaultAdapter(); + mProfileConnector.connect(context, listener); + mCloseGuard = new CloseGuard(); + mCloseGuard.open("close"); + } + + /** + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public void close() { + mProfileConnector.disconnect(); + } + + private IBluetoothLeAudio getService() { + return mProfileConnector.getService(); + } + + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + protected void finalize() { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + close(); + } + + /** + * Initiate connection to a profile of the remote bluetooth device. + * + * <p> This API returns false in scenarios like the profile on the + * device is already connected or Bluetooth is not turned on. + * When this API returns true, it is guaranteed that + * connection state intent for the profile will be broadcasted with + * the state. Users can get the connection state of the profile + * from this intent. + * + * + * @param device Remote Bluetooth Device + * @return false on immediate error, true otherwise + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean connect(@Nullable BluetoothDevice device) { + if (DBG) log("connect(" + device + ")"); + try { + final IBluetoothLeAudio service = getService(); + if (service != null && mAdapter.isEnabled() && isValidDevice(device)) { + return service.connect(device); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + + /** + * Initiate disconnection from a profile + * + * <p> This API will return false in scenarios like the profile on the + * Bluetooth device is not in connected state etc. When this API returns, + * true, it is guaranteed that the connection state change + * intent will be broadcasted with the state. Users can get the + * disconnection state of the profile from this intent. + * + * <p> If the disconnection is initiated by a remote device, the state + * will transition from {@link #STATE_CONNECTED} to + * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the + * host (local) device the state will transition from + * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to + * state {@link #STATE_DISCONNECTED}. The transition to + * {@link #STATE_DISCONNECTING} can be used to distinguish between the + * two scenarios. + * + * + * @param device Remote Bluetooth Device + * @return false on immediate error, true otherwise + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean disconnect(@Nullable BluetoothDevice device) { + if (DBG) log("disconnect(" + device + ")"); + try { + final IBluetoothLeAudio service = getService(); + if (service != null && mAdapter.isEnabled() && isValidDevice(device)) { + return service.disconnect(device); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + + /** + * {@inheritDoc} + */ + @Override + public @NonNull List<BluetoothDevice> getConnectedDevices() { + if (VDBG) log("getConnectedDevices()"); + try { + final IBluetoothLeAudio service = getService(); + if (service != null && mAdapter.isEnabled()) { + return service.getConnectedDevices(); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates( + @NonNull int[] states) { + if (VDBG) log("getDevicesMatchingStates()"); + try { + final IBluetoothLeAudio service = getService(); + if (service != null && mAdapter.isEnabled()) { + return service.getDevicesMatchingConnectionStates(states); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } + } + + /** + * {@inheritDoc} + */ + @Override + @RequiresPermission(Manifest.permission.BLUETOOTH) + public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) { + if (VDBG) log("getState(" + device + ")"); + try { + final IBluetoothLeAudio service = getService(); + if (service != null && mAdapter.isEnabled() + && isValidDevice(device)) { + return service.getConnectionState(device); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return BluetoothProfile.STATE_DISCONNECTED; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return BluetoothProfile.STATE_DISCONNECTED; + } + } + + /** + * Select a connected device as active. + * + * The active device selection is per profile. An active device's + * purpose is profile-specific. For example, LeAudio audio + * streaming is to the active LeAudio device. If a remote device + * is not connected, it cannot be selected as active. + * + * <p> This API returns false in scenarios like the profile on the + * device is not connected or Bluetooth is not turned on. + * When this API returns true, it is guaranteed that the + * {@link #ACTION_LEAUDIO_ACTIVE_DEVICE_CHANGED} intent will be broadcasted + * with the active device. + * + * + * @param device the remote Bluetooth device. Could be null to clear + * the active device and stop streaming audio to a Bluetooth device. + * @return false on immediate error, true otherwise + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean setActiveDevice(@Nullable BluetoothDevice device) { + if (DBG) log("setActiveDevice(" + device + ")"); + try { + final IBluetoothLeAudio service = getService(); + if (service != null && mAdapter.isEnabled() + && ((device == null) || isValidDevice(device))) { + service.setActiveDevice(device); + return true; + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + + /** + * Get the connected LeAudio devices that are active + * + * @return the list of active devices. Returns empty list on error. + * @hide + */ + @NonNull + @RequiresPermission(Manifest.permission.BLUETOOTH) + public List<BluetoothDevice> getActiveDevices() { + if (VDBG) log("getActiveDevices()"); + try { + final IBluetoothLeAudio service = getService(); + if (service != null && mAdapter.isEnabled()) { + return service.getActiveDevices(); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<>(); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList<>(); + } + } + + /** + * Get device group id. Devices with same group id belong to same group (i.e left and right + * earbud) + * @param device LE Audio capable device + * @return group id that this device currently belongs to + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public int getGroupId(@NonNull BluetoothDevice device) { + if (VDBG) log("getGroupId()"); + try { + final IBluetoothLeAudio service = getService(); + if (service != null && mAdapter.isEnabled()) { + return service.getGroupId(device); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return GROUP_ID_INVALID; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return GROUP_ID_INVALID; + } + } + + /** + * Set connection policy of the profile + * + * <p> The device should already be paired. + * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, + * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} + * + * @param device Paired bluetooth device + * @param connectionPolicy is the connection policy to set to for this profile + * @return true if connectionPolicy is set, false on error + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean setConnectionPolicy(@NonNull BluetoothDevice device, + @ConnectionPolicy int connectionPolicy) { + if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); + try { + final IBluetoothLeAudio service = getService(); + if (service != null && mAdapter.isEnabled() + && isValidDevice(device)) { + if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + return false; + } + return service.setConnectionPolicy(device, connectionPolicy); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + + /** + * Get the connection policy of the profile. + * + * <p> The connection policy can be any of: + * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, + * {@link #CONNECTION_POLICY_UNKNOWN} + * + * @param device Bluetooth device + * @return connection policy of the device + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) { + if (VDBG) log("getConnectionPolicy(" + device + ")"); + try { + final IBluetoothLeAudio service = getService(); + if (service != null && mAdapter.isEnabled() + && isValidDevice(device)) { + return service.getConnectionPolicy(device); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + } + } + + + /** + * Helper for converting a state to a string. + * + * For debug use only - strings are not internationalized. + * + * @hide + */ + public static String stateToString(int state) { + switch (state) { + case STATE_DISCONNECTED: + return "disconnected"; + case STATE_CONNECTING: + return "connecting"; + case STATE_CONNECTED: + return "connected"; + case STATE_DISCONNECTING: + return "disconnecting"; + default: + return "<unknown state " + state + ">"; + } + } + + private boolean isValidDevice(@Nullable BluetoothDevice device) { + if (device == null) return false; + + if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; + return false; + } + + private static void log(String msg) { + Log.d(TAG, msg); + } +} diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index db851c4f33b9..c31b04e81456 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -207,12 +207,19 @@ public interface BluetoothProfile { int HEARING_AID = 21; /** + * LE Audio Device + * + * @hide + */ + int LE_AUDIO = 22; + + /** * Max profile ID. This value should be updated whenever a new profile is added to match * the largest value assigned to a profile. * * @hide */ - int MAX_PROFILE_ID = 21; + int MAX_PROFILE_ID = 22; /** * Default priority for devices that we try to auto-connect to and diff --git a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java index 3fd20f12381e..c6007f1184f5 100644 --- a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java +++ b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java @@ -513,4 +513,19 @@ public class HdmiDeviceInfo implements Parcelable { && mDeviceId == other.mDeviceId && mAdopterId == other.mAdopterId; } + + @Override + public int hashCode() { + return java.util.Objects.hash( + mHdmiDeviceType, + mPhysicalAddress, + mPortId, + mLogicalAddress, + mDeviceType, + mVendorId, + mDevicePowerStatus, + mDisplayName, + mDeviceId, + mAdopterId); + } } diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java index c2586fa0c825..269bbf20c8b1 100644 --- a/core/java/android/net/CaptivePortal.java +++ b/core/java/android/net/CaptivePortal.java @@ -15,7 +15,6 @@ */ package android.net; -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; @@ -24,8 +23,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; - /** * A class allowing apps handling the {@link ConnectivityManager#ACTION_CAPTIVE_PORTAL_SIGN_IN} * activity to indicate to the system different outcomes of captive portal sign in. This class is @@ -75,17 +72,6 @@ public class CaptivePortal implements Parcelable { private final IBinder mBinder; /** @hide */ - @IntDef(value = { - MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY, - MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_DISMISSED, - MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_UNWANTED, - MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_WANTED_AS_IS, - MetricsEvent.CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR, - }) - public @interface EventId { - } - - /** @hide */ public CaptivePortal(@NonNull IBinder binder) { mBinder = binder; } @@ -176,7 +162,7 @@ public class CaptivePortal implements Parcelable { * @hide */ @SystemApi - public void logEvent(@EventId int eventId, @NonNull String packageName) { + public void logEvent(int eventId, @NonNull String packageName) { try { ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName); } catch (RemoteException e) { diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 4b38d6377f37..3f2c966f9ed2 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -684,7 +684,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage + @SystemApi public static final int TYPE_PROXY = 16; /** diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index d130bc5d37e7..b951aca6d680 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -67,7 +67,7 @@ public final class PowerManager { /* NOTE: Wake lock levels were previously defined as a bit field, except that only a few * combinations were actually supported so the bit field was removed. This explains * why the numbering scheme is so odd. If adding a new wake lock level, any unused - * value (in frameworks/base/core/proto/android/os/enums.proto) can be used. + * value (in frameworks/proto_logging/stats/enums/os/enums.proto) can be used. */ /** diff --git a/core/java/android/service/autofill/TEST_MAPPING b/core/java/android/service/autofill/TEST_MAPPING new file mode 100644 index 000000000000..87a17ebee36d --- /dev/null +++ b/core/java/android/service/autofill/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "imports": [ + { + "path": "frameworks/base/services/autofill/java/com/android/server/autofill" + } + ] +} diff --git a/core/java/android/view/autofill/TEST_MAPPING b/core/java/android/view/autofill/TEST_MAPPING new file mode 100644 index 000000000000..87a17ebee36d --- /dev/null +++ b/core/java/android/view/autofill/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "imports": [ + { + "path": "frameworks/base/services/autofill/java/com/android/server/autofill" + } + ] +} diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index dde9c3089370..b91e7d39f51c 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -251,15 +251,8 @@ public final class WebViewFactory { Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()"); try { Class<WebViewFactoryProvider> providerClass = getProviderClass(); - Method staticFactory = null; - try { - staticFactory = providerClass.getMethod( + Method staticFactory = providerClass.getMethod( CHROMIUM_WEBVIEW_FACTORY_METHOD, WebViewDelegate.class); - } catch (Exception e) { - if (DEBUG) { - Log.w(LOGTAG, "error instantiating provider with static factory method", e); - } - } Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactoryProvider invocation"); try { @@ -267,12 +260,12 @@ public final class WebViewFactory { staticFactory.invoke(null, new WebViewDelegate()); if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance); return sProviderInstance; - } catch (Exception e) { - Log.e(LOGTAG, "error instantiating provider", e); - throw new AndroidRuntimeException(e); } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); } + } catch (Exception e) { + Log.e(LOGTAG, "error instantiating provider", e); + throw new AndroidRuntimeException(e); } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 2357f368c428..02a930017906 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -964,6 +964,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @hide */ public static void preloadFontCache() { + if (Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) { + return; + } Paint p = new Paint(); p.setAntiAlias(true); // Ensure that the Typeface is loaded here. diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 5a6905699535..60dd0eb8a780 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1815,6 +1815,16 @@ <permission android:name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi @hide Allows system APK to update Wifi/Cellular coex channels to avoid. + <p>Not for use by third-party applications. --> + <permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" + android:protectionLevel="signature" /> + + <!-- @SystemApi @hide Allows applications to access Wifi/Cellular coex channels being avoided. + <p>Not for use by third-party applications. --> + <permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" + android:protectionLevel="signature|privileged" /> + <!-- ======================================= --> <!-- Permissions for short range, peripheral networks --> <!-- ======================================= --> diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index 5871e2e04687..7e992989426d 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -52,6 +52,7 @@ import android.os.Parcelable; import android.os.PersistableBundle; import android.os.RemoteCallback; import android.os.RemoteException; +import android.os.SharedMemory; import android.platform.test.annotations.Presubmit; import android.view.DisplayAdjustments.FixedRotationAdjustments; import android.view.DisplayCutout; @@ -440,7 +441,8 @@ public class TransactionParcelTests { IUiAutomationConnection iUiAutomationConnection, int i, boolean b, boolean b1, boolean b2, boolean b3, Configuration configuration, CompatibilityInfo compatibilityInfo, Map map, Bundle bundle1, String s1, - AutofillOptions ao, ContentCaptureOptions co, long[] disableCompatChanges) + AutofillOptions ao, ContentCaptureOptions co, long[] disableCompatChanges, + SharedMemory serializedSystemFontMap) throws RemoteException { } diff --git a/core/tests/hdmitests/Android.bp b/core/tests/hdmitests/Android.bp index 2194d4b030ce..4755e0ea5259 100644 --- a/core/tests/hdmitests/Android.bp +++ b/core/tests/hdmitests/Android.bp @@ -19,6 +19,7 @@ android_test { static_libs: [ "androidx.test.rules", "frameworks-base-testutils", + "guava-android-testlib", "truth-prebuilt", ], libs: ["android.test.runner"], diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java new file mode 100755 index 000000000000..4c0de629c464 --- /dev/null +++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.hdmi; + +import androidx.test.filters.SmallTest; + +import com.google.common.testing.EqualsTester; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link HdmiDeviceInfo} */ +@RunWith(JUnit4.class) +@SmallTest +public class HdmiDeviceInfoTest { + + @Test + public void testEquals() { + int logicalAddr = 0x00; + int phyAddr = 0x1000; + int portId = 1; + int deviceType = 0; + int vendorId = 0x123456; + String displayName = "test device"; + int powerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; + int deviceId = 3; + int adopterId = 2; + + new EqualsTester() + .addEqualityGroup(new HdmiDeviceInfo()) + .addEqualityGroup( + new HdmiDeviceInfo(phyAddr, portId), new HdmiDeviceInfo(phyAddr, portId)) + .addEqualityGroup( + new HdmiDeviceInfo(phyAddr, portId, adopterId, deviceId), + new HdmiDeviceInfo(phyAddr, portId, adopterId, deviceId)) + .addEqualityGroup( + new HdmiDeviceInfo( + logicalAddr, phyAddr, portId, deviceType, vendorId, displayName), + new HdmiDeviceInfo( + logicalAddr, phyAddr, portId, deviceType, vendorId, displayName)) + .addEqualityGroup( + new HdmiDeviceInfo( + logicalAddr, + phyAddr, + portId, + deviceType, + vendorId, + displayName, + powerStatus), + new HdmiDeviceInfo( + logicalAddr, + phyAddr, + portId, + deviceType, + vendorId, + displayName, + powerStatus)) + .testEquals(); + } +} diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 36ef0a48fa20..24987daf87b5 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -81,6 +81,9 @@ public class Typeface { private static String TAG = "Typeface"; + /** @hide */ + public static final boolean ENABLE_LAZY_TYPEFACE_INITIALIZATION = false; + private static final NativeAllocationRegistry sRegistry = NativeAllocationRegistry.createMalloced( Typeface.class.getClassLoader(), nativeGetReleaseFunc()); @@ -1329,7 +1332,9 @@ public class Typeface { } static { - loadPreinstalledSystemFontMap(); + if (!ENABLE_LAZY_TYPEFACE_INITIALIZATION) { + loadPreinstalledSystemFontMap(); + } } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java index f199072f7bca..d3032f83fc1c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java @@ -136,13 +136,6 @@ class AppPair implements ShellTaskOrganizer.TaskListener { mAppPairLayout = null; } - void setVisible(boolean visible) { - if (mAppPairLayout == null) { - return; - } - mAppPairLayout.setDividerVisibility(visible); - } - @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { if (mRootTaskInfo == null || taskInfo.taskId == mRootTaskInfo.taskId) { @@ -160,32 +153,41 @@ class AppPair implements ShellTaskOrganizer.TaskListener { if (mTaskLeash1 == null || mTaskLeash2 == null) return; - setVisible(true); + mAppPairLayout.init(); final SurfaceControl dividerLeash = mAppPairLayout.getDividerLeash(); final Rect dividerBounds = mAppPairLayout.getDividerBounds(); // TODO: Is there more we need to do here? - mSyncQueue.runInSync(t -> t - .setPosition(mTaskLeash1, mTaskInfo1.positionInParent.x, - mTaskInfo1.positionInParent.y) - .setPosition(mTaskLeash2, mTaskInfo2.positionInParent.x, - mTaskInfo2.positionInParent.y) - .setLayer(dividerLeash, Integer.MAX_VALUE) - .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top) - .show(mRootTaskLeash) - .show(dividerLeash) - .show(mTaskLeash1) - .show(mTaskLeash2)); + mSyncQueue.runInSync(t -> { + t.setPosition(mTaskLeash1, mTaskInfo1.positionInParent.x, + mTaskInfo1.positionInParent.y) + .setPosition(mTaskLeash2, mTaskInfo2.positionInParent.x, + mTaskInfo2.positionInParent.y) + .setLayer(dividerLeash, Integer.MAX_VALUE) + .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top) + .show(mRootTaskLeash) + .show(mTaskLeash1) + .show(mTaskLeash2); + }); } @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { if (taskInfo.taskId == getRootTaskId()) { + if (mRootTaskInfo.isVisible != taskInfo.isVisible) { + mSyncQueue.runInSync(t -> { + if (taskInfo.isVisible) { + t.show(mRootTaskLeash); + } else { + t.hide(mRootTaskLeash); + } + }); + } mRootTaskInfo = taskInfo; if (mAppPairLayout != null && mAppPairLayout.updateConfiguration(mRootTaskInfo.configuration)) { - // Update bounds when there is root bounds or orientation changed. + // Update bounds when root bounds or its orientation changed. final WindowContainerTransaction wct = new WindowContainerTransaction(); final SurfaceControl dividerLeash = mAppPairLayout.getDividerLeash(); final Rect dividerBounds = mAppPairLayout.getDividerBounds(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java index f8703f7ec0bc..8c8655e1ff1f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java @@ -16,7 +16,6 @@ package com.android.wm.shell.apppairs; -import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY; @@ -45,21 +44,18 @@ import com.android.wm.shell.R; /** * Records and handles layout of a pair of apps. */ -// TODO(172704238): add tests final class AppPairLayout { private static final String DIVIDER_WINDOW_TITLE = "AppPairDivider"; - private final Context mContext; - private final AppPairWindowManager mAppPairWindowManager; - private final SurfaceControlViewHost mViewHost; - + private final Display mDisplay; private final int mDividerWindowWidth; private final int mDividerWindowInsets; + private final AppPairWindowManager mAppPairWindowManager; - private boolean mIsLandscape; + private Context mContext; private Rect mRootBounds; private DIVIDE_POLICY mDividePolicy; - private DividerView mDividerView; + private SurfaceControlViewHost mViewHost; private SurfaceControl mDividerLeash; AppPairLayout( @@ -68,7 +64,7 @@ final class AppPairLayout { Configuration configuration, SurfaceControl rootLeash) { mContext = context.createConfigurationContext(configuration); - mIsLandscape = isLandscape(configuration); + mDisplay = display; mRootBounds = configuration.windowConfiguration.getBounds(); mDividerWindowWidth = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.docked_stack_divider_thickness); @@ -76,26 +72,22 @@ final class AppPairLayout { com.android.internal.R.dimen.docked_stack_divider_insets); mAppPairWindowManager = new AppPairWindowManager(configuration, rootLeash); - mViewHost = new SurfaceControlViewHost(mContext, display, mAppPairWindowManager); mDividePolicy = DIVIDE_POLICY.MIDDLE; - mDividePolicy.update(mIsLandscape, mRootBounds, mDividerWindowWidth, mDividerWindowInsets); + mDividePolicy.update(mRootBounds, mDividerWindowWidth, mDividerWindowInsets); } boolean updateConfiguration(Configuration configuration) { mAppPairWindowManager.setConfiguration(configuration); final Rect rootBounds = configuration.windowConfiguration.getBounds(); - final boolean isLandscape = isLandscape(configuration); - if (mIsLandscape == isLandscape && isIdenticalBounds(mRootBounds, rootBounds)) { + if (isIdenticalBounds(mRootBounds, rootBounds)) { return false; } - mIsLandscape = isLandscape; + mContext = mContext.createConfigurationContext(configuration); mRootBounds = rootBounds; - mDividePolicy.update(mIsLandscape, mRootBounds, mDividerWindowWidth, mDividerWindowInsets); - mViewHost.relayout( - mDividePolicy.mDividerBounds.width(), - mDividePolicy.mDividerBounds.height()); - // TODO(172704238): handle divider bar rotation. + mDividePolicy.update(mRootBounds, mDividerWindowWidth, mDividerWindowInsets); + release(); + init(); return true; } @@ -116,22 +108,19 @@ final class AppPairLayout { } void release() { - if (mViewHost == null) return; + if (mViewHost == null) { + return; + } mViewHost.release(); + mDividerLeash = null; + mViewHost = null; } - void setDividerVisibility(boolean visible) { - if (mDividerView == null) { - initDivider(); - } - if (visible) { - mDividerView.show(); - } else { - mDividerView.hide(); + void init() { + if (mViewHost == null) { + mViewHost = new SurfaceControlViewHost(mContext, mDisplay, mAppPairWindowManager); } - } - private void initDivider() { final DividerView dividerView = (DividerView) LayoutInflater.from(mContext) .inflate(R.layout.split_divider, null); @@ -147,14 +136,9 @@ final class AppPairLayout { lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION; mViewHost.setView(dividerView, lp); - mDividerView = dividerView; mDividerLeash = mAppPairWindowManager.getSurfaceControl(mViewHost.getWindowToken()); } - private static boolean isLandscape(Configuration configuration) { - return configuration.orientation == ORIENTATION_LANDSCAPE; - } - private static boolean isIdenticalBounds(Rect bounds1, Rect bounds2) { return bounds1.left == bounds2.left && bounds1.top == bounds2.top && bounds1.right == bounds2.right && bounds1.bottom == bounds2.bottom; @@ -167,8 +151,7 @@ final class AppPairLayout { enum DIVIDE_POLICY { MIDDLE; - void update(boolean isLandscape, Rect rootBounds, int dividerWindowWidth, - int dividerWindowInsets) { + void update(Rect rootBounds, int dividerWindowWidth, int dividerWindowInsets) { final int dividerOffset = dividerWindowWidth / 2; final int boundsOffset = dividerOffset - dividerWindowInsets; @@ -179,7 +162,7 @@ final class AppPairLayout { switch (this) { case MIDDLE: default: - if (isLandscape) { + if (isLandscape(rootBounds)) { mDividerBounds.left = rootBounds.width() / 2 - dividerOffset; mDividerBounds.right = rootBounds.width() / 2 + dividerOffset; mBounds1.left = rootBounds.width() / 2 + boundsOffset; @@ -193,6 +176,10 @@ final class AppPairLayout { } } + private boolean isLandscape(Rect bounds) { + return bounds.width() > bounds.height(); + } + Rect mDividerBounds; Rect mBounds1; Rect mBounds2; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java index af06764145e3..ef3e3e0220e7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java @@ -36,6 +36,4 @@ public interface AppPairs { void dump(@NonNull PrintWriter pw, String prefix); /** Called when the shell organizer has been registered. */ void onOrganizerRegistered(); - /** Called when the visibility of the keyguard changes. */ - void onKeyguardVisibilityChanged(boolean showing); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java index 925a4f36d5e6..f2f09820639a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java @@ -16,8 +16,6 @@ package com.android.wm.shell.apppairs; -import static android.app.ActivityTaskManager.INVALID_TASK_ID; - import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG; import android.app.ActivityManager; @@ -30,15 +28,13 @@ import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.common.TaskStackListenerCallback; -import com.android.wm.shell.common.TaskStackListenerImpl; import java.io.PrintWriter; /** * Class manages app-pairs multitasking mode and implements the main interface {@link AppPairs}. */ -public class AppPairsController implements AppPairs, TaskStackListenerCallback { +public class AppPairsController implements AppPairs { private static final String TAG = AppPairsController.class.getSimpleName(); private final ShellTaskOrganizer mTaskOrganizer; @@ -48,14 +44,12 @@ public class AppPairsController implements AppPairs, TaskStackListenerCallback { // Active app-pairs mapped by root task id key. private final SparseArray<AppPair> mActiveAppPairs = new SparseArray<>(); private final DisplayController mDisplayController; - private int mForegroundTaskId = INVALID_TASK_ID; public AppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue, - DisplayController displayController, TaskStackListenerImpl taskStackListener) { + DisplayController displayController) { mTaskOrganizer = organizer; mSyncQueue = syncQueue; mDisplayController = displayController; - taskStackListener.addListener(this); } @Override @@ -71,27 +65,6 @@ public class AppPairsController implements AppPairs, TaskStackListenerCallback { } @Override - public void onTaskMovedToFront(int taskId) { - mForegroundTaskId = INVALID_TASK_ID; - for (int i = mActiveAppPairs.size() - 1; i >= 0; --i) { - final AppPair candidate = mActiveAppPairs.valueAt(i); - final boolean containForegroundTask = candidate.contains(taskId); - candidate.setVisible(containForegroundTask); - if (containForegroundTask) { - mForegroundTaskId = candidate.getRootTaskId(); - } - } - } - - @Override - public void onKeyguardVisibilityChanged(boolean showing) { - if (mForegroundTaskId == INVALID_TASK_ID) { - return; - } - mActiveAppPairs.get(mForegroundTaskId).setVisible(!showing); - } - - @Override public boolean pair(int taskId1, int taskId2) { final ActivityManager.RunningTaskInfo task1 = mTaskOrganizer.getRunningTaskInfo(taskId1); final ActivityManager.RunningTaskInfo task2 = mTaskOrganizer.getRunningTaskInfo(taskId2); diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt index 1e328a8dae40..c85561d96091 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt @@ -17,7 +17,7 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Presubmit -import androidx.test.filters.FlakyTest +import android.view.Surface import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER @@ -54,7 +54,6 @@ import org.junit.runners.Parameterized @RequiresDevice @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@FlakyTest(bugId = 161435597) class OpenAppToSplitScreenTest( testName: String, flickerSpec: Flicker @@ -67,7 +66,8 @@ class OpenAppToSplitScreenTest( val testApp = StandardAppHelper(instrumentation, "com.android.wm.shell.flicker.testapp", "SimpleApp") - return FlickerTestRunnerFactory(instrumentation) + // b/161435597 causes the test not to work on 90 degrees + return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0)) .buildTest { configuration -> withTestName { buildTestTag("appToSplitScreen", testApp, configuration) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateOneLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateOneLaunchedAppTest.kt new file mode 100644 index 000000000000..d2371bd766f5 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateOneLaunchedAppTest.kt @@ -0,0 +1,95 @@ +/* + * 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.splitscreen + +import androidx.test.filters.FlakyTest +import android.view.Surface +import androidx.test.filters.RequiresDevice +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.Flicker +import com.android.server.wm.flicker.FlickerTestRunner +import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.helpers.StandardAppHelper +import com.android.server.wm.flicker.startRotation +import com.android.server.wm.flicker.endRotation +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.setRotation +import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.server.wm.flicker.repetitions +import org.junit.FixMethodOrder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test open app to split screen. + * To run this test: `atest WMShellFlickerTests:SplitScreenRotateOneLaunchedAppTest` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@FlakyTest +class SplitScreenRotateOneLaunchedAppTest( + testName: String, + flickerSpec: Flicker +) : FlickerTestRunner(testName, flickerSpec) { + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<Array<Any>> { + val instrumentation = InstrumentationRegistry.getInstrumentation() + val testApp = StandardAppHelper(instrumentation, + "com.android.wm.shell.flicker.testapp", "SimpleApp") + + return FlickerTestRunnerFactory(instrumentation, repetitions = 3) + .buildTest { configuration -> + withTestName { + buildTestTag("splitScreenRotateOneApp", testApp, configuration) + } + repeat { configuration.repetitions } + setup { + test { + device.wakeUpAndGoToHomeScreen() + testApp.open() + device.launchSplitScreen() + device.waitForIdle() + } + eachRun { + this.setRotation(configuration.startRotation) + } + } + teardown { + eachRun { + setRotation(Surface.ROTATION_0) + } + test { + testApp.exit() + if (device.isInSplitScreen()) { + device.exitSplitScreen() + } + } + } + transitions { + this.setRotation(configuration.endRotation) + } + } + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateTwoLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateTwoLaunchedAppTest.kt new file mode 100644 index 000000000000..67346424acd2 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateTwoLaunchedAppTest.kt @@ -0,0 +1,104 @@ +/* + * 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.splitscreen + +import androidx.test.filters.FlakyTest +import android.view.Surface +import androidx.test.filters.RequiresDevice +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.Flicker +import com.android.server.wm.flicker.FlickerTestRunner +import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.helpers.StandardAppHelper +import com.android.server.wm.flicker.startRotation +import com.android.server.wm.flicker.endRotation +import com.android.server.wm.flicker.helpers.buildTestTag +import com.android.server.wm.flicker.helpers.exitSplitScreen +import com.android.server.wm.flicker.helpers.reopenAppFromOverview +import com.android.server.wm.flicker.helpers.isInSplitScreen +import com.android.server.wm.flicker.helpers.launchSplitScreen +import com.android.server.wm.flicker.helpers.setRotation +import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.server.wm.flicker.repetitions +import org.junit.FixMethodOrder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test open app to split screen. + * To run this test: `atest WMShellFlickerTests:SplitScreenRotateTwoLaunchedAppTest` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@FlakyTest +class SplitScreenRotateTwoLaunchedAppTest( + testName: String, + flickerSpec: Flicker +) : FlickerTestRunner(testName, flickerSpec) { + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<Array<Any>> { + val instrumentation = InstrumentationRegistry.getInstrumentation() + val testApp = StandardAppHelper(instrumentation, + "com.android.wm.shell.flicker.testapp", "SimpleApp") + val secondaryApp = StandardAppHelper(instrumentation, + "com.android.wm.shell.flicker.testapp", + "SplitScreenSecondaryApp") + + return FlickerTestRunnerFactory(instrumentation, repetitions = 3) + .buildTest { configuration -> + withTestName { + buildTestTag("splitScreenRotateTwoApps", testApp, configuration) + } + repeat { configuration.repetitions } + setup { + test { + device.wakeUpAndGoToHomeScreen() + testApp.open() + device.pressHome() + secondaryApp.open() + device.pressHome() + device.launchSplitScreen() + device.reopenAppFromOverview() + device.waitForIdle() + } + eachRun { + this.setRotation(configuration.startRotation) + } + } + teardown { + eachRun { + setRotation(Surface.ROTATION_0) + } + test { + testApp.exit() + secondaryApp.exit() + if (device.isInSplitScreen()) { + device.exitSplitScreen() + } + } + } + transitions { + this.setRotation(configuration.endRotation) + } + } + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java new file mode 100644 index 000000000000..c9d32c4b1f76 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java @@ -0,0 +1,89 @@ +/* + * 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.apppairs; + +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.res.Configuration; +import android.graphics.Rect; +import android.view.Display; +import android.view.SurfaceControl; + +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.wm.shell.ShellTestCase; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** Tests for {@link AppPairLayout} */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class AppPairLayoutTests extends ShellTestCase { + @Mock SurfaceControl mSurfaceControl; + private Display mDisplay; + private Configuration mConfiguration; + private AppPairLayout mAppPairLayout; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mConfiguration = getConfiguration(false); + mDisplay = mContext.getDisplay(); + mAppPairLayout = new AppPairLayout(mContext, mDisplay, mConfiguration, mSurfaceControl); + } + + @After + @UiThreadTest + public void tearDown() { + mAppPairLayout.release(); + } + + @Test + @UiThreadTest + public void testUpdateConfiguration() { + assertThat(mAppPairLayout.updateConfiguration(getConfiguration(false))).isFalse(); + assertThat(mAppPairLayout.updateConfiguration(getConfiguration(true))).isTrue(); + } + + @Test + @UiThreadTest + public void testInitRelease() { + mAppPairLayout.init(); + assertThat(mAppPairLayout.getDividerLeash()).isNotNull(); + mAppPairLayout.release(); + assertThat(mAppPairLayout.getDividerLeash()).isNull(); + } + + private static Configuration getConfiguration(boolean isLandscape) { + final Configuration configuration = new Configuration(); + configuration.unset(); + configuration.orientation = isLandscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT; + configuration.windowConfiguration.setBounds( + new Rect(0, 0, isLandscape ? 2160 : 1080, isLandscape ? 1080 : 2160)); + return configuration; + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java index 754f73246c86..f12648a7f709 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java @@ -34,7 +34,6 @@ import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.common.TaskStackListenerImpl; import org.junit.After; import org.junit.Before; @@ -52,7 +51,6 @@ public class AppPairTests extends ShellTestCase { @Mock private SyncTransactionQueue mSyncQueue; @Mock private ShellTaskOrganizer mTaskOrganizer; @Mock private DisplayController mDisplayController; - @Mock private TaskStackListenerImpl mTaskStackListener; @Before public void setUp() { @@ -60,8 +58,7 @@ public class AppPairTests extends ShellTestCase { mController = new TestAppPairsController( mTaskOrganizer, mSyncQueue, - mDisplayController, - mTaskStackListener); + mDisplayController); when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext); when(mDisplayController.getDisplay(anyInt())).thenReturn( mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY)); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java index 6d441ab898ec..f8c68d2018da 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java @@ -34,7 +34,6 @@ import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.common.TaskStackListenerImpl; import org.junit.After; import org.junit.Before; @@ -52,7 +51,6 @@ public class AppPairsControllerTests extends ShellTestCase { @Mock private SyncTransactionQueue mSyncQueue; @Mock private ShellTaskOrganizer mTaskOrganizer; @Mock private DisplayController mDisplayController; - @Mock private TaskStackListenerImpl mTaskStackListener; @Before public void setUp() { @@ -60,8 +58,7 @@ public class AppPairsControllerTests extends ShellTestCase { mController = new TestAppPairsController( mTaskOrganizer, mSyncQueue, - mDisplayController, - mTaskStackListener); + mDisplayController); mPool = mController.getPool(); when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext); when(mDisplayController.getDisplay(anyInt())).thenReturn( diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java index d3dbbfe37985..8ece913de53f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java @@ -24,7 +24,6 @@ import androidx.test.filters.SmallTest; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.common.TaskStackListenerImpl; import org.junit.After; import org.junit.Before; @@ -42,7 +41,6 @@ public class AppPairsPoolTests { @Mock private SyncTransactionQueue mSyncQueue; @Mock private ShellTaskOrganizer mTaskOrganizer; @Mock private DisplayController mDisplayController; - @Mock private TaskStackListenerImpl mTaskStackListener; @Before public void setUp() { @@ -50,8 +48,7 @@ public class AppPairsPoolTests { mController = new TestAppPairsController( mTaskOrganizer, mSyncQueue, - mDisplayController, - mTaskStackListener); + mDisplayController); mPool = mController.getPool(); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java index e61cc91c394b..be0963628933 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java @@ -19,14 +19,13 @@ package com.android.wm.shell.apppairs; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.common.TaskStackListenerImpl; public class TestAppPairsController extends AppPairsController { TestAppPairsPool mPool; public TestAppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue, - DisplayController displayController, TaskStackListenerImpl taskStackListener) { - super(organizer, syncQueue, displayController, taskStackListener); + DisplayController displayController) { + super(organizer, syncQueue, displayController); mPool = new TestAppPairsPool(this); setPairsPool(mPool); } diff --git a/media/java/android/media/metrics/IPlaybackMetricsManager.aidl b/media/java/android/media/metrics/IPlaybackMetricsManager.aidl index fcb7d608f662..47debe90c854 100644 --- a/media/java/android/media/metrics/IPlaybackMetricsManager.aidl +++ b/media/java/android/media/metrics/IPlaybackMetricsManager.aidl @@ -23,5 +23,6 @@ import android.media.metrics.PlaybackMetrics; * @hide */ interface IPlaybackMetricsManager { - void reportPlaybackMetrics(in PlaybackMetrics metrics, int userId); + void reportPlaybackMetrics(in String sessionId, in PlaybackMetrics metrics, int userId); + String getSessionId(int userId); }
\ No newline at end of file diff --git a/media/java/android/media/metrics/PlaybackMetricsManager.java b/media/java/android/media/metrics/PlaybackMetricsManager.java index 3606f53d7220..d51ff473696d 100644 --- a/media/java/android/media/metrics/PlaybackMetricsManager.java +++ b/media/java/android/media/metrics/PlaybackMetricsManager.java @@ -16,6 +16,7 @@ package android.media.metrics; +import android.annotation.NonNull; import android.os.RemoteException; /** @@ -38,10 +39,24 @@ public class PlaybackMetricsManager { /** * Reports playback metrics. + * @hide + */ + public void reportPlaybackMetrics(@NonNull String sessionId, PlaybackMetrics metrics) { + try { + mService.reportPlaybackMetrics(sessionId, metrics, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Creates a playback session. */ - public void reportPlaybackMetrics(PlaybackMetrics metrics) { + public PlaybackSession createSession() { try { - mService.reportPlaybackMetrics(metrics, mUserId); + String id = mService.getSessionId(mUserId); + PlaybackSession session = new PlaybackSession(id, this); + return session; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/media/java/android/media/metrics/PlaybackSession.java b/media/java/android/media/metrics/PlaybackSession.java new file mode 100644 index 000000000000..4ad89067952c --- /dev/null +++ b/media/java/android/media/metrics/PlaybackSession.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.metrics; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import com.android.internal.util.AnnotationValidations; + +import java.util.Objects; + +/** + * @hide + */ +public final class PlaybackSession implements AutoCloseable { + private final @NonNull String mId; + private final @NonNull PlaybackMetricsManager mManager; + private boolean mClosed = false; + + /** + * Creates a new PlaybackSession. + * + * @hide + */ + public PlaybackSession(@NonNull String id, @NonNull PlaybackMetricsManager manager) { + mId = id; + mManager = manager; + AnnotationValidations.validate(NonNull.class, null, mId); + AnnotationValidations.validate(NonNull.class, null, mManager); + } + + /** + * Reports playback metrics. + */ + public void reportPlaybackMetrics(@NonNull PlaybackMetrics metrics) { + mManager.reportPlaybackMetrics(mId, metrics); + } + + public @NonNull String getId() { + return mId; + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PlaybackSession that = (PlaybackSession) o; + return Objects.equals(mId, that.mId); + } + + @Override + public int hashCode() { + return Objects.hash(mId); + } + + @Override + public void close() throws Exception { + mClosed = true; + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java index 00f94f5c2e64..9d4669a5a37d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java @@ -18,6 +18,7 @@ package com.android.settingslib.media; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.content.Context; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.media.MediaRoute2Info; import android.media.MediaRouter2Manager; @@ -56,8 +57,9 @@ public class BluetoothMediaDevice extends MediaDevice { @Override public Drawable getIcon() { - final Drawable drawable = getIconWithoutBackground(); - if (!isFastPairDevice()) { + final Drawable drawable = + BluetoothUtils.getBtDrawableWithDescription(mContext, mCachedDevice).first; + if (!(drawable instanceof BitmapDrawable)) { setColorFilter(drawable); } return BluetoothUtils.buildAdvancedDrawable(mContext, drawable); @@ -65,9 +67,7 @@ public class BluetoothMediaDevice extends MediaDevice { @Override public Drawable getIconWithoutBackground() { - return isFastPairDevice() - ? BluetoothUtils.getBtDrawableWithDescription(mContext, mCachedDevice).first - : mContext.getDrawable(R.drawable.ic_headphone); + return BluetoothUtils.getBtClassDrawableWithDescription(mContext, mCachedDevice).first; } @Override diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java index 8973d116e438..e887c45083c0 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.when; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; +import android.graphics.drawable.BitmapDrawable; import com.android.settingslib.bluetooth.CachedBluetoothDevice; @@ -96,4 +97,17 @@ public class BluetoothMediaDeviceTest { assertThat(mBluetoothMediaDevice.isFastPairDevice()).isFalse(); } + + @Test + public void getIcon_isNotFastPairDevice_drawableTypeIsNotBitmapDrawable() { + final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class); + when(mDevice.getDevice()).thenReturn(bluetoothDevice); + + final String value = "False"; + final byte[] bytes = value.getBytes(); + when(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) + .thenReturn(bytes); + + assertThat(mBluetoothMediaDevice.getIcon() instanceof BitmapDrawable).isFalse(); + } } diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml index 6c20c1e95c6d..2bf41d2472be 100644 --- a/packages/SystemUI/res/layout/global_screenshot.xml +++ b/packages/SystemUI/res/layout/global_screenshot.xml @@ -40,18 +40,4 @@ android:visibility="gone" android:pointerIcon="crosshair"/> <include layout="@layout/global_screenshot_static"/> - <FrameLayout - android:id="@+id/global_screenshot_dismiss_button" - android:layout_width="@dimen/screenshot_dismiss_button_tappable_size" - android:layout_height="@dimen/screenshot_dismiss_button_tappable_size" - android:elevation="7dp" - android:visibility="gone" - android:contentDescription="@string/screenshot_dismiss_description"> - <ImageView - android:id="@+id/global_screenshot_dismiss_image" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_margin="@dimen/screenshot_dismiss_button_margin" - android:src="@drawable/screenshot_cancel"/> - </FrameLayout> </com.android.systemui.screenshot.ScreenshotView> diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml index 096ec7ddd004..9f63c4334a8c 100644 --- a/packages/SystemUI/res/layout/global_screenshot_static.xml +++ b/packages/SystemUI/res/layout/global_screenshot_static.xml @@ -17,7 +17,6 @@ <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:fitsSystemWindows="true" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView @@ -62,4 +61,22 @@ </LinearLayout> </HorizontalScrollView> <include layout="@layout/global_screenshot_preview"/> + <FrameLayout + android:id="@+id/global_screenshot_dismiss_button" + android:layout_width="@dimen/screenshot_dismiss_button_tappable_size" + android:layout_height="@dimen/screenshot_dismiss_button_tappable_size" + android:elevation="7dp" + android:visibility="gone" + app:layout_constraintStart_toEndOf="@id/global_screenshot_preview" + app:layout_constraintEnd_toEndOf="@id/global_screenshot_preview" + app:layout_constraintTop_toTopOf="@id/global_screenshot_preview" + app:layout_constraintBottom_toTopOf="@id/global_screenshot_preview" + android:contentDescription="@string/screenshot_dismiss_description"> + <ImageView + android:id="@+id/global_screenshot_dismiss_image" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_margin="@dimen/screenshot_dismiss_button_margin" + android:src="@drawable/screenshot_cancel"/> + </FrameLayout> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java index 70a57cc8bd2a..e24a513437ea 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,44 +14,39 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static com.android.systemui.classifier.FalsingManagerProxy.FALSING_SUCCESS; +import static com.android.systemui.classifier.FalsingModule.BRIGHT_LINE_GESTURE_CLASSIFERS; -import android.app.ActivityManager; -import android.content.res.Resources; import android.net.Uri; import android.os.Build; import android.util.IndentingPrintWriter; import android.util.Log; import android.view.MotionEvent; -import android.view.ViewConfiguration; import androidx.annotation.NonNull; import com.android.internal.logging.MetricsLogger; -import com.android.systemui.R; -import com.android.systemui.classifier.Classifier; -import com.android.systemui.classifier.FalsingDataProvider; import com.android.systemui.classifier.FalsingDataProvider.SessionListener; -import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.dagger.qualifiers.TestHarness; import com.android.systemui.dock.DockManager; import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.statusbar.phone.NotificationTapHelper; -import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.sensors.ThresholdSensor; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayDeque; -import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Queue; +import java.util.Set; import java.util.StringJoiner; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.inject.Named; /** * FalsingManager designed to make clear why a touch was rejected. @@ -68,6 +63,7 @@ public class BrightLineFalsingManager implements FalsingManager { private final DockManager mDockManager; private final SingleTapClassifier mSingleTapClassifier; private final DoubleTapClassifier mDoubleTapClassifier; + private final boolean mTestHarness; private final MetricsLogger mMetricsLogger; private int mIsFalseTouchCalls; private static final Queue<String> RECENT_INFO_LOG = @@ -75,7 +71,7 @@ public class BrightLineFalsingManager implements FalsingManager { private static final Queue<DebugSwipeRecord> RECENT_SWIPES = new ArrayDeque<>(RECENT_SWIPE_LOG_SIZE + 1); - private final List<FalsingClassifier> mClassifiers; + private final Collection<FalsingClassifier> mClassifiers; private final SessionListener mSessionListener = new SessionListener() { @Override @@ -93,29 +89,17 @@ public class BrightLineFalsingManager implements FalsingManager { @Inject public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider, - DeviceConfigProxy deviceConfigProxy, @Main Resources resources, - ViewConfiguration viewConfiguration, DockManager dockManager) { + DockManager dockManager, MetricsLogger metricsLogger, + @Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers, + SingleTapClassifier singleTapClassifier, DoubleTapClassifier doubleTapClassifier, + @TestHarness boolean testHarness) { mDataProvider = falsingDataProvider; mDockManager = dockManager; - - mMetricsLogger = new MetricsLogger(); - mClassifiers = new ArrayList<>(); - DistanceClassifier distanceClassifier = - new DistanceClassifier(mDataProvider, deviceConfigProxy); - ProximityClassifier proximityClassifier = - new ProximityClassifier(distanceClassifier, mDataProvider, deviceConfigProxy); - mClassifiers.add(new PointerCountClassifier(mDataProvider)); - mClassifiers.add(new TypeClassifier(mDataProvider)); - mClassifiers.add(new DiagonalClassifier(mDataProvider, deviceConfigProxy)); - mClassifiers.add(distanceClassifier); - mClassifiers.add(proximityClassifier); - mClassifiers.add(new ZigZagClassifier(mDataProvider, deviceConfigProxy)); - - mSingleTapClassifier = new SingleTapClassifier( - mDataProvider, viewConfiguration.getScaledTouchSlop()); - mDoubleTapClassifier = new DoubleTapClassifier(mDataProvider, mSingleTapClassifier, - resources.getDimension(R.dimen.double_tap_slop), - NotificationTapHelper.DOUBLE_TAP_TIMEOUT_MS); + mMetricsLogger = metricsLogger; + mClassifiers = classifiers; + mSingleTapClassifier = singleTapClassifier; + mDoubleTapClassifier = doubleTapClassifier; + mTestHarness = testHarness; mDataProvider.addSessionListener(mSessionListener); } @@ -132,7 +116,7 @@ public class BrightLineFalsingManager implements FalsingManager { return mPreviousResult; } - mPreviousResult = !ActivityManager.isRunningInUserTestHarness() + mPreviousResult = !mTestHarness && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked() && mClassifiers.stream().anyMatch(falsingClassifier -> { boolean result = falsingClassifier.isFalseTouch(); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java index a73ccf575249..92dd8b74e959 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE; @@ -23,11 +23,12 @@ import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE; import android.provider.DeviceConfig; -import com.android.systemui.classifier.FalsingDataProvider; import com.android.systemui.util.DeviceConfigProxy; import java.util.Locale; +import javax.inject.Inject; + /** * False on swipes that are too close to 45 degrees. * @@ -47,6 +48,7 @@ class DiagonalClassifier extends FalsingClassifier { private final float mHorizontalAngleRange; private final float mVerticalAngleRange; + @Inject DiagonalClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) { super(dataProvider); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java index 524d524f38b6..50d55f6f6028 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_FLING_THRESHOLD_IN; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_SWIPE_THRESHOLD_IN; @@ -27,12 +27,13 @@ import android.provider.DeviceConfig; import android.view.MotionEvent; import android.view.VelocityTracker; -import com.android.systemui.classifier.FalsingDataProvider; import com.android.systemui.util.DeviceConfigProxy; import java.util.List; import java.util.Locale; +import javax.inject.Inject; + /** * Ensure that the swipe + momentum covers a minimum distance. */ @@ -54,6 +55,7 @@ class DistanceClassifier extends FalsingClassifier { private boolean mDistanceDirty; private DistanceVectors mCachedDistance; + @Inject DistanceClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) { super(dataProvider); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java index a27ea6172414..1c8f4208edba 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java @@ -14,15 +14,19 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; -import android.view.MotionEvent; +import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TIMEOUT_MS; +import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TOUCH_SLOP; -import com.android.systemui.classifier.FalsingDataProvider; +import android.view.MotionEvent; import java.util.List; import java.util.Queue; +import javax.inject.Inject; +import javax.inject.Named; + /** * Returns a false touch if the most two recent gestures are not taps or are too far apart. */ @@ -34,8 +38,10 @@ public class DoubleTapClassifier extends FalsingClassifier { private StringBuilder mReason = new StringBuilder(); + @Inject DoubleTapClassifier(FalsingDataProvider dataProvider, SingleTapClassifier singleTapClassifier, - float doubleTapSlop, long doubleTapTimeMs) { + @Named(DOUBLE_TAP_TOUCH_SLOP) float doubleTapSlop, + @Named(DOUBLE_TAP_TIMEOUT_MS) long doubleTapTimeMs) { super(dataProvider); mSingleTapClassifier = singleTapClassifier; mDoubleTapSlop = doubleTapSlop; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java index 568dc432729f..82575c3e639e 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,12 +14,10 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import android.view.MotionEvent; -import com.android.systemui.classifier.Classifier; -import com.android.systemui.classifier.FalsingDataProvider; import com.android.systemui.util.sensors.ProximitySensor; import java.util.List; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java index b29871c1c3d0..009b311f2363 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java @@ -21,9 +21,6 @@ import android.view.MotionEvent; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; -import com.android.systemui.classifier.brightline.BrightLineFalsingManager; -import com.android.systemui.classifier.brightline.FalsingClassifier; -import com.android.systemui.classifier.brightline.TimeLimitedMotionEventBuffer; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.util.time.SystemClock; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index 74629411c13d..d4f58c324d39 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -24,7 +24,6 @@ import android.view.MotionEvent; import androidx.annotation.NonNull; import com.android.systemui.Dumpable; -import com.android.systemui.classifier.brightline.BrightLineFalsingManager; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java index 937bcbaa6222..7b7f17e1568b 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java @@ -16,16 +16,69 @@ package com.android.systemui.classifier; +import android.content.res.Resources; +import android.view.ViewConfiguration; + +import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.statusbar.phone.NotificationTapHelper; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import javax.inject.Named; import dagger.Binds; import dagger.Module; +import dagger.Provides; +import dagger.multibindings.ElementsIntoSet; /** Dagger Module for Falsing. */ @Module public interface FalsingModule { + String BRIGHT_LINE_GESTURE_CLASSIFERS = "bright_line_gesture_classifiers"; + String SINGLE_TAP_TOUCH_SLOP = "falsing_single_tap_touch_slop"; + String DOUBLE_TAP_TOUCH_SLOP = "falsing_double_tap_touch_slop"; + String DOUBLE_TAP_TIMEOUT_MS = "falsing_double_tap_timeout_ms"; + /** */ @Binds @SysUISingleton FalsingCollector bindsFalsingCollector(FalsingCollectorImpl impl); + + /** */ + @Provides + @ElementsIntoSet + @Named(BRIGHT_LINE_GESTURE_CLASSIFERS) + static Set<FalsingClassifier> providesBrightLineGestureClassifiers( + DistanceClassifier distanceClassifier, ProximityClassifier proximityClassifier, + PointerCountClassifier pointerCountClassifier, TypeClassifier typeClassifier, + DiagonalClassifier diagonalClassifier, ZigZagClassifier zigZagClassifier) { + return new HashSet<>(Arrays.asList( + pointerCountClassifier, typeClassifier, diagonalClassifier, distanceClassifier, + proximityClassifier, zigZagClassifier)); + } + + /** */ + @Provides + @Named(DOUBLE_TAP_TIMEOUT_MS) + static long providesDoubleTapTimeoutMs() { + return NotificationTapHelper.DOUBLE_TAP_TIMEOUT_MS; + } + + /** */ + @Provides + @Named(DOUBLE_TAP_TOUCH_SLOP) + static float providesDoubleTapTouchSlop(@Main Resources resources) { + return resources.getDimension(R.dimen.double_tap_slop); + } + + /** */ + @Provides + @Named(SINGLE_TAP_TOUCH_SLOP) + static float providesSingleTapTouchSlop(ViewConfiguration viewConfiguration) { + return viewConfiguration.getScaledTouchSlop(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java index dd5d8a8f557b..0565165e1e8d 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,17 +14,17 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN; import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; import android.view.MotionEvent; -import com.android.systemui.classifier.FalsingDataProvider; - import java.util.Locale; +import javax.inject.Inject; + /** * False touch if more than one finger touches the screen. * @@ -37,6 +37,7 @@ class PointerCountClassifier extends FalsingClassifier { private static final int MAX_ALLOWED_POINTERS_SWIPE_DOWN = 2; private int mMaxPointerCount; + @Inject PointerCountClassifier(FalsingDataProvider dataProvider) { super(dataProvider); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java index 3551c241e71e..6e73fc06de4c 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD; import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; @@ -22,12 +22,13 @@ import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; import android.provider.DeviceConfig; import android.view.MotionEvent; -import com.android.systemui.classifier.FalsingDataProvider; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.sensors.ProximitySensor; import java.util.Locale; +import javax.inject.Inject; + /** * False touch if proximity sensor is covered for more than a certain percentage of the gesture. @@ -47,10 +48,11 @@ class ProximityClassifier extends FalsingClassifier { private long mNearDurationNs; private float mPercentNear; + @Inject ProximityClassifier(DistanceClassifier distanceClassifier, FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) { super(dataProvider); - this.mDistanceClassifier = distanceClassifier; + mDistanceClassifier = distanceClassifier; mPercentCoveredThreshold = deviceConfigProxy.getFloat( DeviceConfig.NAMESPACE_SYSTEMUI, diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java index 8c7648149e44..6b7a1413bc74 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java @@ -14,14 +14,17 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; -import android.view.MotionEvent; +import static com.android.systemui.classifier.FalsingModule.SINGLE_TAP_TOUCH_SLOP; -import com.android.systemui.classifier.FalsingDataProvider; +import android.view.MotionEvent; import java.util.List; +import javax.inject.Inject; +import javax.inject.Named; + /** * Falsing classifier that accepts or rejects a single gesture as a tap. */ @@ -29,7 +32,9 @@ public class SingleTapClassifier extends FalsingClassifier { private final float mTouchSlop; private String mReason; - SingleTapClassifier(FalsingDataProvider dataProvider, float touchSlop) { + @Inject + SingleTapClassifier(FalsingDataProvider dataProvider, + @Named(SINGLE_TAP_TOUCH_SLOP) float touchSlop) { super(dataProvider); mTouchSlop = touchSlop; } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java index 7430a1eda920..7969b4e83ac0 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import android.view.MotionEvent; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java index f62871f383b3..711a0fc0f478 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK; @@ -26,12 +26,13 @@ import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE; import static com.android.systemui.classifier.Classifier.UNLOCK; -import com.android.systemui.classifier.FalsingDataProvider; +import javax.inject.Inject; /** * Ensure that the swipe direction generally matches that of the interaction type. */ public class TypeClassifier extends FalsingClassifier { + @Inject TypeClassifier(FalsingDataProvider dataProvider) { super(dataProvider); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java index 9ca77d364bc4..383dda498b49 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_X_PRIMARY_DEVIANCE; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_X_SECONDARY_DEVIANCE; @@ -25,13 +25,14 @@ import android.graphics.Point; import android.provider.DeviceConfig; import android.view.MotionEvent; -import com.android.systemui.classifier.FalsingDataProvider; import com.android.systemui.util.DeviceConfigProxy; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import javax.inject.Inject; + /** * Penalizes gestures that change direction in either the x or y too much. */ @@ -56,6 +57,7 @@ class ZigZagClassifier extends FalsingClassifier { private float mLastMaxXDeviance; private float mLastMaxYDeviance; + @Inject ZigZagClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) { super(dataProvider); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java index 53383d65e379..d683a74aedcc 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java @@ -16,11 +16,13 @@ package com.android.systemui.dagger; +import android.app.ActivityManager; import android.content.Context; import android.util.DisplayMetrics; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLoggerImpl; +import com.android.systemui.dagger.qualifiers.TestHarness; import com.android.systemui.util.concurrency.GlobalConcurrencyModule; import com.android.wm.shell.animation.FlingAnimationUtils; @@ -66,4 +68,10 @@ public class GlobalModule { static UiEventLogger provideUiEventLogger() { return new UiEventLoggerImpl(); } + + @Provides + @TestHarness + static boolean provideIsTestHarness() { + return ActivityManager.isRunningInUserTestHarness(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java new file mode 100644 index 000000000000..f68ab188c93c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dagger.qualifiers; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Qualifier; + + +/** + * An annotation for injecting whether or not we are running in a test environment. + */ +@Qualifier +@Documented +@Retention(RUNTIME) +public @interface TestHarness { +} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 35874cd8bb28..d7f9c6163b1d 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -16,20 +16,20 @@ package com.android.systemui.screenshot; -import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT; import static java.util.Objects.requireNonNull; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.app.Notification; import android.content.ComponentName; import android.content.Context; -import android.content.res.Configuration; +import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.PixelFormat; @@ -52,7 +52,8 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.SurfaceControl; import android.view.View; -import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowInsets; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -60,6 +61,8 @@ import android.widget.Toast; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.logging.UiEventLogger; +import com.android.internal.policy.PhoneWindow; +import com.android.settingslib.applications.InterestingConfigChanges; import com.android.systemui.R; import com.android.systemui.util.DeviceConfigProxy; @@ -141,12 +144,13 @@ public class ScreenshotController { private final WindowManager mWindowManager; private final WindowManager.LayoutParams mWindowLayoutParams; - private final Display mDisplay; private final DisplayMetrics mDisplayMetrics; private final AccessibilityManager mAccessibilityManager; private final MediaActionSound mCameraSound; private final ScrollCaptureClient mScrollCaptureClient; private final DeviceConfigProxy mConfigProxy; + private final PhoneWindow mWindow; + private final View mDecorView; private final Binder mWindowToken; private ScreenshotView mScreenshotView; @@ -156,9 +160,6 @@ public class ScreenshotController { private Animator mScreenshotAnimation; private Runnable mOnCompleteRunnable; - private boolean mInDarkMode; - private boolean mDirectionLTR; - private boolean mOrientationPortrait; private final Handler mScreenshotHandler = new Handler(Looper.getMainLooper()) { @Override @@ -174,6 +175,15 @@ public class ScreenshotController { } }; + /** Tracks config changes that require re-creating UI */ + private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges( + ActivityInfo.CONFIG_ORIENTATION + | ActivityInfo.CONFIG_LAYOUT_DIRECTION + | ActivityInfo.CONFIG_LOCALE + | ActivityInfo.CONFIG_UI_MODE + | ActivityInfo.CONFIG_SCREEN_LAYOUT + | ActivityInfo.CONFIG_ASSETS_PATHS); + @Inject ScreenshotController( Context context, @@ -188,25 +198,20 @@ public class ScreenshotController { mUiEventLogger = uiEventLogger; final DisplayManager dm = requireNonNull(context.getSystemService(DisplayManager.class)); - mDisplay = dm.getDisplay(DEFAULT_DISPLAY); - mContext = context.createDisplayContext(mDisplay); + final Display display = dm.getDisplay(DEFAULT_DISPLAY); + final Context displayContext = context.createDisplayContext(display); + mContext = displayContext.createWindowContext(TYPE_SCREENSHOT, null); mWindowManager = mContext.getSystemService(WindowManager.class); mAccessibilityManager = AccessibilityManager.getInstance(mContext); mConfigProxy = configProxy; - reloadAssets(); - Configuration config = mContext.getResources().getConfiguration(); - mInDarkMode = config.isNightModeActive(); - mDirectionLTR = config.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR; - mOrientationPortrait = config.orientation == ORIENTATION_PORTRAIT; mWindowToken = new Binder("ScreenshotController"); mScrollCaptureClient.setHostWindowToken(mWindowToken); // Setup the window that we are going to use mWindowLayoutParams = new WindowManager.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0, - WindowManager.LayoutParams.TYPE_SCREENSHOT, + MATCH_PARENT, MATCH_PARENT, /* xpos */ 0, /* ypos */ 0, TYPE_SCREENSHOT, WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL @@ -217,13 +222,21 @@ public class ScreenshotController { mWindowLayoutParams.setTitle("ScreenshotAnimation"); mWindowLayoutParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - mWindowLayoutParams.setFitInsetsTypes(0 /* types */); mWindowLayoutParams.token = mWindowToken; // This is needed to let touches pass through outside the touchable areas mWindowLayoutParams.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; + mWindow = new PhoneWindow(mContext); + mWindow.setWindowManager(mWindowManager, null, null); + mWindow.requestFeature(Window.FEATURE_NO_TITLE); + mWindow.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS); + mWindow.setBackgroundDrawableResource(android.R.color.transparent); + mDecorView = mWindow.getDecorView(); + + reloadAssets(); + mDisplayMetrics = new DisplayMetrics(); - mDisplay.getRealMetrics(mDisplayMetrics); + display.getRealMetrics(mDisplayMetrics); // Setup the Camera shutter sound mCameraSound = new MediaActionSound(); @@ -233,7 +246,6 @@ public class ScreenshotController { void takeScreenshotFullscreen(Consumer<Uri> finisher, Runnable onComplete) { mOnCompleteRunnable = onComplete; - mDisplay.getRealMetrics(mDisplayMetrics); takeScreenshotInternal( finisher, new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); @@ -254,19 +266,18 @@ public class ScreenshotController { return; } - if (aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) { - saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, false); - } else { - saveScreenshot(screenshot, finisher, - new Rect(0, 0, screenshot.getWidth(), screenshot.getHeight()), Insets.NONE, - true); + boolean showFlash = false; + if (!aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) { + showFlash = true; + visibleInsets = Insets.NONE; + screenshotScreenBounds.set(0, 0, screenshot.getWidth(), screenshot.getHeight()); } + saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, showFlash); } /** * Displays a screenshot selector */ - @SuppressLint("ClickableViewAccessibility") void takeScreenshotPartial(final Consumer<Uri> finisher, Runnable onComplete) { dismissScreenshot(true); mOnCompleteRunnable = onComplete; @@ -296,70 +307,27 @@ public class ScreenshotController { } } - private void onConfigChanged(Configuration newConfig) { - boolean needsUpdate = false; - // dark mode - if (newConfig.isNightModeActive()) { - // Night mode is active, we're using dark theme - if (!mInDarkMode) { - mInDarkMode = true; - needsUpdate = true; - } - } else { - // Night mode is not active, we're using the light theme - if (mInDarkMode) { - mInDarkMode = false; - needsUpdate = true; - } - } - - // RTL configuration - switch (newConfig.getLayoutDirection()) { - case View.LAYOUT_DIRECTION_LTR: - if (!mDirectionLTR) { - mDirectionLTR = true; - needsUpdate = true; - } - break; - case View.LAYOUT_DIRECTION_RTL: - if (mDirectionLTR) { - mDirectionLTR = false; - needsUpdate = true; - } - break; - } - - // portrait/landscape orientation - switch (newConfig.orientation) { - case ORIENTATION_PORTRAIT: - if (!mOrientationPortrait) { - mOrientationPortrait = true; - needsUpdate = true; - } - break; - case ORIENTATION_LANDSCAPE: - if (mOrientationPortrait) { - mOrientationPortrait = false; - needsUpdate = true; - } - break; - } - - if (needsUpdate) { - reloadAssets(); - } - } - /** * Update assets (called when the dark theme status changes). We only need to update the dismiss * button and the actions container background, since the buttons are re-inflated on demand. */ private void reloadAssets() { - boolean wasAttached = mScreenshotView != null && mScreenshotView.isAttachedToWindow(); + boolean wasAttached = mDecorView.isAttachedToWindow(); if (wasAttached) { - mWindowManager.removeView(mScreenshotView); + mWindowManager.removeView(mDecorView); } + // respect the display cutout in landscape (since we'd otherwise overlap) but not portrait + int orientation = mContext.getResources().getConfiguration().orientation; + mWindowLayoutParams.setFitInsetsTypes( + orientation == ORIENTATION_PORTRAIT ? 0 : WindowInsets.Type.displayCutout()); + + // ignore system bar insets for the purpose of window layout + mDecorView.setOnApplyWindowInsetsListener((v, insets) -> v.onApplyWindowInsets( + new WindowInsets.Builder(insets) + .setInsets(WindowInsets.Type.all(), Insets.NONE) + .build())); + // Inflate the screenshot layout mScreenshotView = (ScreenshotView) LayoutInflater.from(mContext).inflate(R.layout.global_screenshot, null); @@ -382,9 +350,8 @@ public class ScreenshotController { return false; }); - if (wasAttached) { - mWindowManager.addView(mScreenshotView, mWindowLayoutParams); - } + // view is added to window manager in startAnimation + mWindow.setContentView(mScreenshotView, mWindowLayoutParams); } /** @@ -448,7 +415,9 @@ public class ScreenshotController { mScreenBitmap.setHasAlpha(false); mScreenBitmap.prepareToDraw(); - onConfigChanged(mContext.getResources().getConfiguration()); + if (mConfigChanges.applyNewConfig(mContext.getResources())) { + reloadAssets(); + } // The window is focusable by default setWindowFocusable(true); @@ -510,10 +479,10 @@ public class ScreenshotController { mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT); mScreenshotHandler.post(() -> { if (!mScreenshotView.isAttachedToWindow()) { - mWindowManager.addView(mScreenshotView, mWindowLayoutParams); + mWindowManager.addView(mWindow.getDecorView(), mWindowLayoutParams); } - mScreenshotView.prepareForAnimation(mScreenBitmap, screenRect, screenInsets); + mScreenshotView.prepareForAnimation(mScreenBitmap, screenInsets); mScreenshotHandler.post(() -> { mScreenshotView.getViewTreeObserver().addOnComputeInternalInsetsListener( @@ -541,7 +510,7 @@ public class ScreenshotController { private void resetScreenshotView() { if (mScreenshotView.isAttachedToWindow()) { - mWindowManager.removeView(mScreenshotView); + mWindowManager.removeView(mDecorView); } mScreenshotView.reset(); mOnCompleteRunnable.run(); @@ -636,8 +605,8 @@ public class ScreenshotController { } else { mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; } - if (mScreenshotView.isAttachedToWindow()) { - mWindowManager.updateViewLayout(mScreenshotView, mWindowLayoutParams); + if (mDecorView.isAttachedToWindow()) { + mWindowManager.updateViewLayout(mDecorView, mWindowLayoutParams); } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java index b020275ae3ae..3814bd2999e9 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java @@ -240,8 +240,7 @@ public class ScreenshotView extends FrameLayout implements setOnApplyWindowInsetsListener((v, insets) -> { if (QuickStepContract.isGesturalMode(mNavMode)) { - Insets gestureInsets = insets.getInsets( - WindowInsets.Type.systemGestures()); + Insets gestureInsets = insets.getInsets(WindowInsets.Type.systemGestures()); mLeftInset = gestureInsets.left; mRightInset = gestureInsets.right; } else { @@ -272,7 +271,7 @@ public class ScreenshotView extends FrameLayout implements mScreenshotSelectorView.requestFocus(); } - void prepareForAnimation(Bitmap bitmap, Rect screenRect, Insets screenInsets) { + void prepareForAnimation(Bitmap bitmap, Insets screenInsets) { mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, bitmap, screenInsets)); // make static preview invisible (from gone) so we can query its location on screen mScreenshotPreview.setVisibility(View.INVISIBLE); @@ -284,6 +283,8 @@ public class ScreenshotView extends FrameLayout implements Rect previewBounds = new Rect(); mScreenshotPreview.getBoundsOnScreen(previewBounds); + int[] previewLocation = new int[2]; + mScreenshotPreview.getLocationInWindow(previewLocation); float cornerScale = mCornerSizeX / (mOrientationPortrait ? bounds.width() : bounds.height()); @@ -310,7 +311,8 @@ public class ScreenshotView extends FrameLayout implements // animate from the current location, to the static preview location final PointF startPos = new PointF(bounds.centerX(), bounds.centerY()); - final PointF finalPos = new PointF(previewBounds.centerX(), previewBounds.centerY()); + final PointF finalPos = new PointF(previewLocation[0] + previewBounds.width() / 2f, + previewLocation[1] + previewBounds.height() / 2f); ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1); toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java index 2c82bcb24ad0..4aaea8041abd 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java @@ -41,6 +41,8 @@ import android.os.UserManager; import android.util.Log; import android.view.WindowManager; +import androidx.annotation.NonNull; + import com.android.internal.logging.UiEventLogger; import com.android.internal.util.ScreenshotHelper; import com.android.systemui.R; @@ -57,9 +59,8 @@ public class TakeScreenshotService extends Service { private final UserManager mUserManager; private final UiEventLogger mUiEventLogger; private final ScreenshotNotificationsController mNotificationsController; - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - + private final Handler mHandler; + private final BroadcastReceiver mCloseSystemDialogs = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction()) && mScreenshot != null) { @@ -68,72 +69,11 @@ public class TakeScreenshotService extends Service { } }; - private Handler mHandler = new Handler(Looper.myLooper()) { - @Override - public void handleMessage(Message msg) { - final Messenger callback = msg.replyTo; - Consumer<Uri> uriConsumer = uri -> { - Message reply = Message.obtain(null, SCREENSHOT_MSG_URI, uri); - try { - callback.send(reply); - } catch (RemoteException e) { - } - }; - Runnable onComplete = () -> { - Message reply = Message.obtain(null, SCREENSHOT_MSG_PROCESS_COMPLETE); - try { - callback.send(reply); - } catch (RemoteException e) { - } - }; - - // If the storage for this user is locked, we have no place to store - // the screenshot, so skip taking it instead of showing a misleading - // animation and error notification. - if (!mUserManager.isUserUnlocked()) { - Log.w(TAG, "Skipping screenshot because storage is locked!"); - mNotificationsController.notifyScreenshotError( - R.string.screenshot_failed_to_save_user_locked_text); - post(() -> uriConsumer.accept(null)); - post(onComplete); - return; - } - - ScreenshotHelper.ScreenshotRequest screenshotRequest = - (ScreenshotHelper.ScreenshotRequest) msg.obj; - - mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource())); - - switch (msg.what) { - case WindowManager.TAKE_SCREENSHOT_FULLSCREEN: - mScreenshot.takeScreenshotFullscreen(uriConsumer, onComplete); - break; - case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION: - mScreenshot.takeScreenshotPartial(uriConsumer, onComplete); - break; - case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE: - Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap( - screenshotRequest.getBitmapBundle()); - Rect screenBounds = screenshotRequest.getBoundsInScreen(); - Insets insets = screenshotRequest.getInsets(); - int taskId = screenshotRequest.getTaskId(); - int userId = screenshotRequest.getUserId(); - ComponentName topComponent = screenshotRequest.getTopComponent(); - mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets, - taskId, userId, topComponent, uriConsumer, onComplete); - break; - default: - Log.d(TAG, "Invalid screenshot option: " + msg.what); - } - } - }; - @Inject - public TakeScreenshotService( - ScreenshotController screenshotController, - UserManager userManager, + public TakeScreenshotService(ScreenshotController screenshotController, UserManager userManager, UiEventLogger uiEventLogger, ScreenshotNotificationsController notificationsController) { + mHandler = new Handler(Looper.getMainLooper(), this::handleMessage); mScreenshot = screenshotController; mUserManager = userManager; mUiEventLogger = uiEventLogger; @@ -141,13 +81,9 @@ public class TakeScreenshotService extends Service { } @Override - public IBinder onBind(Intent intent) { - // register broadcast receiver - IntentFilter filter = new IntentFilter(ACTION_CLOSE_SYSTEM_DIALOGS); - registerReceiver(mBroadcastReceiver, filter); - + public IBinder onBind(@NonNull Intent intent) { + registerReceiver(mCloseSystemDialogs, new IntentFilter(ACTION_CLOSE_SYSTEM_DIALOGS)); return new Messenger(mHandler).getBinder(); - } @Override @@ -155,7 +91,73 @@ public class TakeScreenshotService extends Service { if (mScreenshot != null) { mScreenshot.dismissScreenshot(true); } - unregisterReceiver(mBroadcastReceiver); + unregisterReceiver(mCloseSystemDialogs); + return false; + } + + /** Respond to incoming Message via Binder (Messenger) */ + private boolean handleMessage(Message msg) { + final Messenger replyTo = msg.replyTo; + final Runnable onComplete = () -> sendComplete(replyTo); + final Consumer<Uri> uriConsumer = (uri) -> reportUri(replyTo, uri); + + // If the storage for this user is locked, we have no place to store + // the screenshot, so skip taking it instead of showing a misleading + // animation and error notification. + if (!mUserManager.isUserUnlocked()) { + Log.w(TAG, "Skipping screenshot because storage is locked!"); + mNotificationsController.notifyScreenshotError( + R.string.screenshot_failed_to_save_user_locked_text); + uriConsumer.accept(null); + onComplete.run(); + return true; + } + + ScreenshotHelper.ScreenshotRequest screenshotRequest = + (ScreenshotHelper.ScreenshotRequest) msg.obj; + + mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource())); + + switch (msg.what) { + case WindowManager.TAKE_SCREENSHOT_FULLSCREEN: + mScreenshot.takeScreenshotFullscreen(uriConsumer, onComplete); + break; + case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION: + mScreenshot.takeScreenshotPartial(uriConsumer, onComplete); + break; + case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE: + Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap( + screenshotRequest.getBitmapBundle()); + Rect screenBounds = screenshotRequest.getBoundsInScreen(); + Insets insets = screenshotRequest.getInsets(); + int taskId = screenshotRequest.getTaskId(); + int userId = screenshotRequest.getUserId(); + ComponentName topComponent = screenshotRequest.getTopComponent(); + mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets, + taskId, userId, topComponent, uriConsumer, onComplete); + break; + default: + Log.w(TAG, "Invalid screenshot option: " + msg.what); + return false; + } return true; + }; + + private void sendComplete(Messenger target) { + try { + Log.d(TAG, "sendComplete: " + target); + target.send(Message.obtain(null, SCREENSHOT_MSG_PROCESS_COMPLETE)); + } catch (RemoteException e) { + Log.d(TAG, "ignored remote exception", e); + } + } + + private void reportUri(Messenger target, Uri uri) { + try { + Log.d(TAG, "reportUri: " + target + " -> " + uri); + target.send(Message.obtain(null, SCREENSHOT_MSG_URI, uri)); + } catch (RemoteException e) { + Log.d(TAG, "ignored remote exception", e); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index a252a7a12274..3765e5a26e8e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -69,7 +69,6 @@ import com.android.systemui.util.wakelock.WakeLock; import java.io.FileDescriptor; import java.io.PrintWriter; import java.text.NumberFormat; -import java.util.IllegalFormatConversionException; import javax.inject.Inject; @@ -575,24 +574,12 @@ public class KeyguardIndicationController implements StateListener, String percentage = NumberFormat.getPercentInstance() .format(mBatteryLevel / 100f); if (hasChargingTime) { - // We now have battery percentage in these strings and it's expected that all - // locales will also have it in the future. For now, we still have to support the old - // format until all languages get the new translations. String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes( mContext, mChargingTimeRemaining); - try { - return mContext.getResources().getString(chargingId, chargingTimeFormatted, - percentage); - } catch (IllegalFormatConversionException e) { - return mContext.getResources().getString(chargingId, chargingTimeFormatted); - } + return mContext.getResources().getString(chargingId, chargingTimeFormatted, + percentage); } else { - // Same as above - try { - return mContext.getResources().getString(chargingId, percentage); - } catch (IllegalFormatConversionException e) { - return mContext.getResources().getString(chargingId); - } + return mContext.getResources().getString(chargingId, percentage); } } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java index 411fbc3ad64c..a879a1ef4b77 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java @@ -53,7 +53,6 @@ import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.tracing.ProtoTracer; import com.android.systemui.tracing.nano.SystemUiTraceProto; import com.android.wm.shell.ShellCommandHandler; -import com.android.wm.shell.apppairs.AppPairs; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout; import com.android.wm.shell.nano.WmShellTraceProto; import com.android.wm.shell.onehanded.OneHanded; @@ -99,13 +98,11 @@ public final class WMShell extends SystemUI private final Optional<HideDisplayCutout> mHideDisplayCutoutOptional; private final ProtoTracer mProtoTracer; private final Optional<ShellCommandHandler> mShellCommandHandler; - private final Optional<AppPairs> mAppPairsOptional; private boolean mIsSysUiStateValid; private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback; private KeyguardUpdateMonitorCallback mPipKeyguardCallback; private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback; - private KeyguardUpdateMonitorCallback mAppPairsKeyguardCallback; @Inject public WMShell(Context context, CommandQueue commandQueue, @@ -119,8 +116,7 @@ public final class WMShell extends SystemUI Optional<OneHanded> oneHandedOptional, Optional<HideDisplayCutout> hideDisplayCutoutOptional, ProtoTracer protoTracer, - Optional<ShellCommandHandler> shellCommandHandler, - Optional<AppPairs> appPairsOptional) { + Optional<ShellCommandHandler> shellCommandHandler) { super(context); mCommandQueue = commandQueue; mConfigurationController = configurationController; @@ -135,7 +131,6 @@ public final class WMShell extends SystemUI mProtoTracer = protoTracer; mProtoTracer.add(this); mShellCommandHandler = shellCommandHandler; - mAppPairsOptional = appPairsOptional; } @Override @@ -145,7 +140,6 @@ public final class WMShell extends SystemUI mSplitScreenOptional.ifPresent(this::initSplitScreen); mOneHandedOptional.ifPresent(this::initOneHanded); mHideDisplayCutoutOptional.ifPresent(this::initHideDisplayCutout); - mAppPairsOptional.ifPresent(this::initAppPairs); } @VisibleForTesting @@ -294,16 +288,6 @@ public final class WMShell extends SystemUI }); } - void initAppPairs(AppPairs appPairs) { - mAppPairsKeyguardCallback = new KeyguardUpdateMonitorCallback() { - @Override - public void onKeyguardVisibilityChanged(boolean showing) { - appPairs.onKeyguardVisibilityChanged(showing); - } - }; - mKeyguardUpdateMonitor.registerCallback(mAppPairsKeyguardCallback); - } - @Override public void writeToProto(SystemUiTraceProto proto) { if (proto.wmShell == null) { diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java index 4505b2a87c78..7a1c05890873 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java @@ -84,10 +84,8 @@ public class WMShellModule { @WMSingleton @Provides static AppPairs provideAppPairs(ShellTaskOrganizer shellTaskOrganizer, - SyncTransactionQueue syncQueue, DisplayController displayController, - TaskStackListenerImpl taskStackListener) { - return new AppPairsController(shellTaskOrganizer, syncQueue, displayController, - taskStackListener); + SyncTransactionQueue syncQueue, DisplayController displayController) { + return new AppPairsController(shellTaskOrganizer, syncQueue, displayController); } @WMSingleton diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java new file mode 100644 index 000000000000..19f0a15c8936 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.classifier; + +import static com.android.systemui.util.mockito.KotlinMockitoHelpersKt.any; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.testing.AndroidTestingRunner; +import android.view.MotionEvent; + +import androidx.test.filters.SmallTest; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.testing.FakeMetricsLogger; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.dock.DockManagerFake; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class BrightLineClassifierTest extends SysuiTestCase { + private BrightLineFalsingManager mBrightLineFalsingManager; + @Mock + private FalsingDataProvider mFalsingDataProvider; + private final DockManagerFake mDockManager = new DockManagerFake(); + private final MetricsLogger mMetricsLogger = new FakeMetricsLogger(); + private final Set<FalsingClassifier> mClassifiers = new HashSet<>(); + @Mock + private SingleTapClassifier mSingleTapClassfier; + @Mock + private DoubleTapClassifier mDoubleTapClassifier; + @Mock + private FalsingClassifier mClassifierA; + @Mock + private FalsingClassifier mClassifierB; + private final List<MotionEvent> mMotionEventList = new ArrayList<>(); + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mClassifiers.add(mClassifierA); + mClassifiers.add(mClassifierB); + when(mFalsingDataProvider.isDirty()).thenReturn(true); + when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList); + mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mDockManager, + mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier, false); + } + + @Test + public void testRegisterSessionListener() { + verify(mFalsingDataProvider).addSessionListener( + any(FalsingDataProvider.SessionListener.class)); + + mBrightLineFalsingManager.cleanup(); + verify(mFalsingDataProvider).removeSessionListener( + any(FalsingDataProvider.SessionListener.class)); + } + + @Test + public void testIsFalseTouch_NoClassifiers() { + mClassifiers.clear(); + + assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse(); + } + + @Test + public void testIsFalseTouch_ClassffiersPass() { + assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse(); + } + + @Test + public void testIsFalseTouch_ClassifierARejects() { + when(mClassifierA.isFalseTouch()).thenReturn(true); + assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isTrue(); + } + + @Test + public void testIsFalseTouch_ClassifierBRejects() { + when(mClassifierB.isFalseTouch()).thenReturn(true); + assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isTrue(); + } + + @Test + public void testIsFalseTouch_FaceAuth() { + // Even when the classifiers report a false, we should allow. + when(mClassifierA.isFalseTouch()).thenReturn(true); + when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true); + + assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse(); + } + + @Test + public void testIsFalseTouch_Docked() { + // Even when the classifiers report a false, we should allow. + when(mClassifierA.isFalseTouch()).thenReturn(true); + mDockManager.setIsDocked(true); + + assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse(); + } + + @Test + public void testIsFalseTap_BasicCheck() { + when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(false); + + assertThat(mBrightLineFalsingManager.isFalseTap(false)).isTrue(); + + when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(true); + + assertThat(mBrightLineFalsingManager.isFalseTap(false)).isFalse(); + } + + @Test + public void testIsFalseTap_RobustCheck_NoFaceAuth() { + when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(true); + mFalsingDataProvider.setJustUnlockedWithFace(false); + assertThat(mBrightLineFalsingManager.isFalseTap(true)).isTrue(); + } + + @Test + public void testIsFalseTap_RobustCheck_FaceAuth() { + when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(true); + when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true); + assertThat(mBrightLineFalsingManager.isFalseTap(true)).isFalse(); + } + + @Test + public void testIsFalseDoubleTap() { + when(mDoubleTapClassifier.isFalseTouch()).thenReturn(false); + + assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isFalse(); + + when(mDoubleTapClassifier.isFalseTouch()).thenReturn(true); + + assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isTrue(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java index 714d6581ff00..7659db8cc9ef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE; import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE; @@ -27,8 +27,6 @@ import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; -import com.android.systemui.classifier.ClassifierTest; -import com.android.systemui.classifier.FalsingDataProvider; import com.android.systemui.util.DeviceConfigProxyFake; import org.junit.After; diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java index d66c7a9d43a5..013fa369e876 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @@ -23,8 +23,6 @@ import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; -import com.android.systemui.classifier.ClassifierTest; -import com.android.systemui.classifier.FalsingDataProvider; import com.android.systemui.util.DeviceConfigProxyFake; import org.junit.After; diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java index 288ab0ad6596..4c4108a0cb90 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @@ -27,9 +27,6 @@ import android.view.MotionEvent; import androidx.test.filters.SmallTest; -import com.android.systemui.classifier.ClassifierTest; -import com.android.systemui.classifier.FalsingDataProvider; - import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java index b512f0d6ef32..ee289b5b922d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; @@ -26,8 +26,6 @@ import android.view.MotionEvent; import androidx.test.filters.SmallTest; -import com.android.systemui.classifier.ClassifierTest; - import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java index c2e290f166a3..38b025f675ee 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static com.android.systemui.classifier.Classifier.GENERIC; import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; @@ -28,8 +28,6 @@ import android.view.MotionEvent; import androidx.test.filters.SmallTest; -import com.android.systemui.classifier.ClassifierTest; -import com.android.systemui.classifier.FalsingDataProvider; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.sensors.ProximitySensor; diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java index d67f2b833deb..941e12e475f9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @@ -25,9 +25,6 @@ import android.view.MotionEvent; import androidx.test.filters.SmallTest; -import com.android.systemui.classifier.ClassifierTest; -import com.android.systemui.classifier.FalsingDataProvider; - import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBufferTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedMotionEventBufferTest.java index 1dfffb271f02..6e312594a2e4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBufferTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedMotionEventBufferTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java index 5f3b84c2f7ae..6b9bb4fedd16 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK; import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE; @@ -33,9 +33,6 @@ import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; -import com.android.systemui.classifier.ClassifierTest; -import com.android.systemui.classifier.FalsingDataProvider; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java index e49262f5099f..339dd9e9e6d2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.classifier.brightline; +package com.android.systemui.classifier; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @@ -23,7 +23,6 @@ import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; -import com.android.systemui.classifier.ClassifierTest; import com.android.systemui.util.DeviceConfigProxyFake; import org.junit.After; diff --git a/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java b/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java index a6355880c660..37540621557f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java @@ -22,6 +22,7 @@ package com.android.systemui.dock; public class DockManagerFake implements DockManager { DockEventListener mCallback; AlignmentStateListener mAlignmentListener; + private boolean mDocked; @Override public void addListener(DockEventListener callback) { @@ -45,7 +46,11 @@ public class DockManagerFake implements DockManager { @Override public boolean isDocked() { - return false; + return mDocked; + } + + public void setIsDocked(boolean docked) { + mDocked = docked; } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java index 822a6f2ad810..ef25b73fd748 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java @@ -34,7 +34,6 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.tracing.ProtoTracer; import com.android.wm.shell.ShellCommandHandler; -import com.android.wm.shell.apppairs.AppPairs; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.onehanded.OneHandedGestureHandler; @@ -69,7 +68,6 @@ public class WMShellTest extends SysuiTestCase { @Mock HideDisplayCutout mHideDisplayCutout; @Mock ProtoTracer mProtoTracer; @Mock ShellCommandHandler mShellCommandHandler; - @Mock AppPairs mAppPairs; @Before public void setUp() { @@ -79,7 +77,7 @@ public class WMShellTest extends SysuiTestCase { mKeyguardUpdateMonitor, mNavigationModeController, mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen), Optional.of(mOneHanded), Optional.of(mHideDisplayCutout), mProtoTracer, - Optional.of(mShellCommandHandler), Optional.of(mAppPairs)); + Optional.of(mShellCommandHandler)); when(mPip.getPipTouchHandler()).thenReturn(mPipTouchHandler); } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index be7643ecbd4e..61de53a2a483 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -558,12 +558,13 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo if (mAms.getMagnificationMode(displayId) == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) { magnificationGestureHandler = new WindowMagnificationGestureHandler(displayContext, - mAms.getWindowMagnificationMgr(), mAms::onMagnificationScaleChanged, - detectControlGestures, triggerable, displayId); + mAms.getWindowMagnificationMgr(), mAms.getMagnificationController(), + detectControlGestures, triggerable, + displayId); } else { magnificationGestureHandler = new FullScreenMagnificationGestureHandler(displayContext, - mAms.getFullScreenMagnificationController(), - mAms::onMagnificationScaleChanged, detectControlGestures, triggerable, + mAms.getFullScreenMagnificationController(), mAms.getMagnificationController(), + detectControlGestures, triggerable, new WindowMagnificationPromptController(displayContext, mUserId), displayId); } return magnificationGestureHandler; diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 4c85490a8086..be2f8f16a412 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -119,7 +119,6 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.accessibility.magnification.FullScreenMagnificationController; import com.android.server.accessibility.magnification.MagnificationController; -import com.android.server.accessibility.magnification.MagnificationGestureHandler; import com.android.server.accessibility.magnification.WindowMagnificationManager; import com.android.server.pm.UserManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; @@ -153,7 +152,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub AccessibilityUserState.ServiceInfoChangeListener, AccessibilityWindowManager.AccessibilityEventSender, AccessibilitySecurityPolicy.AccessibilityUserManager, - MagnificationGestureHandler.ScaleChangedListener, SystemActionPerformer.SystemActionsChangedListener { private static final boolean DEBUG = false; @@ -1066,17 +1064,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } - @Override - public void onMagnificationScaleChanged(int displayId, int mode) { - synchronized (mLock) { - final int capabilities = - getCurrentUserStateLocked().getMagnificationCapabilitiesLocked(); - if (capabilities == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) { - getWindowMagnificationMgr().showMagnificationButton(displayId, mode); - } - } - } - /** * Called by AccessibilityInputFilter when it creates or destroys the motionEventInjector. * Not using a getter because the AccessibilityInputFilter isn't thread-safe @@ -3000,6 +2987,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } + /** + * Getter of {@link MagnificationController}. + * + * @return MagnificationController + */ + MagnificationController getMagnificationController() { + synchronized (mLock) { + return mMagnificationController; + } + } + @Override public void associateEmbeddedHierarchy(@NonNull IBinder host, @NonNull IBinder embedded) { synchronized (mLock) { @@ -3584,6 +3582,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, userState.mUserId); if (capabilities != userState.getMagnificationCapabilitiesLocked()) { userState.setMagnificationCapabilitiesLocked(capabilities); + mMagnificationController.setMagnificationCapabilities(capabilities); return true; } return false; diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java index efb9d87a0bfd..7483ff3ef3f4 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java @@ -62,9 +62,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.accessibility.gestures.GestureUtils; -import java.util.ArrayDeque; -import java.util.Queue; - /** * This class handles full screen magnification in response to touch events. * @@ -115,13 +112,10 @@ import java.util.Queue; */ @SuppressWarnings("WeakerAccess") public class FullScreenMagnificationGestureHandler extends MagnificationGestureHandler { - private static final String LOG_TAG = "FullScreenMagnificationGestureHandler"; - private static final boolean DEBUG_ALL = false; private static final boolean DEBUG_STATE_TRANSITIONS = false | DEBUG_ALL; private static final boolean DEBUG_DETECTING = false | DEBUG_ALL; private static final boolean DEBUG_PANNING_SCALING = false | DEBUG_ALL; - private static final boolean DEBUG_EVENT_STREAM = false | DEBUG_ALL; // The MIN_SCALE is different from MagnificationController.MIN_SCALE due // to AccessibilityService.MagnificationController#setScale() has @@ -139,41 +133,12 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH private final ScreenStateReceiver mScreenStateReceiver; private final WindowMagnificationPromptController mPromptController; - /** - * {@code true} if this detector should detect and respond to triple-tap - * gestures for engaging and disengaging magnification, - * {@code false} if it should ignore such gestures - */ - final boolean mDetectTripleTap; - - /** - * Whether {@link DetectingState#mShortcutTriggered shortcut} is enabled - */ - final boolean mDetectShortcutTrigger; - @VisibleForTesting State mCurrentState; @VisibleForTesting State mPreviousState; private PointerCoords[] mTempPointerCoords; private PointerProperties[] mTempPointerProperties; - private final int mDisplayId; - - private final Queue<MotionEvent> mDebugInputEventHistory; - private final Queue<MotionEvent> mDebugOutputEventHistory; - - /** - * @param context Context for resolving various magnification-related resources - * @param fullScreenMagnificationController the {@link FullScreenMagnificationController} - * - * @param detectTripleTap {@code true} if this detector should detect and respond to triple-tap - * gestures for engaging and disengaging magnification, - * {@code false} if it should ignore such gestures - * @param detectShortcutTrigger {@code true} if this detector should be "triggerable" by some - * external shortcut invoking {@link #notifyShortcutTriggered}, - * {@code false} if it should ignore such triggers. - * @param displayId The logical display id. - */ public FullScreenMagnificationGestureHandler(Context context, FullScreenMagnificationController fullScreenMagnificationController, ScaleChangedListener listener, @@ -181,23 +146,20 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH boolean detectShortcutTrigger, @NonNull WindowMagnificationPromptController promptController, int displayId) { - super(listener); + super(displayId, detectTripleTap, detectShortcutTrigger, listener); if (DEBUG_ALL) { - Log.i(LOG_TAG, + Log.i(mLogTag, "FullScreenMagnificationGestureHandler(detectTripleTap = " + detectTripleTap + ", detectShortcutTrigger = " + detectShortcutTrigger + ")"); } mFullScreenMagnificationController = fullScreenMagnificationController; mPromptController = promptController; - mDisplayId = displayId; mDelegatingState = new DelegatingState(); mDetectingState = new DetectingState(context); mViewportDraggingState = new ViewportDraggingState(); mPanningScalingState = new PanningScalingState(context); - mDetectTripleTap = detectTripleTap; - mDetectShortcutTrigger = detectShortcutTrigger; if (mDetectShortcutTrigger) { mScreenStateReceiver = new ScreenStateReceiver(context, this); mScreenStateReceiver.register(); @@ -205,36 +167,11 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH mScreenStateReceiver = null; } - mDebugInputEventHistory = DEBUG_EVENT_STREAM ? new ArrayDeque<>() : null; - mDebugOutputEventHistory = DEBUG_EVENT_STREAM ? new ArrayDeque<>() : null; - transitionTo(mDetectingState); } @Override - public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (DEBUG_EVENT_STREAM) { - storeEventInto(mDebugInputEventHistory, event); - try { - onMotionEventInternal(event, rawEvent, policyFlags); - } catch (Exception e) { - throw new RuntimeException( - "Exception following input events: " + mDebugInputEventHistory, e); - } - } else { - onMotionEventInternal(event, rawEvent, policyFlags); - } - } - - private void onMotionEventInternal(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (DEBUG_ALL) Slog.i(LOG_TAG, "onMotionEvent(" + event + ")"); - - if ((!mDetectTripleTap && !mDetectShortcutTrigger) - || !event.isFromSource(SOURCE_TOUCHSCREEN)) { - dispatchTransformedEvent(event, rawEvent, policyFlags); - return; - } - + void onMotionEventInternal(MotionEvent event, MotionEvent rawEvent, int policyFlags) { handleEventWith(mCurrentState, event, rawEvent, policyFlags); } @@ -259,7 +196,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH @Override public void onDestroy() { if (DEBUG_STATE_TRANSITIONS) { - Slog.i(LOG_TAG, "onDestroy(); delayed = " + Slog.i(mLogTag, "onDestroy(); delayed = " + MotionEventInfo.toString(mDetectingState.mDelayedEventQueue)); } @@ -299,31 +236,6 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH mPanningScalingState.clear(); } - private void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent, - int policyFlags) { - if (DEBUG_EVENT_STREAM) { - storeEventInto(mDebugOutputEventHistory, event); - try { - super.onMotionEvent(event, rawEvent, policyFlags); - } catch (Exception e) { - throw new RuntimeException( - "Exception downstream following input events: " + mDebugInputEventHistory - + "\nTransformed into output events: " + mDebugOutputEventHistory, - e); - } - } else { - super.onMotionEvent(event, rawEvent, policyFlags); - } - } - - private static void storeEventInto(Queue<MotionEvent> queue, MotionEvent event) { - queue.add(MotionEvent.obtain(event)); - // Prune old events - while (!queue.isEmpty() && (event.getEventTime() - queue.peek().getEventTime() > 5000)) { - queue.remove().recycle(); - } - } - private PointerCoords[] getTempPointerCoordsWithMinSize(int size) { final int oldSize = (mTempPointerCoords != null) ? mTempPointerCoords.length : 0; if (oldSize < size) { @@ -358,7 +270,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH private void transitionTo(State state) { if (DEBUG_STATE_TRANSITIONS) { - Slog.i(LOG_TAG, + Slog.i(mLogTag, (State.nameOf(mCurrentState) + " -> " + State.nameOf(state) + " at " + asList(copyOfRange(new RuntimeException().getStackTrace(), 1, 5))) .replace(getClass().getName(), "")); @@ -440,7 +352,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH return true; } if (DEBUG_PANNING_SCALING) { - Slog.i(LOG_TAG, "Panned content by scrollX: " + distanceX + Slog.i(mLogTag, "Panned content by scrollX: " + distanceX + " scrollY: " + distanceY); } mFullScreenMagnificationController.offsetMagnifiedRegion(mDisplayId, distanceX, @@ -480,7 +392,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH final float pivotX = detector.getFocusX(); final float pivotY = detector.getFocusY(); - if (DEBUG_PANNING_SCALING) Slog.i(LOG_TAG, "Scaled content to: " + scale + "x"); + if (DEBUG_PANNING_SCALING) Slog.i(mLogTag, "Scaled content to: " + scale + "x"); mFullScreenMagnificationController.setScale(mDisplayId, scale, pivotX, pivotY, false, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); mListener.onMagnificationScaleChanged(mDisplayId, getMode()); @@ -945,7 +857,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH private void onTripleTap(MotionEvent up) { if (DEBUG_DETECTING) { - Slog.i(LOG_TAG, "onTripleTap(); delayed: " + Slog.i(mLogTag, "onTripleTap(); delayed: " + MotionEventInfo.toString(mDelayedEventQueue)); } clear(); @@ -965,7 +877,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH void transitionToViewportDraggingStateAndClear(MotionEvent down) { - if (DEBUG_DETECTING) Slog.i(LOG_TAG, "onTripleTapAndHold()"); + if (DEBUG_DETECTING) Slog.i(mLogTag, "onTripleTapAndHold()"); clear(); mViewportDraggingState.mZoomedInBeforeDrag = @@ -997,7 +909,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH if (mShortcutTriggered == state) { return; } - if (DEBUG_DETECTING) Slog.i(LOG_TAG, "setShortcutTriggered(" + state + ")"); + if (DEBUG_DETECTING) Slog.i(mLogTag, "setShortcutTriggered(" + state + ")"); mShortcutTriggered = state; mFullScreenMagnificationController.setForceShowMagnifiableBounds(mDisplayId, state); @@ -1030,7 +942,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH } private void zoomOn(float centerX, float centerY) { - if (DEBUG_DETECTING) Slog.i(LOG_TAG, "zoomOn(" + centerX + ", " + centerY + ")"); + if (DEBUG_DETECTING) Slog.i(mLogTag, "zoomOn(" + centerX + ", " + centerY + ")"); final float scale = MathUtils.constrain( mFullScreenMagnificationController.getPersistedScale(), @@ -1042,7 +954,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH } private void zoomOff() { - if (DEBUG_DETECTING) Slog.i(LOG_TAG, "zoomOff()"); + if (DEBUG_DETECTING) Slog.i(mLogTag, "zoomOff()"); mFullScreenMagnificationController.reset(mDisplayId, /* animate */ true); } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java index 6f81b5cfe3e6..df88ceb95d9e 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java @@ -37,7 +37,8 @@ import com.android.server.accessibility.AccessibilityManagerService; * Handles all magnification controllers initialization, generic interactions * and magnification mode transition. */ -public class MagnificationController implements WindowMagnificationManager.Callback { +public class MagnificationController implements WindowMagnificationManager.Callback, + MagnificationGestureHandler.ScaleChangedListener { private static final boolean DEBUG = false; private static final String TAG = "MagnificationController"; @@ -50,6 +51,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb private FullScreenMagnificationController mFullScreenMagnificationController; private WindowMagnificationManager mWindowMagnificationMgr; + private int mMagnificationCapabilities = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; /** * A callback to inform the magnification transition result. @@ -82,10 +84,18 @@ public class MagnificationController implements WindowMagnificationManager.Callb public void onPerformScaleAction(int displayId, float scale) { getWindowMagnificationMgr().setScale(displayId, scale); getWindowMagnificationMgr().persistScale(displayId); - mAms.onMagnificationScaleChanged(displayId, + onMagnificationScaleChanged(displayId, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); } + @Override + public void onMagnificationScaleChanged(int displayId, int mode) { + if (mMagnificationCapabilities != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) { + return; + } + getWindowMagnificationMgr().showMagnificationButton(displayId, mode); + } + /** * Transitions to the target Magnification mode with current center of the magnification mode * if it is available. @@ -182,6 +192,10 @@ public class MagnificationController implements WindowMagnificationManager.Callb } } + public void setMagnificationCapabilities(int capabilities) { + mMagnificationCapabilities = capabilities; + } + private DisableMagnificationCallback getDisableMagnificationEndRunnableLocked( int displayId) { return mMagnificationEndRunnableSparseArray.get(displayId); diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java index d6f53d2c225c..386d0bbf35ec 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java @@ -16,32 +16,127 @@ package com.android.server.accessibility.magnification; +import static android.view.InputDevice.SOURCE_TOUCHSCREEN; + +import android.annotation.NonNull; +import android.util.Log; +import android.util.Slog; +import android.view.MotionEvent; + import com.android.server.accessibility.BaseEventStreamTransformation; +import java.util.ArrayDeque; +import java.util.Queue; + /** * A base class that detects gestures and defines common methods for magnification. */ public abstract class MagnificationGestureHandler extends BaseEventStreamTransformation { - protected final ScaleChangedListener mListener; + protected final String mLogTag = this.getClass().getSimpleName(); + protected static final boolean DEBUG_ALL = Log.isLoggable("MagnificationGestureHandler", + Log.DEBUG); + protected static final boolean DEBUG_EVENT_STREAM = false | DEBUG_ALL; + private final Queue<MotionEvent> mDebugInputEventHistory; + private final Queue<MotionEvent> mDebugOutputEventHistory; - protected MagnificationGestureHandler(ScaleChangedListener listener) { - mListener = listener; - } + /** + * The logical display id. + */ + protected final int mDisplayId; /** - * Interface for listening to the magnification scaling gesture. + * {@code true} if this detector should be "triggerable" by some + * external shortcut invoking {@link #notifyShortcutTriggered}, + * {@code false} if it should ignore such triggers. */ + protected final boolean mDetectShortcutTrigger; + + /** + * {@code true} if this detector should detect and respond to triple-tap + * gestures for engaging and disengaging magnification, + * {@code false} if it should ignore such gestures + */ + protected final boolean mDetectTripleTap; + + /** Interface for listening to the magnification scaling gesture. */ public interface ScaleChangedListener { /** * Called when the magnification scale is changed by users. * * @param displayId The logical display id - * @param mode The magnification mode + * @param mode The magnification mode */ void onMagnificationScaleChanged(int displayId, int mode); } + protected final ScaleChangedListener mListener; + + protected MagnificationGestureHandler(int displayId, boolean detectTripleTap, + boolean detectShortcutTrigger, + @NonNull ScaleChangedListener listener) { + mDisplayId = displayId; + mDetectTripleTap = detectTripleTap; + mDetectShortcutTrigger = detectShortcutTrigger; + mListener = listener; + + mDebugInputEventHistory = DEBUG_EVENT_STREAM ? new ArrayDeque<>() : null; + mDebugOutputEventHistory = DEBUG_EVENT_STREAM ? new ArrayDeque<>() : null; + } + + @Override + public final void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { + if (DEBUG_ALL) { + Slog.i(mLogTag, "onMotionEvent(" + event + ")"); + } + if (DEBUG_EVENT_STREAM) { + storeEventInto(mDebugInputEventHistory, event); + } + if (shouldDispatchTransformedEvent(event)) { + dispatchTransformedEvent(event, rawEvent, policyFlags); + } else { + onMotionEventInternal(event, rawEvent, policyFlags); + } + } + + private boolean shouldDispatchTransformedEvent(MotionEvent event) { + if ((!mDetectTripleTap && !mDetectShortcutTrigger) || !event.isFromSource( + SOURCE_TOUCHSCREEN)) { + return true; + } + return false; + } + + final void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent, + int policyFlags) { + if (DEBUG_EVENT_STREAM) { + storeEventInto(mDebugOutputEventHistory, event); + try { + super.onMotionEvent(event, rawEvent, policyFlags); + return; + } catch (Exception e) { + throw new RuntimeException( + "Exception downstream following input events: " + mDebugInputEventHistory + + "\nTransformed into output events: " + mDebugOutputEventHistory, + e); + } + } + super.onMotionEvent(event, rawEvent, policyFlags); + } + + private static void storeEventInto(Queue<MotionEvent> queue, MotionEvent event) { + queue.add(MotionEvent.obtain(event)); + // Prune old events + while (!queue.isEmpty() && (event.getEventTime() - queue.peek().getEventTime() > 5000)) { + queue.remove().recycle(); + } + } + + /** + * Called when this MagnificationGestureHandler handles the motion event. + */ + abstract void onMotionEventInternal(MotionEvent event, MotionEvent rawEvent, int policyFlags); + /** * Called when the shortcut target is magnification. */ @@ -51,7 +146,6 @@ public abstract class MagnificationGestureHandler extends BaseEventStreamTransfo * Indicates the magnification mode. * * @return the magnification mode of the handler - * * @see android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN * @see android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW */ diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java index 7d6067c8e1da..7f26b2755900 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java @@ -27,7 +27,6 @@ import android.annotation.Nullable; import android.content.Context; import android.graphics.Point; import android.provider.Settings; -import android.util.Log; import android.util.MathUtils; import android.util.Slog; import android.view.Display; @@ -38,9 +37,7 @@ import com.android.server.accessibility.EventStreamTransformation; import com.android.server.accessibility.gestures.MultiTap; import com.android.server.accessibility.gestures.MultiTapAndHold; -import java.util.ArrayDeque; import java.util.List; -import java.util.Queue; /** * This class handles window magnification in response to touch events and shortcut. @@ -64,12 +61,9 @@ import java.util.Queue; */ @SuppressWarnings("WeakerAccess") public class WindowMagnificationGestureHandler extends MagnificationGestureHandler { - private static final String LOG_TAG = "WindowMagnificationGestureHandler"; - private static final boolean DEBUG_ALL = Log.isLoggable(LOG_TAG, Log.DEBUG); private static final boolean DEBUG_STATE_TRANSITIONS = false | DEBUG_ALL; private static final boolean DEBUG_DETECTING = false | DEBUG_ALL; - private static final boolean DEBUG_EVENT_STREAM = false | DEBUG_ALL; //Ensure the range has consistency with FullScreenMagnificationGestureHandler. private static final float MIN_SCALE = 2.0f; @@ -88,38 +82,26 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl @VisibleForTesting State mPreviousState; - final boolean mDetectShortcutTrigger; - private MotionEventDispatcherDelegate mMotionEventDispatcherDelegate; - private final int mDisplayId; private final Context mContext; private final Point mTempPoint = new Point(); - private final Queue<MotionEvent> mDebugOutputEventHistory; - - /** - * @param context Context for resolving various magnification-related resources - * @param windowMagnificationMgr The {@link WindowMagnificationManager} - * @param displayId The logical display id. - */ public WindowMagnificationGestureHandler(Context context, WindowMagnificationManager windowMagnificationMgr, - ScaleChangedListener listener, boolean detectTripleTap, - boolean detectShortcutTrigger, int displayId) { - super(listener); + ScaleChangedListener listener, + boolean detectTripleTap, boolean detectShortcutTrigger, int displayId) { + super(displayId, detectTripleTap, detectShortcutTrigger, listener); if (DEBUG_ALL) { - Slog.i(LOG_TAG, + Slog.i(mLogTag, "WindowMagnificationGestureHandler() , displayId = " + displayId + ")"); } mContext = context; mWindowMagnificationMgr = windowMagnificationMgr; - mDetectShortcutTrigger = detectShortcutTrigger; - mDisplayId = displayId; mMotionEventDispatcherDelegate = new MotionEventDispatcherDelegate(context, - (event, rawEvent, policyFlags) -> super.onMotionEvent( - event, rawEvent, policyFlags)); + (event, rawEvent, policyFlags) -> dispatchTransformedEvent(event, rawEvent, + policyFlags)); mDelegatingState = new DelegatingState(mMotionEventDispatcherDelegate); - mDetectingState = new DetectingState(context, detectTripleTap); + mDetectingState = new DetectingState(context, mDetectTripleTap); mObservePanningScalingState = new PanningScalingGestureState( new PanningScalingHandler(context, MAX_SCALE, MIN_SCALE, true, new PanningScalingHandler.MagnificationDelegate() { @@ -142,24 +124,14 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl } })); - mDebugOutputEventHistory = DEBUG_EVENT_STREAM ? new ArrayDeque<>() : null; - transitionTo(mDetectingState); } @Override - public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (DEBUG_ALL) { - Slog.i(LOG_TAG, "onMotionEvent(" + event + ")"); - } - if (!event.isFromSource(SOURCE_TOUCHSCREEN)) { - dispatchTransformedEvent(event, rawEvent, policyFlags); - return; - } else { - // To keep InputEventConsistencyVerifiers within GestureDetectors happy. - mObservePanningScalingState.mPanningScalingHandler.onTouchEvent(event); - mCurrentState.onMotionEvent(event, rawEvent, policyFlags); - } + void onMotionEventInternal(MotionEvent event, MotionEvent rawEvent, int policyFlags) { + // To keep InputEventConsistencyVerifiers within GestureDetectors happy. + mObservePanningScalingState.mPanningScalingHandler.onTouchEvent(event); + mCurrentState.onMotionEvent(event, rawEvent, policyFlags); } @Override @@ -173,7 +145,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl @Override public void onDestroy() { if (DEBUG_ALL) { - Slog.i(LOG_TAG, "onDestroy(); delayed = " + Slog.i(mLogTag, "onDestroy(); delayed = " + mDetectingState.toString()); } mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true); @@ -183,7 +155,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl @Override public void notifyShortcutTriggered() { if (DEBUG_ALL) { - Slog.i(LOG_TAG, "notifyShortcutTriggered():"); + Slog.i(mLogTag, "notifyShortcutTriggered():"); } if (!mDetectShortcutTrigger) { return; @@ -205,7 +177,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl private void enableWindowMagnifier(float centerX, float centerY) { if (DEBUG_ALL) { - Slog.i(LOG_TAG, "enableWindowMagnifier :" + centerX + ", " + centerY); + Slog.i(mLogTag, "enableWindowMagnifier :" + centerX + ", " + centerY); } final float scale = MathUtils.constrain( @@ -216,7 +188,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl private void disableWindowMagnifier() { if (DEBUG_ALL) { - Slog.i(LOG_TAG, "disableWindowMagnifier()"); + Slog.i(mLogTag, "disableWindowMagnifier()"); } mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, false); } @@ -231,7 +203,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl private void onTripleTap(MotionEvent up) { if (DEBUG_DETECTING) { - Slog.i(LOG_TAG, "onTripleTap()"); + Slog.i(mLogTag, "onTripleTap()"); } toggleMagnification(up.getX(), up.getY()); } @@ -240,30 +212,6 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl transitionTo(mDetectingState); } - private void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent, - int policyFlags) { - if (DEBUG_EVENT_STREAM) { - storeEventInto(mDebugOutputEventHistory, event); - try { - super.onMotionEvent(event, rawEvent, policyFlags); - } catch (Exception e) { - throw new RuntimeException( - "Exception downstream following input events: " + mDebugOutputEventHistory, - e); - } - } else { - super.onMotionEvent(event, rawEvent, policyFlags); - } - } - - private static void storeEventInto(Queue<MotionEvent> queue, MotionEvent event) { - queue.add(MotionEvent.obtain(event)); - // Prune old events. - while (!queue.isEmpty() && (event.getEventTime() - queue.peek().getEventTime() > 5000)) { - queue.remove().recycle(); - } - } - /** * An interface to intercept the {@link MotionEvent} for gesture detection. The intercepted * events should be delivered to next {@link EventStreamTransformation} with { @@ -293,7 +241,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl private void transitionTo(State state) { if (DEBUG_STATE_TRANSITIONS) { - Slog.i(LOG_TAG, "state transition: " + (State.nameOf(mCurrentState) + " -> " + Slog.i(mLogTag, "state transition: " + (State.nameOf(mCurrentState) + " -> " + State.nameOf(state) + " at " + asList(copyOfRange(new RuntimeException().getStackTrace(), 1, 5))) .replace(getClass().getName(), "")); @@ -451,10 +399,10 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl List<MotionEventInfo> delayedEventQueue, MotionEvent motionEvent) { if (DEBUG_DETECTING) { - Slog.d(LOG_TAG, "onGestureDetected : gesture = " + Slog.d(mLogTag, "onGestureDetected : gesture = " + MagnificationGestureMatcher.gestureIdToString( gestureId)); - Slog.d(LOG_TAG, + Slog.d(mLogTag, "onGestureDetected : delayedEventQueue = " + delayedEventQueue); } if (gestureId == MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN @@ -474,7 +422,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl List<MotionEventInfo> delayedEventQueue, MotionEvent motionEvent) { if (DEBUG_DETECTING) { - Slog.d(LOG_TAG, + Slog.d(mLogTag, "onGestureCancelled : delayedEventQueue = " + delayedEventQueue); } mMotionEventDispatcherDelegate.sendDelayedMotionEvents(delayedEventQueue, diff --git a/services/autofill/java/com/android/server/autofill/TEST_MAPPING b/services/autofill/java/com/android/server/autofill/TEST_MAPPING new file mode 100644 index 000000000000..cf058add0262 --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/TEST_MAPPING @@ -0,0 +1,15 @@ +{ + "presubmit": [ + { + "name": "CtsAutoFillServiceTestCases", + "options": [ + { + "include-annotation": "android.platform.test.annotations.Presubmit" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + } + ] +} diff --git a/services/core/Android.bp b/services/core/Android.bp index 614863d6b8f5..17e3456e565b 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -145,6 +145,7 @@ java_library_static { "SurfaceFlingerProperties", "com.android.sysprop.watchdog", ], + javac_shard_size: 50, } java_genrule { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index e8ee18c6f4d4..f0677a23765c 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -41,6 +41,7 @@ import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID; import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; @@ -6354,18 +6355,71 @@ public class ConnectivityService extends IConnectivityManager.Stub nai.declaredMetered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED); } - /** Propagates to |nc| the capabilities declared by the underlying networks of |nai|. */ - private void mixInUnderlyingCapabilities(NetworkAgentInfo nai, NetworkCapabilities nc) { - Network[] underlyingNetworks = nai.declaredUnderlyingNetworks; - Network defaultNetwork = getNetwork(getDefaultNetwork()); + /** Modifies |caps| based on the capabilities of the specified underlying networks. */ + @VisibleForTesting + void applyUnderlyingCapabilities(@Nullable Network[] underlyingNetworks, + @NonNull NetworkCapabilities caps, boolean declaredMetered) { + final Network defaultNetwork = getNetwork(getDefaultNetwork()); if (underlyingNetworks == null && defaultNetwork != null) { // null underlying networks means to track the default. underlyingNetworks = new Network[] { defaultNetwork }; } + int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN }; + int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; + int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; + boolean metered = declaredMetered; // metered if any underlying is metered, or agentMetered + boolean roaming = false; // roaming if any underlying is roaming + boolean congested = false; // congested if any underlying is congested + boolean suspended = true; // suspended if all underlying are suspended + + boolean hadUnderlyingNetworks = false; + if (null != underlyingNetworks) { + for (Network underlyingNetwork : underlyingNetworks) { + final NetworkAgentInfo underlying = + getNetworkAgentInfoForNetwork(underlyingNetwork); + if (underlying == null) continue; + + final NetworkCapabilities underlyingCaps = underlying.networkCapabilities; + hadUnderlyingNetworks = true; + for (int underlyingType : underlyingCaps.getTransportTypes()) { + transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType); + } - // TODO(b/124469351): Get capabilities directly from ConnectivityService instead. - final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); - Vpn.applyUnderlyingCapabilities(cm, underlyingNetworks, nc, nai.declaredMetered); + // Merge capabilities of this underlying network. For bandwidth, assume the + // worst case. + downKbps = NetworkCapabilities.minBandwidth(downKbps, + underlyingCaps.getLinkDownstreamBandwidthKbps()); + upKbps = NetworkCapabilities.minBandwidth(upKbps, + underlyingCaps.getLinkUpstreamBandwidthKbps()); + // If this underlying network is metered, the VPN is metered (it may cost money + // to send packets on this network). + metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED); + // If this underlying network is roaming, the VPN is roaming (the billing structure + // is different than the usual, local one). + roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING); + // If this underlying network is congested, the VPN is congested (the current + // condition of the network affects the performance of this network). + congested |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_CONGESTED); + // If this network is not suspended, the VPN is not suspended (the VPN + // is able to transfer some data). + suspended &= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED); + } + } + if (!hadUnderlyingNetworks) { + // No idea what the underlying networks are; assume reasonable defaults + metered = true; + roaming = false; + congested = false; + suspended = false; + } + + caps.setTransportTypes(transportTypes); + caps.setLinkDownstreamBandwidthKbps(downKbps); + caps.setLinkUpstreamBandwidthKbps(upKbps); + caps.setCapability(NET_CAPABILITY_NOT_METERED, !metered); + caps.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming); + caps.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested); + caps.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended); } /** @@ -6422,7 +6476,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } if (nai.supportsUnderlyingNetworks()) { - mixInUnderlyingCapabilities(nai, newNc); + applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, newNc, nai.declaredMetered); } return newNc; diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java index d6bd5a1d7c4c..a45466d98563 100644 --- a/services/core/java/com/android/server/TestNetworkService.java +++ b/services/core/java/com/android/server/TestNetworkService.java @@ -29,9 +29,9 @@ import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkAgent; +import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; +import android.net.NetworkProvider; import android.net.RouteInfo; import android.net.StringNetworkSpecifier; import android.net.TestNetworkInterface; @@ -62,7 +62,8 @@ import java.util.concurrent.atomic.AtomicInteger; /** @hide */ class TestNetworkService extends ITestNetworkManager.Stub { @NonNull private static final String TAG = TestNetworkService.class.getSimpleName(); - @NonNull private static final String TEST_NETWORK_TYPE = "TEST_NETWORK"; + @NonNull private static final String TEST_NETWORK_LOGTAG = "TestNetworkAgent"; + @NonNull private static final String TEST_NETWORK_PROVIDER_NAME = TAG; @NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger(); @NonNull private final Context mContext; @@ -72,6 +73,9 @@ class TestNetworkService extends ITestNetworkManager.Stub { @NonNull private final HandlerThread mHandlerThread; @NonNull private final Handler mHandler; + @NonNull private final ConnectivityManager mCm; + @NonNull private final NetworkProvider mNetworkProvider; + // Native method stubs private static native int jniCreateTunTap(boolean isTun, @NonNull String iface); @@ -85,6 +89,10 @@ class TestNetworkService extends ITestNetworkManager.Stub { mContext = Objects.requireNonNull(context, "missing Context"); mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService"); mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance"); + mCm = mContext.getSystemService(ConnectivityManager.class); + mNetworkProvider = new NetworkProvider(mContext, mHandler.getLooper(), + TEST_NETWORK_PROVIDER_NAME); + mCm.registerNetworkProvider(mNetworkProvider); } /** @@ -150,9 +158,6 @@ class TestNetworkService extends ITestNetworkManager.Stub { private static final int NETWORK_SCORE = 1; // Use a low, non-zero score. private final int mUid; - @NonNull private final NetworkInfo mNi; - @NonNull private final NetworkCapabilities mNc; - @NonNull private final LinkProperties mLp; @GuardedBy("mBinderLock") @NonNull @@ -161,20 +166,18 @@ class TestNetworkService extends ITestNetworkManager.Stub { @NonNull private final Object mBinderLock = new Object(); private TestNetworkAgent( - @NonNull Looper looper, @NonNull Context context, - @NonNull NetworkInfo ni, + @NonNull Looper looper, + @NonNull NetworkAgentConfig config, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int uid, - @NonNull IBinder binder) + @NonNull IBinder binder, + @NonNull NetworkProvider np) throws RemoteException { - super(looper, context, TEST_NETWORK_TYPE, ni, nc, lp, NETWORK_SCORE); + super(context, looper, TEST_NETWORK_LOGTAG, nc, lp, NETWORK_SCORE, config, np); mUid = uid; - mNi = ni; - mNc = nc; - mLp = lp; synchronized (mBinderLock) { mBinder = binder; // Binder null-checks in create() @@ -203,9 +206,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { } private void teardown() { - mNi.setDetailedState(DetailedState.DISCONNECTED, null, null); - mNi.setIsAvailable(false); - sendNetworkInfo(mNi); + unregister(); // Synchronize on mBinderLock to ensure that unlinkToDeath is never called more than // once (otherwise it could throw an exception) @@ -238,11 +239,6 @@ class TestNetworkService extends ITestNetworkManager.Stub { Objects.requireNonNull(context, "missing Context"); // iface and binder validity checked by caller - // Build network info with special testing type - NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_TEST, 0, TEST_NETWORK_TYPE, ""); - ni.setDetailedState(DetailedState.CONNECTED, null, null); - ni.setIsAvailable(true); - // Build narrow set of NetworkCapabilities, useful only for testing NetworkCapabilities nc = new NetworkCapabilities(); nc.clearAll(); // Remove default capabilities. @@ -290,7 +286,12 @@ class TestNetworkService extends ITestNetworkManager.Stub { lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null, iface)); } - return new TestNetworkAgent(looper, context, ni, nc, lp, callingUid, binder); + final TestNetworkAgent agent = new TestNetworkAgent(context, looper, + new NetworkAgentConfig.Builder().build(), nc, lp, callingUid, binder, + mNetworkProvider); + agent.register(); + agent.markConnected(); + return agent; } /** diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index df1081e43262..da6e7ff84525 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -252,6 +252,7 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; +import android.os.SharedMemory; import android.os.ShellCallback; import android.os.StrictMode; import android.os.SystemClock; @@ -348,6 +349,7 @@ import com.android.server.appop.AppOpsService; import com.android.server.compat.PlatformCompat; import com.android.server.contentcapture.ContentCaptureManagerInternal; import com.android.server.firewall.IntentFirewall; +import com.android.server.graphics.fonts.FontManagerInternal; import com.android.server.job.JobSchedulerInternal; import com.android.server.pm.Installer; import com.android.server.pm.permission.PermissionManagerServiceInternal; @@ -4358,6 +4360,11 @@ public class ActivityManagerService extends IActivityManager.Stub app.info.packageName); } } + SharedMemory serializedSystemFontMap = null; + final FontManagerInternal fm = LocalServices.getService(FontManagerInternal.class); + if (fm != null) { + serializedSystemFontMap = fm.getSerializedSystemFontMap(); + } checkTime(startTime, "attachApplicationLocked: immediately before bindApplication"); bindApplicationTimeMillis = SystemClock.elapsedRealtime(); @@ -4383,7 +4390,7 @@ public class ActivityManagerService extends IActivityManager.Stub app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions, - app.mDisabledCompatChanges); + app.mDisabledCompatChanges, serializedSystemFontMap); } else { thread.bindApplication(processName, appInfo, providerList, null, profilerInfo, null, null, null, testMode, @@ -4393,7 +4400,7 @@ public class ActivityManagerService extends IActivityManager.Stub app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions, - app.mDisabledCompatChanges); + app.mDisabledCompatChanges, serializedSystemFontMap); } if (profilerInfo != null) { profilerInfo.closeFd(); diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 234dcc9d74a5..3445275b76dd 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -18,10 +18,7 @@ package com.android.server.connectivity; import static android.Manifest.permission.BIND_VPN_SERVICE; import static android.net.ConnectivityManager.NETID_UNSET; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.RouteInfo.RTN_THROW; import static android.net.RouteInfo.RTN_UNREACHABLE; @@ -111,7 +108,6 @@ import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnInfo; import com.android.internal.net.VpnProfile; -import com.android.internal.util.ArrayUtils; import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; import com.android.server.net.BaseNetworkObserver; @@ -463,99 +459,6 @@ public class Vpn { } /** - * Updates {@link #mNetworkCapabilities} based on current underlying networks and returns a - * defensive copy. - * - * <p>Does not propagate updated capabilities to apps. - * - * @param defaultNetwork underlying network for VPNs following platform's default - */ - public synchronized NetworkCapabilities updateCapabilities(@Nullable Network defaultNetwork) { - if (mConfig == null) { - // VPN is not running. - return null; - } - - Network[] underlyingNetworks = mConfig.underlyingNetworks; - if (underlyingNetworks == null && defaultNetwork != null) { - // null underlying networks means to track the default. - underlyingNetworks = new Network[] { defaultNetwork }; - } - // Only apps targeting Q and above can explicitly declare themselves as metered. - final boolean isAlwaysMetered = mIsPackageTargetingAtLeastQ && mConfig.isMetered; - - applyUnderlyingCapabilities( - mConnectivityManager, - underlyingNetworks, - mNetworkCapabilities, - isAlwaysMetered); - - return new NetworkCapabilities(mNetworkCapabilities); - } - - @VisibleForTesting - public static void applyUnderlyingCapabilities( - @NonNull final ConnectivityManager cm, - @Nullable final Network[] underlyingNetworks, - @NonNull final NetworkCapabilities caps, - final boolean isAlwaysMetered) { - int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN }; - int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; - int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; - boolean metered = isAlwaysMetered; // metered if any underlying is metered, or alwaysMetered - boolean roaming = false; // roaming if any underlying is roaming - boolean congested = false; // congested if any underlying is congested - boolean suspended = true; // suspended if all underlying are suspended - - boolean hadUnderlyingNetworks = false; - if (null != underlyingNetworks) { - for (Network underlying : underlyingNetworks) { - // TODO(b/124469351): Get capabilities directly from ConnectivityService instead. - final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying); - if (underlyingCaps == null) continue; - hadUnderlyingNetworks = true; - for (int underlyingType : underlyingCaps.getTransportTypes()) { - transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType); - } - - // Merge capabilities of this underlying network. For bandwidth, assume the - // worst case. - downKbps = NetworkCapabilities.minBandwidth(downKbps, - underlyingCaps.getLinkDownstreamBandwidthKbps()); - upKbps = NetworkCapabilities.minBandwidth(upKbps, - underlyingCaps.getLinkUpstreamBandwidthKbps()); - // If this underlying network is metered, the VPN is metered (it may cost money - // to send packets on this network). - metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED); - // If this underlying network is roaming, the VPN is roaming (the billing structure - // is different than the usual, local one). - roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING); - // If this underlying network is congested, the VPN is congested (the current - // condition of the network affects the performance of this network). - congested |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_CONGESTED); - // If this network is not suspended, the VPN is not suspended (the VPN - // is able to transfer some data). - suspended &= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED); - } - } - if (!hadUnderlyingNetworks) { - // No idea what the underlying networks are; assume the safer defaults - metered = true; - roaming = false; - congested = false; - suspended = false; - } - - caps.setTransportTypes(transportTypes); - caps.setLinkDownstreamBandwidthKbps(downKbps); - caps.setLinkUpstreamBandwidthKbps(upKbps); - caps.setCapability(NET_CAPABILITY_NOT_METERED, !metered); - caps.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming); - caps.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested); - caps.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended); - } - - /** * Chooses whether to force all connections to go though VPN. * * Used to enable/disable legacy VPN lockdown. diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerInternal.java b/services/core/java/com/android/server/graphics/fonts/FontManagerInternal.java new file mode 100644 index 000000000000..e4b7b03a8e07 --- /dev/null +++ b/services/core/java/com/android/server/graphics/fonts/FontManagerInternal.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.graphics.fonts; + +import android.annotation.Nullable; +import android.os.SharedMemory; + +/** Local interface for {@link FontManagerService}. */ +public interface FontManagerInternal { + + /** Returns a SharedMemory in which the system font map is serialized. */ + @Nullable SharedMemory getSerializedSystemFontMap(); +} diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java new file mode 100644 index 000000000000..22921ad1ecc2 --- /dev/null +++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.graphics.fonts; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.graphics.Typeface; +import android.os.SharedMemory; +import android.system.ErrnoException; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; +import com.android.server.LocalServices; +import com.android.server.SystemService; + +import java.io.IOException; + +/** A service for managing system fonts. */ +// TODO(b/173619554): Add API to update fonts. +public final class FontManagerService { + + private static final String TAG = "FontManagerService"; + + /** Class to manage FontManagerService's lifecycle. */ + public static final class Lifecycle extends SystemService { + private final FontManagerService mService; + + public Lifecycle(@NonNull Context context) { + super(context); + mService = new FontManagerService(); + } + + @Override + public void onStart() { + LocalServices.addService(FontManagerInternal.class, + new FontManagerInternal() { + @Override + @Nullable + public SharedMemory getSerializedSystemFontMap() { + return mService.getSerializedSystemFontMap(); + } + }); + } + } + + @GuardedBy("this") + @Nullable + private SharedMemory mSerializedSystemFontMap = null; + + @Nullable + private SharedMemory getSerializedSystemFontMap() { + synchronized (FontManagerService.this) { + if (mSerializedSystemFontMap == null) { + mSerializedSystemFontMap = createSerializedSystemFontMapLocked(); + } + return mSerializedSystemFontMap; + } + } + + @Nullable + private SharedMemory createSerializedSystemFontMapLocked() { + // TODO(b/173619554): use updated fonts. + try { + return Typeface.serializeFontMap(Typeface.getSystemFontMap()); + } catch (IOException | ErrnoException e) { + Slog.e(TAG, "Failed to serialize SystemServer system font map", e); + } + return null; + } +} diff --git a/services/core/java/com/android/server/hdmi/CecMessageBuffer.java b/services/core/java/com/android/server/hdmi/CecMessageBuffer.java new file mode 100644 index 000000000000..8f971fd7db07 --- /dev/null +++ b/services/core/java/com/android/server/hdmi/CecMessageBuffer.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.hdmi; + +import java.util.ArrayList; +import java.util.List; + +/** + * Buffer for processing the incoming CEC messages while allocating logical addresses. + */ +final class CecMessageBuffer { + private List<HdmiCecMessage> mBuffer = new ArrayList<>(); + private HdmiControlService mHdmiControlService; + + CecMessageBuffer(HdmiControlService hdmiControlService) { + mHdmiControlService = hdmiControlService; + } + + /** + * Adds a message to the buffer. + * Only certain types of messages need to be buffered. + * @param message The message to add to the buffer + * @return Whether the message was added to the buffer + */ + public boolean bufferMessage(HdmiCecMessage message) { + switch (message.getOpcode()) { + case Constants.MESSAGE_ACTIVE_SOURCE: + bufferActiveSource(message); + return true; + case Constants.MESSAGE_IMAGE_VIEW_ON: + case Constants.MESSAGE_TEXT_VIEW_ON: + bufferImageOrTextViewOn(message); + return true; + case Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST: + bufferSystemAudioModeRequest(message); + return true; + // Add here if new message that needs to buffer + default: + // Do not need to buffer messages other than above + return false; + } + } + + /** + * Process all messages in the buffer. + */ + public void processMessages() { + for (final HdmiCecMessage message : mBuffer) { + mHdmiControlService.runOnServiceThread(new Runnable() { + @Override + public void run() { + mHdmiControlService.handleCecCommand(message); + } + }); + } + mBuffer.clear(); + } + + private void bufferActiveSource(HdmiCecMessage message) { + if (!replaceMessageIfBuffered(message, Constants.MESSAGE_ACTIVE_SOURCE)) { + mBuffer.add(message); + } + } + + private void bufferImageOrTextViewOn(HdmiCecMessage message) { + if (!replaceMessageIfBuffered(message, Constants.MESSAGE_IMAGE_VIEW_ON) + && !replaceMessageIfBuffered(message, Constants.MESSAGE_TEXT_VIEW_ON)) { + mBuffer.add(message); + } + } + + private void bufferSystemAudioModeRequest(HdmiCecMessage message) { + if (!replaceMessageIfBuffered(message, Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST)) { + mBuffer.add(message); + } + } + + // Returns true if the message is replaced + private boolean replaceMessageIfBuffered(HdmiCecMessage message, int opcode) { + for (int i = 0; i < mBuffer.size(); i++) { + HdmiCecMessage bufferedMessage = mBuffer.get(i); + if (bufferedMessage.getOpcode() == opcode) { + mBuffer.set(i, message); + return true; + } + } + return false; + } +} diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java index 2374ece1dd65..a261fa1f2741 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java @@ -22,19 +22,12 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringDef; -import android.content.ContentResolver; import android.content.Context; import android.content.SharedPreferences; -import android.database.ContentObserver; import android.hardware.hdmi.HdmiControlManager; -import android.net.Uri; import android.os.Environment; -import android.os.Handler; -import android.os.Looper; import android.os.SystemProperties; -import android.os.UserHandle; import android.provider.Settings.Global; -import android.util.ArrayMap; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -95,23 +88,6 @@ public class HdmiCecConfig { @Nullable private final CecSettings mProductConfig; @Nullable private final CecSettings mVendorOverride; - private final ArrayMap<Setting, Set<SettingChangeListener>> - mSettingChangeListeners = new ArrayMap<>(); - - private SettingsObserver mSettingsObserver; - - /** - * Listener used to get notifications when value of a setting changes. - */ - public interface SettingChangeListener { - /** - * Called when value of a setting changes. - * - * @param setting name of a CEC setting that changed - */ - void onChange(@NonNull @CecSettingName String setting); - } - /** * Setting storage input/output helper class. */ @@ -183,18 +159,6 @@ public class HdmiCecConfig { } } - private class SettingsObserver extends ContentObserver { - SettingsObserver(Handler handler) { - super(handler); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - String setting = uri.getLastPathSegment(); - HdmiCecConfig.this.notifyGlobalSettingChanged(setting); - } - } - @VisibleForTesting HdmiCecConfig(@NonNull Context context, @NonNull StorageAdapter storageAdapter, @@ -347,7 +311,6 @@ public class HdmiCecConfig { } else if (storage == STORAGE_SHARED_PREFS) { Slog.d(TAG, "Setting '" + storageKey + "' shared pref."); mStorageAdapter.storeSharedPref(storageKey, value); - notifySettingChanged(setting); } } @@ -355,103 +318,6 @@ public class HdmiCecConfig { return Integer.decode(value.getIntValue()); } - private void notifyGlobalSettingChanged(String setting) { - switch (setting) { - case Global.HDMI_CONTROL_ENABLED: - notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED); - break; - case Global.HDMI_CEC_VERSION: - notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION); - break; - case Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP: - notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP); - break; - } - } - - private void notifySettingChanged(@NonNull @CecSettingName String name) { - Setting setting = getSetting(name); - if (setting == null) { - throw new IllegalArgumentException("Setting '" + name + "' does not exist."); - } - notifySettingChanged(setting); - } - - private void notifySettingChanged(@NonNull Setting setting) { - Set<SettingChangeListener> listeners = mSettingChangeListeners.get(setting); - if (listeners == null) { - return; // No listeners registered, do nothing. - } - for (SettingChangeListener listener: listeners) { - listener.onChange(setting.getName()); - } - } - - /** - * This method registers Global Setting change observer. - * Needs to be called once after initialization of HdmiCecConfig. - */ - public void registerGlobalSettingsObserver(Looper looper) { - Handler handler = new Handler(looper); - mSettingsObserver = new SettingsObserver(handler); - ContentResolver resolver = mContext.getContentResolver(); - String[] settings = new String[] { - Global.HDMI_CONTROL_ENABLED, - Global.HDMI_CEC_VERSION, - Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP, - }; - for (String setting: settings) { - resolver.registerContentObserver(Global.getUriFor(setting), false, - mSettingsObserver, UserHandle.USER_ALL); - } - } - - /** - * This method unregisters Global Setting change observer. - */ - public void unregisterGlobalSettingsObserver() { - ContentResolver resolver = mContext.getContentResolver(); - resolver.unregisterContentObserver(mSettingsObserver); - } - - /** - * Register change listener for a given setting name. - */ - public void registerChangeListener(@NonNull @CecSettingName String name, - SettingChangeListener listener) { - Setting setting = getSetting(name); - if (setting == null) { - throw new IllegalArgumentException("Setting '" + name + "' does not exist."); - } - @Storage int storage = getStorage(setting); - if (storage != STORAGE_GLOBAL_SETTINGS && storage != STORAGE_SHARED_PREFS) { - throw new IllegalArgumentException("Change listeners for setting '" + name - + "' not supported."); - } - if (!mSettingChangeListeners.containsKey(setting)) { - mSettingChangeListeners.put(setting, new HashSet<>()); - } - mSettingChangeListeners.get(setting).add(listener); - } - - /** - * Remove change listener for a given setting name. - */ - public void removeChangeListener(@NonNull @CecSettingName String name, - SettingChangeListener listener) { - Setting setting = getSetting(name); - if (setting == null) { - throw new IllegalArgumentException("Setting '" + name + "' does not exist."); - } - if (mSettingChangeListeners.containsKey(setting)) { - Set<SettingChangeListener> listeners = mSettingChangeListeners.get(setting); - listeners.remove(listener); - if (listeners.isEmpty()) { - mSettingChangeListeners.remove(setting); - } - } - } - /** * Returns a list of all settings based on the XML metadata. */ diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index fd825d6f6288..56b73ba04d89 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -405,74 +405,7 @@ public class HdmiControlService extends SystemService { // Use getAtomWriter() instead of accessing directly, to allow dependency injection for testing. private HdmiCecAtomWriter mAtomWriter = new HdmiCecAtomWriter(); - // Buffer for processing the incoming cec messages while allocating logical addresses. - private final class CecMessageBuffer { - private List<HdmiCecMessage> mBuffer = new ArrayList<>(); - - public boolean bufferMessage(HdmiCecMessage message) { - switch (message.getOpcode()) { - case Constants.MESSAGE_ACTIVE_SOURCE: - bufferActiveSource(message); - return true; - case Constants.MESSAGE_IMAGE_VIEW_ON: - case Constants.MESSAGE_TEXT_VIEW_ON: - bufferImageOrTextViewOn(message); - return true; - case Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST: - bufferSystemAudioModeRequest(message); - return true; - // Add here if new message that needs to buffer - default: - // Do not need to buffer messages other than above - return false; - } - } - - public void processMessages() { - for (final HdmiCecMessage message : mBuffer) { - runOnServiceThread(new Runnable() { - @Override - public void run() { - handleCecCommand(message); - } - }); - } - mBuffer.clear(); - } - - private void bufferActiveSource(HdmiCecMessage message) { - if (!replaceMessageIfBuffered(message, Constants.MESSAGE_ACTIVE_SOURCE)) { - mBuffer.add(message); - } - } - - private void bufferImageOrTextViewOn(HdmiCecMessage message) { - if (!replaceMessageIfBuffered(message, Constants.MESSAGE_IMAGE_VIEW_ON) && - !replaceMessageIfBuffered(message, Constants.MESSAGE_TEXT_VIEW_ON)) { - mBuffer.add(message); - } - } - - private void bufferSystemAudioModeRequest(HdmiCecMessage message) { - if (!replaceMessageIfBuffered(message, Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST)) { - mBuffer.add(message); - } - } - - // Returns true if the message is replaced - private boolean replaceMessageIfBuffered(HdmiCecMessage message, int opcode) { - for (int i = 0; i < mBuffer.size(); i++) { - HdmiCecMessage bufferedMessage = mBuffer.get(i); - if (bufferedMessage.getOpcode() == opcode) { - mBuffer.set(i, message); - return true; - } - } - return false; - } - } - - private final CecMessageBuffer mCecMessageBuffer = new CecMessageBuffer(); + private CecMessageBuffer mCecMessageBuffer = new CecMessageBuffer(this); private final SelectRequestBuffer mSelectRequestBuffer = new SelectRequestBuffer(); @@ -563,7 +496,6 @@ public class HdmiControlService extends SystemService { if (mMessageValidator == null) { mMessageValidator = new HdmiCecMessageValidator(this); } - mHdmiCecConfig.registerGlobalSettingsObserver(mIoLooper); } private void bootCompleted() { @@ -988,6 +920,11 @@ public class HdmiControlService extends SystemService { mMessageValidator = messageValidator; } + @VisibleForTesting + void setCecMessageBuffer(CecMessageBuffer cecMessageBuffer) { + this.mCecMessageBuffer = cecMessageBuffer; + } + /** * Returns {@link Looper} of main thread. Use this {@link Looper} instance * for tasks that are running on main service thread. diff --git a/services/core/java/com/android/server/media/MediaKeyDispatcher.java b/services/core/java/com/android/server/media/MediaKeyDispatcher.java index 0dbc8392b610..63618eef250a 100644 --- a/services/core/java/com/android/server/media/MediaKeyDispatcher.java +++ b/services/core/java/com/android/server/media/MediaKeyDispatcher.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; +import android.content.Context; import android.media.session.ISessionManager; import android.media.session.MediaSession; import android.os.Binder; @@ -60,7 +61,7 @@ public abstract class MediaKeyDispatcher { private Map<Integer, Integer> mOverriddenKeyEvents; - public MediaKeyDispatcher() { + public MediaKeyDispatcher(Context context) { // Constructor used for reflection mOverriddenKeyEvents = new HashMap<>(); mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_PLAY, 0); diff --git a/services/core/java/com/android/server/media/MediaServerUtils.java b/services/core/java/com/android/server/media/MediaServerUtils.java index 5fa2b1ceaae9..a4f11b2470f1 100644 --- a/services/core/java/com/android/server/media/MediaServerUtils.java +++ b/services/core/java/com/android/server/media/MediaServerUtils.java @@ -18,6 +18,9 @@ package com.android.server.media; import android.content.Context; import android.content.pm.PackageManager; +import android.media.AudioAttributes; +import android.media.AudioManager; +import android.media.AudioPlaybackConfiguration; import android.os.Binder; import java.io.PrintWriter; @@ -29,7 +32,7 @@ class MediaServerUtils { /** * Verify that caller holds {@link android.Manifest.permission#DUMP}. */ - public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) { + static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) { if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump " + tag + " from from pid=" @@ -40,4 +43,18 @@ class MediaServerUtils { return true; } } + + /** + * Whether the given stream is currently active or not. + */ + static boolean isStreamActive(AudioManager audioManager, int stream) { + for (AudioPlaybackConfiguration configuration + : audioManager.getActivePlaybackConfigurations()) { + AudioAttributes attributes = configuration.getAudioAttributes(); + if (attributes != null && attributes.getVolumeControlStream() == stream) { + return configuration.isActive(); + } + } + return false; + } } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index f9973529a120..ea6e7d7d0bf6 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -23,7 +23,6 @@ import android.content.Intent; import android.content.pm.ParceledListSlice; import android.media.AudioAttributes; import android.media.AudioManager; -import android.media.AudioSystem; import android.media.MediaMetadata; import android.media.Rating; import android.media.VolumeProvider; @@ -513,7 +512,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR public void run() { try { if (useSuggested) { - if (AudioSystem.isStreamActive(stream, 0)) { + if (MediaServerUtils.isStreamActive(mAudioManager, stream)) { mAudioManager.adjustSuggestedStreamVolumeForUid(stream, direction, flags, opPackageName, uid, pid, mContext.getApplicationInfo().targetSdkVersion); diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index c23bfc442bd9..11dbef21b34f 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -43,7 +43,6 @@ import android.content.pm.ParceledListSlice; import android.content.pm.UserInfo; import android.media.AudioManager; import android.media.AudioPlaybackConfiguration; -import android.media.AudioSystem; import android.media.IRemoteVolumeControllerCallback; import android.media.Session2Token; import android.media.session.IActiveSessionsListener; @@ -94,7 +93,6 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Map; /** * System implementation of MediaSessionManager @@ -149,7 +147,6 @@ public class MediaSessionService extends SystemService implements Monitor { private SessionPolicyProvider mCustomSessionPolicyProvider; private MediaKeyDispatcher mCustomMediaKeyDispatcher; - private Map<Integer, Integer> mOverriddenKeyEventsMap; public MediaSessionService(Context context) { super(context); @@ -780,7 +777,6 @@ public class MediaSessionService extends SystemService implements Monitor { private void instantiateCustomDispatcher(String nameFromTesting) { synchronized (mLock) { mCustomMediaKeyDispatcher = null; - mOverriddenKeyEventsMap = null; String customDispatcherClassName = (nameFromTesting == null) ? mContext.getResources().getString(R.string.config_customMediaKeyDispatcher) @@ -788,9 +784,10 @@ public class MediaSessionService extends SystemService implements Monitor { try { if (!TextUtils.isEmpty(customDispatcherClassName)) { Class customDispatcherClass = Class.forName(customDispatcherClassName); - Constructor constructor = customDispatcherClass.getDeclaredConstructor(); - mCustomMediaKeyDispatcher = (MediaKeyDispatcher) constructor.newInstance(); - mOverriddenKeyEventsMap = mCustomMediaKeyDispatcher.getOverriddenKeyEvents(); + Constructor constructor = + customDispatcherClass.getDeclaredConstructor(Context.class); + mCustomMediaKeyDispatcher = + (MediaKeyDispatcher) constructor.newInstance(mContext); } } catch (ClassNotFoundException | InstantiationException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { @@ -810,9 +807,10 @@ public class MediaSessionService extends SystemService implements Monitor { try { if (!TextUtils.isEmpty(customProviderClassName)) { Class customProviderClass = Class.forName(customProviderClassName); - Constructor constructor = customProviderClass.getDeclaredConstructor(); + Constructor constructor = + customProviderClass.getDeclaredConstructor(Context.class); mCustomSessionPolicyProvider = - (SessionPolicyProvider) constructor.newInstance(); + (SessionPolicyProvider) constructor.newInstance(mContext); } } catch (ClassNotFoundException | InstantiationException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { @@ -2019,7 +2017,7 @@ public class MediaSessionService extends SystemService implements Monitor { boolean preferSuggestedStream = false; if (isValidLocalStreamType(suggestedStream) - && AudioSystem.isStreamActive(suggestedStream, 0)) { + && MediaServerUtils.isStreamActive(mAudioManager, suggestedStream)) { preferSuggestedStream = true; } if (session == null || preferSuggestedStream) { @@ -2028,7 +2026,8 @@ public class MediaSessionService extends SystemService implements Monitor { + ". flags=" + flags + ", preferSuggestedStream=" + preferSuggestedStream + ", session=" + session); } - if (musicOnly && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) { + if (musicOnly && !MediaServerUtils.isStreamActive(mAudioManager, + AudioManager.STREAM_MUSIC)) { if (DEBUG_KEY_EVENT) { Log.d(TAG, "Nothing is playing on the music stream. Skipping volume event," + " flags=" + flags); @@ -2382,9 +2381,12 @@ public class MediaSessionService extends SystemService implements Monitor { return; } - int overriddenKeyEvents = (mCustomMediaKeyDispatcher == null) ? 0 - : mCustomMediaKeyDispatcher.getOverriddenKeyEvents() - .get(keyEvent.getKeyCode()); + int overriddenKeyEvents = 0; + if (mCustomMediaKeyDispatcher != null + && mCustomMediaKeyDispatcher.getOverriddenKeyEvents() != null) { + overriddenKeyEvents = mCustomMediaKeyDispatcher.getOverriddenKeyEvents() + .get(keyEvent.getKeyCode()); + } cancelTrackingIfNeeded(packageName, pid, uid, asSystemService, keyEvent, needWakeLock, opPackageName, stream, musicOnly, overriddenKeyEvents); if (!needTracking(keyEvent, overriddenKeyEvents)) { diff --git a/services/core/java/com/android/server/media/SessionPolicyProvider.java b/services/core/java/com/android/server/media/SessionPolicyProvider.java index 5f02a075344e..332c85adec01 100644 --- a/services/core/java/com/android/server/media/SessionPolicyProvider.java +++ b/services/core/java/com/android/server/media/SessionPolicyProvider.java @@ -18,6 +18,7 @@ package com.android.server.media; import android.annotation.IntDef; import android.annotation.NonNull; +import android.content.Context; import android.media.session.MediaSession; import java.lang.annotation.Retention; @@ -54,7 +55,7 @@ public abstract class SessionPolicyProvider { */ static final int SESSION_POLICY_IGNORE_BUTTON_SESSION = 1 << 1; - public SessionPolicyProvider() { + public SessionPolicyProvider(Context context) { // Constructor used for reflection } diff --git a/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java b/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java index adb98695161a..9c68349af7d5 100644 --- a/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java +++ b/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java @@ -19,13 +19,17 @@ package com.android.server.media.metrics; import android.content.Context; import android.media.metrics.IPlaybackMetricsManager; import android.media.metrics.PlaybackMetrics; +import android.util.Base64; import com.android.server.SystemService; +import java.security.SecureRandom; + /** * System service manages playback metrics. */ public final class PlaybackMetricsManagerService extends SystemService { + private final SecureRandom mSecureRandom; /** * Initializes the playback metrics manager service. @@ -34,6 +38,7 @@ public final class PlaybackMetricsManagerService extends SystemService { */ public PlaybackMetricsManagerService(Context context) { super(context); + mSecureRandom = new SecureRandom(); } @Override @@ -44,8 +49,16 @@ public final class PlaybackMetricsManagerService extends SystemService { private final class BinderService extends IPlaybackMetricsManager.Stub { @Override - public void reportPlaybackMetrics(PlaybackMetrics metrics, int userId) { + public void reportPlaybackMetrics(String sessionId, PlaybackMetrics metrics, int userId) { // TODO: log it to statsd } + + @Override + public String getSessionId(int userId) { + byte[] byteId = new byte[16]; // 128 bits + mSecureRandom.nextBytes(byteId); + String id = Base64.encodeToString(byteId, Base64.DEFAULT); + return id; + } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e95b1a2b9d7a..85659edd1321 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1741,6 +1741,14 @@ public class PackageManagerService extends IPackageManager.Stub private final PackageUsage mPackageUsage = new PackageUsage(); private final CompilerStats mCompilerStats = new CompilerStats(); + /** + * Invalidate the package info cache, which includes updating the cached computer. + * @hide + */ + public static void invalidatePackageInfoCache() { + PackageManager.invalidatePackageInfoCache(); + } + class PackageHandler extends Handler { PackageHandler(Looper looper) { @@ -2683,14 +2691,14 @@ public class PackageManagerService extends IPackageManager.Stub // We normally invalidate when we write settings, but in cases where we delay and // coalesce settings writes, this strategy would have us invalidate the cache too late. // Invalidating on schedule addresses this problem. - PackageManager.invalidatePackageInfoCache(); + invalidatePackageInfoCache(); if (!mHandler.hasMessages(WRITE_SETTINGS)) { mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY); } } void scheduleWritePackageListLocked(int userId) { - PackageManager.invalidatePackageInfoCache(); + invalidatePackageInfoCache(); if (!mHandler.hasMessages(WRITE_PACKAGE_LIST)) { Message msg = mHandler.obtainMessage(WRITE_PACKAGE_LIST); msg.arg1 = userId; @@ -2704,7 +2712,7 @@ public class PackageManagerService extends IPackageManager.Stub } void scheduleWritePackageRestrictionsLocked(int userId) { - PackageManager.invalidatePackageInfoCache(); + invalidatePackageInfoCache(); final int[] userIds = (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[]{userId}; for (int nextUserId : userIds) { @@ -6939,8 +6947,7 @@ public class PackageManagerService extends IPackageManager.Stub private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId, String resolvedType, int flags) { - PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities - .get(userId); + PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId); //TODO(b/158003772): Remove double query List<PersistentPreferredActivity> pprefs = ppir != null ? ppir.queryIntent(intent, resolvedType, @@ -6959,8 +6966,7 @@ public class PackageManagerService extends IPackageManager.Stub private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags, List<ResolveInfo> query, boolean debug, int userId) { final int N = query.size(); - PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities - .get(userId); + PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId); // Get the list of persistent preferred activities that handle the intent if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for presistent preferred activities..."); List<PersistentPreferredActivity> pprefs = ppir != null @@ -7060,7 +7066,7 @@ public class PackageManagerService extends IPackageManager.Stub return pri; } - PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId); + PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); // Get the list of preferred activities that handle the intent if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities..."); List<PreferredActivity> prefs = pir != null @@ -7287,7 +7293,7 @@ public class PackageManagerService extends IPackageManager.Stub private List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent, String resolvedType, int userId) { - CrossProfileIntentResolver resolver = mSettings.mCrossProfileIntentResolvers.get(userId); + CrossProfileIntentResolver resolver = mSettings.getCrossProfileIntentResolvers(userId); if (resolver != null) { return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId); } @@ -9889,7 +9895,7 @@ public class PackageManagerService extends IPackageManager.Stub android.Manifest.permission.INTERACT_ACROSS_PROFILES, PermissionChecker.PID_UNKNOWN, callingUid, - mPmInternal.getPackage(callingUid).getPackageName()) + getPackage(callingUid).getPackageName()) == PermissionChecker.PERMISSION_GRANTED) { return; } @@ -20447,7 +20453,7 @@ public class PackageManagerService extends IPackageManager.Stub } synchronized (mLock) { - final PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId); + final PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); if (pir != null) { // Get all of the existing entries that exactly match this filter. final ArrayList<PreferredActivity> existing = pir.findFilters(filter); @@ -20544,35 +20550,7 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mLock") private void clearPackagePreferredActivitiesLPw(String packageName, @NonNull SparseBooleanArray outUserChanged, int userId) { - ArrayList<PreferredActivity> removed = null; - for (int i=0; i<mSettings.mPreferredActivities.size(); i++) { - final int thisUserId = mSettings.mPreferredActivities.keyAt(i); - PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i); - if (userId != UserHandle.USER_ALL && userId != thisUserId) { - continue; - } - Iterator<PreferredActivity> it = pir.filterIterator(); - while (it.hasNext()) { - PreferredActivity pa = it.next(); - // Mark entry for removal only if it matches the package name - // and the entry is of type "always". - if (packageName == null || - (pa.mPref.mComponent.getPackageName().equals(packageName) - && pa.mPref.mAlways)) { - if (removed == null) { - removed = new ArrayList<>(); - } - removed.add(pa); - } - } - if (removed != null) { - for (int j=0; j<removed.size(); j++) { - PreferredActivity pa = removed.get(j); - pir.removeFilter(pa); - } - outUserChanged.put(thisUserId, true); - } - } + mSettings.clearPackagePreferredActivities(packageName, outUserChanged, userId); } /** This method takes a specific user id as well as UserHandle.USER_ALL. */ @@ -20689,7 +20667,7 @@ public class PackageManagerService extends IPackageManager.Stub final int userId = UserHandle.getCallingUserId(); // reader synchronized (mLock) { - PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId); + PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); if (pir != null) { final Iterator<PreferredActivity> it = pir.filterIterator(); while (it.hasNext()) { @@ -20744,35 +20722,9 @@ public class PackageManagerService extends IPackageManager.Stub throw new SecurityException( "clearPackagePersistentPreferredActivities can only be run by the system"); } - ArrayList<PersistentPreferredActivity> removed = null; boolean changed = false; synchronized (mLock) { - for (int i=0; i<mSettings.mPersistentPreferredActivities.size(); i++) { - final int thisUserId = mSettings.mPersistentPreferredActivities.keyAt(i); - PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities - .valueAt(i); - if (userId != thisUserId) { - continue; - } - Iterator<PersistentPreferredActivity> it = ppir.filterIterator(); - while (it.hasNext()) { - PersistentPreferredActivity ppa = it.next(); - // Mark entry for removal only if it matches the package name. - if (ppa.mComponent.getPackageName().equals(packageName)) { - if (removed == null) { - removed = new ArrayList<>(); - } - removed.add(ppa); - } - } - if (removed != null) { - for (int j=0; j<removed.size(); j++) { - PersistentPreferredActivity ppa = removed.get(j); - ppir.removeFilter(ppa); - } - changed = true; - } - } + changed = mSettings.clearPackagePersistentPreferredActivities(packageName, userId); } if (changed) { updateDefaultHomeNotLocked(userId); @@ -22152,33 +22104,9 @@ public class PackageManagerService extends IPackageManager.Stub } synchronized (mLock) { - // Verify that all of the preferred activity components actually - // exist. It is possible for applications to be updated and at - // that point remove a previously declared activity component that - // had been set as a preferred activity. We try to clean this up - // the next time we encounter that preferred activity, but it is - // possible for the user flow to never be able to return to that - // situation so here we do a validity check to make sure we haven't - // left any junk around. - ArrayList<PreferredActivity> removed = new ArrayList<>(); - for (int i=0; i<mSettings.mPreferredActivities.size(); i++) { - PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i); - removed.clear(); - for (PreferredActivity pa : pir.filterSet()) { - if (!mComponentResolver.isActivityDefined(pa.mPref.mComponent)) { - removed.add(pa); - } - } - if (removed.size() > 0) { - for (int r=0; r<removed.size(); r++) { - PreferredActivity pa = removed.get(r); - Slog.w(TAG, "Removing dangling preferred activity: " - + pa.mPref.mComponent); - pir.removeFilter(pa); - } - mSettings.writePackageRestrictionsLPr( - mSettings.mPreferredActivities.keyAt(i)); - } + ArrayList<Integer> changed = mSettings.systemReady(mComponentResolver); + for (int i = 0; i < changed.size(); i++) { + mSettings.writePackageRestrictionsLPr(changed.get(i)); } } @@ -22689,17 +22617,7 @@ public class PackageManagerService extends IPackageManager.Stub } if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) { - for (int i=0; i<mSettings.mPreferredActivities.size(); i++) { - PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i); - int user = mSettings.mPreferredActivities.keyAt(i); - if (pir.dump(pw, - dumpState.getTitlePrinted() - ? "\nPreferred Activities User " + user + ":" - : "Preferred Activities User " + user + ":", " ", - packageName, true, false)) { - dumpState.setTitlePrinted(true); - } - } + mSettings.dumpPreferred(pw, dumpState, packageName); } if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) { @@ -24798,6 +24716,26 @@ public class PackageManagerService extends IPackageManager.Stub } } + private AndroidPackage getPackage(String packageName) { + synchronized (mLock) { + packageName = resolveInternalPackageNameLPr( + packageName, PackageManager.VERSION_CODE_HIGHEST); + return mPackages.get(packageName); + } + } + + private AndroidPackage getPackage(int uid) { + synchronized (mLock) { + final String[] packageNames = getPackagesForUidInternal(uid, Process.SYSTEM_UID); + AndroidPackage pkg = null; + final int numPackages = packageNames == null ? 0 : packageNames.length; + for (int i = 0; pkg == null && i < numPackages; i++) { + pkg = mPackages.get(packageNames[i]); + } + return pkg; + } + } + private class PackageManagerInternalImpl extends PackageManagerInternal { @Override public List<ApplicationInfo> getInstalledApplications(int flags, int userId, @@ -24908,24 +24846,12 @@ public class PackageManagerService extends IPackageManager.Stub @Override public AndroidPackage getPackage(String packageName) { - synchronized (mLock) { - packageName = resolveInternalPackageNameLPr( - packageName, PackageManager.VERSION_CODE_HIGHEST); - return mPackages.get(packageName); - } + return PackageManagerService.this.getPackage(packageName); } @Override public AndroidPackage getPackage(int uid) { - synchronized (mLock) { - final String[] packageNames = getPackagesForUidInternal(uid, Process.SYSTEM_UID); - AndroidPackage pkg = null; - final int numPackages = packageNames == null ? 0 : packageNames.length; - for (int i = 0; pkg == null && i < numPackages; i++) { - pkg = mPackages.get(packageNames[i]); - } - return pkg; - } + return PackageManagerService.this.getPackage(uid); } @Nullable @@ -25532,7 +25458,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - PackageManager.invalidatePackageInfoCache(); + invalidatePackageInfoCache(); return true; } diff --git a/services/core/java/com/android/server/pm/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java index 804faa1b7f0f..ff6b73b36f62 100644 --- a/services/core/java/com/android/server/pm/PreferredComponent.java +++ b/services/core/java/com/android/server/pm/PreferredComponent.java @@ -252,6 +252,37 @@ public class PreferredComponent { return numMatch == NS; } + public boolean sameSet(PreferredComponent pc) { + if (mSetPackages == null || pc == null || pc.mSetPackages == null + || !sameComponent(pc.mComponent)) { + return false; + } + final int otherPackageCount = pc.mSetPackages.length; + final int packageCount = mSetPackages.length; + if (otherPackageCount != packageCount) { + return false; + } + for (int i = 0; i < packageCount; i++) { + if (!mSetPackages[i].equals(pc.mSetPackages[i]) + || !mSetClasses[i].equals(pc.mSetClasses[i])) { + return false; + } + } + return true; + } + + /** Returns true if the preferred component represents the provided ComponentName. */ + private boolean sameComponent(ComponentName comp) { + if (mComponent == null || comp == null) { + return false; + } + if (mComponent.getPackageName().equals(comp.getPackageName()) + && mComponent.getClassName().equals(comp.getClassName())) { + return true; + } + return false; + } + public boolean isSuperset(List<ResolveInfo> query, boolean excludeSetupWizardPackage) { if (mSetPackages == null) { return query == null; diff --git a/services/core/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java index a261e29b05a7..ff3df130a3cc 100644 --- a/services/core/java/com/android/server/pm/PreferredIntentResolver.java +++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java @@ -22,6 +22,7 @@ import android.content.IntentFilter; import java.io.PrintWriter; import com.android.server.IntentResolver; +import java.util.ArrayList; public class PreferredIntentResolver extends IntentResolver<PreferredActivity, PreferredActivity> { @@ -45,4 +46,24 @@ public class PreferredIntentResolver protected IntentFilter getIntentFilter(@NonNull PreferredActivity input) { return input; } + + public boolean shouldAddPreferredActivity(PreferredActivity pa) { + ArrayList<PreferredActivity> pal = findFilters(pa); + if (pal == null || pal.isEmpty()) { + return true; + } + if (!pa.mPref.mAlways) { + return false; + } + final int activityCount = pal.size(); + for (int i = 0; i < activityCount; i++) { + PreferredActivity cur = pal.get(i); + if (cur.mPref.mAlways + && cur.mPref.mMatch == (pa.mPref.mMatch & IntentFilter.MATCH_CATEGORY_MASK) + && cur.mPref.sameSet(pa.mPref)) { + return false; + } + } + return true; + } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 966090cb96a7..f47b4b46fdd4 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -369,16 +369,16 @@ public final class Settings { // The user's preferred activities associated with particular intent // filters. - final SparseArray<PreferredIntentResolver> mPreferredActivities = + private final SparseArray<PreferredIntentResolver> mPreferredActivities = new SparseArray<PreferredIntentResolver>(); // The persistent preferred activities of the user's profile/device owner // associated with particular intent filters. - final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities = + private final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities = new SparseArray<PersistentPreferredIntentResolver>(); // For every user, it is used to find to which other users the intent can be forwarded. - final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers = + private final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers = new SparseArray<CrossProfileIntentResolver>(); final ArrayMap<String, SharedUserSetting> mSharedUsers = new ArrayMap<>(); @@ -467,7 +467,7 @@ public final class Settings { } private static void invalidatePackageCache() { - PackageManager.invalidatePackageInfoCache(); + PackageManagerService.invalidatePackageInfoCache(); ChangeIdStateCache.invalidate(); } @@ -1312,8 +1312,7 @@ public final class Settings { PreferredActivity pa = new PreferredActivity(parser); if (pa.mPref.getParseError() == null) { final PreferredIntentResolver resolver = editPreferredActivitiesLPw(userId); - ArrayList<PreferredActivity> pal = resolver.findFilters(pa); - if (pal == null || pal.size() == 0 || pa.mPref.mAlways) { + if (resolver.shouldAddPreferredActivity(pa)) { resolver.addFilter(pa); } } else { @@ -5543,4 +5542,130 @@ public final class Settings { } } } + + /** + * Accessor for preferred activities + */ + PersistentPreferredIntentResolver getPersistentPreferredActivities(int userId) { + return mPersistentPreferredActivities.get(userId); + } + + PreferredIntentResolver getPreferredActivities(int userId) { + return mPreferredActivities.get(userId); + } + + CrossProfileIntentResolver getCrossProfileIntentResolvers(int userId) { + return mCrossProfileIntentResolvers.get(userId); + } + + /** This method takes a specific user id as well as UserHandle.USER_ALL. */ + void clearPackagePreferredActivities(String packageName, + @NonNull SparseBooleanArray outUserChanged, int userId) { + ArrayList<PreferredActivity> removed = null; + for (int i = 0; i < mPreferredActivities.size(); i++) { + final int thisUserId = mPreferredActivities.keyAt(i); + PreferredIntentResolver pir = mPreferredActivities.valueAt(i); + if (userId != UserHandle.USER_ALL && userId != thisUserId) { + continue; + } + Iterator<PreferredActivity> it = pir.filterIterator(); + while (it.hasNext()) { + PreferredActivity pa = it.next(); + // Mark entry for removal only if it matches the package name + // and the entry is of type "always". + if (packageName == null + || (pa.mPref.mComponent.getPackageName().equals(packageName) + && pa.mPref.mAlways)) { + if (removed == null) { + removed = new ArrayList<>(); + } + removed.add(pa); + } + } + if (removed != null) { + for (int j = 0; j < removed.size(); j++) { + PreferredActivity pa = removed.get(j); + pir.removeFilter(pa); + } + outUserChanged.put(thisUserId, true); + } + } + } + + boolean clearPackagePersistentPreferredActivities(String packageName, int userId) { + ArrayList<PersistentPreferredActivity> removed = null; + boolean changed = false; + for (int i = 0; i < mPersistentPreferredActivities.size(); i++) { + final int thisUserId = mPersistentPreferredActivities.keyAt(i); + PersistentPreferredIntentResolver ppir = mPersistentPreferredActivities.valueAt(i); + if (userId != thisUserId) { + continue; + } + Iterator<PersistentPreferredActivity> it = ppir.filterIterator(); + while (it.hasNext()) { + PersistentPreferredActivity ppa = it.next(); + // Mark entry for removal only if it matches the package name. + if (ppa.mComponent.getPackageName().equals(packageName)) { + if (removed == null) { + removed = new ArrayList<>(); + } + removed.add(ppa); + } + } + if (removed != null) { + for (int j = 0; j < removed.size(); j++) { + PersistentPreferredActivity ppa = removed.get(j); + ppir.removeFilter(ppa); + } + changed = true; + } + } + return changed; + } + + ArrayList<Integer> systemReady(ComponentResolver resolver) { + // Verify that all of the preferred activity components actually + // exist. It is possible for applications to be updated and at + // that point remove a previously declared activity component that + // had been set as a preferred activity. We try to clean this up + // the next time we encounter that preferred activity, but it is + // possible for the user flow to never be able to return to that + // situation so here we do a validity check to make sure we haven't + // left any junk around. + ArrayList<Integer> changed = new ArrayList<>(); + ArrayList<PreferredActivity> removed = new ArrayList<>(); + for (int i = 0; i < mPreferredActivities.size(); i++) { + PreferredIntentResolver pir = mPreferredActivities.valueAt(i); + removed.clear(); + for (PreferredActivity pa : pir.filterSet()) { + if (!resolver.isActivityDefined(pa.mPref.mComponent)) { + removed.add(pa); + } + } + if (removed.size() > 0) { + for (int r = 0; r < removed.size(); r++) { + PreferredActivity pa = removed.get(r); + Slog.w(TAG, "Removing dangling preferred activity: " + + pa.mPref.mComponent); + pir.removeFilter(pa); + } + changed.add(mPreferredActivities.keyAt(i)); + } + } + return changed; + } + + void dumpPreferred(PrintWriter pw, DumpState dumpState, String packageName) { + for (int i = 0; i < mPreferredActivities.size(); i++) { + PreferredIntentResolver pir = mPreferredActivities.valueAt(i); + int user = mPreferredActivities.keyAt(i); + if (pir.dump(pw, + dumpState.getTitlePrinted() + ? "\nPreferred Activities User " + user + ":" + : "Preferred Activities User " + user + ":", " ", + packageName, true, false)) { + dumpState.setTitlePrinted(true); + } + } + } } diff --git a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java index 98293570507c..c9595c2eec2b 100644 --- a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java +++ b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java @@ -177,8 +177,28 @@ public class PowerStatsDataStorage { // filename, so any files that don't match the current version number can be deleted. File[] files = mDataStorageDir.listFiles(); for (int i = 0; i < files.length; i++) { - if (!files[i].getName().matches(dataStorageFilename + "(.*)")) { - files[i].delete(); + // Meter and model files are stored in the same directory. + // + // The format of filenames on disk is: + // log.powerstats.meter.version.timestamp + // log.powerstats.model.version.timestamp + // + // The format of dataStorageFilenames is: + // log.powerstats.meter.version + // log.powerstats.model.version + // + // A PowerStatsDataStorage object is created for meter and model data. Strip off + // the version and check that the current file we're checking starts with the stem + // (log.powerstats.meter or log.powerstats.model). If the stem matches and the + // version number is different, delete the old file. + int versionDot = dataStorageFilename.lastIndexOf('.'); + String beforeVersionDot = dataStorageFilename.substring(0, versionDot); + // Check that the stems match. + if (files[i].getName().startsWith(beforeVersionDot)) { + // Check that the version number matches. If not, delete the old file. + if (!files[i].getName().startsWith(dataStorageFilename)) { + files[i].delete(); + } } } diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index b4ca7c5f6ff1..6a50b793de0f 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -425,20 +425,20 @@ class ActivityMetricsLogger { mLastLogTimeSecs = now; mWindowState = WINDOW_STATE_INVALID; - Task stack = mSupervisor.mRootWindowContainer.getTopDisplayFocusedStack(); - if (stack == null) { + Task rootTask = mSupervisor.mRootWindowContainer.getTopDisplayFocusedRootTask(); + if (rootTask == null) { return; } - if (stack.isActivityTypeAssistant()) { + if (rootTask.isActivityTypeAssistant()) { mWindowState = WINDOW_STATE_ASSISTANT; return; } - @WindowingMode int windowingMode = stack.getWindowingMode(); + @WindowingMode int windowingMode = rootTask.getWindowingMode(); if (windowingMode == WINDOWING_MODE_PINNED) { - stack = mSupervisor.mRootWindowContainer.findStackBehind(stack); - windowingMode = stack.getWindowingMode(); + rootTask = mSupervisor.mRootWindowContainer.findRootTaskBehind(rootTask); + windowingMode = rootTask.getWindowingMode(); } switch (windowingMode) { case WINDOWING_MODE_FULLSCREEN: @@ -456,7 +456,7 @@ class ActivityMetricsLogger { break; default: if (windowingMode != WINDOWING_MODE_UNDEFINED) { - throw new IllegalStateException("Unknown windowing mode for stack=" + stack + throw new IllegalStateException("Unknown windowing mode for task=" + rootTask + " windowingMode=" + windowingMode); } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 75273ecb7534..1b8cc082f598 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1491,13 +1491,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } - ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller, + private ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller, int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage, @Nullable String _launchedFromFeature, Intent _intent, String _resolvedType, ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo, String _resultWho, int _reqCode, boolean _componentSpecified, boolean _rootVoiceInteraction, ActivityTaskSupervisor supervisor, - ActivityOptions options, ActivityRecord sourceRecord) { + ActivityOptions options, ActivityRecord sourceRecord, PersistableBundle persistentState, + TaskDescription _taskDescription, long _createTime) { super(_service.mWindowManager, new Token(_intent).asBinder(), TYPE_APPLICATION, true, null /* displayContent */, false /* ownerCanManageAppTokens */); @@ -1652,6 +1653,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mHandoverLaunchDisplayId = options.getLaunchDisplayId(); mLaunchCookie = options.getLaunchCookie(); } + + mPersistentState = persistentState; + taskDescription = _taskDescription; + if (_createTime > 0) { + createTime = _createTime; + } } /** @@ -2550,15 +2557,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return FINISH_RESULT_CANCELLED; } - final Task stack = getRootTask(); - final boolean mayAdjustTop = (isState(RESUMED) || stack.mResumedActivity == null) - && stack.isFocusedStackOnDisplay() + final Task rootTask = getRootTask(); + final boolean mayAdjustTop = (isState(RESUMED) || rootTask.mResumedActivity == null) + && rootTask.isFocusedStackOnDisplay() // Do not adjust focus task because the task will be reused to launch new activity. && !task.isClearingToReuseTask(); final boolean shouldAdjustGlobalFocus = mayAdjustTop // It must be checked before {@link #makeFinishingLocked} is called, because a stack // is not visible if it only contains finishing activities. - && mRootWindowContainer.isTopDisplayFocusedStack(stack); + && mRootWindowContainer.isTopDisplayFocusedRootTask(rootTask); mAtmService.deferWindowLayout(); try { @@ -2623,12 +2630,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Tell window manager to prepare for this one to be removed. setVisibility(false); - if (stack.mPausingActivity == null) { + if (rootTask.mPausingActivity == null) { ProtoLog.v(WM_DEBUG_STATES, "Finish needs to pause: %s", this); if (DEBUG_USER_LEAVING) { Slog.v(TAG_USER_LEAVING, "finish() => pause with userLeaving=false"); } - stack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */, + rootTask.startPausingLocked(false /* userLeaving */, false /* uiSleeping */, null /* resuming */, "finish"); } @@ -2827,7 +2834,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A false /* markFrozenIfConfigChanged */, true /* deferResume */); } if (activityRemoved) { - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } ProtoLog.d(WM_DEBUG_CONTAINERS, "destroyIfPossible: r=%s destroy returned " @@ -2849,7 +2856,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mTaskSupervisor.mFinishingActivities.add(this); } resumeKeyDispatchingLocked(); - return mRootWindowContainer.resumeFocusedStacksTopActivities(); + return mRootWindowContainer.resumeFocusedTasksTopActivities(); } /** @@ -3014,7 +3021,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A removeFromHistory(reason); } - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } /** @@ -5206,7 +5213,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } else { if (deferRelaunchUntilPaused) { destroyImmediately("stop-config"); - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } else { mRootWindowContainer.updatePreviousProcess(this); } @@ -5703,7 +5710,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // First find the real culprit... if this activity has stopped, then the key dispatching // timeout should not be caused by this. if (stopped) { - final Task stack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task stack = mRootWindowContainer.getTopDisplayFocusedRootTask(); if (stack == null) { return this; } @@ -6091,7 +6098,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) { t.setLayer(leash, getAnimationLayer()); - getDisplayContent().assignStackOrdering(); + getDisplayContent().assignRootTaskOrdering(); } @Override @@ -7544,18 +7551,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A throw new XmlPullParserException("restoreActivity resolver error. Intent=" + intent + " resolvedType=" + resolvedType); } - final ActivityRecord r = new ActivityRecord(service, null /* caller */, - 0 /* launchedFromPid */, launchedFromUid, launchedFromPackage, launchedFromFeature, - intent, resolvedType, aInfo, service.getConfiguration(), null /* resultTo */, - null /* resultWho */, 0 /* reqCode */, componentSpecified, - false /* rootVoiceInteraction */, taskSupervisor, null /* options */, - null /* sourceRecord */); - - r.mPersistentState = persistentState; - r.taskDescription = taskDescription; - r.createTime = createTime; - - return r; + return new ActivityRecord.Builder(service) + .setLaunchedFromUid(launchedFromUid) + .setLaunchedFromPackage(launchedFromPackage) + .setLaunchedFromFeature(launchedFromFeature) + .setIntent(intent) + .setResolvedType(resolvedType) + .setActivityInfo(aInfo) + .setComponentSpecified(componentSpecified) + .setPersistentState(persistentState) + .setTaskDescription(taskDescription) + .setCreateTime(createTime) + .build(); } private static boolean isInVrUiMode(Configuration config) { @@ -7983,4 +7990,138 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } return false; } + + static class Builder { + private final ActivityTaskManagerService mAtmService; + private WindowProcessController mCallerApp; + private int mLaunchedFromPid; + private int mLaunchedFromUid; + private String mLaunchedFromPackage; + private String mLaunchedFromFeature; + private Intent mIntent; + private String mResolvedType; + private ActivityInfo mActivityInfo; + private Configuration mConfiguration; + private ActivityRecord mResultTo; + private String mResultWho; + private int mRequestCode; + private boolean mComponentSpecified; + private boolean mRootVoiceInteraction; + private ActivityOptions mOptions; + private ActivityRecord mSourceRecord; + private PersistableBundle mPersistentState; + private TaskDescription mTaskDescription; + private long mCreateTime; + + Builder(ActivityTaskManagerService service) { + mAtmService = service; + } + + Builder setCaller(@NonNull WindowProcessController caller) { + mCallerApp = caller; + return this; + } + + Builder setLaunchedFromPid(int pid) { + mLaunchedFromPid = pid; + return this; + } + + Builder setLaunchedFromUid(int uid) { + mLaunchedFromUid = uid; + return this; + } + + Builder setLaunchedFromPackage(String fromPackage) { + mLaunchedFromPackage = fromPackage; + return this; + } + + Builder setLaunchedFromFeature(String fromFeature) { + mLaunchedFromFeature = fromFeature; + return this; + } + + Builder setIntent(Intent intent) { + mIntent = intent; + return this; + } + + Builder setResolvedType(String resolvedType) { + mResolvedType = resolvedType; + return this; + } + + Builder setActivityInfo(ActivityInfo activityInfo) { + mActivityInfo = activityInfo; + return this; + } + + Builder setResultTo(ActivityRecord resultTo) { + mResultTo = resultTo; + return this; + } + + Builder setResultWho(String resultWho) { + mResultWho = resultWho; + return this; + } + + Builder setRequestCode(int reqCode) { + mRequestCode = reqCode; + return this; + } + + Builder setComponentSpecified(boolean componentSpecified) { + mComponentSpecified = componentSpecified; + return this; + } + + Builder setRootVoiceInteraction(boolean rootVoiceInteraction) { + mRootVoiceInteraction = rootVoiceInteraction; + return this; + } + + Builder setActivityOptions(ActivityOptions options) { + mOptions = options; + return this; + } + + Builder setConfiguration(Configuration config) { + mConfiguration = config; + return this; + } + + Builder setSourceRecord(ActivityRecord source) { + mSourceRecord = source; + return this; + } + + private Builder setPersistentState(PersistableBundle persistentState) { + mPersistentState = persistentState; + return this; + } + + private Builder setTaskDescription(TaskDescription taskDescription) { + mTaskDescription = taskDescription; + return this; + } + + private Builder setCreateTime(long createTime) { + mCreateTime = createTime; + return this; + } + + ActivityRecord build() { + if (mConfiguration == null) { + mConfiguration = mAtmService.getConfiguration(); + } + return new ActivityRecord(mAtmService, mCallerApp, mLaunchedFromPid, + mLaunchedFromUid, mLaunchedFromPackage, mLaunchedFromFeature, mIntent, + mResolvedType, mActivityInfo, mConfiguration, mResultTo, mResultWho, + mRequestCode, mComponentSpecified, mRootVoiceInteraction, + mAtmService.mTaskSupervisor, mOptions, mSourceRecord, mPersistentState, + mTaskDescription, mCreateTime); + } + } } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index b88b54ef08f5..1ff3a3fb1d35 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -664,7 +664,7 @@ class ActivityStarter { synchronized (mService.mGlobalLock) { final boolean globalConfigWillChange = mRequest.globalConfig != null && mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0; - final Task stack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task stack = mRootWindowContainer.getTopDisplayFocusedRootTask(); if (stack != null) { stack.mConfigWillChange = globalConfigWillChange; } @@ -900,7 +900,7 @@ class ActivityStarter { ActivityRecord sourceRecord = null; ActivityRecord resultRecord = null; if (resultTo != null) { - sourceRecord = mRootWindowContainer.isInAnyStack(resultTo); + sourceRecord = mRootWindowContainer.isInAnyTask(resultTo); if (DEBUG_RESULTS) { Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord); } @@ -1135,7 +1135,7 @@ class ActivityStarter { if (DEBUG_PERMISSIONS_REVIEW) { final Task focusedStack = - mRootWindowContainer.getTopDisplayFocusedStack(); + mRootWindowContainer.getTopDisplayFocusedRootTask(); Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false) + "} from uid " + callingUid + " on display " + (focusedStack == null ? DEFAULT_DISPLAY @@ -1161,12 +1161,25 @@ class ActivityStarter { aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/); } + final ActivityRecord r = new ActivityRecord.Builder(mService) + .setCaller(callerApp) + .setLaunchedFromPid(callingPid) + .setLaunchedFromUid(callingUid) + .setLaunchedFromPackage(callingPackage) + .setLaunchedFromFeature(callingFeatureId) + .setIntent(intent) + .setResolvedType(resolvedType) + .setActivityInfo(aInfo) + .setConfiguration(mService.getGlobalConfiguration()) + .setResultTo(resultRecord) + .setResultWho(resultWho) + .setRequestCode(requestCode) + .setComponentSpecified(request.componentSpecified) + .setRootVoiceInteraction(voiceSession != null) + .setActivityOptions(checkedOptions) + .setSourceRecord(sourceRecord) + .build(); - final ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid, - callingPackage, callingFeatureId, intent, resolvedType, aInfo, - mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode, - request.componentSpecified, voiceSession != null, mSupervisor, checkedOptions, - sourceRecord); mLastStartActivityRecord = r; if (r.appTimeTracker == null && sourceRecord != null) { @@ -1175,7 +1188,7 @@ class ActivityStarter { r.appTimeTracker = sourceRecord.appTimeTracker; } - final Task stack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task stack = mRootWindowContainer.getTopDisplayFocusedRootTask(); // If we are starting an activity that is not from the same uid as the currently resumed // one, check whether app switches are allowed. @@ -1718,7 +1731,7 @@ class ActivityStarter { // If the activity being launched is the same as the one currently at the top, then // we need to check if it should only be launched once. - final Task topStack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task topStack = mRootWindowContainer.getTopDisplayFocusedRootTask(); if (topStack != null) { startResult = deliverToCurrentTopIfNeeded(topStack, intentGrants); if (startResult != START_SUCCESS) { @@ -1806,14 +1819,14 @@ class ActivityStarter { // task stack to be focusable, then ensure that we now update the focused stack // accordingly. if (mTargetStack.isTopActivityFocusable() - && !mRootWindowContainer.isTopDisplayFocusedStack(mTargetStack)) { + && !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetStack)) { mTargetStack.moveToFront("startActivityInner"); } - mRootWindowContainer.resumeFocusedStacksTopActivities( + mRootWindowContainer.resumeFocusedTasksTopActivities( mTargetStack, mStartActivity, mOptions); } } - mRootWindowContainer.updateUserStack(mStartActivity.mUserId, mTargetStack); + mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetStack); // Update the recent tasks list immediately when the activity starts mSupervisor.mRecentTasks.add(mStartActivity.getTask()); @@ -1849,7 +1862,7 @@ class ActivityStarter { private void computeLaunchParams(ActivityRecord r, ActivityRecord sourceRecord, Task targetTask) { final Task sourceStack = mSourceStack != null ? mSourceStack - : mRootWindowContainer.getTopDisplayFocusedStack(); + : mRootWindowContainer.getTopDisplayFocusedRootTask(); if (sourceStack != null && sourceStack.inSplitScreenWindowingMode() && (mOptions == null || mOptions.getLaunchWindowingMode() == WINDOWING_MODE_UNDEFINED)) { @@ -2048,7 +2061,7 @@ class ActivityStarter { // For paranoia, make sure we have correctly resumed the top activity. topStack.mLastPausedActivity = null; if (mDoResume) { - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } ActivityOptions.abort(mOptions); if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { @@ -2347,7 +2360,7 @@ class ActivityStarter { if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { ActivityRecord checkedCaller = sourceRecord; if (checkedCaller == null) { - Task topFocusedStack = mRootWindowContainer.getTopDisplayFocusedStack(); + Task topFocusedStack = mRootWindowContainer.getTopDisplayFocusedRootTask(); if (topFocusedStack != null) { checkedCaller = topFocusedStack.topRunningNonDelayedActivityLocked(mNotTop); } @@ -2567,7 +2580,7 @@ class ActivityStarter { // to the front if the caller is not itself in the front. final boolean differentTopTask; if (mTargetStack.getDisplayArea() == mPreferredTaskDisplayArea) { - final Task focusStack = mTargetStack.mDisplayContent.getFocusedStack(); + final Task focusStack = mTargetStack.mDisplayContent.getFocusedRootTask(); final ActivityRecord curTop = (focusStack == null) ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop); final Task topTask = curTop != null ? curTop.getTask() : null; @@ -2634,11 +2647,11 @@ class ActivityStarter { if (next != null) { next.setCurrentLaunchCanTurnScreenOn(true); } - mRootWindowContainer.resumeFocusedStacksTopActivities(mTargetStack, null, mOptions); + mRootWindowContainer.resumeFocusedTasksTopActivities(mTargetStack, null, mOptions); } else { ActivityOptions.abort(mOptions); } - mRootWindowContainer.updateUserStack(mStartActivity.mUserId, mTargetStack); + mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetStack); } private void setNewTask(Task taskToAffiliate) { @@ -2713,7 +2726,7 @@ class ActivityStarter { final boolean onTop = (aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind; - return mRootWindowContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams, + return mRootWindowContainer.getLaunchRootTask(r, aOptions, task, onTop, mLaunchParams, mRequest.realCallingPid, mRequest.realCallingUid); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 8ba76be65cb6..3710120a7934 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -1156,7 +1156,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { // If this is coming from the currently resumed activity, it is // effectively saying that app switches are allowed at this point. - final Task stack = getTopDisplayFocusedStack(); + final Task stack = getTopDisplayFocusedRootTask(); if (stack != null && stack.mResumedActivity != null && stack.mResumedActivity.info.applicationInfo.uid == Binder.getCallingUid()) { mAppSwitchesAllowedTime = 0; @@ -1470,7 +1470,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { sourceToken = resultTo; } - sourceRecord = mRootWindowContainer.isInAnyStack(sourceToken); + sourceRecord = mRootWindowContainer.isInAnyTask(sourceToken); if (sourceRecord == null) { throw new SecurityException("Called with bad activity token: " + sourceToken); } @@ -2039,7 +2039,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public boolean isTopActivityImmersive() { enforceNotIsolatedCaller("isTopActivityImmersive"); synchronized (mGlobalLock) { - final Task topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedRootTask(); if (topFocusedStack == null) { return false; } @@ -2074,7 +2074,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public int getFrontActivityScreenCompatMode() { enforceNotIsolatedCaller("getFrontActivityScreenCompatMode"); synchronized (mGlobalLock) { - final Task stack = getTopDisplayFocusedStack(); + final Task stack = getTopDisplayFocusedRootTask(); final ActivityRecord r = stack != null ? stack.topRunningActivity() : null; if (r == null) { return ActivityManager.COMPAT_MODE_UNKNOWN; @@ -2089,7 +2089,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { "setFrontActivityScreenCompatMode"); ApplicationInfo ai; synchronized (mGlobalLock) { - final Task stack = getTopDisplayFocusedStack(); + final Task stack = getTopDisplayFocusedRootTask(); final ActivityRecord r = stack != null ? stack.topRunningActivity() : null; if (r == null) { Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity"); @@ -2165,7 +2165,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public void notifyActivityDrawn(IBinder token) { if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY, "notifyActivityDrawn: token=" + token); synchronized (mGlobalLock) { - ActivityRecord r = mRootWindowContainer.isInAnyStack(token); + ActivityRecord r = mRootWindowContainer.isInAnyTask(token); if (r != null) { r.getRootTask().notifyActivityDrawnLocked(r); } @@ -2201,7 +2201,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - Task focusedStack = getTopDisplayFocusedStack(); + Task focusedStack = getTopDisplayFocusedRootTask(); if (focusedStack != null) { return mRootWindowContainer.getRootTaskInfo(focusedStack.mTaskId); } @@ -2219,14 +2219,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final long callingId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - final Task task = mRootWindowContainer.getStack(taskId); + final Task task = mRootWindowContainer.getRootTask(taskId); if (task == null) { Slog.w(TAG, "setFocusedRootTask: No task with id=" + taskId); return; } final ActivityRecord r = task.topRunningActivity(); if (r != null && r.moveFocusableActivityToTop("setFocusedRootTask")) { - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } } } finally { @@ -2248,7 +2248,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } final ActivityRecord r = task.topRunningActivityLocked(); if (r != null && r.moveFocusableActivityToTop("setFocusedTask")) { - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } } } finally { @@ -2508,7 +2508,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { final long origId = Binder.clearCallingIdentity(); try { - final Task topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedRootTask(); if (topFocusedStack != null) { topFocusedStack.unhandledBackLocked(); } @@ -2820,7 +2820,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { ProtoLog.d(WM_DEBUG_TASKS, "moveTaskToRootTask: moving task=%d to " + "rootTaskId=%d toTop=%b", taskId, rootTaskId, toTop); - final Task rootTask = mRootWindowContainer.getStack(rootTaskId); + final Task rootTask = mRootWindowContainer.getRootTask(rootTaskId); if (rootTask == null) { throw new IllegalStateException( "moveTaskToRootTask: No rootTask for rootTaskId=" + rootTaskId); @@ -3088,8 +3088,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return; } - final Task stack = mRootWindowContainer.getTopDisplayFocusedStack(); - if (stack == null || task != stack.getTopMostTask()) { + final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); + if (rootTask == null || task != rootTask.getTopMostTask()) { throw new IllegalArgumentException("Invalid task, not in foreground"); } @@ -3370,7 +3370,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } final Task stack = r.getRootTask(); - final Task task = stack.getDisplayArea().createStack(stack.getWindowingMode(), + final Task task = stack.getDisplayArea().createRootTask(stack.getWindowingMode(), stack.getActivityType(), !ON_TOP, ainfo, intent, false /* createdByOrganizer */); @@ -3533,7 +3533,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { try { ProtoLog.d(WM_DEBUG_TASKS, "moveRootTaskToDisplay: moving taskId=%d to " + "displayId=%d", taskId, displayId); - mRootWindowContainer.moveStackToDisplay(taskId, displayId, ON_TOP); + mRootWindowContainer.moveRootTaskToDisplay(taskId, displayId, ON_TOP); } finally { Binder.restoreCallingIdentity(ident); } @@ -3741,7 +3741,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { "enqueueAssistContext()"); synchronized (mGlobalLock) { - final Task stack = getTopDisplayFocusedStack(); + final Task stack = getTopDisplayFocusedRootTask(); ActivityRecord activity = stack != null ? stack.getTopNonFinishingActivity() : null; if (activity == null) { Slog.w(TAG, "getAssistContextExtras failed: no top activity"); @@ -3870,7 +3870,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public boolean isAssistDataAllowedOnCurrentActivity() { int userId; synchronized (mGlobalLock) { - final Task focusedStack = getTopDisplayFocusedStack(); + final Task focusedStack = getTopDisplayFocusedRootTask(); if (focusedStack == null || focusedStack.isActivityTypeAssistant()) { return false; } @@ -3890,7 +3890,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { try { synchronized (mGlobalLock) { ActivityRecord caller = ActivityRecord.forTokenLocked(token); - ActivityRecord top = getTopDisplayFocusedStack().getTopNonFinishingActivity(); + ActivityRecord top = getTopDisplayFocusedRootTask().getTopNonFinishingActivity(); if (top != caller) { Slog.w(TAG, "showAssistFromActivity failed: caller " + caller + " is not current top " + top); @@ -4069,7 +4069,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final long ident = Binder.clearCallingIdentity(); try { - return mRootWindowContainer.moveTopStackActivityToPinnedRootTask(rootTaskId); + return mRootWindowContainer.moveTopRootTaskActivityToPinnedRootTask(rootTaskId); } finally { Binder.restoreCallingIdentity(ident); } @@ -4113,7 +4113,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { r.setPictureInPictureParams(params); final float aspectRatio = r.pictureInPictureArgs.getAspectRatio(); final List<RemoteAction> actions = r.pictureInPictureArgs.getActions(); - mRootWindowContainer.moveActivityToPinnedStack( + mRootWindowContainer.moveActivityToPinnedRootTask( r, "enterPictureInPictureMode"); final Task stack = r.getRootTask(); stack.setPictureInPictureAspectRatio(aspectRatio); @@ -4345,7 +4345,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) { Slog.i(TAG, "Activity tried to startLocalVoiceInteraction"); synchronized (mGlobalLock) { - ActivityRecord activity = getTopDisplayFocusedStack().getTopNonFinishingActivity(); + ActivityRecord activity = getTopDisplayFocusedRootTask().getTopNonFinishingActivity(); if (ActivityRecord.forTokenLocked(callingActivity) != activity) { throw new SecurityException("Only focused activity can call startVoiceInteraction"); } @@ -4749,7 +4749,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (r.requestedVrComponent != null && r.getDisplayId() != DEFAULT_DISPLAY) { Slog.i(TAG, "Moving " + r.shortComponentName + " from display " + r.getDisplayId() + " to main display for VR"); - mRootWindowContainer.moveStackToDisplay( + mRootWindowContainer.moveRootTaskToDisplay( r.getRootTaskId(), DEFAULT_DISPLAY, true /* toTop */); } mH.post(() -> { @@ -4813,8 +4813,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } - Task getTopDisplayFocusedStack() { - return mRootWindowContainer.getTopDisplayFocusedStack(); + Task getTopDisplayFocusedRootTask() { + return mRootWindowContainer.getTopDisplayFocusedRootTask(); } /** Pokes the task persister. */ @@ -5827,7 +5827,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** Applies latest configuration and/or visibility updates if needed. */ boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) { boolean kept = true; - final Task mainStack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task mainStack = mRootWindowContainer.getTopDisplayFocusedRootTask(); // mainStack is null during startup. if (mainStack != null) { if (changes != 0 && starting == null) { @@ -6082,8 +6082,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { static final int REPORT_TIME_TRACKER_MSG = 1; - static final int FIRST_ACTIVITY_STACK_MSG = 100; - static final int FIRST_SUPERVISOR_STACK_MSG = 200; + static final int FIRST_ACTIVITY_TASK_MSG = 100; + static final int FIRST_SUPERVISOR_TASK_MSG = 200; H(Looper looper) { super(looper); @@ -6292,7 +6292,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { "setFocusedActivity: No activity record matching token=" + token); } if (r.moveFocusableActivityToTop("setFocusedActivity")) { - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } } } @@ -6796,7 +6796,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (!restarting && hasVisibleActivities) { deferWindowLayout(); try { - if (!mRootWindowContainer.resumeFocusedStacksTopActivities()) { + if (!mRootWindowContainer.resumeFocusedTasksTopActivities()) { // If there was nothing to resume, and we are not already restarting // this process, but there is a visible activity that is hosted by the // process...then make sure all visible activities are running, taking @@ -6849,7 +6849,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (mRootWindowContainer.finishDisabledPackageActivities( packageName, disabledClasses, true /* doit */, false /* evenPersistent */, userId, false /* onlyRemoveNoProcess */) && booted) { - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); mTaskSupervisor.scheduleIdle(); } @@ -6879,7 +6879,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void resumeTopActivities(boolean scheduleIdle) { synchronized (mGlobalLock) { - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); if (scheduleIdle) { mTaskSupervisor.scheduleIdle(); } @@ -7056,7 +7056,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mRootWindowContainer.dumpDisplayConfigs(pw, " "); } if (dumpAll) { - final Task topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedRootTask(); if (dumpPackage == null && topFocusedStack != null) { pw.println(" mConfigWillChange: " + topFocusedStack.mConfigWillChange); } @@ -7139,7 +7139,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { if (dumpPackage == null) { getGlobalConfiguration().dumpDebug(proto, GLOBAL_CONFIGURATION); - final Task topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedRootTask(); if (topFocusedStack != null) { proto.write(CONFIG_WILL_CHANGE, topFocusedStack.mConfigWillChange); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index d0c26af82d99..73d99724c65f 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -63,7 +63,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; -import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_STACK_MSG; +import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_TASK_MSG; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED; import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE; @@ -176,18 +176,18 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { /** How long we wait until giving up on the activity telling us it released the top state. */ private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT = 500; - private static final int IDLE_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG; - private static final int IDLE_NOW_MSG = FIRST_SUPERVISOR_STACK_MSG + 1; - private static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_STACK_MSG + 2; - private static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 3; - private static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 4; - private static final int PROCESS_STOPPING_AND_FINISHING_MSG = FIRST_SUPERVISOR_STACK_MSG + 5; - private static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_STACK_MSG + 12; - private static final int RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 13; - private static final int REPORT_MULTI_WINDOW_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 14; - private static final int REPORT_PIP_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 15; - private static final int START_HOME_MSG = FIRST_SUPERVISOR_STACK_MSG + 16; - private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 17; + private static final int IDLE_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG; + private static final int IDLE_NOW_MSG = FIRST_SUPERVISOR_TASK_MSG + 1; + private static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_TASK_MSG + 2; + private static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG + 3; + private static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG + 4; + private static final int PROCESS_STOPPING_AND_FINISHING_MSG = FIRST_SUPERVISOR_TASK_MSG + 5; + private static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_TASK_MSG + 12; + private static final int RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG + 13; + private static final int REPORT_MULTI_WINDOW_MODE_CHANGED_MSG = FIRST_SUPERVISOR_TASK_MSG + 14; + private static final int REPORT_PIP_MODE_CHANGED_MSG = FIRST_SUPERVISOR_TASK_MSG + 15; + private static final int START_HOME_MSG = FIRST_SUPERVISOR_TASK_MSG + 16; + private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG + 17; // Used to indicate that windows of activities should be preserved during the resize. static final boolean PRESERVE_WINDOWS = true; @@ -202,8 +202,8 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // Used to indicate that a task is removed it should also be removed from recents. static final boolean REMOVE_FROM_RECENTS = true; - /** True if the docked stack is currently being resized. */ - private boolean mDockedStackResizing; + /** True if the docked root task is currently being resized. */ + private boolean mDockedRootTaskResizing; // Activity actions an app cannot start if it uses a permission which is not granted. private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION = @@ -307,7 +307,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { /** The target stack bounds for the picture-in-picture mode changed that we need to report to * the application */ - private Rect mPipModeChangedTargetStackBounds; + private Rect mPipModeChangedTargetRootTaskBounds; /** Used on user changes */ final ArrayList<UserState> mStartingUsers = new ArrayList<>(); @@ -386,17 +386,17 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { final ActivityRecord r; final ActivityRecord sourceRecord; final int startFlags; - final Task stack; + final Task rootTask; final WindowProcessController callerApp; final NeededUriGrants intentGrants; PendingActivityLaunch(ActivityRecord r, ActivityRecord sourceRecord, - int startFlags, Task stack, WindowProcessController callerApp, + int startFlags, Task rootTask, WindowProcessController callerApp, NeededUriGrants intentGrants) { this.r = r; this.sourceRecord = sourceRecord; this.startFlags = startFlags; - this.stack = stack; + this.rootTask = rootTask; this.callerApp = callerApp; this.intentGrants = intentGrants; } @@ -501,11 +501,11 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { getKeyguardController().setWindowManager(wm); } - void moveRecentsStackToFront(String reason) { - final Task recentsStack = mRootWindowContainer.getDefaultTaskDisplayArea() - .getStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS); - if (recentsStack != null) { - recentsStack.moveToFront(reason); + void moveRecentsRootTaskToFront(String reason) { + final Task recentsRootTask = mRootWindowContainer.getDefaultTaskDisplayArea() + .getRootTask(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS); + if (recentsRootTask != null) { + recentsRootTask.moveToFront(reason); } } @@ -944,7 +944,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // launching the initial activity (that is, home), so that it can have // a chance to initialize itself while in the background, making the // switch back to it faster and look better. - if (mRootWindowContainer.isTopDisplayFocusedStack(rootTask)) { + if (mRootWindowContainer.isTopDisplayFocusedRootTask(rootTask)) { mService.getActivityStartController().startSetupActivity(); } @@ -1376,10 +1376,10 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { task.setBounds(bounds); Task stack = - mRootWindowContainer.getLaunchStack(null, options, task, ON_TOP); + mRootWindowContainer.getLaunchRootTask(null, options, task, ON_TOP); if (stack != currentStack) { - moveHomeStackToFrontIfNeeded(flags, stack.getDisplayArea(), reason); + moveHomeRootTaskToFrontIfNeeded(flags, stack.getDisplayArea(), reason); task.reparent(stack, ON_TOP, REPARENT_KEEP_ROOT_TASK_AT_FRONT, !ANIMATE, DEFER_RESUME, reason); currentStack = stack; @@ -1398,7 +1398,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { } if (!reparented) { - moveHomeStackToFrontIfNeeded(flags, currentStack.getDisplayArea(), reason); + moveHomeRootTaskToFrontIfNeeded(flags, currentStack.getDisplayArea(), reason); } final ActivityRecord r = task.getTopNonFinishingActivity(); @@ -1412,16 +1412,16 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { mRootWindowContainer.getDefaultTaskDisplayArea(), currentStack, forceNonResizeable); } - private void moveHomeStackToFrontIfNeeded(int flags, TaskDisplayArea taskDisplayArea, + private void moveHomeRootTaskToFrontIfNeeded(int flags, TaskDisplayArea taskDisplayArea, String reason) { - final Task focusedStack = taskDisplayArea.getFocusedStack(); + final Task focusedRootTask = taskDisplayArea.getFocusedRootTask(); if ((taskDisplayArea.getWindowingMode() == WINDOWING_MODE_FULLSCREEN && (flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) - || (focusedStack != null && focusedStack.isActivityTypeRecents())) { + || (focusedRootTask != null && focusedRootTask.isActivityTypeRecents())) { // We move home stack to front when we are on a fullscreen display area and caller has // requested the home activity to move with it. Or the previous stack is recents. - taskDisplayArea.moveHomeStackToFront(reason); + taskDisplayArea.moveHomeRootTaskToFront(reason); } } @@ -1441,15 +1441,15 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { } void setSplitScreenResizing(boolean resizing) { - if (resizing == mDockedStackResizing) { + if (resizing == mDockedRootTaskResizing) { return; } - mDockedStackResizing = resizing; + mDockedRootTaskResizing = resizing; mWindowManager.setDockedStackResizing(resizing); } - private void removePinnedStackInSurfaceTransaction(Task stack) { + private void removePinnedRootTaskInSurfaceTransaction(Task rootTask) { /** * Workaround: Force-stop all the activities in the pinned stack before we reparent them * to the fullscreen stack. This is to guarantee that when we are removing a stack, @@ -1459,9 +1459,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { * marked invisible as well and added to the stopping list. After which we process the * stopping list by handling the idle. */ - stack.cancelAnimation(); - stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */); - stack.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); + rootTask.cancelAnimation(); + rootTask.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */); + rootTask.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); activityIdleInternal(null /* idleActivity */, false /* fromTimeout */, true /* processPausingActivities */, null /* configuration */); @@ -1471,17 +1471,17 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { mService.deferWindowLayout(); try { - stack.setWindowingMode(WINDOWING_MODE_UNDEFINED); - if (stack.getWindowingMode() != WINDOWING_MODE_FREEFORM) { - stack.setBounds(null); + rootTask.setWindowingMode(WINDOWING_MODE_UNDEFINED); + if (rootTask.getWindowingMode() != WINDOWING_MODE_FREEFORM) { + rootTask.setBounds(null); } - toDisplay.getDefaultTaskDisplayArea().positionTaskBehindHome(stack); + toDisplay.getDefaultTaskDisplayArea().positionTaskBehindHome(rootTask); // Follow on the workaround: activities are kept force hidden till the new windowing // mode is set. - stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */); + rootTask.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */); mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } finally { mService.continueWindowLayout(); } @@ -1489,7 +1489,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { private void removeRootTaskInSurfaceTransaction(Task rootTask) { if (rootTask.getWindowingMode() == WINDOWING_MODE_PINNED) { - removePinnedStackInSurfaceTransaction(rootTask); + removePinnedRootTaskInSurfaceTransaction(rootTask); } else { final PooledConsumer c = PooledLambda.obtainConsumer( ActivityTaskSupervisor::processRemoveTask, this, PooledLambda.__(Task.class)); @@ -1627,7 +1627,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { */ boolean restoreRecentTaskLocked(Task task, ActivityOptions aOptions, boolean onTop) { final Task stack = - mRootWindowContainer.getLaunchStack(null, aOptions, task, onTop); + mRootWindowContainer.getLaunchRootTask(null, aOptions, task, onTop); final WindowContainer parent = task.getParent(); if (parent == stack || task == stack) { @@ -1668,7 +1668,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { * the various checks on tasks that are going to be reparented from one stack to another. */ // TODO: Look into changing users to this method to DisplayContent.resolveWindowingMode() - Task getReparentTargetStack(Task task, Task stack, boolean toTop) { + Task getReparentTargetRootTask(Task task, Task stack, boolean toTop) { final Task prevStack = task.getRootTask(); final int rootTaskId = stack.mTaskId; final boolean inMultiWindowMode = stack.inMultiWindowMode(); @@ -1709,7 +1709,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { if (prevStack != null) { return prevStack; } - stack = stack.getDisplayArea().createStack( + stack = stack.getDisplayArea().createRootTask( WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), toTop); } return stack; @@ -1739,7 +1739,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { boolean timedout = false; final long endTime = System.currentTimeMillis() + timeout; while (true) { - if (!mRootWindowContainer.putStacksToSleep( + if (!mRootWindowContainer.putTasksToSleep( true /* allowDelay */, true /* shuttingDown */)) { long timeRemaining = endTime - System.currentTimeMillis(); if (timeRemaining > 0) { @@ -1776,7 +1776,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { return; } - if (!mRootWindowContainer.putStacksToSleep( + if (!mRootWindowContainer.putTasksToSleep( allowDelay, false /* shuttingDown */)) { return; } @@ -1931,7 +1931,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { mService.getLockTaskController().dump(pw, prefix); pw.print(prefix); pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser); - pw.println(prefix + "mUserStackInFront=" + mRootWindowContainer.mUserStackInFront); + pw.println(prefix + "mUserRootTaskInFront=" + mRootWindowContainer.mUserRootTaskInFront); pw.println(prefix + "mVisibilityTransactionDepth=" + mVisibilityTransactionDepth); if (!mWaitingForActivityVisible.isEmpty()) { pw.println(prefix + "mWaitingForActivityVisible="); @@ -2058,7 +2058,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { */ void updateTopResumedActivityIfNeeded() { final ActivityRecord prevTopActivity = mTopResumedActivity; - final Task topStack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task topStack = mRootWindowContainer.getTopDisplayFocusedRootTask(); if (topStack == null || topStack.mResumedActivity == prevTopActivity) { if (mService.isSleepingLocked()) { // There won't be a next resumed activity. The top process should still be updated @@ -2242,7 +2242,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { } } - void logStackState() { + void logRootTaskState() { mActivityMetricsLogger.logWindowState(); } @@ -2281,7 +2281,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { task.forAllActivities(c); c.recycle(); - mPipModeChangedTargetStackBounds = targetStackBounds; + mPipModeChangedTargetRootTaskBounds = targetStackBounds; if (!mHandler.hasMessages(REPORT_PIP_MODE_CHANGED_MSG)) { mHandler.sendEmptyMessage(REPORT_PIP_MODE_CHANGED_MSG); @@ -2436,7 +2436,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { case REPORT_PIP_MODE_CHANGED_MSG: { for (int i = mPipModeChangedActivities.size() - 1; i >= 0; i--) { final ActivityRecord r = mPipModeChangedActivities.remove(i); - r.updatePictureInPictureMode(mPipModeChangedTargetStackBounds, + r.updatePictureInPictureMode(mPipModeChangedTargetRootTaskBounds, false /* forceUpdate */); } } break; @@ -2452,7 +2452,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { activityIdleFromMessage((ActivityRecord) msg.obj, false /* fromTimeout */); } break; case RESUME_TOP_ACTIVITY_MSG: { - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } break; case SLEEP_TIMEOUT_MSG: { if (mService.isSleepingOrShuttingDownLocked()) { @@ -2542,7 +2542,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // from whatever is started from the recents activity, so move the home stack // forward. // TODO (b/115289124): Multi-display supports for recents. - mRootWindowContainer.getDefaultTaskDisplayArea().moveHomeStackToFront( + mRootWindowContainer.getDefaultTaskDisplayArea().moveHomeRootTaskToFront( "startActivityFromRecents"); } @@ -2570,6 +2570,11 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { mService.getActivityStartController().postStartActivityProcessingForLastStarter( task.getTopNonFinishingActivity(), ActivityManager.START_TASK_TO_FRONT, task.getRootTask()); + + // As it doesn't go to ActivityStarter.executeRequest() path, we need to resume + // app switching here also. + mService.resumeAppSwitches(); + return ActivityManager.START_TASK_TO_FRONT; } callingPackage = task.mCallingPackage; diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index 4b349542e347..c22bd20da042 100644 --- a/services/core/java/com/android/server/wm/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -17,10 +17,10 @@ package com.android.server.wm; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; -import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import android.app.ActivityManager; import android.app.AppGlobals; @@ -313,7 +313,7 @@ public final class CompatModePackages { scheduleWrite(); - final Task stack = mService.getTopDisplayFocusedStack(); + final Task stack = mService.getTopDisplayFocusedRootTask(); ActivityRecord starting = stack.restartPackage(packageName); // Tell all processes that loaded this package about the change. diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 5df50500f3e2..1d2cd0a0a350 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1320,7 +1320,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp false /* deferResume */, null /* result */); activityRecord.frozenBeforeDestroy = true; if (!kept) { - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } } else { // We have a new configuration to push so we need to update ATMS for now. @@ -2243,26 +2243,26 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * activity type. Null is no compatible stack on the display. */ @Nullable - Task getStack(int windowingMode, int activityType) { + Task getRootTask(int windowingMode, int activityType) { return getItemFromTaskDisplayAreas(taskDisplayArea -> - taskDisplayArea.getStack(windowingMode, activityType)); + taskDisplayArea.getRootTask(windowingMode, activityType)); } @Nullable - Task getStack(int rootTaskId) { + Task getRootTask(int rootTaskId) { return getItemFromTaskDisplayAreas(taskDisplayArea -> - taskDisplayArea.getStack(rootTaskId)); + taskDisplayArea.getRootTask(rootTaskId)); } - protected int getStackCount() { + protected int getRootTaskCount() { return reduceOnAllTaskDisplayAreas((taskDisplayArea, count) -> - count + taskDisplayArea.getStackCount(), 0 /* initValue */); + count + taskDisplayArea.getRootTaskCount(), 0 /* initValue */); } @VisibleForTesting @Nullable - Task getTopStack() { - return getItemFromTaskDisplayAreas(TaskDisplayArea::getTopStack); + Task getTopRootTask() { + return getItemFromTaskDisplayAreas(TaskDisplayArea::getTopRootTask); } /** @@ -2926,7 +2926,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mClosingApps.valueAt(i).writeIdentifierToProto(proto, CLOSING_APPS); } - final Task focusedStack = getFocusedStack(); + final Task focusedStack = getFocusedRootTask(); if (focusedStack != null) { proto.write(FOCUSED_ROOT_TASK_ID, focusedStack.getRootTaskId()); final ActivityRecord focusedActivity = focusedStack.getDisplayArea() @@ -2970,7 +2970,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp public void dump(PrintWriter pw, String prefix, boolean dumpAll) { super.dump(pw, prefix, dumpAll); pw.print(prefix); - pw.println("Display: mDisplayId=" + mDisplayId + " stacks=" + getStackCount()); + pw.println("Display: mDisplayId=" + mDisplayId + " stacks=" + getRootTaskCount()); final String subPrefix = " " + prefix; pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x"); pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity); @@ -3068,13 +3068,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp pw.println(prefix + "splitScreenPrimaryStack=" + splitScreenPrimaryStack.getName()); } // TODO: Support recents on non-default task containers - final Task recentsStack = getDefaultTaskDisplayArea().getStack( + final Task recentsStack = getDefaultTaskDisplayArea().getRootTask( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS); if (recentsStack != null) { pw.println(prefix + "recentsStack=" + recentsStack.getName()); } final Task dreamStack = - getStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_DREAM); + getRootTask(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_DREAM); if (dreamStack != null) { pw.println(prefix + "dreamStack=" + dreamStack.getName()); } @@ -4516,9 +4516,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } } - void assignStackOrdering() { + void assignRootTaskOrdering() { forAllTaskDisplayAreas(taskDisplayArea -> { - taskDisplayArea.assignStackOrdering(getPendingTransaction()); + taskDisplayArea.assignRootTaskOrdering(getPendingTransaction()); }); } @@ -5083,7 +5083,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mWmService.requestTraversal(); } - static boolean alwaysCreateStack(int windowingMode, int activityType) { + static boolean alwaysCreateRootTask(int windowingMode, int activityType) { // Always create a stack for fullscreen, freeform, and split-screen-secondary windowing // modes so that we can manage visual ordering and return types correctly. return activityType == ACTIVITY_TYPE_STANDARD @@ -5097,13 +5097,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp static boolean canReuseExistingTask(int windowingMode, int activityType) { // Existing Tasks can be reused if a new stack will be created anyway, or for the Dream - // because there can only ever be one DreamActivity. - return alwaysCreateStack(windowingMode, activityType) + return alwaysCreateRootTask(windowingMode, activityType) || activityType == ACTIVITY_TYPE_DREAM; } @Nullable - Task getFocusedStack() { - return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedStack); + Task getFocusedRootTask() { + return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedRootTask); } /** @@ -5340,19 +5340,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // Check if all task display areas have only the empty home stacks left. boolean hasNonEmptyHomeStack = forAllTaskDisplayAreas(taskDisplayArea -> { - if (taskDisplayArea.getStackCount() != 1) { + if (taskDisplayArea.getRootTaskCount() != 1) { return true; } - final Task stack = taskDisplayArea.getStackAt(0); + final Task stack = taskDisplayArea.getRootTaskAt(0); return !stack.isActivityTypeHome() || stack.hasChild(); }); if (!hasNonEmptyHomeStack) { // Release this display if only empty home stack(s) are left. This display will be // released along with the stack(s) removal. forAllTaskDisplayAreas(taskDisplayArea -> { - taskDisplayArea.getStackAt(0).removeIfPossible(); + taskDisplayArea.getRootTaskAt(0).removeIfPossible(); }); - } else if (getTopStack() == null) { + } else if (getTopRootTask() == null) { removeIfPossible(); mRootWindowContainer.mTaskSupervisor .getKeyguardController().onDisplayRemoved(mDisplayId); @@ -5379,7 +5379,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } boolean shouldSleep() { - return (getStackCount() == 0 || !mAllSleepTokens.isEmpty()) + return (getRootTaskCount() == 0 || !mAllSleepTokens.isEmpty()) && (mAtmService.mRunningVoice == null); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 826b7259a9ff..2ddd00101769 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -2046,7 +2046,7 @@ public class DisplayPolicy { // requests to hide the status bar. Not sure if there is another way that to be the // case though. if (!topIsFullscreen || mDisplayContent.getDefaultTaskDisplayArea() - .isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) { + .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) { topAppHidesStatusBar = false; } } @@ -2830,9 +2830,9 @@ public class DisplayPolicy { private int updateSystemBarsLw(WindowState win, int disableFlags) { final boolean dockedStackVisible = mDisplayContent.getDefaultTaskDisplayArea() - .isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); final boolean freeformStackVisible = mDisplayContent.getDefaultTaskDisplayArea() - .isStackVisible(WINDOWING_MODE_FREEFORM); + .isRootTaskVisible(WINDOWING_MODE_FREEFORM); final boolean resizing = mDisplayContent.getDockedDividerController().isResizing(); // We need to force system bars when the docked stack is visible, when the freeform stack diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index d308766b9fe5..ee150c31184c 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -392,9 +392,9 @@ class InsetsPolicy { private boolean forceShowsSystemBarsForWindowingMode() { final boolean isDockedStackVisible = mDisplayContent.getDefaultTaskDisplayArea() - .isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); final boolean isFreeformStackVisible = mDisplayContent.getDefaultTaskDisplayArea() - .isStackVisible(WINDOWING_MODE_FREEFORM); + .isRootTaskVisible(WINDOWING_MODE_FREEFORM); final boolean isResizing = mDisplayContent.getDockedDividerController().isResizing(); // We need to force system bars when the docked stack is visible, when the freeform stack diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index ebd91a093326..e45310a99fbd 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -211,7 +211,7 @@ class KeyguardController { updateKeyguardSleepToken(); // Some stack visibility might change (e.g. docked stack) - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); mRootWindowContainer.addStartingWindowsForVisibleActivities(); mWindowManager.executeAppTransition(); @@ -595,8 +595,8 @@ class KeyguardController { @Nullable private Task getRootTaskForControllingOccluding(DisplayContent display) { return display.getItemFromTaskDisplayAreas(taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task task = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task task = taskDisplayArea.getRootTaskAt(sNdx); if (task != null && task.isFocusableAndVisible() && !task.inPinnedWindowingMode()) { return task; diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java index b6b172eeae5b..8745e95dba4d 100644 --- a/services/core/java/com/android/server/wm/LaunchParamsController.java +++ b/services/core/java/com/android/server/wm/LaunchParamsController.java @@ -143,7 +143,7 @@ class LaunchParamsController { try { if (mTmpParams.mPreferredTaskDisplayArea != null && task.getDisplayArea() != mTmpParams.mPreferredTaskDisplayArea) { - mService.mRootWindowContainer.moveStackToTaskDisplayArea(task.getRootTaskId(), + mService.mRootWindowContainer.moveRootTaskToTaskDisplayArea(task.getRootTaskId(), mTmpParams.mPreferredTaskDisplayArea, true /* onTop */); } diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index ee3978746488..4b3a43432fc5 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -504,7 +504,7 @@ public class LockTaskController { return; } task.performClearTaskLocked(); - mSupervisor.mRootWindowContainer.resumeFocusedStacksTopActivities(); + mSupervisor.mRootWindowContainer.resumeFocusedTasksTopActivities(); } /** @@ -640,7 +640,7 @@ public class LockTaskController { if (andResume) { mSupervisor.findTaskToMoveToFront(task, 0, null, reason, lockTaskModeState != LOCK_TASK_MODE_NONE); - mSupervisor.mRootWindowContainer.resumeFocusedStacksTopActivities(); + mSupervisor.mRootWindowContainer.resumeFocusedTasksTopActivities(); final Task rootTask = task.getRootTask(); if (rootTask != null) { rootTask.mDisplayContent.executeAppTransition(); @@ -717,7 +717,7 @@ public class LockTaskController { } if (taskChanged) { - mSupervisor.mRootWindowContainer.resumeFocusedStacksTopActivities(); + mSupervisor.mRootWindowContainer.resumeFocusedTasksTopActivities(); } } diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index ba6b27ac3252..5598937da63d 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -36,13 +36,13 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.os.Process.SYSTEM_UID; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; -import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS; import android.annotation.Nullable; import android.app.ActivityManager; @@ -220,7 +220,7 @@ class RecentTasks { final RootWindowContainer rac = mService.mRootWindowContainer; final DisplayContent dc = rac.getDisplayContent(displayId).mDisplayContent; if (dc.pointWithinAppWindow(x, y)) { - final Task stack = mService.getTopDisplayFocusedStack(); + final Task stack = mService.getTopDisplayFocusedRootTask(); final Task topTask = stack != null ? stack.getTopMostTask() : null; resetFreezeTaskListReordering(topTask); } @@ -328,7 +328,7 @@ class RecentTasks { @VisibleForTesting void resetFreezeTaskListReorderingOnTimeout() { synchronized (mService.mGlobalLock) { - final Task focusedStack = mService.getTopDisplayFocusedStack(); + final Task focusedStack = mService.getTopDisplayFocusedRootTask(); final Task topTask = focusedStack != null ? focusedStack.getTopMostTask() : null; resetFreezeTaskListReordering(topTask); } diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 823dc51e939f..067c772dad93 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -29,7 +29,7 @@ import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP; -import static com.android.server.wm.TaskDisplayArea.getStackAbove; +import static com.android.server.wm.TaskDisplayArea.getRootTaskAbove; import android.annotation.Nullable; import android.app.ActivityOptions; @@ -45,13 +45,13 @@ import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; import com.android.server.wm.ActivityMetricsLogger.LaunchingState; import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks; +import com.android.server.wm.TaskDisplayArea.OnRootTaskOrderChangedListener; /** * Manages the recents animation, including the reordering of the stacks for the transition and * cleanup. See {@link com.android.server.wm.RecentsAnimationController}. */ -class RecentsAnimation implements RecentsAnimationCallbacks, - TaskDisplayArea.OnStackOrderChangedListener { +class RecentsAnimation implements RecentsAnimationCallbacks, OnRootTaskOrderChangedListener { private static final String TAG = RecentsAnimation.class.getSimpleName(); private final ActivityTaskManagerService mService; @@ -106,7 +106,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, void preloadRecentsActivity() { ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Preload recents with %s", mTargetIntent); - Task targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED, + Task targetStack = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED, mTargetActivityType); ActivityRecord targetActivity = getTargetActivity(targetStack); if (targetActivity != null) { @@ -127,7 +127,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // Create the activity record. Because the activity is invisible, this doesn't really // start the client. startRecentsActivityInBackground("preloadRecents"); - targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED, + targetStack = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED, mTargetActivityType); targetActivity = getTargetActivity(targetStack); if (targetActivity == null) { @@ -165,12 +165,12 @@ class RecentsAnimation implements RecentsAnimationCallbacks, Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "RecentsAnimation#startRecentsActivity"); // If the activity is associated with the recents stack, then try and get that first - Task targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED, + Task targetStack = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED, mTargetActivityType); ActivityRecord targetActivity = getTargetActivity(targetStack); final boolean hasExistingActivity = targetActivity != null; if (hasExistingActivity) { - mRestoreTargetBehindStack = getStackAbove(targetStack); + mRestoreTargetBehindStack = getRootTaskAbove(targetStack); if (mRestoreTargetBehindStack == null) { notifyAnimationCancelBeforeStart(recentsAnimationRunner); ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, @@ -197,9 +197,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks, try { if (hasExistingActivity) { // Move the recents activity into place for the animation if it is not top most - mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(targetStack); + mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(targetStack); ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s", - targetStack, getStackAbove(targetStack)); + targetStack, getRootTaskAbove(targetStack)); // If there are multiple tasks in the target stack (ie. the home stack, with 3p // and default launchers coexisting), then move the task to the top as a part of @@ -213,12 +213,12 @@ class RecentsAnimation implements RecentsAnimationCallbacks, startRecentsActivityInBackground("startRecentsActivity_noTargetActivity"); // Move the recents activity into place for the animation - targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED, + targetStack = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED, mTargetActivityType); targetActivity = getTargetActivity(targetStack); - mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(targetStack); + mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(targetStack); ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s", - targetStack, getStackAbove(targetStack)); + targetStack, getRootTaskAbove(targetStack)); mWindowManager.prepareAppTransitionNone(); mWindowManager.executeAppTransition(); @@ -257,7 +257,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, START_TASK_TO_FRONT, targetActivity, options); // Register for stack order changes - mDefaultTaskDisplayArea.registerStackOrderChangedListener(this); + mDefaultTaskDisplayArea.registerRootTaskOrderChangedListener(this); } catch (Exception e) { Slog.e(TAG, "Failed to start recents activity", e); throw e; @@ -275,7 +275,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mWindowManager.getRecentsAnimationController(), reorderMode); // Unregister for stack order changes - mDefaultTaskDisplayArea.unregisterStackOrderChangedListener(this); + mDefaultTaskDisplayArea.unregisterRootTaskOrderChangedListener(this); final RecentsAnimationController controller = mWindowManager.getRecentsAnimationController(); @@ -303,7 +303,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, try { mWindowManager.cleanupRecentsAnimation(reorderMode); - final Task targetStack = mDefaultTaskDisplayArea.getStack( + final Task targetStack = mDefaultTaskDisplayArea.getRootTask( WINDOWING_MODE_UNDEFINED, mTargetActivityType); // Prefer to use the original target activity instead of top activity because // we may have moved another task to top (starting 3p launcher). @@ -348,10 +348,10 @@ class RecentsAnimation implements RecentsAnimationCallbacks, } else if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION){ // Restore the target stack to its previous position final TaskDisplayArea taskDisplayArea = targetActivity.getDisplayArea(); - taskDisplayArea.moveStackBehindStack(targetStack, + taskDisplayArea.moveRootTaskBehindRootTask(targetStack, mRestoreTargetBehindStack); if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) { - final Task aboveTargetStack = getStackAbove(targetStack); + final Task aboveTargetStack = getRootTaskAbove(targetStack); if (mRestoreTargetBehindStack != null && aboveTargetStack != mRestoreTargetBehindStack) { ProtoLog.w(WM_DEBUG_RECENTS_ANIMATIONS, @@ -378,7 +378,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mWindowManager.prepareAppTransitionNone(); mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, false); - mService.mRootWindowContainer.resumeFocusedStacksTopActivities(); + mService.mRootWindowContainer.resumeFocusedTasksTopActivities(); // No reason to wait for the pausing activity in this case, as the hiding of // surfaces needs to be done immediately. @@ -412,9 +412,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks, } @Override - public void onStackOrderChanged(Task stack) { - ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onStackOrderChanged(): stack=%s", stack); - if (mDefaultTaskDisplayArea.getIndexOf(stack) == -1 || !stack.shouldBeVisible(null)) { + public void onRootTaskOrderChanged(Task rootTask) { + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onStackOrderChanged(): stack=%s", rootTask); + if (mDefaultTaskDisplayArea.getIndexOf(rootTask) == -1 || !rootTask.shouldBeVisible(null)) { // The stack is not visible, so ignore this change return; } @@ -428,8 +428,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // cases: // 1) The next launching task is not being animated by the recents animation // 2) The next task is home activity. (i.e. pressing home key to back home in recents). - if ((!controller.isAnimatingTask(stack.getTopMostTask()) - || controller.isTargetApp(stack.getTopNonFinishingActivity())) + if ((!controller.isAnimatingTask(rootTask.getTopMostTask()) + || controller.isTargetApp(rootTask.getTopNonFinishingActivity())) && controller.shouldDeferCancelUntilNextTransition()) { // Always prepare an app transition since we rely on the transition callbacks to cleanup mWindowManager.prepareAppTransitionNone(); @@ -468,8 +468,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, * @return The top stack that is not always-on-top. */ private Task getTopNonAlwaysOnTopStack() { - for (int i = mDefaultTaskDisplayArea.getStackCount() - 1; i >= 0; i--) { - final Task s = mDefaultTaskDisplayArea.getStackAt(i); + for (int i = mDefaultTaskDisplayArea.getRootTaskCount() - 1; i >= 0; i--) { + final Task s = mDefaultTaskDisplayArea.getRootTaskAt(i); if (s.getWindowConfiguration().isAlwaysOnTop()) { continue; } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index abee032d042a..5da668c8c361 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -398,7 +398,7 @@ public class RecentsAnimationController implements DeathRecipient { final ArrayList<Task> visibleTasks = mDisplayContent.getDefaultTaskDisplayArea() .getVisibleTasks(); final Task targetStack = mDisplayContent.getDefaultTaskDisplayArea() - .getStack(WINDOWING_MODE_UNDEFINED, targetActivityType); + .getRootTask(WINDOWING_MODE_UNDEFINED, targetActivityType); if (targetStack != null) { final PooledConsumer c = PooledLambda.obtainConsumer((t, outList) -> { if (!outList.contains(t)) outList.add(t); }, PooledLambda.__(Task.class), diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java index 7bd5d03f1bc1..17cb8905f260 100644 --- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java +++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java @@ -237,7 +237,7 @@ class ResetTargetTaskHelper { while (!mPendingReparentActivities.isEmpty()) { final ActivityRecord r = mPendingReparentActivities.remove(0); - final boolean alwaysCreateTask = DisplayContent.alwaysCreateStack(windowingMode, + final boolean alwaysCreateTask = DisplayContent.alwaysCreateRootTask(windowingMode, activityType); final Task task = alwaysCreateTask ? taskDisplayArea.getBottomMostTask() : mTargetStack.getBottomMostTask(); @@ -251,7 +251,7 @@ class ResetTargetTaskHelper { } if (targetTask == null) { if (alwaysCreateTask) { - targetTask = taskDisplayArea.getOrCreateStack(windowingMode, + targetTask = taskDisplayArea.getOrCreateRootTask(windowingMode, activityType, false /* onTop */); } else { targetTask = mTargetStack.reuseOrCreateTask(r.info, null /*intent*/, diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index cbeaecf7f58c..497087a967f3 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -256,8 +256,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> /** The current user */ int mCurrentUser; - /** Stack id of the front stack when user switched, indexed by userId. */ - SparseIntArray mUserStackInFront = new SparseIntArray(2); + /** Root task id of the front root task when user switched, indexed by userId. */ + SparseIntArray mUserRootTaskInFront = new SparseIntArray(2); /** * A list of tokens that cause the top activity to be put to sleep. @@ -296,7 +296,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> c.recycle(); } finally { mTaskSupervisor.endDeferResume(); - resumeFocusedStacksTopActivities(); + resumeFocusedTasksTopActivities(); } } } @@ -1484,7 +1484,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> boolean fromHomeKey) { // Fallback to top focused display or default display if the displayId is invalid. if (displayId == INVALID_DISPLAY) { - final Task stack = getTopDisplayFocusedStack(); + final Task stack = getTopDisplayFocusedRootTask(); displayId = stack != null ? stack.getDisplayId() : DEFAULT_DISPLAY; } @@ -1510,7 +1510,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> boolean allowInstrumenting, boolean fromHomeKey) { // Fallback to top focused display area if the provided one is invalid. if (taskDisplayArea == null) { - final Task stack = getTopDisplayFocusedStack(); + final Task stack = getTopDisplayFocusedRootTask(); taskDisplayArea = stack != null ? stack.getDisplayArea() : getDefaultTaskDisplayArea(); } @@ -1677,7 +1677,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Only resume home activity if isn't finishing. if (r != null && !r.finishing) { r.moveFocusableActivityToTop(myReason); - return resumeFocusedStacksTopActivities(r.getRootTask(), prev, null); + return resumeFocusedTasksTopActivities(r.getRootTask(), prev, null); } return startHomeOnTaskDisplayArea(mCurrentUser, myReason, taskDisplayArea, false /* allowInstrumenting */, false /* fromHomeKey */); @@ -1831,12 +1831,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> */ List<IBinder> getTopVisibleActivities() { final ArrayList<IBinder> topActivityTokens = new ArrayList<>(); - final Task topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedRootTask(); // Traverse all displays. forAllTaskDisplayAreas(taskDisplayArea -> { // Traverse all stacks on a display area. - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task stack = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task stack = taskDisplayArea.getRootTaskAt(sNdx); // Get top activity from a visible stack and add it to the list. if (stack.shouldBeVisible(null /* starting */)) { final ActivityRecord top = stack.getTopNonFinishingActivity(); @@ -1854,9 +1854,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } @Nullable - Task getTopDisplayFocusedStack() { + Task getTopDisplayFocusedRootTask() { for (int i = getChildCount() - 1; i >= 0; --i) { - final Task focusedStack = getChildAt(i).getFocusedStack(); + final Task focusedStack = getChildAt(i).getFocusedRootTask(); if (focusedStack != null) { return focusedStack; } @@ -1866,7 +1866,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> @Nullable ActivityRecord getTopResumedActivity() { - final Task focusedStack = getTopDisplayFocusedStack(); + final Task focusedStack = getTopDisplayFocusedRootTask(); if (focusedStack == null) { return null; } @@ -1879,8 +1879,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedActivity); } - boolean isTopDisplayFocusedStack(Task stack) { - return stack != null && stack == getTopDisplayFocusedStack(); + boolean isTopDisplayFocusedRootTask(Task task) { + return task != null && task == getTopDisplayFocusedRootTask(); } void updatePreviousProcess(ActivityRecord r) { @@ -1891,9 +1891,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // previous app if this activity is being hosted by the process that is actually still the // foreground. WindowProcessController fgApp = reduceOnAllTaskDisplayAreas((taskDisplayArea, app) -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task stack = taskDisplayArea.getStackAt(sNdx); - if (isTopDisplayFocusedStack(stack)) { + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task stack = taskDisplayArea.getRootTaskAt(sNdx); + if (isTopDisplayFocusedRootTask(stack)) { final ActivityRecord resumedActivity = stack.getResumedActivity(); if (resumedActivity != null) { app = resumedActivity.app; @@ -1926,8 +1926,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return; } - for (int taskNdx = displayArea.getStackCount() - 1; taskNdx >= 0; --taskNdx) { - final Task rootTask = displayArea.getStackAt(taskNdx); + for (int taskNdx = displayArea.getRootTaskCount() - 1; taskNdx >= 0; --taskNdx) { + final Task rootTask = displayArea.getRootTaskAt(taskNdx); if (rootTask.getVisibility(null /*starting*/) == TASK_VISIBILITY_INVISIBLE) { break; } @@ -2009,7 +2009,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } boolean switchUser(int userId, UserState uss) { - final Task topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedRootTask(); final int focusStackId = topFocusedStack != null ? topFocusedStack.getRootTaskId() : INVALID_TASK_ID; // We dismiss the docked stack whenever we switch users. @@ -2021,19 +2021,19 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // appropriate. removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED); - mUserStackInFront.put(mCurrentUser, focusStackId); + mUserRootTaskInFront.put(mCurrentUser, focusStackId); mCurrentUser = userId; mTaskSupervisor.mStartingUsers.add(uss); forAllTaskDisplayAreas(taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task stack = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task stack = taskDisplayArea.getRootTaskAt(sNdx); stack.switchUser(userId); } }); - final int restoreStackId = mUserStackInFront.get(userId); - Task stack = getStack(restoreStackId); + final int restoreStackId = mUserRootTaskInFront.get(userId); + Task stack = getRootTask(restoreStackId); if (stack == null) { stack = getDefaultTaskDisplayArea().getOrCreateRootHomeTask(); } @@ -2048,20 +2048,20 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } void removeUser(int userId) { - mUserStackInFront.delete(userId); + mUserRootTaskInFront.delete(userId); } /** - * Update the last used stack id for non-current user (current user's last - * used stack is the focused stack) + * Update the last used root task id for non-current user (current user's last + * used root task is the focused root task) */ - void updateUserStack(int userId, Task stack) { + void updateUserRootTask(int userId, Task rootTask) { if (userId != mCurrentUser) { - if (stack == null) { - stack = getDefaultTaskDisplayArea().getOrCreateRootHomeTask(); + if (rootTask == null) { + rootTask = getDefaultTaskDisplayArea().getOrCreateRootHomeTask(); } - mUserStackInFront.put(userId, stack.getRootTaskId()); + mUserRootTaskInFront.put(userId, rootTask.getRootTaskId()); } } @@ -2072,8 +2072,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * @param taskDisplayArea The task display area to move stack to. * @param onTop Indicates whether container should be place on top or on bottom. */ - void moveStackToTaskDisplayArea(int stackId, TaskDisplayArea taskDisplayArea, boolean onTop) { - final Task stack = getStack(stackId); + void moveRootTaskToTaskDisplayArea(int stackId, TaskDisplayArea taskDisplayArea, + boolean onTop) { + final Task stack = getRootTask(stackId); if (stack == null) { throw new IllegalArgumentException("moveStackToTaskDisplayArea: Unknown stackId=" + stackId); @@ -2101,22 +2102,23 @@ class RootWindowContainer extends WindowContainer<DisplayContent> /** * Move stack with all its existing content to specified display. * - * @param stackId Id of stack to move. + * @param rootTaskId Id of stack to move. * @param displayId Id of display to move stack to. * @param onTop Indicates whether container should be place on top or on bottom. */ - void moveStackToDisplay(int stackId, int displayId, boolean onTop) { + void moveRootTaskToDisplay(int rootTaskId, int displayId, boolean onTop) { final DisplayContent displayContent = getDisplayContentOrCreate(displayId); if (displayContent == null) { throw new IllegalArgumentException("moveStackToDisplay: Unknown displayId=" + displayId); } - moveStackToTaskDisplayArea(stackId, displayContent.getDefaultTaskDisplayArea(), onTop); + moveRootTaskToTaskDisplayArea(rootTaskId, displayContent.getDefaultTaskDisplayArea(), + onTop); } - boolean moveTopStackActivityToPinnedRootTask(int rootTaskId) { - final Task rootTask = getStack(rootTaskId); + boolean moveTopRootTaskActivityToPinnedRootTask(int rootTaskId) { + final Task rootTask = getRootTask(rootTaskId); if (rootTask == null) { throw new IllegalArgumentException( "moveTopStackActivityToPinnedRootTask: Unknown rootTaskId=" + rootTaskId); @@ -2135,11 +2137,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return false; } - moveActivityToPinnedStack(r, "moveTopStackActivityToPinnedRootTask"); + moveActivityToPinnedRootTask(r, "moveTopStackActivityToPinnedRootTask"); return true; } - void moveActivityToPinnedStack(ActivityRecord r, String reason) { + void moveActivityToPinnedRootTask(ActivityRecord r, String reason) { mService.deferWindowLayout(); final TaskDisplayArea taskDisplayArea = r.getDisplayArea(); @@ -2159,25 +2161,26 @@ class RootWindowContainer extends WindowContainer<DisplayContent> r.getDisplayContent().prepareAppTransition(TRANSIT_NONE); final boolean singleActivity = task.getChildCount() == 1; - final Task stack; + final Task rootTask; if (singleActivity) { - stack = task; + rootTask = task; } else { // In the case of multiple activities, we will create a new task for it and then // move the PIP activity into the task. - stack = taskDisplayArea.createStack(WINDOWING_MODE_UNDEFINED, r.getActivityType(), - ON_TOP, r.info, r.intent, false /* createdByOrganizer */); + rootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_UNDEFINED, + r.getActivityType(), ON_TOP, r.info, r.intent, + false /* createdByOrganizer */); // It's possible the task entering PIP is in freeform, so save the last // non-fullscreen bounds. Then when this new PIP task exits PIP, it can restore // to its previous freeform bounds. - stack.setLastNonFullscreenBounds(task.mLastNonFullscreenBounds); - stack.setBounds(task.getBounds()); + rootTask.setLastNonFullscreenBounds(task.mLastNonFullscreenBounds); + rootTask.setBounds(task.getBounds()); // There are multiple activities in the task and moving the top activity should // reveal/leave the other activities in their original task. // On the other hand, ActivityRecord#onParentChanged takes care of setting the // up-to-dated pinned stack information on this newly created stack. - r.reparent(stack, MAX_VALUE, reason); + r.reparent(rootTask, MAX_VALUE, reason); // In the case of this activity entering PIP due to it being moved to the back, // the old activity would have a TRANSIT_TASK_TO_BACK transition that needs to be @@ -2196,17 +2199,17 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // The intermediate windowing mode to be set on the ActivityRecord later. // This needs to happen before the re-parenting, otherwise we will always set the // ActivityRecord to be fullscreen. - final int intermediateWindowingMode = stack.getWindowingMode(); - if (stack.getParent() != taskDisplayArea) { + final int intermediateWindowingMode = rootTask.getWindowingMode(); + if (rootTask.getParent() != taskDisplayArea) { // stack is nested, but pinned tasks need to be direct children of their // display area, so reparent. - stack.reparent(taskDisplayArea, true /* onTop */); + rootTask.reparent(taskDisplayArea, true /* onTop */); } // Defer the windowing mode change until after the transition to prevent the activity // from doing work and changing the activity visuals while animating // TODO(task-org): Figure-out more structured way to do this long term. r.setWindowingMode(intermediateWindowingMode); - stack.setWindowingMode(WINDOWING_MODE_PINNED); + rootTask.setWindowingMode(WINDOWING_MODE_PINNED); // Reset the state that indicates it can enter PiP while pausing after we've moved it // to the pinned stack @@ -2216,7 +2219,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } ensureActivitiesVisible(null, 0, false /* preserveWindows */); - resumeFocusedStacksTopActivities(); + resumeFocusedTasksTopActivities(); notifyActivityPipModeChanged(r); } @@ -2288,13 +2291,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished. */ int finishTopCrashedActivities(WindowProcessController app, String reason) { - Task focusedStack = getTopDisplayFocusedStack(); + Task focusedStack = getTopDisplayFocusedRootTask(); Task finishedTask = reduceOnAllTaskDisplayAreas((taskDisplayArea, task) -> { // It is possible that request to finish activity might also remove its task and // stack, so we need to be careful with indexes in the loop and check child count // every time. - for (int stackNdx = 0; stackNdx < taskDisplayArea.getStackCount(); ++stackNdx) { - final Task stack = taskDisplayArea.getStackAt(stackNdx); + for (int stackNdx = 0; stackNdx < taskDisplayArea.getRootTaskCount(); ++stackNdx) { + final Task stack = taskDisplayArea.getRootTaskAt(stackNdx); final Task t = stack.finishTopCrashedActivityLocked(app, reason); if (stack == focusedStack || task == null) { task = t; @@ -2305,21 +2308,21 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return finishedTask != null ? finishedTask.mTaskId : INVALID_TASK_ID; } - boolean resumeFocusedStacksTopActivities() { - return resumeFocusedStacksTopActivities(null, null, null); + boolean resumeFocusedTasksTopActivities() { + return resumeFocusedTasksTopActivities(null, null, null); } - boolean resumeFocusedStacksTopActivities( - Task targetStack, ActivityRecord target, ActivityOptions targetOptions) { + boolean resumeFocusedTasksTopActivities( + Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions) { if (!mTaskSupervisor.readyToResume()) { return false; } boolean result = false; - if (targetStack != null && (targetStack.isTopStackInDisplayArea() - || getTopDisplayFocusedStack() == targetStack)) { - result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); + if (targetRootTask != null && (targetRootTask.isTopStackInDisplayArea() + || getTopDisplayFocusedRootTask() == targetRootTask)) { + result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions); } for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { @@ -2327,13 +2330,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final boolean curResult = result; boolean resumedOnDisplay = display.reduceOnAllTaskDisplayAreas( (taskDisplayArea, resumed) -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task stack = taskDisplayArea.getStackAt(sNdx); - final ActivityRecord topRunningActivity = stack.topRunningActivity(); - if (!stack.isFocusableAndVisible() || topRunningActivity == null) { + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task rootTask = taskDisplayArea.getRootTaskAt(sNdx); + final ActivityRecord topRunningActivity = rootTask.topRunningActivity(); + if (!rootTask.isFocusableAndVisible() || topRunningActivity == null) { continue; } - if (stack == targetStack) { + if (rootTask == targetRootTask) { // Simply update the result for targetStack because the targetStack // had already resumed in above. We don't want to resume it again, // especially in some cases, it would cause a second launch failure @@ -2341,12 +2344,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> resumed |= curResult; continue; } - if (taskDisplayArea.isTopStack(stack) + if (taskDisplayArea.isTopRootTask(rootTask) && topRunningActivity.isState(RESUMED)) { // Kick off any lingering app transitions form the MoveTaskToFront // operation, but only consider the top task and stack on that // display. - stack.executeAppTransition(targetOptions); + rootTask.executeAppTransition(targetOptions); } else { resumed |= topRunningActivity.makeActiveIfNeeded(target); } @@ -2359,10 +2362,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // crashed) it's possible that nothing was resumed on a display. Requesting resume // of top activity in focused stack explicitly will make sure that at least home // activity is started and resumed, and no recursion occurs. - final Task focusedStack = display.getFocusedStack(); - if (focusedStack != null) { - result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions); - } else if (targetStack == null) { + final Task focusedRoot = display.getFocusedRootTask(); + if (focusedRoot != null) { + result |= focusedRoot.resumeTopActivityUncheckedLocked(target, targetOptions); + } else if (targetRootTask == null) { result |= resumeHomeActivity(null /* prev */, "no-focusable-task", display.getDefaultTaskDisplayArea()); } @@ -2388,8 +2391,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Set the sleeping state of the stacks on the display. display.forAllTaskDisplayAreas(taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task stack = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task stack = taskDisplayArea.getRootTaskAt(sNdx); if (displayShouldSleep) { stack.goToSleepIfPossible(false /* shuttingDown */); } else { @@ -2416,34 +2419,34 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } } - protected Task getStack(int stackId) { + protected Task getRootTask(int rooTaskId) { for (int i = getChildCount() - 1; i >= 0; --i) { - final Task stack = getChildAt(i).getStack(stackId); - if (stack != null) { - return stack; + final Task rootTask = getChildAt(i).getRootTask(rooTaskId); + if (rootTask != null) { + return rootTask; } } return null; } - /** @see DisplayContent#getStack(int, int) */ - Task getStack(int windowingMode, int activityType) { + /** @see DisplayContent#getRootTask(int, int) */ + Task getRootTask(int windowingMode, int activityType) { for (int i = getChildCount() - 1; i >= 0; --i) { - final Task stack = getChildAt(i).getStack(windowingMode, activityType); - if (stack != null) { - return stack; + final Task rootTask = getChildAt(i).getRootTask(windowingMode, activityType); + if (rootTask != null) { + return rootTask; } } return null; } - private Task getStack(int windowingMode, int activityType, + private Task getRootTask(int windowingMode, int activityType, int displayId) { DisplayContent display = getDisplayContent(displayId); if (display == null) { return null; } - return display.getStack(windowingMode, activityType); + return display.getRootTask(windowingMode, activityType); } private RootTaskInfo getRootTaskInfo(Task task) { @@ -2488,7 +2491,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } RootTaskInfo getRootTaskInfo(int taskId) { - Task task = getStack(taskId); + Task task = getRootTask(taskId); if (task != null) { return getRootTaskInfo(task); } @@ -2496,12 +2499,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } RootTaskInfo getRootTaskInfo(int windowingMode, int activityType) { - final Task stack = getStack(windowingMode, activityType); + final Task stack = getRootTask(windowingMode, activityType); return (stack != null) ? getRootTaskInfo(stack) : null; } RootTaskInfo getRootTaskInfo(int windowingMode, int activityType, int displayId) { - final Task stack = getStack(windowingMode, activityType, displayId); + final Task stack = getRootTask(windowingMode, activityType, displayId); return (stack != null) ? getRootTaskInfo(stack) : null; } @@ -2510,8 +2513,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> ArrayList<RootTaskInfo> list = new ArrayList<>(); if (displayId == INVALID_DISPLAY) { forAllTaskDisplayAreas(taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task stack = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task stack = taskDisplayArea.getRootTaskAt(sNdx); list.add(getRootTaskInfo(stack)); } }); @@ -2522,8 +2525,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return list; } display.forAllTaskDisplayAreas(taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task stack = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task stack = taskDisplayArea.getRootTaskAt(sNdx); list.add(getRootTaskInfo(stack)); } }); @@ -2595,16 +2598,16 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mDisplayManagerInternal.setDisplayAccessUIDs(mDisplayAccessUIDs); } - Task findStackBehind(Task stack) { - final TaskDisplayArea taskDisplayArea = stack.getDisplayArea(); + Task findRootTaskBehind(Task rootTask) { + final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea(); if (taskDisplayArea != null) { - for (int i = taskDisplayArea.getStackCount() - 1; i >= 0; i--) { - if (taskDisplayArea.getStackAt(i) == stack && i > 0) { - return taskDisplayArea.getStackAt(i - 1); + for (int i = taskDisplayArea.getRootTaskCount() - 1; i >= 0; i--) { + if (taskDisplayArea.getRootTaskAt(i) == rootTask && i > 0) { + return taskDisplayArea.getRootTaskAt(i - 1); } } } - throw new IllegalStateException("Failed to find a stack behind stack=" + stack + throw new IllegalStateException("Failed to find a root task behind root task =" + rootTask + " in=" + taskDisplayArea); } @@ -2740,22 +2743,22 @@ class RootWindowContainer extends WindowContainer<DisplayContent> r.destroyImmediately(mDestroyAllActivitiesReason); } - // Tries to put all activity stacks to sleep. Returns true if all stacks were + // Tries to put all activity tasks to sleep. Returns true if all tasks were // successfully put to sleep. - boolean putStacksToSleep(boolean allowDelay, boolean shuttingDown) { + boolean putTasksToSleep(boolean allowDelay, boolean shuttingDown) { return reduceOnAllTaskDisplayAreas((taskDisplayArea, result) -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { // Stacks and activities could be removed while putting activities to sleep if // the app process was gone. This prevents us getting exception by accessing an // invalid stack index. - if (sNdx >= taskDisplayArea.getStackCount()) { + if (sNdx >= taskDisplayArea.getRootTaskCount()) { continue; } - final Task stack = taskDisplayArea.getStackAt(sNdx); + final Task task = taskDisplayArea.getRootTaskAt(sNdx); if (allowDelay) { - result &= stack.goToSleepIfPossible(shuttingDown); + result &= task.goToSleepIfPossible(shuttingDown); } else { - stack.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, + task.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS); } } @@ -2824,9 +2827,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return false; } - Task getLaunchStack(@Nullable ActivityRecord r, + Task getLaunchRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop) { - return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */, + return getLaunchRootTask(r, options, candidateTask, onTop, null /* launchParams */, -1 /* no realCallingPid */, -1 /* no realCallingUid */); } @@ -2841,7 +2844,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid} * @return The stack to use for the launch or INVALID_STACK_ID. */ - Task getLaunchStack(@Nullable ActivityRecord r, + Task getLaunchRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop, @Nullable LaunchParamsController.LaunchParams launchParams, int realCallingPid, int realCallingUid) { @@ -2894,7 +2897,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> realCallingPid, realCallingUid, r.info); if (canLaunchOnDisplayFromStartRequest || canLaunchOnDisplay(r, tdaDisplayId)) { if (r != null) { - final Task result = getValidLaunchStackInTaskDisplayArea( + final Task result = getValidLaunchRootTaskInTaskDisplayArea( taskDisplayArea, r, candidateTask, options, launchParams); if (result != null) { return result; @@ -2902,7 +2905,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } // Falling back to default task container taskDisplayArea = taskDisplayArea.mDisplayContent.getDefaultTaskDisplayArea(); - stack = taskDisplayArea.getOrCreateStack(r, options, candidateTask, activityType, + stack = taskDisplayArea.getOrCreateRootTask(r, options, candidateTask, activityType, onTop); if (stack != null) { return stack; @@ -2956,7 +2959,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } } - return container.getOrCreateStack(r, options, candidateTask, activityType, onTop); + return container.getOrCreateRootTask(r, options, candidateTask, activityType, onTop); } /** @return true if activity record is null or can be launched on provided display. */ @@ -2977,7 +2980,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * @return Existing stack if there is a valid one, new dynamic stack if it is valid or null. */ @VisibleForTesting - Task getValidLaunchStackInTaskDisplayArea(@NonNull TaskDisplayArea taskDisplayArea, + Task getValidLaunchRootTaskInTaskDisplayArea(@NonNull TaskDisplayArea taskDisplayArea, @NonNull ActivityRecord r, @Nullable Task candidateTask, @Nullable ActivityOptions options, @Nullable LaunchParamsController.LaunchParams launchParams) { @@ -3016,9 +3019,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> r.getActivityType()); // Return the topmost valid stack on the display. - for (int i = taskDisplayArea.getStackCount() - 1; i >= 0; --i) { - final Task stack = taskDisplayArea.getStackAt(i); - if (isValidLaunchStack(stack, r, windowingMode)) { + for (int i = taskDisplayArea.getRootTaskCount() - 1; i >= 0; --i) { + final Task stack = taskDisplayArea.getRootTaskAt(i); + if (isValidLaunchRootTask(stack, r, windowingMode)) { return stack; } } @@ -3030,15 +3033,15 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final int activityType = options != null && options.getLaunchActivityType() != ACTIVITY_TYPE_UNDEFINED ? options.getLaunchActivityType() : r.getActivityType(); - return taskDisplayArea.createStack(windowingMode, activityType, true /*onTop*/); + return taskDisplayArea.createRootTask(windowingMode, activityType, true /*onTop*/); } return null; } // TODO: Can probably be consolidated into getLaunchStack()... - private boolean isValidLaunchStack(Task stack, ActivityRecord r, int windowingMode) { - switch (stack.getActivityType()) { + private boolean isValidLaunchRootTask(Task task, ActivityRecord r, int windowingMode) { + switch (task.getActivityType()) { case ACTIVITY_TYPE_HOME: return r.isActivityTypeHome(); case ACTIVITY_TYPE_RECENTS: @@ -3048,13 +3051,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent> case ACTIVITY_TYPE_DREAM: return r.isActivityTypeDream(); } - if (stack.mCreatedByOrganizer) { + if (task.mCreatedByOrganizer) { // Don't launch directly into task created by organizer...but why can't we? return false; } // There is a 1-to-1 relationship between stack and task when not in // primary split-windowing mode. - if (stack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY + if (task.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && r.supportsSplitScreenWindowingMode() && (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || windowingMode == WINDOWING_MODE_UNDEFINED)) { @@ -3091,8 +3094,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * candidate. * @return Next focusable {@link Task}, {@code null} if not found. */ - Task getNextFocusableStack(@NonNull Task currentFocus, - boolean ignoreCurrent) { + Task getNextFocusableRootTask(@NonNull Task currentFocus, boolean ignoreCurrent) { // First look for next focusable stack on the same display TaskDisplayArea preferredDisplayArea = currentFocus.getDisplayArea(); if (preferredDisplayArea == null) { @@ -3101,7 +3103,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> preferredDisplayArea = getDisplayContent(currentFocus.mPrevDisplayId) .getDefaultTaskDisplayArea(); } - final Task preferredFocusableStack = preferredDisplayArea.getNextFocusableStack( + final Task preferredFocusableStack = preferredDisplayArea.getNextFocusableRootTask( currentFocus, ignoreCurrent); if (preferredFocusableStack != null) { return preferredFocusableStack; @@ -3121,7 +3123,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> continue; } final Task nextFocusableStack = display.getDefaultTaskDisplayArea() - .getNextFocusableStack(currentFocus, ignoreCurrent); + .getNextFocusableRootTask(currentFocus, ignoreCurrent); if (nextFocusableStack != null) { return nextFocusableStack; } @@ -3257,9 +3259,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> void finishVoiceTask(IVoiceInteractionSession session) { forAllTaskDisplayAreas(taskDisplayArea -> { - final int numStacks = taskDisplayArea.getStackCount(); + final int numStacks = taskDisplayArea.getRootTaskCount(); for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final Task stack = taskDisplayArea.getStackAt(stackNdx); + final Task stack = taskDisplayArea.getRootTaskAt(stackNdx); stack.finishVoiceTask(session); } }); @@ -3302,7 +3304,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // If the focused stack is not null or not empty, there should have some activities // resuming or resumed. Make sure these activities are idle. - final Task stack = display.getFocusedStack(); + final Task stack = display.getFocusedRootTask(); if (stack == null || !stack.hasActivity()) { continue; } @@ -3322,8 +3324,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> boolean[] foundResumed = {false}; final boolean foundInvisibleResumedActivity = forAllTaskDisplayAreas( taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task stack = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task stack = taskDisplayArea.getRootTaskAt(sNdx); final ActivityRecord r = stack.getResumedActivity(); if (r != null) { if (!r.nowVisible) { @@ -3344,8 +3346,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> boolean[] pausing = {true}; final boolean hasActivityNotCompleted = forAllTaskDisplayAreas( taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task stack = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task stack = taskDisplayArea.getRootTaskAt(sNdx); final ActivityRecord r = stack.mPausingActivity; if (r != null && !r.isState(PAUSED, STOPPED, STOPPING, FINISHING)) { ProtoLog.d(WM_DEBUG_STATES, "allPausedActivitiesComplete: " @@ -3410,10 +3412,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> void cancelInitializingActivities() { forAllTaskDisplayAreas(taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { // We don't want to clear starting window for activities that aren't occluded // as we need to display their starting window until they are done initializing. - taskDisplayArea.getStackAt(sNdx).forAllOccludedActivities( + taskDisplayArea.getRootTaskAt(sNdx).forAllOccludedActivities( ActivityRecord::cancelInitializing); } }); @@ -3453,7 +3455,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Resolve the stack the task should be placed in now based on options // and reparent if needed. final Task launchStack = - getLaunchStack(null, aOptions, task, onTop); + getLaunchRootTask(null, aOptions, task, onTop); if (launchStack != null && task.getRootTask() != launchStack) { final int reparentMode = onTop ? REPARENT_MOVE_ROOT_TASK_TO_FRONT : REPARENT_LEAVE_ROOT_TASK_IN_PLACE; @@ -3498,7 +3500,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return task; } - ActivityRecord isInAnyStack(IBinder token) { + ActivityRecord isInAnyTask(IBinder token) { final ActivityRecord r = ActivityRecord.forTokenLocked(token); return (r != null && r.isDescendantOf(this)) ? r : null; } @@ -3568,7 +3570,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> ArrayList<ActivityRecord> getDumpActivities(String name, boolean dumpVisibleStacksOnly, boolean dumpFocusedStackOnly) { if (dumpFocusedStackOnly) { - final Task topFocusedStack = getTopDisplayFocusedStack(); + final Task topFocusedStack = getTopDisplayFocusedRootTask(); if (topFocusedStack != null) { return topFocusedStack.getDumpActivitiesLocked(name); } else { @@ -3577,8 +3579,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } else { ArrayList<ActivityRecord> activities = new ArrayList<>(); forAllTaskDisplayAreas(taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task stack = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task stack = taskDisplayArea.getRootTaskAt(sNdx); if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) { activities.addAll(stack.getDumpActivitiesLocked(name)); } @@ -3592,7 +3594,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> public void dump(PrintWriter pw, String prefix, boolean dumpAll) { super.dump(pw, prefix, dumpAll); pw.print(prefix); - pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedStack()); + pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedRootTask()); for (int i = getChildCount() - 1; i >= 0; --i) { final DisplayContent display = getChildAt(i); display.dump(pw, prefix, dumpAll); @@ -3632,8 +3634,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> pw.print(displayContent.mDisplayId); pw.println(" (activities from top to bottom):"); displayContent.forAllTaskDisplayAreas(taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task stack = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task stack = taskDisplayArea.getRootTaskAt(sNdx); if (needSep[0]) { pw.println(); } diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java index 7b5b0ad870dd..6ef5d4da63cb 100644 --- a/services/core/java/com/android/server/wm/RunningTasks.java +++ b/services/core/java/com/android/server/wm/RunningTasks.java @@ -67,7 +67,7 @@ class RunningTasks { mProfileIds = profileIds; mAllowed = allowed; mFilterOnlyVisibleRecents = filterOnlyVisibleRecents; - mTopDisplayFocusStack = root.getTopDisplayFocusedStack(); + mTopDisplayFocusStack = root.getTopDisplayFocusedRootTask(); mRecentTasks = root.mService.getRecentTasks(); final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this, diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index fb441fa94893..4b65ce0f7088 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -101,7 +101,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG; +import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_TASK_MSG; import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; @@ -599,7 +599,7 @@ class Task extends WindowContainer<WindowContainer> { private final AnimatingActivityRegistry mAnimatingActivityRegistry = new AnimatingActivityRegistry(); - private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 1; + private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_TASK_MSG + 1; private final Handler mHandler; @@ -652,7 +652,7 @@ class Task extends WindowContainer<WindowContainer> { if (mUpdateConfig) { // Ensure the resumed state of the focus activity if we updated the configuration of // any activity. - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } } @@ -975,7 +975,7 @@ class Task extends WindowContainer<WindowContainer> { } mResizeMode = resizeMode; mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); updateTaskDescription(); } @@ -1030,7 +1030,7 @@ class Task extends WindowContainer<WindowContainer> { // activities stay the same. mRootWindowContainer.ensureActivitiesVisible(r, 0, preserveWindow); if (!kept) { - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } } } @@ -1098,7 +1098,7 @@ class Task extends WindowContainer<WindowContainer> { final RootWindowContainer root = mRootWindowContainer; final WindowManagerService windowManager = mAtmService.mWindowManager; final Task sourceStack = getRootTask(); - final Task toStack = supervisor.getReparentTargetStack(this, preferredStack, + final Task toStack = supervisor.getReparentTargetRootTask(this, preferredStack, position == MAX_VALUE); if (toStack == sourceStack) { return false; @@ -1136,7 +1136,7 @@ class Task extends WindowContainer<WindowContainer> { boolean kept = true; try { final ActivityRecord r = topRunningActivityLocked(); - final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack) + final boolean wasFocused = r != null && root.isTopDisplayFocusedRootTask(sourceStack) && (topRunningActivityLocked() == r); final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r; final boolean wasPaused = r != null && sourceStack.mPausingActivity == r; @@ -1176,7 +1176,7 @@ class Task extends WindowContainer<WindowContainer> { && moveStackMode == REPARENT_KEEP_ROOT_TASK_AT_FRONT) { // Move recents to front so it is not behind home stack when going into docked // mode - mTaskSupervisor.moveRecentsStackToFront(reason); + mTaskSupervisor.moveRecentsRootTaskToFront(reason); } } finally { mAtmService.continueWindowLayout(); @@ -1193,7 +1193,7 @@ class Task extends WindowContainer<WindowContainer> { // The task might have already been running and its visibility needs to be synchronized // with the visibility of the stack / windows. root.ensureActivitiesVisible(null, 0, !mightReplaceWindow); - root.resumeFocusedStacksTopActivities(); + root.resumeFocusedTasksTopActivities(); } // TODO: Handle incorrect request to move before the actual move, not after. @@ -1696,7 +1696,7 @@ class Task extends WindowContainer<WindowContainer> { // A rootable task that is now being added to be the child of an organized task. Making // sure the stack references is keep updated. if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) { - getDisplayArea().addStackReferenceIfNeeded((Task) child); + getDisplayArea().addRootTaskReferenceIfNeeded((Task) child); } // Make sure the list of display UID allowlists is updated @@ -1746,7 +1746,7 @@ class Task extends WindowContainer<WindowContainer> { // A rootable child task that is now being removed from an organized task. Making sure // the stack references is keep updated. if (mCreatedByOrganizer && r.asTask() != null) { - getDisplayArea().removeStackReferenceIfNeeded((Task) r); + getDisplayArea().removeRootTaskReferenceIfNeeded((Task) r); } if (!mChildren.contains(r)) { Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this); @@ -2303,7 +2303,7 @@ class Task extends WindowContainer<WindowContainer> { } if (prevWindowingMode != getWindowingMode()) { - taskDisplayArea.onStackWindowingModeChanged(this); + taskDisplayArea.onRootTaskWindowingModeChanged(this); } if (mDisplayContent == null) { @@ -2330,7 +2330,7 @@ class Task extends WindowContainer<WindowContainer> { } if (windowingModeChanged) { - taskDisplayArea.onStackWindowingModeChanged(this); + taskDisplayArea.onRootTaskWindowingModeChanged(this); } if (hasNewOverrideBounds) { if (inSplitScreenWindowingMode()) { @@ -3097,7 +3097,7 @@ class Task extends WindowContainer<WindowContainer> { boolean moveDisplayToTop) { Task focusableTask = getNextFocusableTask(allowFocusSelf); if (focusableTask == null) { - focusableTask = mRootWindowContainer.getNextFocusableStack(this, !allowFocusSelf); + focusableTask = mRootWindowContainer.getNextFocusableRootTask(this, !allowFocusSelf); } if (focusableTask == null) { return null; @@ -5133,7 +5133,7 @@ class Task extends WindowContainer<WindowContainer> { // The change in force-hidden state will change visibility without triggering a stack // order change, so we should reset the preferred top focusable stack to ensure it's not // used if a new activity is started from this task. - getDisplayArea().resetPreferredTopFocusableStackIfBelow(this); + getDisplayArea().resetPreferredTopFocusableRootTaskIfBelow(this); } return true; } @@ -5276,14 +5276,14 @@ class Task extends WindowContainer<WindowContainer> { } mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } /** Resume next focusable stack after reparenting to another display. */ void postReparent() { adjustFocusToNextFocusableTask("reparent", true /* allowFocusSelf */, true /* moveDisplayToTop */); - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); // Update visibility of activities before notifying WM. This way it won't try to resize // windows that are no longer visible. mRootWindowContainer.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, @@ -5320,7 +5320,7 @@ class Task extends WindowContainer<WindowContainer> { // cutting between them. // TODO(b/70677280): This is a workaround until we can fix as part of b/70677280. final Task topFullScreenStack = - taskDisplayArea.getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN); + taskDisplayArea.getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN); if (topFullScreenStack != null) { final Task primarySplitScreenStack = taskDisplayArea.getRootSplitScreenPrimaryTask(); @@ -5335,10 +5335,10 @@ class Task extends WindowContainer<WindowContainer> { if (!isActivityTypeHome() && returnsToHomeStack()) { // Make sure the home stack is behind this stack since that is where we should return to // when this stack is no longer visible. - taskDisplayArea.moveHomeStackToFront(reason + " returnToHome"); + taskDisplayArea.moveHomeRootTaskToFront(reason + " returnToHome"); } - final Task lastFocusedTask = isRootTask() ? taskDisplayArea.getFocusedStack() : null; + final Task lastFocusedTask = isRootTask() ? taskDisplayArea.getFocusedRootTask() : null; if (task == null) { task = this; } @@ -5366,7 +5366,7 @@ class Task extends WindowContainer<WindowContainer> { if (parentTask != null) { parentTask.moveToBack(reason, this); } else { - final Task lastFocusedTask = displayArea.getFocusedStack(); + final Task lastFocusedTask = displayArea.getFocusedRootTask(); displayArea.positionChildAt(POSITION_BOTTOM, this, false /*includingParents*/); displayArea.updateLastFocusedRootTask(lastFocusedTask, reason); } @@ -5515,7 +5515,7 @@ class Task extends WindowContainer<WindowContainer> { if (prev == null) { if (resuming == null) { Slog.wtf(TAG, "Trying to pause when nothing is resumed"); - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } return false; } @@ -5622,7 +5622,7 @@ class Task extends WindowContainer<WindowContainer> { // pause, so just treat it as being paused now. ProtoLog.v(WM_DEBUG_STATES, "Activity not running, resuming next."); if (resuming == null) { - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } return false; } @@ -5675,9 +5675,9 @@ class Task extends WindowContainer<WindowContainer> { } if (resumeNext) { - final Task topStack = mRootWindowContainer.getTopDisplayFocusedStack(); + final Task topStack = mRootWindowContainer.getTopDisplayFocusedRootTask(); if (topStack != null && !topStack.shouldSleepOrShutDownActivities()) { - mRootWindowContainer.resumeFocusedStacksTopActivities(topStack, prev, null); + mRootWindowContainer.resumeFocusedTasksTopActivities(topStack, prev, null); } else { checkReadyForSleep(); final ActivityRecord top = topStack != null ? topStack.topRunningActivity() : null; @@ -5686,7 +5686,7 @@ class Task extends WindowContainer<WindowContainer> { // something. Also if the top activity on the stack is not the just paused // activity, we need to go ahead and resume it to ensure we complete an // in-flight app switch. - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } } } @@ -5709,7 +5709,7 @@ class Task extends WindowContainer<WindowContainer> { boolean isTopStackInDisplayArea() { final TaskDisplayArea taskDisplayArea = getDisplayArea(); - return taskDisplayArea != null && taskDisplayArea.isTopStack(this); + return taskDisplayArea != null && taskDisplayArea.isTopRootTask(this); } /** @@ -5717,7 +5717,7 @@ class Task extends WindowContainer<WindowContainer> { * otherwise. */ boolean isFocusedStackOnDisplay() { - return mDisplayContent != null && this == mDisplayContent.getFocusedStack(); + return mDisplayContent != null && this == mDisplayContent.getFocusedRootTask(); } /** @@ -5795,7 +5795,7 @@ class Task extends WindowContainer<WindowContainer> { */ boolean isTopSplitScreenStack() { return inSplitScreenWindowingMode() - && this == getDisplayArea().getTopStackInWindowingMode(getWindowingMode()); + && this == getDisplayArea().getTopRootTaskInWindowingMode(getWindowingMode()); } void checkTranslucentActivityWaiting(ActivityRecord top) { @@ -5879,7 +5879,7 @@ class Task extends WindowContainer<WindowContainer> { * * NOTE: It is not safe to call this method directly as it can cause an activity in a * non-focused stack to be resumed. - * Use {@link RootWindowContainer#resumeFocusedStacksTopActivities} to resume the + * Use {@link RootWindowContainer#resumeFocusedTasksTopActivities} to resume the * right activity for the current system state. */ @GuardedBy("mService") @@ -6033,7 +6033,7 @@ class Task extends WindowContainer<WindowContainer> { mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid); ActivityRecord lastResumed = null; - final Task lastFocusedStack = taskDisplayArea.getLastFocusedStack(); + final Task lastFocusedStack = taskDisplayArea.getLastFocusedRootTask(); if (lastFocusedStack != null && lastFocusedStack != this) { // So, why aren't we using prev here??? See the param comment on the method. prev // doesn't represent the last resumed activity. However, the last focus stack does if @@ -6048,7 +6048,7 @@ class Task extends WindowContainer<WindowContainer> { } } - boolean pausing = taskDisplayArea.pauseBackStacks(userLeaving, next); + boolean pausing = taskDisplayArea.pauseBackTasks(userLeaving, next); if (mResumedActivity != null) { ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Pausing %s", mResumedActivity); pausing |= startPausingLocked(userLeaving, false /* uiSleeping */, next, @@ -6069,7 +6069,7 @@ class Task extends WindowContainer<WindowContainer> { // Since the start-process is asynchronous, if we already know the process of next // activity isn't running, we can start the process earlier to save the time to wait // for the current activity to be paused. - final boolean isTop = this == taskDisplayArea.getFocusedStack(); + final boolean isTop = this == taskDisplayArea.getFocusedRootTask(); mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop, isTop ? "pre-top-activity" : "pre-activity"); } @@ -6359,7 +6359,7 @@ class Task extends WindowContainer<WindowContainer> { // Try to move focus to the next visible stack with a running activity if this // stack is not covering the entire screen or is on a secondary display with no home // stack. - return mRootWindowContainer.resumeFocusedStacksTopActivities(nextFocusedStack, + return mRootWindowContainer.resumeFocusedTasksTopActivities(nextFocusedStack, prev, null /* targetOptions */); } } @@ -6839,7 +6839,7 @@ class Task extends WindowContainer<WindowContainer> { AppTimeTracker timeTracker, boolean deferResume, String reason) { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr); - final Task topStack = getDisplayArea().getTopStack(); + final Task topStack = getDisplayArea().getTopRootTask(); final ActivityRecord topActivity = topStack != null ? topStack.getTopNonFinishingActivity() : null; @@ -6902,7 +6902,7 @@ class Task extends WindowContainer<WindowContainer> { } if (!deferResume) { - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } } finally { mDisplayContent.continueUpdateImeTarget(); @@ -6975,7 +6975,7 @@ class Task extends WindowContainer<WindowContainer> { // resumed in this case, so we need to execute it explicitly. mDisplayContent.executeAppTransition(); } else { - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } return true; } @@ -7280,7 +7280,7 @@ class Task extends WindowContainer<WindowContainer> { final boolean wasResumed = topRunningActivity == task.getRootTask().mResumedActivity; boolean toTop = position >= getChildCount(); - boolean includingParents = toTop || getDisplayArea().getNextFocusableStack(this, + boolean includingParents = toTop || getDisplayArea().getNextFocusableRootTask(this, true /* ignoreCurrent */) == null; if (WindowManagerDebugConfig.DEBUG_ROOT_TASK) { Slog.i(TAG_WM, "positionChildAt: positioning task=" + task + " at " + position); @@ -7309,7 +7309,7 @@ class Task extends WindowContainer<WindowContainer> { // The task might have already been running and its visibility needs to be synchronized with // the visibility of the stack / windows. ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); } public void setAlwaysOnTop(boolean alwaysOnTop) { @@ -7431,7 +7431,7 @@ class Task extends WindowContainer<WindowContainer> { // If there are other focusable stacks on the display, the z-order of the display should not // be changed just because a task was placed at the bottom. E.g. if it is moving the topmost // task to bottom, the next focusable stack on the same display should be focused. - final Task nextFocusableStack = getDisplayArea().getNextFocusableStack( + final Task nextFocusableStack = getDisplayArea().getNextFocusableRootTask( child.getRootTask(), true /* ignoreCurrent */); positionChildAtBottom(child, nextFocusableStack == null /* includingParents */); } diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java index 4682ba836426..b4d069c0edc1 100644 --- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java +++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java @@ -193,7 +193,7 @@ class TaskChangeNotificationController { switch (msg.what) { case LOG_STACK_STATE_MSG: { synchronized (mServiceLock) { - mTaskSupervisor.logStackState(); + mTaskSupervisor.logRootTaskState(); } break; } diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 81b8200aa2b4..4498a8c82583 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -38,7 +38,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK; -import static com.android.server.wm.DisplayContent.alwaysCreateStack; +import static com.android.server.wm.DisplayContent.alwaysCreateRootTask; import static com.android.server.wm.Task.ActivityState.RESUMED; import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK; @@ -107,9 +107,9 @@ final class TaskDisplayArea extends DisplayArea<Task> { // TODO(b/159029784): Remove when getStack() behavior is cleaned-up private Task mRootRecentsTask; - private final ArrayList<Task> mTmpAlwaysOnTopStacks = new ArrayList<>(); - private final ArrayList<Task> mTmpNormalStacks = new ArrayList<>(); - private final ArrayList<Task> mTmpHomeStacks = new ArrayList<>(); + private final ArrayList<Task> mTmpAlwaysOnTopRootTasks = new ArrayList<>(); + private final ArrayList<Task> mTmpNormalRootTasks = new ArrayList<>(); + private final ArrayList<Task> mTmpHomeRootTasks = new ArrayList<>(); private final IntArray mTmpNeedsZBoostIndexes = new IntArray(); private int mTmpLayerForSplitScreenDividerAnchor; private int mTmpLayerForAnimationLayer; @@ -128,23 +128,25 @@ final class TaskDisplayArea extends DisplayArea<Task> { * have the topmost index, it is used as a preferred candidate to prevent being unable to resume * target stack properly when there are other focusable always-on-top stacks. */ - Task mPreferredTopFocusableStack; + Task mPreferredTopFocusableRootTask; private final RootWindowContainer.FindTaskResult mTmpFindTaskResult = new RootWindowContainer.FindTaskResult(); /** - * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused - * stack has been resumed. If stacks are changing position this will hold the old stack until - * the new stack becomes resumed after which it will be set to current focused stack. + * If this is the same as {@link #getFocusedRootTask} then the activity on the top of the + * focused root task has been resumed. If root tasks are changing position this will hold the + * old root task until the new root task becomes resumed after which it will be set to + * current focused root task. */ - Task mLastFocusedStack; + Task mLastFocusedRootTask; /** * All of the stacks on this display. Order matters, topmost stack is in front of all other * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls - * changing the list should also call {@link #onStackOrderChanged()}. + * changing the list should also call {@link #onRootTaskOrderChanged(Task)}. */ - private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>(); + private ArrayList<OnRootTaskOrderChangedListener> mRootTaskOrderChangedCallbacks = + new ArrayList<>(); /** * The task display area is removed from the system and we are just waiting for all activities @@ -181,7 +183,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { * Returns the topmost stack on the display that is compatible with the input windowing mode * and activity type. Null is no compatible stack on the display. */ - Task getStack(int windowingMode, int activityType) { + Task getRootTask(int windowingMode, int activityType) { if (activityType == ACTIVITY_TYPE_HOME) { return mRootHomeTask; } else if (activityType == ACTIVITY_TYPE_RECENTS) { @@ -208,7 +210,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { } @VisibleForTesting - Task getTopStack() { + Task getTopRootTask() { final int count = getChildCount(); return count > 0 ? getChildAt(count - 1) : null; } @@ -255,68 +257,68 @@ final class TaskDisplayArea extends DisplayArea<Task> { return visibleTasks; } - void onStackWindowingModeChanged(Task stack) { - removeStackReferenceIfNeeded(stack); - addStackReferenceIfNeeded(stack); - if (stack == mRootPinnedTask && getTopStack() != stack) { + void onRootTaskWindowingModeChanged(Task rootTask) { + removeRootTaskReferenceIfNeeded(rootTask); + addRootTaskReferenceIfNeeded(rootTask); + if (rootTask == mRootPinnedTask && getTopRootTask() != rootTask) { // Looks like this stack changed windowing mode to pinned. Move it to the top. - positionChildAt(POSITION_TOP, stack, false /* includingParents */); + positionChildAt(POSITION_TOP, rootTask, false /* includingParents */); } } - void addStackReferenceIfNeeded(Task stack) { - if (stack.isActivityTypeHome()) { + void addRootTaskReferenceIfNeeded(Task rootTask) { + if (rootTask.isActivityTypeHome()) { if (mRootHomeTask != null) { - if (!stack.isDescendantOf(mRootHomeTask)) { + if (!rootTask.isDescendantOf(mRootHomeTask)) { throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack=" + mRootHomeTask + " already exist on display=" + this - + " stack=" + stack); + + " stack=" + rootTask); } } else { - mRootHomeTask = stack; + mRootHomeTask = rootTask; } - } else if (stack.isActivityTypeRecents()) { + } else if (rootTask.isActivityTypeRecents()) { if (mRootRecentsTask != null) { - if (!stack.isDescendantOf(mRootRecentsTask)) { + if (!rootTask.isDescendantOf(mRootRecentsTask)) { throw new IllegalArgumentException("addStackReferenceIfNeeded: recents stack=" + mRootRecentsTask + " already exist on display=" + this - + " stack=" + stack); + + " stack=" + rootTask); } } else { - mRootRecentsTask = stack; + mRootRecentsTask = rootTask; } } - if (!stack.isRootTask()) { + if (!rootTask.isRootTask()) { return; } - final int windowingMode = stack.getWindowingMode(); + final int windowingMode = rootTask.getWindowingMode(); if (windowingMode == WINDOWING_MODE_PINNED) { if (mRootPinnedTask != null) { throw new IllegalArgumentException( "addStackReferenceIfNeeded: pinned stack=" + mRootPinnedTask - + " already exist on display=" + this + " stack=" + stack); + + " already exist on display=" + this + " stack=" + rootTask); } - mRootPinnedTask = stack; + mRootPinnedTask = rootTask; } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { if (mRootSplitScreenPrimaryTask != null) { throw new IllegalArgumentException( "addStackReferenceIfNeeded: split screen primary stack=" + mRootSplitScreenPrimaryTask - + " already exist on display=" + this + " stack=" + stack); + + " already exist on display=" + this + " stack=" + rootTask); } - mRootSplitScreenPrimaryTask = stack; + mRootSplitScreenPrimaryTask = rootTask; } } - void removeStackReferenceIfNeeded(Task stack) { - if (stack == mRootHomeTask) { + void removeRootTaskReferenceIfNeeded(Task rootTask) { + if (rootTask == mRootHomeTask) { mRootHomeTask = null; - } else if (stack == mRootRecentsTask) { + } else if (rootTask == mRootRecentsTask) { mRootRecentsTask = null; - } else if (stack == mRootPinnedTask) { + } else if (rootTask == mRootPinnedTask) { mRootPinnedTask = null; - } else if (stack == mRootSplitScreenPrimaryTask) { + } else if (rootTask == mRootSplitScreenPrimaryTask) { mRootSplitScreenPrimaryTask = null; } } @@ -325,20 +327,20 @@ final class TaskDisplayArea extends DisplayArea<Task> { void addChild(Task task, int position) { if (DEBUG_ROOT_TASK) Slog.d(TAG_WM, "Set task=" + task + " on taskDisplayArea=" + this); - addStackReferenceIfNeeded(task); - position = findPositionForStack(position, task, true /* adding */); + addRootTaskReferenceIfNeeded(task); + position = findPositionForRootTask(position, task, true /* adding */); super.addChild(task, position); mAtmService.updateSleepIfNeededLocked(); - onStackOrderChanged(task); + onRootTaskOrderChanged(task); } @Override protected void removeChild(Task stack) { super.removeChild(stack); - onStackRemoved(stack); + onRootTaskRemoved(stack); mAtmService.updateSleepIfNeededLocked(); - removeStackReferenceIfNeeded(stack); + removeRootTaskReferenceIfNeeded(stack); } @Override @@ -367,7 +369,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { if (!mDisplayContent.isTrusted() && !getParent().isOnTop()) { includingParents = false; } - final int targetPosition = findPositionForStack(position, child, false /* adding */); + final int targetPosition = findPositionForRootTask(position, child, false /* adding */); super.positionChildAt(targetPosition, child, false /* includingParents */); if (includingParents && getParent() != null && (moveToTop || moveToBottom)) { @@ -385,16 +387,16 @@ final class TaskDisplayArea extends DisplayArea<Task> { // preferred stack is set only when moving an existing stack to top instead of adding a new // stack that may be too early (e.g. in the middle of launching or reparenting). if (moveToTop && child.isFocusableAndVisible()) { - mPreferredTopFocusableStack = child; - } else if (mPreferredTopFocusableStack == child) { - mPreferredTopFocusableStack = null; + mPreferredTopFocusableRootTask = child; + } else if (mPreferredTopFocusableRootTask == child) { + mPreferredTopFocusableRootTask = null; } // Update the top resumed activity because the preferred top focusable task may be changed. mAtmService.mTaskSupervisor.updateTopResumedActivityIfNeeded(); if (mChildren.indexOf(child) != oldPosition) { - onStackOrderChanged(child); + onRootTaskOrderChanged(child); } } @@ -469,21 +471,21 @@ final class TaskDisplayArea extends DisplayArea<Task> { return 0; } - private int findMinPositionForStack(Task stack) { + private int findMinPositionForRootTask(Task rootTask) { int minPosition = POSITION_BOTTOM; for (int i = 0; i < mChildren.size(); ++i) { - if (getPriority(getStackAt(i)) < getPriority(stack)) { + if (getPriority(getRootTaskAt(i)) < getPriority(rootTask)) { minPosition = i; } else { break; } } - if (stack.isAlwaysOnTop()) { + if (rootTask.isAlwaysOnTop()) { // Since a stack could be repositioned while still being one of the children, we check // if this always-on-top stack already exists and if so, set the minPosition to its // previous position. - final int currentIndex = getIndexOf(stack); + final int currentIndex = getIndexOf(rootTask); if (currentIndex > minPosition) { minPosition = currentIndex; } @@ -491,13 +493,13 @@ final class TaskDisplayArea extends DisplayArea<Task> { return minPosition; } - private int findMaxPositionForStack(Task stack) { + private int findMaxPositionForRootTask(Task rootTask) { for (int i = mChildren.size() - 1; i >= 0; --i) { - final Task curr = getStackAt(i); + final Task curr = getRootTaskAt(i); // Since a stack could be repositioned while still being one of the children, we check // if 'curr' is the same stack and skip it if so - final boolean sameStack = curr == stack; - if (getPriority(curr) <= getPriority(stack) && !sameStack) { + final boolean sameRootTask = curr == rootTask; + if (getPriority(curr) <= getPriority(rootTask) && !sameRootTask) { return i; } } @@ -519,16 +521,16 @@ final class TaskDisplayArea extends DisplayArea<Task> { * (including the Dream); otherwise, it is a normal non-always-on-top stack * * @param requestedPosition Position requested by caller. - * @param stack Stack to be added or positioned. + * @param rootTask Root task to be added or positioned. * @param adding Flag indicates whether we're adding a new stack or positioning an * existing. * @return The proper position for the stack. */ - private int findPositionForStack(int requestedPosition, Task stack, boolean adding) { + private int findPositionForRootTask(int requestedPosition, Task rootTask, boolean adding) { // The max possible position we can insert the stack at. - int maxPosition = findMaxPositionForStack(stack); + int maxPosition = findMaxPositionForRootTask(rootTask); // The min possible position we can insert the stack at. - int minPosition = findMinPositionForStack(stack); + int minPosition = findMinPositionForRootTask(rootTask); // Cap the requested position to something reasonable for the previous position check // below. @@ -542,7 +544,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { targetPosition = Math.min(targetPosition, maxPosition); targetPosition = Math.max(targetPosition, minPosition); - int prevPosition = mChildren.indexOf(stack); + int prevPosition = mChildren.indexOf(rootTask); // The positions we calculated above (maxPosition, minPosition) do not take into // consideration the following edge cases. // 1) We need to adjust the position depending on the value "adding". @@ -645,7 +647,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { return SCREEN_ORIENTATION_UNSET; } - if (isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) { + if (isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) { // Apps and their containers are not allowed to specify an orientation while using // root tasks...except for the home stack if it is not resizable and currently // visible (top of) its root task. @@ -672,7 +674,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { } else { // Apps and their containers are not allowed to specify an orientation of full screen // tasks created by organizer. The organizer handles the orientation instead. - final Task task = getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN); + final Task task = getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN); if (task != null && task.isVisible() && task.mCreatedByOrganizer) { return SCREEN_ORIENTATION_UNSPECIFIED; } @@ -697,7 +699,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { @Override void assignChildLayers(SurfaceControl.Transaction t) { - assignStackOrdering(t); + assignRootTaskOrdering(t); for (int i = 0; i < mChildren.size(); i++) { final Task s = mChildren.get(i); @@ -705,37 +707,37 @@ final class TaskDisplayArea extends DisplayArea<Task> { } } - void assignStackOrdering(SurfaceControl.Transaction t) { + void assignRootTaskOrdering(SurfaceControl.Transaction t) { if (getParent() == null) { return; } - mTmpAlwaysOnTopStacks.clear(); - mTmpHomeStacks.clear(); - mTmpNormalStacks.clear(); + mTmpAlwaysOnTopRootTasks.clear(); + mTmpHomeRootTasks.clear(); + mTmpNormalRootTasks.clear(); for (int i = 0; i < mChildren.size(); ++i) { final Task s = mChildren.get(i); if (s.isAlwaysOnTop()) { - mTmpAlwaysOnTopStacks.add(s); + mTmpAlwaysOnTopRootTasks.add(s); } else if (s.isActivityTypeHome()) { - mTmpHomeStacks.add(s); + mTmpHomeRootTasks.add(s); } else { - mTmpNormalStacks.add(s); + mTmpNormalRootTasks.add(s); } } int layer = 0; // Place home stacks to the bottom. - layer = adjustRootTaskLayer(t, mTmpHomeStacks, layer, false /* normalStacks */); + layer = adjustRootTaskLayer(t, mTmpHomeRootTasks, layer, false /* normalStacks */); // The home animation layer is between the home stacks and the normal stacks. final int layerForHomeAnimationLayer = layer++; mTmpLayerForSplitScreenDividerAnchor = layer++; mTmpLayerForAnimationLayer = layer++; - layer = adjustRootTaskLayer(t, mTmpNormalStacks, layer, true /* normalStacks */); + layer = adjustRootTaskLayer(t, mTmpNormalRootTasks, layer, true /* normalStacks */); // The boosted animation layer is between the normal stacks and the always on top // stacks. final int layerForBoostedAnimationLayer = layer++; - adjustRootTaskLayer(t, mTmpAlwaysOnTopStacks, layer, false /* normalStacks */); + adjustRootTaskLayer(t, mTmpAlwaysOnTopRootTasks, layer, false /* normalStacks */); t.setLayer(mHomeAppAnimationLayer, layerForHomeAnimationLayer); t.setLayer(mAppAnimationLayer, mTmpLayerForAnimationLayer); @@ -743,7 +745,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { t.setLayer(mBoostedAppAnimationLayer, layerForBoostedAnimationLayer); } - private int adjustNormalStackLayer(Task s, int layer) { + private int adjustNormalRootTaskLayer(Task s, int layer) { if (s.inSplitScreenWindowingMode()) { // The split screen divider anchor is located above the split screen window. mTmpLayerForSplitScreenDividerAnchor = layer++; @@ -773,7 +775,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { if (!stack.needsZBoost()) { stack.assignLayer(t, startLayer++); if (normalStacks) { - startLayer = adjustNormalStackLayer(stack, startLayer); + startLayer = adjustNormalRootTaskLayer(stack, startLayer); } } else { mTmpNeedsZBoostIndexes.add(i); @@ -785,7 +787,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { final Task stack = stacks.get(mTmpNeedsZBoostIndexes.get(i)); stack.assignLayer(t, startLayer++); if (normalStacks) { - startLayer = adjustNormalStackLayer(stack, startLayer); + startLayer = adjustNormalRootTaskLayer(stack, startLayer); } } return startLayer; @@ -849,22 +851,22 @@ final class TaskDisplayArea extends DisplayArea<Task> { } } - void onStackRemoved(Task stack) { + void onRootTaskRemoved(Task rootTask) { if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) { - Slog.v(TAG_ROOT_TASK, "removeStack: detaching " + stack + " from displayId=" + Slog.v(TAG_ROOT_TASK, "removeStack: detaching " + rootTask + " from displayId=" + mDisplayContent.mDisplayId); } - if (mPreferredTopFocusableStack == stack) { - mPreferredTopFocusableStack = null; + if (mPreferredTopFocusableRootTask == rootTask) { + mPreferredTopFocusableRootTask = null; } mDisplayContent.releaseSelfIfNeeded(); - onStackOrderChanged(stack); + onRootTaskOrderChanged(rootTask); } - void resetPreferredTopFocusableStackIfBelow(Task task) { - if (mPreferredTopFocusableStack != null - && mPreferredTopFocusableStack.compareTo(task) < 0) { - mPreferredTopFocusableStack = null; + void resetPreferredTopFocusableRootTaskIfBelow(Task task) { + if (mPreferredTopFocusableRootTask != null + && mPreferredTopFocusableRootTask.compareTo(task) < 0) { + mPreferredTopFocusableRootTask = null; } } @@ -894,9 +896,9 @@ final class TaskDisplayArea extends DisplayArea<Task> { } } - Task getStack(int rootTaskId) { - for (int i = getStackCount() - 1; i >= 0; --i) { - final Task stack = getStackAt(i); + Task getRootTask(int rootTaskId) { + for (int i = getRootTaskCount() - 1; i >= 0; --i) { + final Task stack = getRootTaskAt(i); if (stack.getRootTaskId() == rootTaskId) { return stack; } @@ -908,10 +910,10 @@ final class TaskDisplayArea extends DisplayArea<Task> { * Returns an existing stack compatible with the windowing mode and activity type or creates one * if a compatible stack doesn't exist. * - * @see #getOrCreateStack(int, int, boolean, Intent, Task) + * @see #getOrCreateRootTask(int, int, boolean, Intent, Task) */ - Task getOrCreateStack(int windowingMode, int activityType, boolean onTop) { - return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */, + Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop) { + return getOrCreateRootTask(windowingMode, activityType, onTop, null /* intent */, null /* candidateTask */); } @@ -921,17 +923,17 @@ final class TaskDisplayArea extends DisplayArea<Task> { * For one level task, the candidate task would be reused to also be the root task or create * a new root task if no candidate task. * - * @see #getStack(int, int) - * @see #createStack(int, int, boolean) + * @see #getRootTask(int, int) + * @see #createRootTask(int, int, boolean) */ - Task getOrCreateStack(int windowingMode, int activityType, boolean onTop, + Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop, Intent intent, Task candidateTask) { // Need to pass in a determined windowing mode to see if a new stack should be created, // so use its parent's windowing mode if it is undefined. - if (!alwaysCreateStack( + if (!alwaysCreateRootTask( windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : getWindowingMode(), activityType)) { - Task stack = getStack(windowingMode, activityType); + Task stack = getRootTask(windowingMode, activityType); if (stack != null) { return stack; } @@ -959,7 +961,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { } return stack; } - return createStack(windowingMode, activityType, onTop, null /*info*/, intent, + return createRootTask(windowingMode, activityType, onTop, null /*info*/, intent, false /* createdByOrganizer */); } @@ -967,9 +969,9 @@ final class TaskDisplayArea extends DisplayArea<Task> { * Returns an existing stack compatible with the input params or creates one * if a compatible stack doesn't exist. * - * @see #getOrCreateStack(int, int, boolean) + * @see #getOrCreateRootTask(int, int, boolean) */ - Task getOrCreateStack(@Nullable ActivityRecord r, + Task getOrCreateRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType, boolean onTop) { // First preference is the windowing mode in the activity options if set. @@ -979,24 +981,24 @@ final class TaskDisplayArea extends DisplayArea<Task> { // UNDEFINED windowing mode is a valid result and means that the new stack will inherit // it's display's windowing mode. windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType); - return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */, + return getOrCreateRootTask(windowingMode, activityType, onTop, null /* intent */, candidateTask); } @VisibleForTesting - int getNextStackId() { + int getNextRootTaskId() { return mAtmService.mTaskSupervisor.getNextTaskIdForUser(); } - Task createStack(int windowingMode, int activityType, boolean onTop) { - return createStack(windowingMode, activityType, onTop, null /* info */, null /* intent */, - false /* createdByOrganizer */); + Task createRootTask(int windowingMode, int activityType, boolean onTop) { + return createRootTask(windowingMode, activityType, onTop, null /* info */, + null /* intent */, false /* createdByOrganizer */); } - Task createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info, + Task createRootTask(int windowingMode, int activityType, boolean onTop, ActivityInfo info, Intent intent, boolean createdByOrganizer) { - return createStack(windowingMode, activityType, onTop, null /* info */, null /* intent */, - false /* createdByOrganizer */ , false /* deferTaskAppear */, + return createRootTask(windowingMode, activityType, onTop, null /* info */, + null /* intent */, false /* createdByOrganizer */, false /* deferTaskAppear */, null /* launchCookie */); } @@ -1022,7 +1024,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { * creating. * @return The newly created stack. */ - Task createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info, + Task createRootTask(int windowingMode, int activityType, boolean onTop, ActivityInfo info, Intent intent, boolean createdByOrganizer, boolean deferTaskAppear, IBinder launchCookie) { if (activityType == ACTIVITY_TYPE_UNDEFINED && !createdByOrganizer) { @@ -1034,7 +1036,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { if (activityType != ACTIVITY_TYPE_STANDARD && activityType != ACTIVITY_TYPE_UNDEFINED) { // For now there can be only one stack of a particular non-standard activity type on a // display. So, get that ignoring whatever windowing mode it is currently in. - Task stack = getStack(WINDOWING_MODE_UNDEFINED, activityType); + Task stack = getRootTask(WINDOWING_MODE_UNDEFINED, activityType); if (stack != null) { throw new IllegalArgumentException("Stack=" + stack + " of activityType=" + activityType + " already on display=" + this + ". Can't have multiple."); @@ -1054,8 +1056,8 @@ final class TaskDisplayArea extends DisplayArea<Task> { getRootPinnedTask().dismissPip(); } - final int stackId = getNextStackId(); - return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent, + final int stackId = getNextRootTaskId(); + return createRootTaskUnchecked(windowingMode, activityType, stackId, onTop, info, intent, createdByOrganizer, deferTaskAppear, launchCookie); } @@ -1065,15 +1067,15 @@ final class TaskDisplayArea extends DisplayArea<Task> { // Only split-screen windowing modes can do this currently... return null; } - for (int i = getStackCount() - 1; i >= 0; --i) { - final Task t = getStackAt(i); + for (int i = getRootTaskCount() - 1; i >= 0; --i) { + final Task t = getRootTaskAt(i); if (!t.mCreatedByOrganizer || t.getRequestedOverrideWindowingMode() != windowingMode) { continue; } // If not already set, pick a launch root which is not the one we are launching into. if (mLaunchRootTask == null) { - for (int j = 0, n = getStackCount(); j < n; ++j) { - final Task tt = getStackAt(j); + for (int j = 0, n = getRootTaskCount(); j < n; ++j) { + final Task tt = getRootTaskAt(j); if (tt.mCreatedByOrganizer && tt != t) { mLaunchRootTask = tt; break; @@ -1086,7 +1088,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { } @VisibleForTesting - Task createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop, + Task createRootTaskUnchecked(int windowingMode, int activityType, int stackId, boolean onTop, ActivityInfo info, Intent intent, boolean createdByOrganizer, boolean deferTaskAppear, IBinder launchCookie) { if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) { @@ -1123,13 +1125,13 @@ final class TaskDisplayArea extends DisplayArea<Task> { * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a * focusable and visible stack from the top of stacks in this display. */ - Task getFocusedStack() { - if (mPreferredTopFocusableStack != null) { - return mPreferredTopFocusableStack; + Task getFocusedRootTask() { + if (mPreferredTopFocusableRootTask != null) { + return mPreferredTopFocusableRootTask; } - for (int i = getStackCount() - 1; i >= 0; --i) { - final Task stack = getStackAt(i); + for (int i = getRootTaskCount() - 1; i >= 0; --i) { + final Task stack = getRootTaskAt(i); if (stack.isFocusableAndVisible()) { return stack; } @@ -1138,22 +1140,22 @@ final class TaskDisplayArea extends DisplayArea<Task> { return null; } - Task getNextFocusableStack(Task currentFocus, boolean ignoreCurrent) { + Task getNextFocusableRootTask(Task currentFocus, boolean ignoreCurrent) { final int currentWindowingMode = currentFocus != null ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED; Task candidate = null; - for (int i = getStackCount() - 1; i >= 0; --i) { - final Task stack = getStackAt(i); - if (ignoreCurrent && stack == currentFocus) { + for (int i = getRootTaskCount() - 1; i >= 0; --i) { + final Task rootTask = getRootTaskAt(i); + if (ignoreCurrent && rootTask == currentFocus) { continue; } - if (!stack.isFocusableAndVisible()) { + if (!rootTask.isFocusableAndVisible()) { continue; } if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY - && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) { + && candidate == null && rootTask.inSplitScreenPrimaryWindowingMode()) { // If the currently focused stack is in split-screen secondary we save off the // top primary split-screen stack as a candidate for focus because we might // prefer focus to move to an other stack to avoid primary split-screen stack @@ -1161,20 +1163,20 @@ final class TaskDisplayArea extends DisplayArea<Task> { // than the next split-screen stack. Assistant stack, I am looking at you... // We only move the focus to the primary-split screen stack if there isn't a // better alternative. - candidate = stack; + candidate = rootTask; continue; } - if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) { + if (candidate != null && rootTask.inSplitScreenSecondaryWindowingMode()) { // Use the candidate stack since we are now at the secondary split-screen. return candidate; } - return stack; + return rootTask; } return candidate; } ActivityRecord getFocusedActivity() { - final Task focusedStack = getFocusedStack(); + final Task focusedStack = getFocusedRootTask(); if (focusedStack == null) { return null; } @@ -1194,8 +1196,8 @@ final class TaskDisplayArea extends DisplayArea<Task> { return resumedActivity; } - Task getLastFocusedStack() { - return mLastFocusedStack; + Task getLastFocusedRootTask() { + return mLastFocusedRootTask; } void updateLastFocusedRootTask(Task prevFocusedTask, String updateLastFocusedTaskReason) { @@ -1203,7 +1205,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { return; } - final Task currentFocusedTask = getFocusedStack(); + final Task currentFocusedTask = getFocusedRootTask(); if (currentFocusedTask == prevFocusedTask) { return; } @@ -1214,27 +1216,27 @@ final class TaskDisplayArea extends DisplayArea<Task> { currentFocusedTask.mLastPausedActivity = null; } - mLastFocusedStack = prevFocusedTask; + mLastFocusedRootTask = prevFocusedTask; EventLogTags.writeWmFocusedStack(mRootWindowContainer.mCurrentUser, mDisplayContent.mDisplayId, currentFocusedTask == null ? -1 : currentFocusedTask.getRootTaskId(), - mLastFocusedStack == null ? -1 : mLastFocusedStack.getRootTaskId(), + mLastFocusedRootTask == null ? -1 : mLastFocusedRootTask.getRootTaskId(), updateLastFocusedTaskReason); } boolean allResumedActivitiesComplete() { - for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityRecord r = getStackAt(stackNdx).getResumedActivity(); + for (int stackNdx = getRootTaskCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityRecord r = getRootTaskAt(stackNdx).getResumedActivity(); if (r != null && !r.isState(RESUMED)) { return false; } } - final Task currentFocusedStack = getFocusedStack(); + final Task currentFocusedStack = getFocusedRootTask(); if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) { Slog.d(TAG_ROOT_TASK, "allResumedActivitiesComplete: mLastFocusedStack changing from=" - + mLastFocusedStack + " to=" + currentFocusedStack); + + mLastFocusedRootTask + " to=" + currentFocusedStack); } - mLastFocusedStack = currentFocusedStack; + mLastFocusedRootTask = currentFocusedStack; return true; } @@ -1249,10 +1251,10 @@ final class TaskDisplayArea extends DisplayArea<Task> { * @param resuming The resuming activity. * @return {@code true} if any activity was paused as a result of this call. */ - boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) { + boolean pauseBackTasks(boolean userLeaving, ActivityRecord resuming) { boolean someActivityPaused = false; - for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final Task stack = getStackAt(stackNdx); + for (int stackNdx = getRootTaskCount() - 1; stackNdx >= 0; --stackNdx) { + final Task stack = getRootTaskAt(stackNdx); final ActivityRecord resumedActivity = stack.getResumedActivity(); if (resumedActivity != null && (stack.getVisibility(resuming) != TASK_VISIBILITY_VISIBLE @@ -1272,8 +1274,8 @@ final class TaskDisplayArea extends DisplayArea<Task> { void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplayArea, RootWindowContainer.FindTaskResult result) { mTmpFindTaskResult.clear(); - for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final Task stack = getStackAt(stackNdx); + for (int stackNdx = getRootTaskCount() - 1; stackNdx >= 0; --stackNdx) { + final Task stack = getRootTaskAt(stackNdx); if (!r.hasCompatibleActivityType(stack) && stack.isLeafTask()) { ProtoLog.d(WM_DEBUG_TASKS, "Skipping stack: (mismatch activity/stack) " + "%s", stack); @@ -1367,7 +1369,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { // The focused task could be a non-resizeable fullscreen root task that is on top of the // other split-screen tasks, therefore had to dismiss split-screen, make sure the current // focused root task can still be on top after dismissal - final Task rootTask = getFocusedStack(); + final Task rootTask = getFocusedRootTask(); final Task toTop = rootTask != null && !rootTask.inSplitScreenWindowingMode() ? rootTask : null; onSplitScreenModeDismissed(toTop); @@ -1380,9 +1382,9 @@ final class TaskDisplayArea extends DisplayArea<Task> { moveSplitScreenTasksToFullScreen(); } finally { final Task topFullscreenStack = toTop != null - ? toTop : getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN); + ? toTop : getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN); final Task homeStack = getOrCreateRootHomeTask(); - if (homeStack != null && ((topFullscreenStack != null && !isTopStack(homeStack)) + if (homeStack != null && ((topFullscreenStack != null && !isTopRootTask(homeStack)) || toTop != null)) { // Whenever split-screen is dismissed we want the home stack directly behind the // current top fullscreen stack so it shows up when the top stack is finished. @@ -1556,8 +1558,8 @@ final class TaskDisplayArea extends DisplayArea<Task> { return windowingMode; } - boolean isTopStack(Task stack) { - return stack == getTopStack(); + boolean isTopRootTask(Task stack) { + return stack == getTopRootTask(); } ActivityRecord topRunningActivity() { @@ -1575,15 +1577,15 @@ final class TaskDisplayArea extends DisplayArea<Task> { */ ActivityRecord topRunningActivity(boolean considerKeyguardState) { ActivityRecord topRunning = null; - final Task focusedStack = getFocusedStack(); + final Task focusedStack = getFocusedRootTask(); if (focusedStack != null) { topRunning = focusedStack.topRunningActivity(); } // Look in other focusable stacks. if (topRunning == null) { - for (int i = getStackCount() - 1; i >= 0; --i) { - final Task stack = getStackAt(i); + for (int i = getRootTaskCount() - 1; i >= 0; --i) { + final Task stack = getRootTaskAt(i); // Only consider focusable stacks other than the current focused one. if (stack == focusedStack || !stack.isTopActivityFocusable()) { continue; @@ -1607,13 +1609,11 @@ final class TaskDisplayArea extends DisplayArea<Task> { return topRunning; } - // TODO (b/157876447): switch to Task related name - protected int getStackCount() { + protected int getRootTaskCount() { return mChildren.size(); } - // TODO (b/157876447): switch to Task related name - protected Task getStackAt(int index) { + protected Task getRootTaskAt(int index) { return mChildren.get(index); } @@ -1633,7 +1633,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { Task getOrCreateRootHomeTask(boolean onTop) { Task homeTask = getRootHomeTask(); if (homeTask == null && mDisplayContent.supportsSystemDecorations()) { - homeTask = createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, onTop); + homeTask = createRootTask(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, onTop); } return homeTask; } @@ -1647,14 +1647,14 @@ final class TaskDisplayArea extends DisplayArea<Task> { * Returns the topmost stack on the display that is compatible with the input windowing mode. * Null is no compatible stack on the display. */ - Task getTopStackInWindowingMode(int windowingMode) { - return getStack(windowingMode, ACTIVITY_TYPE_UNDEFINED); + Task getTopRootTaskInWindowingMode(int windowingMode) { + return getRootTask(windowingMode, ACTIVITY_TYPE_UNDEFINED); } - void moveHomeStackToFront(String reason) { - final Task homeStack = getOrCreateRootHomeTask(); - if (homeStack != null) { - homeStack.moveToFront(reason); + void moveHomeRootTaskToFront(String reason) { + final Task homeRootTask = getOrCreateRootHomeTask(); + if (homeRootTask != null) { + homeRootTask.moveToFront(reason); } } @@ -1665,7 +1665,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { void moveHomeActivityToTop(String reason) { final ActivityRecord top = getHomeActivity(); if (top == null) { - moveHomeStackToFront(reason); + moveHomeRootTaskToFront(reason); return; } top.moveFocusableActivityToTop(reason); @@ -1697,25 +1697,27 @@ final class TaskDisplayArea extends DisplayArea<Task> { /** * Adjusts the {@param stack} behind the last visible stack in the display if necessary. - * Generally used in conjunction with {@link #moveStackBehindStack}. + * Generally used in conjunction with {@link #moveRootTaskBehindRootTask}. */ // TODO(b/151575894): Remove special stack movement methods. - void moveStackBehindBottomMostVisibleStack(Task stack) { - if (stack.shouldBeVisible(null)) { + void moveRootTaskBehindBottomMostVisibleRootTask(Task rootTask) { + if (rootTask.shouldBeVisible(null)) { // Skip if the stack is already visible return; } // Move the stack to the bottom to not affect the following visibility checks - stack.getParent().positionChildAt(POSITION_BOTTOM, stack, false /* includingParents */); + rootTask.getParent().positionChildAt(POSITION_BOTTOM, rootTask, + false /* includingParents */); // Find the next position where the stack should be placed - final boolean isRootTask = stack.isRootTask(); - final int numStacks = isRootTask ? getStackCount() : stack.getParent().getChildCount(); - for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) { - final Task s = isRootTask ? getStackAt(stackNdx) - : (Task) stack.getParent().getChildAt(stackNdx); - if (s == stack) { + final boolean isRootTask = rootTask.isRootTask(); + final int numRootTasks = + isRootTask ? getRootTaskCount() : rootTask.getParent().getChildCount(); + for (int rootTaskNdx = 0; rootTaskNdx < numRootTasks; rootTaskNdx++) { + final Task s = isRootTask ? getRootTaskAt(rootTaskNdx) + : (Task) rootTask.getParent().getChildAt(rootTaskNdx); + if (s == rootTask) { continue; } final int winMode = s.getWindowingMode(); @@ -1723,8 +1725,9 @@ final class TaskDisplayArea extends DisplayArea<Task> { || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; if (s.shouldBeVisible(null) && isValidWindowingMode) { // Move the provided stack to behind this stack - final int position = Math.max(0, stackNdx - 1); - stack.getParent().positionChildAt(position, stack, false /*includingParents */); + final int position = Math.max(0, rootTaskNdx - 1); + rootTask.getParent().positionChildAt(position, rootTask, + false /*includingParents */); break; } } @@ -1733,15 +1736,16 @@ final class TaskDisplayArea extends DisplayArea<Task> { /** * Moves the {@param stack} behind the given {@param behindStack} if possible. If * {@param behindStack} is not currently in the display, then then the stack is moved to the - * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}. + * back. Generally used in conjunction with + * {@link #moveRootTaskBehindBottomMostVisibleRootTask}. */ - void moveStackBehindStack(Task stack, Task behindStack) { - if (behindStack == null || behindStack == stack) { + void moveRootTaskBehindRootTask(Task rootTask, Task behindRootTask) { + if (behindRootTask == null || behindRootTask == rootTask) { return; } - final WindowContainer parent = stack.getParent(); - if (parent == null || parent != behindStack.getParent()) { + final WindowContainer parent = rootTask.getParent(); + if (parent == null || parent != behindRootTask.getParent()) { return; } @@ -1749,12 +1753,12 @@ final class TaskDisplayArea extends DisplayArea<Task> { // list, so we need to adjust the insertion index to account for the removed index // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the // position internally - final int stackIndex = parent.mChildren.indexOf(stack); - final int behindStackIndex = parent.mChildren.indexOf(behindStack); + final int stackIndex = parent.mChildren.indexOf(rootTask); + final int behindStackIndex = parent.mChildren.indexOf(behindRootTask); final int insertIndex = stackIndex <= behindStackIndex ? behindStackIndex - 1 : behindStackIndex; final int position = Math.max(0, insertIndex); - parent.positionChildAt(position, stack, false /* includingParents */); + parent.positionChildAt(position, rootTask, false /* includingParents */); } boolean hasPinnedTask() { @@ -1765,20 +1769,20 @@ final class TaskDisplayArea extends DisplayArea<Task> { * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is * already top-most. */ - static Task getStackAbove(Task stack) { - final WindowContainer wc = stack.getParent(); - final int index = wc.mChildren.indexOf(stack) + 1; + static Task getRootTaskAbove(Task rootTask) { + final WindowContainer wc = rootTask.getParent(); + final int index = wc.mChildren.indexOf(rootTask) + 1; return (index < wc.mChildren.size()) ? (Task) wc.mChildren.get(index) : null; } /** Returns true if the stack in the windowing mode is visible. */ - boolean isStackVisible(int windowingMode) { - final Task stack = getTopStackInWindowingMode(windowingMode); - return stack != null && stack.isVisible(); + boolean isRootTaskVisible(int windowingMode) { + final Task rootTask = getTopRootTaskInWindowingMode(windowingMode); + return rootTask != null && rootTask.isVisible(); } - void removeStack(Task stack) { - removeChild(stack); + void removeRootTask(Task rootTask) { + removeChild(rootTask); } int getDisplayId() { @@ -1794,27 +1798,27 @@ final class TaskDisplayArea extends DisplayArea<Task> { * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the * current animation when the system state changes. */ - void registerStackOrderChangedListener(OnStackOrderChangedListener listener) { - if (!mStackOrderChangedCallbacks.contains(listener)) { - mStackOrderChangedCallbacks.add(listener); + void registerRootTaskOrderChangedListener(OnRootTaskOrderChangedListener listener) { + if (!mRootTaskOrderChangedCallbacks.contains(listener)) { + mRootTaskOrderChangedCallbacks.add(listener); } } /** * Removes a previously registered stack order change listener. */ - void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) { - mStackOrderChangedCallbacks.remove(listener); + void unregisterRootTaskOrderChangedListener(OnRootTaskOrderChangedListener listener) { + mRootTaskOrderChangedCallbacks.remove(listener); } /** - * Notifies of a stack order change + * Notifies of a root task order change * - * @param stack The stack which triggered the order change + * @param rootTask The root task which triggered the order change */ - void onStackOrderChanged(Task stack) { - for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) { - mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack); + void onRootTaskOrderChanged(Task rootTask) { + for (int i = mRootTaskOrderChangedCallbacks.size() - 1; i >= 0; i--) { + mRootTaskOrderChangedCallbacks.get(i).onRootTaskOrderChanged(rootTask); } } @@ -1826,16 +1830,16 @@ final class TaskDisplayArea extends DisplayArea<Task> { /** * Callback for when the order of the stacks in the display changes. */ - interface OnStackOrderChangedListener { - void onStackOrderChanged(Task stack); + interface OnRootTaskOrderChangedListener { + void onRootTaskOrderChanged(Task rootTask); } void ensureActivitiesVisible(ActivityRecord starting, int configChanges, boolean preserveWindows, boolean notifyClients, boolean userLeaving) { mAtmService.mTaskSupervisor.beginActivityVisibilityUpdate(); try { - for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final Task stack = getStackAt(stackNdx); + for (int stackNdx = getRootTaskCount() - 1; stackNdx >= 0; --stackNdx) { + final Task stack = getRootTaskAt(stackNdx); stack.ensureActivitiesVisible(starting, configChanges, preserveWindows, notifyClients, userLeaving); } @@ -1857,7 +1861,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { * @return last reparented stack, or {@code null} if the stacks had to be destroyed. */ Task remove() { - mPreferredTopFocusableStack = null; + mPreferredTopFocusableRootTask = null; // TODO(b/153090332): Allow setting content removal mode per task display area final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove(); final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); @@ -1869,13 +1873,13 @@ final class TaskDisplayArea extends DisplayArea<Task> { // related WindowContainer will also be removed. So, we set display area as removed after // reparenting stack finished. // Keep the order from bottom to top. - int numStacks = getStackCount(); + int numStacks = getRootTaskCount(); final boolean splitScreenActivated = toDisplayArea.isSplitScreenModeActivated(); final Task rootStack = splitScreenActivated ? toDisplayArea - .getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) : null; + .getTopRootTaskInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) : null; for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) { - final Task stack = getStackAt(stackNdx); + final Task stack = getRootTaskAt(stackNdx); // Always finish non-standard type stacks and stacks created by a organizer. // TODO: For stacks created by organizer, consider reparenting children tasks if the use // case arises in the future. @@ -1895,8 +1899,8 @@ final class TaskDisplayArea extends DisplayArea<Task> { } // Stacks may be removed from this display. Ensure each stack will be processed // and the loop will end. - stackNdx -= numStacks - getStackCount(); - numStacks = getStackCount(); + stackNdx -= numStacks - getRootTaskCount(); + numStacks = getRootTaskCount(); } if (lastReparentedStack != null && splitScreenActivated) { if (!lastReparentedStack.supportsSplitScreenWindowingMode()) { @@ -1935,18 +1939,19 @@ final class TaskDisplayArea extends DisplayArea<Task> { pw.println(prefix + "TaskDisplayArea " + getName()); final String doublePrefix = prefix + " "; super.dump(pw, doublePrefix, dumpAll); - if (mPreferredTopFocusableStack != null) { - pw.println(doublePrefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack); + if (mPreferredTopFocusableRootTask != null) { + pw.println(doublePrefix + "mPreferredTopFocusableRootTask=" + + mPreferredTopFocusableRootTask); } - if (mLastFocusedStack != null) { - pw.println(doublePrefix + "mLastFocusedStack=" + mLastFocusedStack); + if (mLastFocusedRootTask != null) { + pw.println(doublePrefix + "mLastFocusedRootTask=" + mLastFocusedRootTask); } final String triplePrefix = doublePrefix + " "; pw.println(doublePrefix + "Application tokens in top down Z order:"); - for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final Task stack = getChildAt(stackNdx); - pw.println(doublePrefix + "* " + stack); - stack.dump(pw, triplePrefix, dumpAll); + for (int rootTaskNdx = getChildCount() - 1; rootTaskNdx >= 0; --rootTaskNdx) { + final Task rootTask = getChildAt(rootTaskNdx); + pw.println(doublePrefix + "* " + rootTask); + rootTask.dump(pw, triplePrefix, dumpAll); } } } diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index 8b2fa52afd22..9d36b84431f3 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -796,9 +796,9 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { @NonNull Rect inOutBounds) { final List<Rect> taskBoundsToCheck = new ArrayList<>(); display.forAllTaskDisplayAreas(taskDisplayArea -> { - int numStacks = taskDisplayArea.getStackCount(); + int numStacks = taskDisplayArea.getRootTaskCount(); for (int sNdx = 0; sNdx < numStacks; ++sNdx) { - final Task task = taskDisplayArea.getStackAt(sNdx); + final Task task = taskDisplayArea.getRootTaskAt(sNdx); if (!task.inFreeformWindowingMode()) { continue; } diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 009a7ef9e4f2..e635219bc6e5 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -478,7 +478,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { // We want to defer the task appear signal until the task is fully created and attached to // to the hierarchy so that the complete starting configuration is in the task info we send // over to the organizer. - final Task task = display.getDefaultTaskDisplayArea().createStack(windowingMode, + final Task task = display.getDefaultTaskDisplayArea().createRootTask(windowingMode, ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(), true /* createdByOrganizer */, true /* deferTaskAppear */, launchCookie); task.setDeferTaskAppear(false /* deferTaskAppear */); @@ -688,8 +688,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } ArrayList<RunningTaskInfo> out = new ArrayList<>(); dc.forAllTaskDisplayAreas(taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task task = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task task = taskDisplayArea.getRootTaskAt(sNdx); if (activityTypes != null && !ArrayUtils.contains(activityTypes, task.getActivityType())) { continue; diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 7d61c1973a2a..7809cbc2a167 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -502,7 +502,8 @@ class WallpaperController { private void findWallpaperTarget() { mFindResults.reset(); - if (mDisplayContent.getDefaultTaskDisplayArea().isStackVisible(WINDOWING_MODE_FREEFORM)) { + if (mDisplayContent.getDefaultTaskDisplayArea() + .isRootTaskVisible(WINDOWING_MODE_FREEFORM)) { // In freeform mode we set the wallpaper as its own target, so we don't need an // additional window to make it visible. mFindResults.setUseTopWallpaperAsTarget(true); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 25049ae6d8b5..f8b5914d3e53 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2922,7 +2922,7 @@ public class WindowManagerService extends IWindowManager.Stub } void getStackBounds(int windowingMode, int activityType, Rect bounds) { - final Task stack = mRoot.getStack(windowingMode, activityType); + final Task stack = mRoot.getRootTask(windowingMode, activityType); if (stack != null) { stack.getBounds(bounds); return; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java index 05b1e4253bc0..ce61d50df1d9 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java @@ -101,9 +101,4 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { public boolean canProfileOwnerResetPasswordWhenLocked(int userId) { return false; } - - public boolean hasKeyPair(String callerPackage, String alias) { - // STOPSHIP: implement delegation code in ArcDevicePolicyManagerWrapperService & nuke this. - return false; - } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 69297f9b67dd..02894b16c079 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -233,6 +233,7 @@ import android.provider.ContactsInternal; import android.provider.Settings; import android.provider.Settings.Global; import android.provider.Telephony; +import android.security.AppUriAuthenticationPolicy; import android.security.IKeyChainAliasCallback; import android.security.IKeyChainService; import android.security.KeyChain; @@ -266,7 +267,6 @@ import android.view.inputmethod.InputMethodInfo; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.compat.IPlatformCompat; import com.android.internal.logging.MetricsLogger; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; @@ -554,7 +554,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private final LockSettingsInternal mLockSettingsInternal; private final DeviceAdminServiceController mDeviceAdminServiceController; private final OverlayPackagesProvider mOverlayPackagesProvider; - private final IPlatformCompat mIPlatformCompat; private final DevicePolicyCacheImpl mPolicyCache = new DevicePolicyCacheImpl(); private final DeviceStateCacheImpl mStateCache = new DeviceStateCacheImpl(); @@ -1154,13 +1153,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return LocalServices.getService(PersistentDataBlockManagerInternal.class); } - LockSettingsInternal getLockSettingsInternal() { - return LocalServices.getService(LockSettingsInternal.class); + AppOpsManager getAppOpsManager() { + return mContext.getSystemService(AppOpsManager.class); } - IPlatformCompat getIPlatformCompat() { - return IPlatformCompat.Stub.asInterface( - ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); + LockSettingsInternal getLockSettingsInternal() { + return LocalServices.getService(LockSettingsInternal.class); } boolean hasUserSetupCompleted(DevicePolicyData userData) { @@ -1433,7 +1431,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mUsageStatsManagerInternal = Objects.requireNonNull( injector.getUsageStatsManagerInternal()); mIPackageManager = Objects.requireNonNull(injector.getIPackageManager()); - mIPlatformCompat = Objects.requireNonNull(injector.getIPlatformCompat()); mIPermissionManager = Objects.requireNonNull(injector.getIPermissionManager()); mTelephonyManager = Objects.requireNonNull(injector.getTelephonyManager()); @@ -3377,13 +3374,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private boolean passwordQualityInvocationOrderCheckEnabled(String packageName, int userId) { - try { - return mIPlatformCompat.isChangeEnabledByPackageName(ADMIN_APP_PASSWORD_COMPLEXITY, - packageName, userId); - } catch (RemoteException e) { - Log.e(LOG_TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e); - } - return getTargetSdk(packageName, userId) > Build.VERSION_CODES.Q; + return mInjector.isChangeEnabled(ADMIN_APP_PASSWORD_COMPLEXITY, packageName, userId); } /** @@ -5031,7 +5022,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final CallerIdentity caller = getCallerIdentity(who, callerPackage); Preconditions.checkCallAuthorization((caller.hasAdminComponent() && (isProfileOwner(caller) || isDeviceOwner(caller))) - || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL))); + || (caller.hasPackage() && (isCallerDelegate(caller, DELEGATION_CERT_INSTALL) + || isCredentialManagementApp(caller, alias, isUserSelectable)))); final long id = mInjector.binderClearCallingIdentity(); try { @@ -5071,7 +5063,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final CallerIdentity caller = getCallerIdentity(who, callerPackage); Preconditions.checkCallAuthorization((caller.hasAdminComponent() && (isProfileOwner(caller) || isDeviceOwner(caller))) - || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL))); + || (caller.hasPackage() && (isCallerDelegate(caller, DELEGATION_CERT_INSTALL) + || isCredentialManagementApp(caller, alias)))); final long id = Binder.clearCallingIdentity(); try { @@ -5275,7 +5268,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } else { Preconditions.checkCallAuthorization((caller.hasAdminComponent() && (isProfileOwner(caller) || isDeviceOwner(caller))) - || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL))); + || (caller.hasPackage() && (isCallerDelegate(caller, DELEGATION_CERT_INSTALL) + || isCredentialManagementApp(caller, alias)))); } // As the caller will be granted access to the key, ensure no UID was specified, as @@ -5371,7 +5365,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final CallerIdentity caller = getCallerIdentity(who, callerPackage); Preconditions.checkCallAuthorization((caller.hasAdminComponent() && (isProfileOwner(caller) || isDeviceOwner(caller))) - || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL))); + || (caller.hasPackage() && (isCallerDelegate(caller, DELEGATION_CERT_INSTALL) + || isCredentialManagementApp(caller, alias)))); final long id = mInjector.binderClearCallingIdentity(); try (final KeyChainConnection keyChainConnection = @@ -5806,6 +5801,70 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + /** + * Check whether a caller application is the credential management app, which can access + * privileged APIs. + * <p> + * This is done by checking that the calling package is authorized to perform the app operation + * {@link android.app.AppOpsManager#OP_MANAGE_CREDENTIALS}. The alias provided must be contained + * in the aliases specified in the credential management app's authentication policy. The + * key pair to install must not be user selectable. + * + * @param caller the calling identity + * @return {@code true} if the calling process is the credential management app. + */ + private boolean isCredentialManagementApp(CallerIdentity caller, String alias, + boolean isUserSelectable) { + // Should not be user selectable + if (isUserSelectable) { + Log.e(LOG_TAG, "The credential management app is not allowed to install a " + + "user selectable key pair"); + return false; + } + return isCredentialManagementApp(caller, alias); + } + + /** + * Check whether a caller application is the credential mangement app, which can access + * privileged APIs. + * <p> + * This is done by checking that the calling package is authorized to perform the app operation + * {@link android.app.AppOpsManager#OP_MANAGE_CREDENTIALS}. The alias provided must be contained + * in the aliases specified in the credential management app's authentication policy. + * + * @param caller the calling identity + * @return {@code true} if the calling process is the credential management app. + */ + private boolean isCredentialManagementApp(CallerIdentity caller, String alias) { + // Should include alias in authentication policy + try (KeyChainConnection connection = KeyChain.bindAsUser(mContext, + caller.getUserHandle())) { + if (!containsAlias(connection.getService().getCredentialManagementAppPolicy(), alias)) { + return false; + } + } catch (RemoteException | InterruptedException e) { + return false; + } + + AppOpsManager appOpsManager = mInjector.getAppOpsManager(); + return appOpsManager != null + ? appOpsManager.noteOpNoThrow(AppOpsManager.OP_MANAGE_CREDENTIALS, caller.getUid(), + caller.getPackageName(), null, null) == AppOpsManager.MODE_ALLOWED + : false; + } + + private static boolean containsAlias(AppUriAuthenticationPolicy policy, String alias) { + for (Map.Entry<String, Map<Uri, String>> appsToUris : + policy.getAppAndUriMappings().entrySet()) { + for (Map.Entry<Uri, String> urisToAliases : appsToUris.getValue().entrySet()) { + if (urisToAliases.getValue().equals(alias)) { + return true; + } + } + } + return false; + } + @Override public void setCertInstallerPackage(ComponentName who, String installerPackage) throws SecurityException { @@ -7415,6 +7474,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { admin.getPackageName(), userId, "set-device-owner"); Slog.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId); + + if (mInjector.userManagerIsHeadlessSystemUserMode()) { + Slog.i(LOG_TAG, "manageUser: " + admin + " on user " + userId); + + manageUser(admin, admin, caller.getUserId(), null); + } return true; } } @@ -9468,29 +9533,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final long id = mInjector.binderClearCallingIdentity(); try { - final String adminPkg = admin.getPackageName(); - try { - // Install the profile owner if not present. - if (!mIPackageManager.isPackageAvailable(adminPkg, userHandle)) { - mIPackageManager.installExistingPackageAsUser(adminPkg, userHandle, - PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, - PackageManager.INSTALL_REASON_POLICY, null); - } - } catch (RemoteException e) { - // Does not happen, same process - } - - // Set admin. - setActiveAdmin(profileOwner, true, userHandle); - final String ownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier()); - setProfileOwner(profileOwner, ownerName, userHandle); - - synchronized (getLockObject()) { - DevicePolicyData policyData = getUserData(userHandle); - policyData.mInitBundle = adminExtras; - policyData.mAdminBroadcastPending = true; - saveSettingsLocked(userHandle); - } + manageUser(admin, profileOwner, userHandle, adminExtras); if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) { Settings.Secure.putIntForUser(mContext.getContentResolver(), @@ -9511,6 +9554,46 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + private void manageUser(ComponentName admin, ComponentName profileOwner, + @UserIdInt int userId, PersistableBundle adminExtras) { + // Check for permission + final CallerIdentity caller = getCallerIdentity(); + Preconditions.checkCallAuthorization(canManageUsers(caller)); + Preconditions.checkCallAuthorization( + hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)); + mInjector.binderWithCleanCallingIdentity(() -> + manageUserNoCheck(admin, profileOwner, userId, adminExtras)); + } + + private void manageUserNoCheck(ComponentName admin, ComponentName profileOwner, + int user, PersistableBundle adminExtras) { + + final String adminPkg = admin.getPackageName(); + try { + // Install the profile owner if not present. + if (!mIPackageManager.isPackageAvailable(adminPkg, user)) { + mIPackageManager.installExistingPackageAsUser(adminPkg, user, + PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, + PackageManager.INSTALL_REASON_POLICY, null); + } + } catch (RemoteException e) { + // Does not happen, same process + } + + // Set admin. + setActiveAdmin(profileOwner, true, user); + final String ownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier()); + setProfileOwner(profileOwner, ownerName, user); + + synchronized (getLockObject()) { + DevicePolicyData policyData = getUserData(user); + policyData.mInitBundle = adminExtras; + policyData.mAdminBroadcastPending = true; + + saveSettingsLocked(user); + } + } + @Override public boolean removeUser(ComponentName who, UserHandle userHandle) { Objects.requireNonNull(who, "ComponentName is null"); @@ -10951,16 +11034,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private boolean isSetSecureSettingLocationModeCheckEnabled(String packageName, int userId) { - long ident = mInjector.binderClearCallingIdentity(); - try { - return mIPlatformCompat.isChangeEnabledByPackageName(USE_SET_LOCATION_ENABLED, - packageName, userId); - } catch (RemoteException e) { - Log.e(LOG_TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e); - return getTargetSdk(packageName, userId) > Build.VERSION_CODES.Q; - } finally { - mInjector.binderRestoreCallingIdentity(ident); - } + return mInjector.isChangeEnabled(USE_SET_LOCATION_ENABLED, packageName, userId); } @Override @@ -12188,8 +12262,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) { return CODE_USER_SETUP_COMPLETED; } - } else { - // STOPSHIP Do proper check in split user mode } return CODE_OK; } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 10b3265cd081..6525e1126478 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -47,6 +47,7 @@ import android.content.res.Resources.Theme; import android.database.sqlite.SQLiteCompatibilityWalFlags; import android.database.sqlite.SQLiteGlobal; import android.graphics.GraphicsStatsService; +import android.graphics.Typeface; import android.hardware.display.DisplayManagerInternal; import android.net.ConnectivityManager; import android.net.ConnectivityModuleConnector; @@ -120,6 +121,7 @@ import com.android.server.display.color.ColorDisplayService; import com.android.server.dreams.DreamManagerService; import com.android.server.emergency.EmergencyAffordanceService; import com.android.server.gpu.GpuService; +import com.android.server.graphics.fonts.FontManagerService; import com.android.server.hdmi.HdmiControlService; import com.android.server.incident.IncidentCompanionService; import com.android.server.input.InputManagerService; @@ -673,6 +675,11 @@ public final class SystemServer implements Dumpable { SystemServerInitThreadPool tp = SystemServerInitThreadPool.start(); mDumper.addDumpable(tp); + // Load preinstalled system fonts for system server, so that WindowManagerService, etc + // can start using Typeface. Note that fonts are required not only for text rendering, + // but also for some text operations (e.g. TextUtils.makeSafeForPresentation()). + Typeface.loadPreinstalledSystemFontMap(); + // Attach JVMTI agent if this is a debuggable build and the system property is set. if (Build.IS_DEBUGGABLE) { // Property is of the form "library_path=parameters". @@ -1604,6 +1611,10 @@ public final class SystemServer implements Dumpable { } t.traceEnd(); + t.traceBegin("StartFontManagerService"); + mSystemServiceManager.startService(FontManagerService.Lifecycle.class); + t.traceEnd(); + t.traceBegin("StartTextServicesManager"); mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class); t.traceEnd(); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java index b9c2e56a4d90..3f3d5e5106c5 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java @@ -17,7 +17,6 @@ package com.android.server.accessibility; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -42,7 +41,6 @@ import android.os.UserHandle; import android.provider.Settings; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; -import android.view.Display; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import androidx.test.InstrumentationRegistry; @@ -208,34 +206,6 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase { } @SmallTest - public void testOnMagnificationScaleChanged_MagnificationCapabilitiesAll_showButton() { - // Request showing magnification button if the magnification capability is all mode. - mA11yms.mUserStates.get( - mA11yms.getCurrentUserIdLocked()).setMagnificationCapabilitiesLocked( - Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL); - - mA11yms.onMagnificationScaleChanged(Display.DEFAULT_DISPLAY, - Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); - - verify(mMockWindowMagnificationMgr).showMagnificationButton(Display.DEFAULT_DISPLAY, - Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); - } - - @SmallTest - public void testOnMagnificationScaleChanged_MagnificationCapabilitiesNotAll_NoAction() { - // Do nothing if the magnification capability is not all mode. - mA11yms.mUserStates.get( - mA11yms.getCurrentUserIdLocked()).setMagnificationCapabilitiesLocked( - Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); - - mA11yms.onMagnificationScaleChanged(Display.DEFAULT_DISPLAY, - Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); - - verify(mMockWindowMagnificationMgr, never()).showMagnificationButton(anyInt(), - anyInt()); - } - - @SmallTest public void testOnMagnificationTransitionFailed_capabilitiesIsAll_fallBackToPreviousMode() { final AccessibilityUserState userState = mA11yms.mUserStates.get( mA11yms.getCurrentUserIdLocked()); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java index e43a002806ee..c038a0f33904 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java @@ -54,7 +54,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.accessibility.EventStreamTransformation; import com.android.server.accessibility.magnification.FullScreenMagnificationController.MagnificationRequestObserver; -import com.android.server.accessibility.magnification.MagnificationGestureHandler.ScaleChangedListener; import com.android.server.testutils.OffsettableClock; import com.android.server.testutils.TestHandler; import com.android.server.wm.WindowManagerInternal; @@ -125,7 +124,7 @@ public class FullScreenMagnificationGestureHandlerTest { private Context mContext; FullScreenMagnificationController mFullScreenMagnificationController; @Mock - ScaleChangedListener mMockScaleChangedListener; + MagnificationGestureHandler.ScaleChangedListener mMockScaleChangedListener; @Mock MagnificationRequestObserver mMagnificationRequestObserver; @Mock @@ -181,8 +180,8 @@ public class FullScreenMagnificationGestureHandlerTest { boolean detectShortcutTrigger) { FullScreenMagnificationGestureHandler h = new FullScreenMagnificationGestureHandler( mContext, mFullScreenMagnificationController, mMockScaleChangedListener, - detectTripleTap, detectShortcutTrigger, mWindowMagnificationPromptController, - DISPLAY_0); + detectTripleTap, detectShortcutTrigger, + mWindowMagnificationPromptController, DISPLAY_0); mHandler = new TestHandler(h.mDetectingState, mClock) { @Override protected String messageToString(Message m) { diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java index aed590b8b7e0..cba618bf94b8 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java @@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -106,8 +107,8 @@ public class MagnificationControllerTest { mock(WindowMagnificationManager.Callback.class))); mMockConnection = new MockWindowMagnificationConnection(true); mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); - mMagnificationController = new MagnificationController(mService, new Object(), mContext, - mScreenMagnificationController, mWindowMagnificationManager); + mMagnificationController = spy(new MagnificationController(mService, new Object(), mContext, + mScreenMagnificationController, mWindowMagnificationManager)); } @After @@ -277,8 +278,32 @@ public class MagnificationControllerTest { verify(mWindowMagnificationManager).setScale(eq(TEST_DISPLAY), eq(newScale)); verify(mWindowMagnificationManager).persistScale(eq(TEST_DISPLAY)); - verify(mService).onMagnificationScaleChanged(eq(TEST_DISPLAY), - eq(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW)); + verify(mMagnificationController).onMagnificationScaleChanged(eq(TEST_DISPLAY), + eq(MODE_WINDOW)); + } + + @Test + public void onMagnificationScaleChanged_capabilitiesAllMode_showMagnificationButton() + throws RemoteException { + mMagnificationController.setMagnificationCapabilities( + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL); + + mMagnificationController.onMagnificationScaleChanged(TEST_DISPLAY, MODE_WINDOW); + + verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY), + eq(MODE_WINDOW)); + } + + @Test + public void onMagnificationScaleChanged_capabilitiesNotAllMode_notShowMagnificationButton() + throws RemoteException { + mMagnificationController.setMagnificationCapabilities( + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); + + mMagnificationController.onMagnificationScaleChanged(TEST_DISPLAY, MODE_WINDOW); + + verify(mWindowMagnificationManager, never()).showMagnificationButton(eq(TEST_DISPLAY), + eq(MODE_WINDOW)); } private void setMagnificationEnabled(int mode) throws RemoteException { diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java index 41b6e987f819..9f930da4ee29 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java @@ -32,7 +32,6 @@ import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.server.accessibility.EventStreamTransformation; -import com.android.server.accessibility.magnification.MagnificationGestureHandler.ScaleChangedListener; import com.android.server.accessibility.utils.TouchEventGenerator; import org.junit.After; @@ -74,7 +73,8 @@ public class WindowMagnificationGestureHandlerTest { mock(WindowMagnificationManager.Callback.class)); mMockConnection = new MockWindowMagnificationConnection(); mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler( - mContext, mWindowMagnificationManager, mock(ScaleChangedListener.class), + mContext, mWindowMagnificationManager, mock( + MagnificationGestureHandler.ScaleChangedListener.class), /** detectTripleTap= */true, /** detectShortcutTrigger= */true, DISPLAY_0); mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); mWindowMagnificationGestureHandler.setNext(strictMock(EventStreamTransformation.class)); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java index de9a5e4f0fe7..d10e075c5136 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java @@ -18,17 +18,13 @@ package com.android.server.hdmi; import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertTrue; -import static junit.framework.Assert.fail; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertThrows; -import android.annotation.NonNull; import android.content.Context; import android.hardware.hdmi.HdmiControlManager; -import android.os.Looper; import android.platform.test.annotations.Presubmit; import android.provider.Settings.Global; @@ -42,21 +38,15 @@ import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - @SmallTest @Presubmit @RunWith(JUnit4.class) public final class HdmiCecConfigTest { private static final String TAG = "HdmiCecConfigTest"; - private static final int TIMEOUT_CONTENT_CHANGE_SEC = 4; - private Context mContext; @Mock private HdmiCecConfig.StorageAdapter mStorageAdapter; - @Mock private HdmiCecConfig.SettingChangeListener mSettingChangeListener; @Before public void setUp() throws Exception { @@ -1029,105 +1019,4 @@ public final class HdmiCecConfigTest { HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED)); } - - @Test - public void registerChangeListener_SharedPref_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"system_audio_mode_muting\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); - hdmiCecConfig.registerChangeListener( - HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, - mSettingChangeListener); - hdmiCecConfig.setIntValue( - HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, - HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED); - verify(mSettingChangeListener).onChange( - HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING); - } - - @Test - public void removeChangeListener_SharedPref_BasicSanity() { - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"system_audio_mode_muting\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); - hdmiCecConfig.registerChangeListener( - HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, - mSettingChangeListener); - hdmiCecConfig.removeChangeListener( - HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, - mSettingChangeListener); - hdmiCecConfig.setIntValue( - HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, - HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED); - verify(mSettingChangeListener, never()).onChange( - HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING); - } - - /** - * Externally modified Global Settings still need to be supported. This test verifies that - * setting change notification is being forwarded to listeners registered via HdmiCecConfig. - */ - @Test - public void globalSettingObserver_BasicSanity() throws Exception { - CountDownLatch notifyLatch = new CountDownLatch(1); - // Get current value of the setting in the system. - String val = Global.getString(mContext.getContentResolver(), Global.HDMI_CONTROL_ENABLED); - HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings( - mContext, mStorageAdapter, - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" - + "<cec-settings>" - + " <setting name=\"hdmi_cec_enabled\"" - + " value-type=\"int\"" - + " user-configurable=\"true\">" - + " <allowed-values>" - + " <value int-value=\"0\" />" - + " <value int-value=\"1\" />" - + " </allowed-values>" - + " <default-value int-value=\"1\" />" - + " </setting>" - + "</cec-settings>", null); - hdmiCecConfig.registerGlobalSettingsObserver(Looper.getMainLooper()); - HdmiCecConfig.SettingChangeListener latchUpdateListener = - new HdmiCecConfig.SettingChangeListener() { - @Override - public void onChange(@NonNull @HdmiControlManager.CecSettingName String setting) { - notifyLatch.countDown(); - assertThat(setting).isEqualTo(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED); - } - }; - hdmiCecConfig.registerChangeListener( - HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, - latchUpdateListener); - // Flip the value of the setting. - Global.putString(mContext.getContentResolver(), Global.HDMI_CONTROL_ENABLED, - ((val == null || val.equals("1")) ? "0" : "1")); - if (!notifyLatch.await(TIMEOUT_CONTENT_CHANGE_SEC, TimeUnit.SECONDS)) { - fail("Timed out waiting for the notify callback"); - } - hdmiCecConfig.unregisterGlobalSettingsObserver(); - // Restore the previous value of the setting in the system. - Global.putString(mContext.getContentResolver(), Global.HDMI_CONTROL_ENABLED, val); - } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java index 9a6eb1cf2623..99bd0d7198c0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java @@ -68,16 +68,16 @@ public class ActivityDisplayTests extends WindowTestsBase { mRootWindowContainer.getDefaultDisplay().getDefaultTaskDisplayArea(); final Task stack = new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build(); - final Task prevFocusedStack = taskDisplayAreas.getFocusedStack(); + final Task prevFocusedStack = taskDisplayAreas.getFocusedRootTask(); stack.moveToFront("moveStackToFront"); // After moving the stack to front, the previous focused should be the last focused. assertTrue(stack.isFocusedStackOnDisplay()); - assertEquals(prevFocusedStack, taskDisplayAreas.getLastFocusedStack()); + assertEquals(prevFocusedStack, taskDisplayAreas.getLastFocusedRootTask()); stack.moveToBack("moveStackToBack", null /* task */); // After moving the stack to back, the stack should be the last focused. - assertEquals(stack, taskDisplayAreas.getLastFocusedStack()); + assertEquals(stack, taskDisplayAreas.getLastFocusedRootTask()); } /** @@ -88,7 +88,7 @@ public class ActivityDisplayTests extends WindowTestsBase { public void testFullscreenStackCanBeFocusedWhenFocusablePinnedStackExists() { // Create a pinned stack and move to front. final Task pinnedStack = mRootWindowContainer.getDefaultTaskDisplayArea() - .createStack(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP); + .createRootTask(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP); final Task pinnedTask = new TaskBuilder(mAtm.mTaskSupervisor) .setParentTask(pinnedStack).build(); new ActivityBuilder(mAtm).setActivityFlags(FLAG_ALWAYS_FOCUSABLE) @@ -108,7 +108,7 @@ public class ActivityDisplayTests extends WindowTestsBase { } /** - * Test {@link TaskDisplayArea#mPreferredTopFocusableStack} will be cleared when + * Test {@link TaskDisplayArea#mPreferredTopFocusableRootTask} will be cleared when * the stack is removed or moved to back, and the focused stack will be according to z-order. */ @Test @@ -128,7 +128,7 @@ public class ActivityDisplayTests extends WindowTestsBase { assertTrue(stack1.isFocusedStackOnDisplay()); // Stack2 should be focused after removing stack1. - stack1.getDisplayArea().removeStack(stack1); + stack1.getDisplayArea().removeRootTask(stack1); assertTrue(stack2.isFocusedStackOnDisplay()); } @@ -155,12 +155,12 @@ public class ActivityDisplayTests extends WindowTestsBase { display.remove(); // The removed display should have no focused stack and its home stack should never resume. - assertNull(display.getFocusedStack()); + assertNull(display.getFocusedRootTask()); verify(homeStack, never()).resumeTopActivityUncheckedLocked(any(), any()); } private Task createFullscreenStackWithSimpleActivityAt(DisplayContent display) { - final Task fullscreenStack = display.getDefaultTaskDisplayArea().createStack( + final Task fullscreenStack = display.getDefaultTaskDisplayArea().createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); final Task fullscreenTask = new TaskBuilder(mAtm.mTaskSupervisor) .setParentTask(fullscreenStack).build(); @@ -191,7 +191,7 @@ public class ActivityDisplayTests extends WindowTestsBase { // Move stack with activity to top. stack.moveToFront("testStackToFront"); - assertEquals(stack, display.getFocusedStack()); + assertEquals(stack, display.getFocusedRootTask()); assertEquals(activity, display.topRunningActivity()); assertNull(display.topRunningActivity(true /* considerKeyguardState */)); @@ -207,7 +207,7 @@ public class ActivityDisplayTests extends WindowTestsBase { // Move empty stack to front. The running activity in focusable stack which below the // empty stack should be returned. emptyStack.moveToFront("emptyStackToFront"); - assertEquals(stack, display.getFocusedStack()); + assertEquals(stack, display.getFocusedRootTask()); assertTopRunningActivity(showWhenLockedActivity, display); } @@ -222,7 +222,7 @@ public class ActivityDisplayTests extends WindowTestsBase { @Test public void testAlwaysOnTopStackLocation() { final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final Task alwaysOnTopStack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM, + final Task alwaysOnTopStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); final ActivityRecord activity = new ActivityBuilder(mAtm) .setTask(alwaysOnTopStack).build(); @@ -232,31 +232,31 @@ public class ActivityDisplayTests extends WindowTestsBase { assertTrue(alwaysOnTopStack.isAlwaysOnTop()); // Ensure always on top state is synced to the children of the stack. assertTrue(alwaysOnTopStack.getTopNonFinishingActivity().isAlwaysOnTop()); - assertEquals(alwaysOnTopStack, taskDisplayArea.getTopStack()); + assertEquals(alwaysOnTopStack, taskDisplayArea.getTopRootTask()); - final Task pinnedStack = taskDisplayArea.createStack( + final Task pinnedStack = taskDisplayArea.createRootTask( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertEquals(pinnedStack, taskDisplayArea.getRootPinnedTask()); - assertEquals(pinnedStack, taskDisplayArea.getTopStack()); + assertEquals(pinnedStack, taskDisplayArea.getTopRootTask()); - final Task anotherAlwaysOnTopStack = taskDisplayArea.createStack( + final Task anotherAlwaysOnTopStack = taskDisplayArea.createRootTask( WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); anotherAlwaysOnTopStack.setAlwaysOnTop(true); taskDisplayArea.positionChildAt(POSITION_TOP, anotherAlwaysOnTopStack, false /* includingParents */); assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop()); - int topPosition = taskDisplayArea.getStackCount() - 1; + int topPosition = taskDisplayArea.getRootTaskCount() - 1; // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the // existing alwaysOnTop stack. - assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 1)); + assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getRootTaskAt(topPosition - 1)); - final Task nonAlwaysOnTopStack = taskDisplayArea.createStack( + final Task nonAlwaysOnTopStack = taskDisplayArea.createRootTask( WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertEquals(taskDisplayArea, nonAlwaysOnTopStack.getDisplayArea()); - topPosition = taskDisplayArea.getStackCount() - 1; + topPosition = taskDisplayArea.getRootTaskCount() - 1; // Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the // existing other non-alwaysOnTop stacks. - assertEquals(nonAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 3)); + assertEquals(nonAlwaysOnTopStack, taskDisplayArea.getRootTaskAt(topPosition - 3)); anotherAlwaysOnTopStack.setAlwaysOnTop(false); taskDisplayArea.positionChildAt(POSITION_TOP, anotherAlwaysOnTopStack, @@ -264,37 +264,37 @@ public class ActivityDisplayTests extends WindowTestsBase { assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop()); // Ensure, when always on top is turned off for a stack, the stack is put just below all // other always on top stacks. - assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 2)); + assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getRootTaskAt(topPosition - 2)); anotherAlwaysOnTopStack.setAlwaysOnTop(true); // Ensure always on top state changes properly when windowing mode changes. anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN); assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop()); - assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 2)); + assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getRootTaskAt(topPosition - 2)); anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM); assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop()); - assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 1)); + assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getRootTaskAt(topPosition - 1)); - final Task dreamStack = taskDisplayArea.createStack( + final Task dreamStack = taskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM, true /* onTop */); assertEquals(taskDisplayArea, dreamStack.getDisplayArea()); assertTrue(dreamStack.isAlwaysOnTop()); - topPosition = taskDisplayArea.getStackCount() - 1; + topPosition = taskDisplayArea.getRootTaskCount() - 1; // Ensure dream shows above all activities, including PiP - assertEquals(dreamStack, taskDisplayArea.getTopStack()); - assertEquals(pinnedStack, taskDisplayArea.getStackAt(topPosition - 1)); + assertEquals(dreamStack, taskDisplayArea.getTopRootTask()); + assertEquals(pinnedStack, taskDisplayArea.getRootTaskAt(topPosition - 1)); - final Task assistStack = taskDisplayArea.createStack( + final Task assistStack = taskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */); assertEquals(taskDisplayArea, assistStack.getDisplayArea()); assertFalse(assistStack.isAlwaysOnTop()); - topPosition = taskDisplayArea.getStackCount() - 1; + topPosition = taskDisplayArea.getRootTaskCount() - 1; // Ensure Assistant shows as a non-always-on-top activity when config_assistantOnTopOfDream // is false and on top of everything when true. final boolean isAssistantOnTop = mContext.getResources() .getBoolean(com.android.internal.R.bool.config_assistantOnTopOfDream); - assertEquals(assistStack, taskDisplayArea.getStackAt( + assertEquals(assistStack, taskDisplayArea.getRootTaskAt( isAssistantOnTop ? topPosition : topPosition - 4)); } @@ -312,13 +312,13 @@ public class ActivityDisplayTests extends WindowTestsBase { private void removeStackTests(Runnable runnable) { final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final Task stack1 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task stack1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); - final Task stack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task stack2 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); - final Task stack3 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task stack3 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); - final Task stack4 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task stack4 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); final Task task1 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(stack1).build(); final Task task2 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(stack2).build(); @@ -333,7 +333,7 @@ public class ActivityDisplayTests extends WindowTestsBase { // Removing stacks from the display while removing stacks. doAnswer(invocation -> { - taskDisplayArea.removeStack(stack2); + taskDisplayArea.removeRootTask(stack2); return true; }).when(mSupervisor).removeTask(eq(task2), anyBoolean(), anyBoolean(), any()); 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 2304efcaef65..2f34f708a562 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -155,7 +155,7 @@ public class ActivityRecordTests extends WindowTestsBase { final Task rootTask = activity.getRootTask(); rootTask.removeChild(task, null /*reason*/); // parentTask should be gone on task removal. - assertNull(mAtm.mRootWindowContainer.getStack(rootTask.mTaskId)); + assertNull(mAtm.mRootWindowContainer.getRootTask(rootTask.mTaskId)); } @Test @@ -384,6 +384,7 @@ public class ActivityRecordTests extends WindowTestsBase { .build(); final Task task = activity.getTask(); activity.setState(DESTROYED, "Testing"); + clearInvocations(mAtm.getLifecycleManager()); final Configuration newConfig = new Configuration(task.getConfiguration()); newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT @@ -408,6 +409,7 @@ public class ActivityRecordTests extends WindowTestsBase { activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), activity.getConfiguration())); + clearInvocations(mAtm.getLifecycleManager()); final Configuration newConfig = new Configuration(activity.getConfiguration()); final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp); final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp); @@ -596,6 +598,7 @@ public class ActivityRecordTests extends WindowTestsBase { final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); try { + clearInvocations(mAtm.getLifecycleManager()); doReturn(false).when(stack).isTranslucent(any()); assertTrue(task.shouldBeVisible(null /* starting */)); @@ -875,7 +878,7 @@ public class ActivityRecordTests extends WindowTestsBase { topRootableTask.moveToFront("test"); assertTrue(topRootableTask.isTopStackInDisplayArea()); assertEquals(topRootableTask, topActivityOnNonTopDisplay.getDisplayArea() - .mPreferredTopFocusableStack); + .mPreferredTopFocusableRootTask); final ActivityRecord secondaryDisplayActivity = createActivityOnDisplay(false /* defaultDisplay */, null /* process */); @@ -883,7 +886,7 @@ public class ActivityRecordTests extends WindowTestsBase { topRootableTask.moveToFront("test"); assertTrue(topRootableTask.isTopStackInDisplayArea()); assertEquals(topRootableTask, - secondaryDisplayActivity.getDisplayArea().mPreferredTopFocusableStack); + secondaryDisplayActivity.getDisplayArea().mPreferredTopFocusableRootTask); // The global top focus activity is on secondary display now. // Finish top activity on default display and verify the next preferred top focusable stack @@ -892,7 +895,7 @@ public class ActivityRecordTests extends WindowTestsBase { topActivityOnNonTopDisplay.finishIfPossible(0 /* resultCode */, null /* resultData */, null /* resultGrants */, "test", false /* oomAdj */); assertEquals(task, task.getTopMostTask()); - assertEquals(task, activity.getDisplayArea().mPreferredTopFocusableStack); + assertEquals(task, activity.getDisplayArea().mPreferredTopFocusableRootTask); } /** @@ -1297,7 +1300,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testDestroyIfPossible() { final ActivityRecord activity = createActivityWithTask(); - doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities(); + doReturn(false).when(mRootWindowContainer).resumeFocusedTasksTopActivities(); activity.destroyIfPossible("test"); assertEquals(DESTROYING, activity.getState()); @@ -1319,7 +1322,7 @@ public class ActivityRecordTests extends WindowTestsBase { homeStack.removeChild(t, "test"); }, true /* traverseTopToBottom */); activity.finishing = true; - doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities(); + doReturn(false).when(mRootWindowContainer).resumeFocusedTasksTopActivities(); // Try to destroy the last activity above the home stack. activity.destroyIfPossible("test"); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index 8ccbb8fe62ad..8e3e668804ff 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -48,7 +48,7 @@ import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT; import static com.android.server.wm.Task.TASK_VISIBILITY_INVISIBLE; import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE; import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; -import static com.android.server.wm.TaskDisplayArea.getStackAbove; +import static com.android.server.wm.TaskDisplayArea.getRootTaskAbove; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; import static com.android.server.wm.WindowContainer.POSITION_TOP; @@ -74,6 +74,8 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.server.wm.TaskDisplayArea.OnRootTaskOrderChangedListener; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -154,7 +156,7 @@ public class ActivityStackTests extends WindowTestsBase { organizer.setMoveToSecondaryOnEnter(false); // Create primary splitscreen stack. - final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack( + final Task primarySplitScreen = mDefaultTaskDisplayArea.createRootTask( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Assert windowing mode. @@ -179,7 +181,7 @@ public class ActivityStackTests extends WindowTestsBase { public void testMoveToPrimarySplitScreenThenMoveToBack() { TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm); // This time, start with a fullscreen activitystack - final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack( + final Task primarySplitScreen = mDefaultTaskDisplayArea.createRootTask( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); primarySplitScreen.reparent(organizer.mPrimary, POSITION_TOP, @@ -205,11 +207,11 @@ public class ActivityStackTests extends WindowTestsBase { TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm); // Set up split-screen with primary on top and secondary containing the home task below // another stack. - final Task primaryTask = mDefaultTaskDisplayArea.createStack( + final Task primaryTask = mDefaultTaskDisplayArea.createRootTask( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final Task homeRoot = mDefaultTaskDisplayArea.getStack( + final Task homeRoot = mDefaultTaskDisplayArea.getRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); - final Task secondaryTask = mDefaultTaskDisplayArea.createStack( + final Task secondaryTask = mDefaultTaskDisplayArea.createRootTask( WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); mDefaultTaskDisplayArea.positionChildAt(POSITION_TOP, organizer.mPrimary, false /* includingParents */); @@ -257,7 +259,7 @@ public class ActivityStackTests extends WindowTestsBase { @Test public void testStackInheritsDisplayWindowingMode() { - final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack( + final Task primarySplitScreen = mDefaultTaskDisplayArea.createRootTask( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode()); @@ -272,7 +274,7 @@ public class ActivityStackTests extends WindowTestsBase { @Test public void testStackOverridesDisplayWindowingMode() { - final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack( + final Task primarySplitScreen = mDefaultTaskDisplayArea.createRootTask( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode()); @@ -365,7 +367,7 @@ public class ActivityStackTests extends WindowTestsBase { verify(stack2).positionChildAtBottom(any(), eq(false) /* includingParents */); // Also move display to back because there is only one stack left. - taskDisplayArea.removeStack(stack1); + taskDisplayArea.removeRootTask(stack1); stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.getTopMostTask()); verify(stack2).positionChildAtBottom(any(), eq(true) /* includingParents */); } @@ -747,8 +749,8 @@ public class ActivityStackTests extends WindowTestsBase { // Ensure that we don't move the home stack if it is already behind the top fullscreen stack int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack); - assertEquals(fullscreenStack, getStackAbove(homeStack)); - mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack); + assertEquals(fullscreenStack, getRootTaskAbove(homeStack)); + mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack); assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack)); } @@ -765,8 +767,8 @@ public class ActivityStackTests extends WindowTestsBase { // Ensure that we don't move the home stack if it is already behind the top fullscreen stack int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack); - assertEquals(fullscreenStack, getStackAbove(homeStack)); - mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack); + assertEquals(fullscreenStack, getRootTaskAbove(homeStack)); + mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack); assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack)); } @@ -783,8 +785,8 @@ public class ActivityStackTests extends WindowTestsBase { // Ensure we don't move the home stack if it is already on top int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack); - assertNull(getStackAbove(homeStack)); - mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack); + assertNull(getRootTaskAbove(homeStack)); + mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack); assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack)); } @@ -807,9 +809,9 @@ public class ActivityStackTests extends WindowTestsBase { // Ensure that we move the home stack behind the bottom most fullscreen stack, ignoring the // pinned stack - assertEquals(fullscreenStack1, getStackAbove(homeStack)); - mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack); - assertEquals(fullscreenStack2, getStackAbove(homeStack)); + assertEquals(fullscreenStack1, getRootTaskAbove(homeStack)); + mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack); + assertEquals(fullscreenStack2, getRootTaskAbove(homeStack)); } @Test @@ -830,9 +832,9 @@ public class ActivityStackTests extends WindowTestsBase { // Ensure that we move the home stack behind the bottom most non-translucent fullscreen // stack - assertEquals(fullscreenStack1, getStackAbove(homeStack)); - mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack); - assertEquals(fullscreenStack1, getStackAbove(homeStack)); + assertEquals(fullscreenStack1, getRootTaskAbove(homeStack)); + mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack); + assertEquals(fullscreenStack1, getRootTaskAbove(homeStack)); } @Test @@ -852,7 +854,7 @@ public class ActivityStackTests extends WindowTestsBase { // Ensure we don't move the home stack behind itself int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack); - mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, homeStack); + mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, homeStack); assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack)); } @@ -873,14 +875,14 @@ public class ActivityStackTests extends WindowTestsBase { final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, fullscreenStack1); - assertEquals(fullscreenStack1, getStackAbove(homeStack)); - mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, fullscreenStack2); - assertEquals(fullscreenStack2, getStackAbove(homeStack)); - mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, fullscreenStack4); - assertEquals(fullscreenStack4, getStackAbove(homeStack)); - mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, fullscreenStack2); - assertEquals(fullscreenStack2, getStackAbove(homeStack)); + mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, fullscreenStack1); + assertEquals(fullscreenStack1, getRootTaskAbove(homeStack)); + mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, fullscreenStack2); + assertEquals(fullscreenStack2, getRootTaskAbove(homeStack)); + mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, fullscreenStack4); + assertEquals(fullscreenStack4, getRootTaskAbove(homeStack)); + mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, fullscreenStack2); + assertEquals(fullscreenStack2, getRootTaskAbove(homeStack)); } @Test @@ -889,7 +891,7 @@ public class ActivityStackTests extends WindowTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); - assertEquals(pinnedStack, getStackAbove(homeStack)); + assertEquals(pinnedStack, getRootTaskAbove(homeStack)); final Task alwaysOnTopStack = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, @@ -897,13 +899,13 @@ public class ActivityStackTests extends WindowTestsBase { alwaysOnTopStack.setAlwaysOnTop(true); assertTrue(alwaysOnTopStack.isAlwaysOnTop()); // Ensure (non-pinned) always on top stack is put below pinned stack. - assertEquals(pinnedStack, getStackAbove(alwaysOnTopStack)); + assertEquals(pinnedStack, getRootTaskAbove(alwaysOnTopStack)); final Task nonAlwaysOnTopStack = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Ensure non always on top stack is put below always on top stacks. - assertEquals(alwaysOnTopStack, getStackAbove(nonAlwaysOnTopStack)); + assertEquals(alwaysOnTopStack, getRootTaskAbove(nonAlwaysOnTopStack)); final Task alwaysOnTopStack2 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, @@ -911,21 +913,21 @@ public class ActivityStackTests extends WindowTestsBase { alwaysOnTopStack2.setAlwaysOnTop(true); assertTrue(alwaysOnTopStack2.isAlwaysOnTop()); // Ensure newly created always on top stack is placed above other all always on top stacks. - assertEquals(pinnedStack, getStackAbove(alwaysOnTopStack2)); + assertEquals(pinnedStack, getRootTaskAbove(alwaysOnTopStack2)); alwaysOnTopStack2.setAlwaysOnTop(false); // Ensure, when always on top is turned off for a stack, the stack is put just below all // other always on top stacks. - assertEquals(alwaysOnTopStack, getStackAbove(alwaysOnTopStack2)); + assertEquals(alwaysOnTopStack, getRootTaskAbove(alwaysOnTopStack2)); alwaysOnTopStack2.setAlwaysOnTop(true); // Ensure always on top state changes properly when windowing mode changes. alwaysOnTopStack2.setWindowingMode(WINDOWING_MODE_FULLSCREEN); assertFalse(alwaysOnTopStack2.isAlwaysOnTop()); - assertEquals(alwaysOnTopStack, getStackAbove(alwaysOnTopStack2)); + assertEquals(alwaysOnTopStack, getRootTaskAbove(alwaysOnTopStack2)); alwaysOnTopStack2.setWindowingMode(WINDOWING_MODE_FREEFORM); assertTrue(alwaysOnTopStack2.isAlwaysOnTop()); - assertEquals(pinnedStack, getStackAbove(alwaysOnTopStack2)); + assertEquals(pinnedStack, getRootTaskAbove(alwaysOnTopStack2)); } @Test @@ -980,7 +982,8 @@ public class ActivityStackTests extends WindowTestsBase { int windowingMode, int activityType, boolean onTop, boolean twoLevelTask) { final Task task; if (activityType == ACTIVITY_TYPE_HOME) { - task = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); + task = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_HOME); mDefaultTaskDisplayArea.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, task, false /* includingParents */); } else if (twoLevelTask) { @@ -1224,12 +1227,12 @@ public class ActivityStackTests extends WindowTestsBase { @Test public void testStackOrderChangedOnRemoveStack() { final Task task = new TaskBuilder(mSupervisor).build(); - StackOrderChangedListener listener = new StackOrderChangedListener(); - mDefaultTaskDisplayArea.registerStackOrderChangedListener(listener); + RootTaskOrderChangedListener listener = new RootTaskOrderChangedListener(); + mDefaultTaskDisplayArea.registerRootTaskOrderChangedListener(listener); try { - mDefaultTaskDisplayArea.removeStack(task); + mDefaultTaskDisplayArea.removeRootTask(task); } finally { - mDefaultTaskDisplayArea.unregisterStackOrderChangedListener(listener); + mDefaultTaskDisplayArea.unregisterRootTaskOrderChangedListener(listener); } assertTrue(listener.mChanged); } @@ -1237,31 +1240,31 @@ public class ActivityStackTests extends WindowTestsBase { @Test public void testStackOrderChangedOnAddPositionStack() { final Task task = new TaskBuilder(mSupervisor).build(); - mDefaultTaskDisplayArea.removeStack(task); + mDefaultTaskDisplayArea.removeRootTask(task); - StackOrderChangedListener listener = new StackOrderChangedListener(); - mDefaultTaskDisplayArea.registerStackOrderChangedListener(listener); + RootTaskOrderChangedListener listener = new RootTaskOrderChangedListener(); + mDefaultTaskDisplayArea.registerRootTaskOrderChangedListener(listener); try { task.mReparenting = true; mDefaultTaskDisplayArea.addChild(task, 0); } finally { - mDefaultTaskDisplayArea.unregisterStackOrderChangedListener(listener); + mDefaultTaskDisplayArea.unregisterRootTaskOrderChangedListener(listener); } assertTrue(listener.mChanged); } @Test public void testStackOrderChangedOnPositionStack() { - StackOrderChangedListener listener = new StackOrderChangedListener(); + RootTaskOrderChangedListener listener = new RootTaskOrderChangedListener(); try { final Task fullscreenStack1 = createStackForShouldBeVisibleTest( mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - mDefaultTaskDisplayArea.registerStackOrderChangedListener(listener); + mDefaultTaskDisplayArea.registerRootTaskOrderChangedListener(listener); mDefaultTaskDisplayArea.positionChildAt(POSITION_BOTTOM, fullscreenStack1, false /*includingParents*/); } finally { - mDefaultTaskDisplayArea.unregisterStackOrderChangedListener(listener); + mDefaultTaskDisplayArea.unregisterRootTaskOrderChangedListener(listener); } assertTrue(listener.mChanged); } @@ -1447,12 +1450,12 @@ public class ActivityStackTests extends WindowTestsBase { assertEquals(expected, task.shouldSleepActivities()); } - private static class StackOrderChangedListener - implements TaskDisplayArea.OnStackOrderChangedListener { + private static class RootTaskOrderChangedListener + implements OnRootTaskOrderChangedListener { public boolean mChanged = false; @Override - public void onStackOrderChanged(Task stack) { + public void onRootTaskOrderChanged(Task rootTask) { mChanged = true; } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java index c799f2902547..ce96771c8c27 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java @@ -33,8 +33,8 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import com.android.server.wm.ActivityTaskSupervisor.PendingActivityLaunch; import com.android.server.wm.ActivityStarter.Factory; +import com.android.server.wm.ActivityTaskSupervisor.PendingActivityLaunch; import org.junit.Before; import org.junit.Test; @@ -77,8 +77,8 @@ public class ActivityStartControllerTests extends WindowTestsBase { .setCreateTask(true) .build(); final int startFlags = random.nextInt(); - final Task stack = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea() - .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final Task rootTask = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); final WindowProcessController wpc = new WindowProcessController(mAtm, mAtm.mContext.getApplicationInfo(), "name", 12345, UserHandle.getUserId(12345), mock(Object.class), @@ -86,7 +86,7 @@ public class ActivityStartControllerTests extends WindowTestsBase { wpc.setThread(mock(IApplicationThread.class)); mController.addPendingActivityLaunch( - new PendingActivityLaunch(activity, source, startFlags, stack, wpc, null)); + new PendingActivityLaunch(activity, source, startFlags, rootTask, wpc, null)); final boolean resume = random.nextBoolean(); mController.doPendingActivityLaunches(resume); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 565bf8b615c7..ef2e88913914 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -326,7 +326,7 @@ public class ActivityStarterTests extends WindowTestsBase { * Creates a {@link ActivityStarter} with default parameters and necessary mocks. * * @param launchFlags The intent flags to launch activity. - * @param mockGetLaunchStack Whether to mock {@link RootWindowContainer#getLaunchStack} for + * @param mockGetLaunchStack Whether to mock {@link RootWindowContainer#getLaunchRootTask} for * always launching to the testing stack. Set to false when allowing * the activity can be launched to any stack that is decided by real * implementation. @@ -342,14 +342,14 @@ public class ActivityStarterTests extends WindowTestsBase { if (mockGetLaunchStack) { // Instrument the stack and task used. final Task stack = mRootWindowContainer.getDefaultTaskDisplayArea() - .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, + .createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Direct starter to use spy stack. doReturn(stack).when(mRootWindowContainer) - .getLaunchStack(any(), any(), any(), anyBoolean()); - doReturn(stack).when(mRootWindowContainer) - .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt()); + .getLaunchRootTask(any(), any(), any(), anyBoolean()); + doReturn(stack).when(mRootWindowContainer).getLaunchRootTask(any(), any(), any(), + anyBoolean(), any(), anyInt(), anyInt()); } // Set up mock package manager internal and make sure no unmocked methods are called @@ -513,8 +513,8 @@ public class ActivityStarterTests extends WindowTestsBase { private void assertNoTasks(DisplayContent display) { display.forAllTaskDisplayAreas(taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task stack = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task stack = taskDisplayArea.getRootTaskAt(sNdx); assertFalse(stack.hasChild()); } }); @@ -806,7 +806,7 @@ public class ActivityStarterTests extends WindowTestsBase { new TestDisplayContent.Builder(mAtm, 1000, 1500) .setPosition(POSITION_BOTTOM).build(); final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea(); - final Task stack = secondaryTaskContainer.createStack( + final Task stack = secondaryTaskContainer.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Create an activity record on the top of secondary display. @@ -828,7 +828,7 @@ public class ActivityStarterTests extends WindowTestsBase { assertEquals(START_DELIVERED_TO_TOP, result); // Ensure secondary display only creates one stack. - verify(secondaryTaskContainer, times(1)).createStack(anyInt(), anyInt(), anyBoolean()); + verify(secondaryTaskContainer, times(1)).createRootTask(anyInt(), anyInt(), anyBoolean()); } /** @@ -848,11 +848,11 @@ public class ActivityStarterTests extends WindowTestsBase { false /* includingParents */); final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea(); final ActivityRecord singleTaskActivity = createSingleTaskActivityOn( - secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN, + secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */)); // Create another activity on top of the secondary display. - final Task topStack = secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN, + final Task topStack = secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); final Task topTask = new TaskBuilder(mSupervisor).setParentTask(topStack).build(); new ActivityBuilder(mAtm).setTask(topTask).build(); @@ -870,7 +870,7 @@ public class ActivityStarterTests extends WindowTestsBase { assertEquals(START_TASK_TO_FRONT, result); // Ensure secondary display only creates two stacks. - verify(secondaryTaskContainer, times(2)).createStack(anyInt(), anyInt(), anyBoolean()); + verify(secondaryTaskContainer, times(2)).createRootTask(anyInt(), anyInt(), anyBoolean()); // The metrics logger should receive the same result and non-null options. verify(mActivityMetricsLogger).notifyActivityLaunched(any() /* launchingState */, eq(result), eq(singleTaskActivity), notNull() /* options */); @@ -938,7 +938,7 @@ public class ActivityStarterTests extends WindowTestsBase { // Create a secondary display at bottom. final TestDisplayContent secondaryDisplay = addNewDisplayContentAt(POSITION_BOTTOM); final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea(); - secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, + secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Put an activity on default display as the top focused activity. @@ -1053,7 +1053,7 @@ public class ActivityStarterTests extends WindowTestsBase { final ActivityStarter starter = prepareStarter(0 /* flags */); starter.mStartActivity = new ActivityBuilder(mAtm).build(); final Task task = new TaskBuilder(mAtm.mTaskSupervisor) - .setParentTask(mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createStack( + .setParentTask(mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */)) .setUserId(10) .build(); @@ -1117,13 +1117,13 @@ public class ActivityStarterTests extends WindowTestsBase { final Task stack = spy( mRootWindowContainer.getDefaultTaskDisplayArea() - .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, + .createRootTask(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, /* onTop */true)); stack.addChild(targetRecord); doReturn(stack).when(mRootWindowContainer) - .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt()); + .getLaunchRootTask(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt()); starter.mStartActivity = new ActivityBuilder(mAtm).build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java index 39bf8eb857b0..5a47493c12cd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java @@ -94,9 +94,9 @@ public class DisplayAreaPolicyTests { @Test public void testTaskDisplayArea_taskPositionChanged_updatesTaskDisplayAreaPosition() { - final Task stack1 = mTaskDisplayArea1.createStack( + final Task stack1 = mTaskDisplayArea1.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final Task stack2 = mTaskDisplayArea2.createStack( + final Task stack2 = mTaskDisplayArea2.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Initial order @@ -155,11 +155,11 @@ public class DisplayAreaPolicyTests { .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(group2) .setTaskDisplayAreas(Lists.newArrayList(taskDisplayArea5))) .build(wms); - final Task stack1 = taskDisplayArea1.createStack( + final Task stack1 = taskDisplayArea1.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final Task stack3 = taskDisplayArea3.createStack( + final Task stack3 = taskDisplayArea3.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final Task stack4 = taskDisplayArea4.createStack( + final Task stack4 = taskDisplayArea4.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Initial order 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 64065e96b0f2..2053bfb45884 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -839,12 +839,12 @@ public class DisplayContentTests extends WindowTestsBase { final DisplayContent newDisplay = createNewDisplay(); final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin"); - final Task stack = mDisplayContent.getTopStack(); + final Task stack = mDisplayContent.getTopRootTask(); final ActivityRecord activity = stack.topRunningActivity(); doReturn(true).when(activity).shouldBeVisibleUnchecked(); final WindowState appWin1 = createWindow(null, TYPE_APPLICATION, newDisplay, "appWin1"); - final Task stack1 = newDisplay.getTopStack(); + final Task stack1 = newDisplay.getTopRootTask(); final ActivityRecord activity1 = stack1.topRunningActivity(); doReturn(true).when(activity1).shouldBeVisibleUnchecked(); appWin.setHasSurface(true); @@ -886,7 +886,7 @@ public class DisplayContentTests extends WindowTestsBase { doReturn(true).when(freeformStack).isVisible(); freeformStack.getTopChild().setBounds(100, 100, 300, 400); - assertTrue(dc.getDefaultTaskDisplayArea().isStackVisible(WINDOWING_MODE_FREEFORM)); + assertTrue(dc.getDefaultTaskDisplayArea().isRootTaskVisible(WINDOWING_MODE_FREEFORM)); freeformStack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_LANDSCAPE); stack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_PORTRAIT); diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java index cd428e10a437..a99e40cc19ec 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java @@ -294,11 +294,11 @@ public class LaunchParamsControllerTests extends WindowTestsBase { mController.registerModifier(positioner); - doNothing().when(mRootWindowContainer).moveStackToTaskDisplayArea(anyInt(), any(), + doNothing().when(mRootWindowContainer).moveRootTaskToTaskDisplayArea(anyInt(), any(), anyBoolean()); mController.layoutTask(task, null /* windowLayout */); - verify(mRootWindowContainer, times(1)).moveStackToTaskDisplayArea(eq(task.getRootTaskId()), - eq(preferredTaskDisplayArea), anyBoolean()); + verify(mRootWindowContainer, times(1)).moveRootTaskToTaskDisplayArea( + eq(task.getRootTaskId()), eq(preferredTaskDisplayArea), anyBoolean()); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java index d701a9df7cb8..b7d8638f06a8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java @@ -115,7 +115,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase { .thenReturn(mTestDisplay); Task stack = mTestDisplay.getDefaultTaskDisplayArea() - .createStack(TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true); + .createRootTask(TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true); mTestTask = new TaskBuilder(mSupervisor).setComponent(TEST_COMPONENT).setParentTask(stack) .build(); mTestTask.mUserId = TEST_USER_ID; @@ -337,7 +337,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase { public void testClearsRecordsOfTheUserOnUserCleanUp() { mTarget.saveTask(mTestTask); - Task stack = mTestDisplay.getDefaultTaskDisplayArea().createStack( + Task stack = mTestDisplay.getDefaultTaskDisplayArea().createRootTask( TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true); final Task anotherTaskOfTheSameUser = new TaskBuilder(mSupervisor) .setComponent(ALTERNATIVE_COMPONENT) @@ -349,7 +349,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase { anotherTaskOfTheSameUser.setHasBeenVisible(true); mTarget.saveTask(anotherTaskOfTheSameUser); - stack = mTestDisplay.getDefaultTaskDisplayArea().createStack(TEST_WINDOWING_MODE, + stack = mTestDisplay.getDefaultTaskDisplayArea().createRootTask(TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true); final Task anotherTaskOfDifferentUser = new TaskBuilder(mSupervisor) .setComponent(TEST_COMPONENT) diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index 7812934bb52f..4892ef3b6322 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -724,7 +724,7 @@ public class RecentTasksTest extends WindowTestsBase { mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */); final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final Task alwaysOnTopTask = taskDisplayArea.createStack(WINDOWING_MODE_MULTI_WINDOW, + final Task alwaysOnTopTask = taskDisplayArea.createRootTask(WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, true /* onTop */); alwaysOnTopTask.setAlwaysOnTop(true); @@ -838,7 +838,7 @@ public class RecentTasksTest extends WindowTestsBase { Task stack = mTasks.get(2).getRootTask(); stack.moveToFront("", mTasks.get(2)); - doReturn(stack).when(mAtm.mRootWindowContainer).getTopDisplayFocusedStack(); + doReturn(stack).when(mAtm.mRootWindowContainer).getTopDisplayFocusedRootTask(); // Simulate the reset from the timeout mRecentTasks.resetFreezeTaskListReorderingOnTimeout(); @@ -858,7 +858,7 @@ public class RecentTasksTest extends WindowTestsBase { mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); final Task homeStack = mTaskContainer.getRootHomeTask(); - final Task aboveHomeStack = mTaskContainer.createStack( + final Task aboveHomeStack = mTaskContainer.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all @@ -875,10 +875,10 @@ public class RecentTasksTest extends WindowTestsBase { public void testBehindHomeStackTasks_expectTaskTrimmed() { mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); - final Task behindHomeStack = mTaskContainer.createStack( + final Task behindHomeStack = mTaskContainer.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); final Task homeStack = mTaskContainer.getRootHomeTask(); - final Task aboveHomeStack = mTaskContainer.createStack( + final Task aboveHomeStack = mTaskContainer.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Add a number of tasks (beyond the max) but ensure that only the task in the stack behind @@ -897,17 +897,17 @@ public class RecentTasksTest extends WindowTestsBase { public void testOtherDisplayTasks_expectNoTrim() { mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); - final Task homeStack = mTaskContainer.getRootHomeTask(); + final Task homeTask = mTaskContainer.getRootHomeTask(); final DisplayContent otherDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP); - final Task otherDisplayStack = otherDisplay.getDefaultTaskDisplayArea() - .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final Task otherDisplayRootTask = otherDisplay.getDefaultTaskDisplayArea().createRootTask( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not // removed - mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build()); - mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(otherDisplayStack).build()); - mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(otherDisplayStack).build()); - mRecentTasks.add(createTaskBuilder(".HomeTask2").setParentTask(homeStack).build()); + mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeTask).build()); + mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(otherDisplayRootTask).build()); + mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(otherDisplayRootTask).build()); + mRecentTasks.add(createTaskBuilder(".HomeTask2").setParentTask(homeTask).build()); triggerTrimAndAssertNoTasksTrimmed(); } @@ -1103,9 +1103,9 @@ public class RecentTasksTest extends WindowTestsBase { private void assertNotRestoreTask(Runnable action) { // Verify stack count doesn't change because task with fullscreen mode and standard type // would have its own stack. - final int originalStackCount = mTaskContainer.getStackCount(); + final int originalStackCount = mTaskContainer.getRootTaskCount(); action.run(); - assertEquals(originalStackCount, mTaskContainer.getStackCount()); + assertEquals(originalStackCount, mTaskContainer.getRootTaskCount()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java index 5ff3ff5a6e0c..63ee5d05fada 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java @@ -89,7 +89,7 @@ public class RecentsAnimationTest extends WindowTestsBase { @Test public void testRecentsActivityVisiblility() { TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task recentsStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); ActivityRecord recentActivity = new ActivityBuilder(mAtm) .setComponent(mRecentsComponent) @@ -118,7 +118,7 @@ public class RecentsAnimationTest extends WindowTestsBase { public void testPreloadRecentsActivity() { TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); final Task homeStack = - defaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); + defaultTaskDisplayArea.getRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); defaultTaskDisplayArea.positionChildAt(POSITION_TOP, homeStack, false /* includingParents */); ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity(); @@ -150,7 +150,7 @@ public class RecentsAnimationTest extends WindowTestsBase { mAtm.startRecentsActivity(recentsIntent, 0 /* eventTime */, null /* recentsAnimationRunner */); - Task recentsStack = defaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, + Task recentsStack = defaultTaskDisplayArea.getRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS); assertThat(recentsStack).isNotNull(); @@ -179,7 +179,7 @@ public class RecentsAnimationTest extends WindowTestsBase { public void testRestartRecentsActivity() throws Exception { // Have a recents activity that is not attached to its process (ActivityRecord.app = null). TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - Task recentsStack = defaultTaskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task recentsStack = defaultTaskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); ActivityRecord recentActivity = new ActivityBuilder(mAtm).setComponent( mRecentsComponent).setCreateTask(true).setParentTask(recentsStack).build(); @@ -251,21 +251,21 @@ public class RecentsAnimationTest extends WindowTestsBase { @Test public void testCancelAnimationOnVisibleStackOrderChange() { TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task fullscreenStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); new ActivityBuilder(mAtm) .setComponent(new ComponentName(mContext.getPackageName(), "App1")) .setCreateTask(true) .setParentTask(fullscreenStack) .build(); - Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task recentsStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); new ActivityBuilder(mAtm) .setComponent(mRecentsComponent) .setCreateTask(true) .setParentTask(recentsStack) .build(); - Task fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task fullscreenStack2 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); new ActivityBuilder(mAtm) .setComponent(new ComponentName(mContext.getPackageName(), "App2")) @@ -292,21 +292,21 @@ public class RecentsAnimationTest extends WindowTestsBase { @Test public void testKeepAnimationOnHiddenStackOrderChange() { TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task fullscreenStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); new ActivityBuilder(mAtm) .setComponent(new ComponentName(mContext.getPackageName(), "App1")) .setCreateTask(true) .setParentTask(fullscreenStack) .build(); - Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task recentsStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); new ActivityBuilder(mAtm) .setComponent(mRecentsComponent) .setCreateTask(true) .setParentTask(recentsStack) .build(); - Task fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task fullscreenStack2 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); new ActivityBuilder(mAtm) .setComponent(new ComponentName(mContext.getPackageName(), "App2")) @@ -329,7 +329,7 @@ public class RecentsAnimationTest extends WindowTestsBase { public void testMultipleUserHomeActivity_findUserHomeTask() { TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultDisplay() .getDefaultTaskDisplayArea(); - Task homeStack = taskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED, + Task homeStack = taskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME); ActivityRecord otherUserHomeActivity = new ActivityBuilder(mAtm) .setParentTask(homeStack) @@ -338,7 +338,7 @@ public class RecentsAnimationTest extends WindowTestsBase { .build(); otherUserHomeActivity.getTask().mUserId = TEST_USER_ID; - Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task fullscreenStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); new ActivityBuilder(mAtm) .setComponent(new ComponentName(mContext.getPackageName(), "App1")) diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index 7ca364cf096f..f79e4cc9fa10 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -94,7 +94,7 @@ public class RootActivityContainerTests extends WindowTestsBase { @Before public void setUp() throws Exception { - mFullscreenStack = mRootWindowContainer.getDefaultTaskDisplayArea().createStack( + mFullscreenStack = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); doNothing().when(mAtm).updateSleepIfNeededLocked(); } @@ -128,7 +128,7 @@ public class RootActivityContainerTests extends WindowTestsBase { ensureStackPlacement(mFullscreenStack, firstActivity, secondActivity); // Move first activity to pinned stack. - mRootWindowContainer.moveActivityToPinnedStack(firstActivity, "initialMove"); + mRootWindowContainer.moveActivityToPinnedRootTask(firstActivity, "initialMove"); final TaskDisplayArea taskDisplayArea = mFullscreenStack.getDisplayArea(); Task pinnedStack = taskDisplayArea.getRootPinnedTask(); @@ -137,11 +137,11 @@ public class RootActivityContainerTests extends WindowTestsBase { ensureStackPlacement(mFullscreenStack, secondActivity); // Move second activity to pinned stack. - mRootWindowContainer.moveActivityToPinnedStack(secondActivity, "secondMove"); + mRootWindowContainer.moveActivityToPinnedRootTask(secondActivity, "secondMove"); // Need to get stacks again as a new instance might have been created. pinnedStack = taskDisplayArea.getRootPinnedTask(); - mFullscreenStack = taskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, + mFullscreenStack = taskDisplayArea.getRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); // Ensure stacks have swapped tasks. ensureStackPlacement(pinnedStack, secondActivity); @@ -166,7 +166,7 @@ public class RootActivityContainerTests extends WindowTestsBase { // Move first activity to pinned stack. - mRootWindowContainer.moveActivityToPinnedStack(secondActivity, "initialMove"); + mRootWindowContainer.moveActivityToPinnedRootTask(secondActivity, "initialMove"); assertTrue(firstActivity.mRequestForceTransition); } @@ -237,9 +237,9 @@ public class RootActivityContainerTests extends WindowTestsBase { doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt()); doReturn(isFocusedStack).when(stack).isFocusedStackOnDisplay(); - doReturn(isFocusedStack ? stack : null).when(display).getFocusedStack(); + doReturn(isFocusedStack ? stack : null).when(display).getFocusedRootTask(); TaskDisplayArea defaultTaskDisplayArea = display.getDefaultTaskDisplayArea(); - doReturn(isFocusedStack ? stack : null).when(defaultTaskDisplayArea).getFocusedStack(); + doReturn(isFocusedStack ? stack : null).when(defaultTaskDisplayArea).getFocusedRootTask(); mRootWindowContainer.applySleepTokens(true); verify(stack, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleepingLocked(); verify(stack, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked( @@ -282,19 +282,19 @@ public class RootActivityContainerTests extends WindowTestsBase { public void testRemovingStackOnAppCrash() { final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer .getDefaultTaskDisplayArea(); - final int originalStackCount = defaultTaskDisplayArea.getStackCount(); - final Task stack = defaultTaskDisplayArea.createStack( + final int originalStackCount = defaultTaskDisplayArea.getRootTaskCount(); + final Task stack = defaultTaskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(stack).build(); - assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount()); + assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getRootTaskCount()); // Let's pretend that the app has crashed. firstActivity.app.setThread(null); mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test"); // Verify that the stack was removed. - assertEquals(originalStackCount, defaultTaskDisplayArea.getStackCount()); + assertEquals(originalStackCount, defaultTaskDisplayArea.getRootTaskCount()); } /** @@ -305,34 +305,34 @@ public class RootActivityContainerTests extends WindowTestsBase { public void testRemovingStackOnAppCrash_multipleDisplayAreas() { final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer .getDefaultTaskDisplayArea(); - final int originalStackCount = defaultTaskDisplayArea.getStackCount(); - final Task stack = defaultTaskDisplayArea.createStack( + final int originalStackCount = defaultTaskDisplayArea.getRootTaskCount(); + final Task stack = defaultTaskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(stack).build(); - assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount()); + assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getRootTaskCount()); final DisplayContent dc = defaultTaskDisplayArea.getDisplayContent(); final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( dc, mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST); - final Task secondStack = secondTaskDisplayArea.createStack( + final Task secondStack = secondTaskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); new ActivityBuilder(mAtm).setTask(secondStack).setUseProcess(firstActivity.app).build(); - assertEquals(1, secondTaskDisplayArea.getStackCount()); + assertEquals(1, secondTaskDisplayArea.getRootTaskCount()); // Let's pretend that the app has crashed. firstActivity.app.setThread(null); mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test"); // Verify that the stacks were removed. - assertEquals(originalStackCount, defaultTaskDisplayArea.getStackCount()); - assertEquals(0, secondTaskDisplayArea.getStackCount()); + assertEquals(originalStackCount, defaultTaskDisplayArea.getRootTaskCount()); + assertEquals(0, secondTaskDisplayArea.getRootTaskCount()); } @Test public void testFocusability() { final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer .getDefaultTaskDisplayArea(); - final Task stack = defaultTaskDisplayArea.createStack( + final Task stack = defaultTaskDisplayArea.createRootTask( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build(); @@ -345,7 +345,7 @@ public class RootActivityContainerTests extends WindowTestsBase { assertFalse(stack.isTopActivityFocusable()); assertFalse(activity.isFocusable()); - final Task pinnedStack = defaultTaskDisplayArea.createStack( + final Task pinnedStack = defaultTaskDisplayArea.createRootTask( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm) .setTask(pinnedStack).build(); @@ -371,7 +371,7 @@ public class RootActivityContainerTests extends WindowTestsBase { public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() { // Create primary split-screen stack with a task and an activity. final Task primaryStack = mRootWindowContainer.getDefaultTaskDisplayArea() - .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, + .createRootTask(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); final Task task = new TaskBuilder(mSupervisor).setParentTask(primaryStack).build(); final ActivityRecord r = new ActivityBuilder(mAtm).setTask(task).build(); @@ -381,7 +381,7 @@ public class RootActivityContainerTests extends WindowTestsBase { final ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); final Task result = - mRootWindowContainer.getLaunchStack(r, options, task, true /* onTop */); + mRootWindowContainer.getLaunchRootTask(r, options, task, true /* onTop */); // Assert that the primary stack is returned. assertEquals(primaryStack, result); @@ -410,7 +410,7 @@ public class RootActivityContainerTests extends WindowTestsBase { false); final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - verify(taskDisplayArea).moveHomeStackToFront(contains(reason)); + verify(taskDisplayArea).moveHomeRootTaskToFront(contains(reason)); } /** @@ -421,7 +421,7 @@ public class RootActivityContainerTests extends WindowTestsBase { public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() { // Create stack/task on default display. final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final Task targetStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task targetStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); final Task targetTask = new TaskBuilder(mSupervisor).setParentTask(targetStack).build(); @@ -429,7 +429,7 @@ public class RootActivityContainerTests extends WindowTestsBase { final TestDisplayContent secondDisplay = addNewDisplayContentAt( DisplayContent.POSITION_TOP); final Task stack = secondDisplay.getDefaultTaskDisplayArea() - .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); + .createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); final Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build(); new ActivityBuilder(mAtm).setTask(task).build(); @@ -437,7 +437,7 @@ public class RootActivityContainerTests extends WindowTestsBase { mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason, false); - verify(taskDisplayArea, never()).moveHomeStackToFront(contains(reason)); + verify(taskDisplayArea, never()).moveHomeRootTaskToFront(contains(reason)); } /** @@ -448,7 +448,7 @@ public class RootActivityContainerTests extends WindowTestsBase { public void testResumeActivityWhenNonTopmostStackIsTopFocused() { // Create a stack at bottom. final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task targetStack = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */)); final Task task = new TaskBuilder(mSupervisor).setParentTask(targetStack).build(); final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build(); @@ -457,10 +457,10 @@ public class RootActivityContainerTests extends WindowTestsBase { // Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it // is the current top focused stack. assertFalse(targetStack.isTopStackInDisplayArea()); - doReturn(targetStack).when(mRootWindowContainer).getTopDisplayFocusedStack(); + doReturn(targetStack).when(mRootWindowContainer).getTopDisplayFocusedRootTask(); // Use the stack as target to resume. - mRootWindowContainer.resumeFocusedStacksTopActivities( + mRootWindowContainer.resumeFocusedTasksTopActivities( targetStack, activity, null /* targetOptions */); // Verify the target stack should resume its activity. @@ -477,14 +477,14 @@ public class RootActivityContainerTests extends WindowTestsBase { mFullscreenStack.removeIfPossible(); final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); taskDisplayArea.getRootHomeTask().removeIfPossible(); - taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); + taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any()); mAtm.setBooted(true); // Trigger resume on all displays - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); // Verify that home activity was started on the default display verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea)); @@ -499,14 +499,14 @@ public class RootActivityContainerTests extends WindowTestsBase { mFullscreenStack.removeIfPossible(); final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); taskDisplayArea.getRootHomeTask().removeIfPossible(); - taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); + taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); // Create an activity on secondary display. final TestDisplayContent secondDisplay = addNewDisplayContentAt( DisplayContent.POSITION_TOP); - final Task stack = secondDisplay.getDefaultTaskDisplayArea() - .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build(); + final Task rootTask = secondDisplay.getDefaultTaskDisplayArea().createRootTask( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build(); new ActivityBuilder(mAtm).setTask(task).build(); doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any()); @@ -514,7 +514,7 @@ public class RootActivityContainerTests extends WindowTestsBase { mAtm.setBooted(true); // Trigger resume on all displays - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); // Verify that home activity was started on the default display verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea)); @@ -528,7 +528,7 @@ public class RootActivityContainerTests extends WindowTestsBase { public void testResumeActivityLingeringTransition() { // Create a stack at top. final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task targetStack = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */)); final Task task = new TaskBuilder(mSupervisor).setParentTask(targetStack).build(); final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build(); @@ -538,7 +538,7 @@ public class RootActivityContainerTests extends WindowTestsBase { assertTrue(targetStack.isTopStackInDisplayArea()); // Use the stack as target to resume. - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); // Verify the lingering app transition is being executed because it's already resumed verify(targetStack, times(1)).executeAppTransition(any()); @@ -548,7 +548,7 @@ public class RootActivityContainerTests extends WindowTestsBase { public void testResumeActivityLingeringTransition_notExecuted() { // Create a stack at bottom. final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); - final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + final Task targetStack = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */)); final Task task = new TaskBuilder(mSupervisor).setParentTask(targetStack).build(); final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build(); @@ -557,10 +557,10 @@ public class RootActivityContainerTests extends WindowTestsBase { // Assume the stack is at the topmost position assertFalse(targetStack.isTopStackInDisplayArea()); - doReturn(targetStack).when(mRootWindowContainer).getTopDisplayFocusedStack(); + doReturn(targetStack).when(mRootWindowContainer).getTopDisplayFocusedRootTask(); // Use the stack as target to resume. - mRootWindowContainer.resumeFocusedStacksTopActivities(); + mRootWindowContainer.resumeFocusedTasksTopActivities(); // Verify the lingering app transition is being executed because it's already resumed verify(targetStack, never()).executeAppTransition(any()); @@ -586,9 +586,9 @@ public class RootActivityContainerTests extends WindowTestsBase { mRootWindowContainer.startHomeOnAllDisplays(0, "testStartHome"); - assertTrue(mRootWindowContainer.getDefaultDisplay().getTopStack().isActivityTypeHome()); - assertNotNull(secondDisplay.getTopStack()); - assertTrue(secondDisplay.getTopStack().isActivityTypeHome()); + assertTrue(mRootWindowContainer.getDefaultDisplay().getTopRootTask().isActivityTypeHome()); + assertNotNull(secondDisplay.getTopRootTask()); + assertTrue(secondDisplay.getTopRootTask().isActivityTypeHome()); } /** @@ -840,7 +840,7 @@ public class RootActivityContainerTests extends WindowTestsBase { } /** - * Test that {@link RootWindowContainer#getLaunchStack} with the real caller id will get the + * Test that {@link RootWindowContainer#getLaunchRootTask} with the real caller id will get the * expected stack when requesting the activity launch on the secondary display. */ @Test @@ -861,7 +861,7 @@ public class RootActivityContainerTests extends WindowTestsBase { options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId, 300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info); - final Task result = mRootWindowContainer.getLaunchStack(r, options, + final Task result = mRootWindowContainer.getLaunchRootTask(r, options, null /* task */, true /* onTop */, null, 300 /* test realCallerPid */, 300 /* test realCallerUid */); @@ -881,7 +881,7 @@ public class RootActivityContainerTests extends WindowTestsBase { final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build(); // Make sure the root task is valid and can be reused on default display. - final Task stack = mRootWindowContainer.getValidLaunchStackInTaskDisplayArea( + final Task stack = mRootWindowContainer.getValidLaunchRootTaskInTaskDisplayArea( mRootWindowContainer.getDefaultTaskDisplayArea(), activity, task, null /* options */, null /* launchParams */); assertEquals(task, stack); @@ -889,7 +889,7 @@ public class RootActivityContainerTests extends WindowTestsBase { @Test public void testSwitchUser_missingHomeRootTask() { - doReturn(mFullscreenStack).when(mRootWindowContainer).getTopDisplayFocusedStack(); + doReturn(mFullscreenStack).when(mRootWindowContainer).getTopDisplayFocusedRootTask(); final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); Task homeStack = taskDisplayArea.getRootHomeTask(); @@ -904,7 +904,7 @@ public class RootActivityContainerTests extends WindowTestsBase { mRootWindowContainer.switchUser(otherUser, null); assertNotNull(taskDisplayArea.getRootHomeTask()); - assertEquals(taskDisplayArea.getTopStack(), taskDisplayArea.getRootHomeTask()); + assertEquals(taskDisplayArea.getTopRootTask(), taskDisplayArea.getRootHomeTask()); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 42193c8fce78..9af2b96f3f78 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -92,7 +92,7 @@ public class RootWindowContainerTests extends WindowTestsBase { public void testAllPausedActivitiesComplete() { DisplayContent displayContent = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY); TaskDisplayArea taskDisplayArea = displayContent.getDefaultTaskDisplayArea(); - Task stack = taskDisplayArea.getStackAt(0); + Task stack = taskDisplayArea.getRootTaskAt(0); ActivityRecord activity = createActivityRecord(displayContent); stack.mPausingActivity = activity; diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java index 95e344d5c184..6821d47d5b1a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java @@ -71,7 +71,7 @@ public class RunningTasksTest extends WindowTestsBase { final int numTasks = 10; int activeTime = 0; for (int i = 0; i < numTasks; i++) { - createTask(display.getDefaultTaskDisplayArea().getStackAt(i % numStacks), + createTask(display.getDefaultTaskDisplayArea().getRootTaskAt(i % numStacks), ".Task" + i, i, activeTime++, null); } diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index 2db736e63391..536ef48065a5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -326,7 +326,7 @@ public class SystemServicesTestRule implements TestRule { // Set the default focused TDA. display.setLastFocusedTaskDisplayArea(taskDisplayArea); spyOn(taskDisplayArea); - final Task homeStack = taskDisplayArea.getStack( + final Task homeStack = taskDisplayArea.getRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); spyOn(homeStack); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java index 28ba710797c9..d80f81642474 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java @@ -181,33 +181,33 @@ public class TaskDisplayAreaTests extends WindowTestsBase { final Task newStack = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent); final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea(); - doReturn(newStack).when(taskDisplayArea).createStack(anyInt(), anyInt(), anyBoolean(), + doReturn(newStack).when(taskDisplayArea).createRootTask(anyInt(), anyInt(), anyBoolean(), any(), any(), anyBoolean()); final int type = ACTIVITY_TYPE_STANDARD; - assertGetOrCreateStack(WINDOWING_MODE_FULLSCREEN, type, candidateTask, + assertGetOrCreateRootTask(WINDOWING_MODE_FULLSCREEN, type, candidateTask, true /* reuseCandidate */); - assertGetOrCreateStack(WINDOWING_MODE_UNDEFINED, type, candidateTask, + assertGetOrCreateRootTask(WINDOWING_MODE_UNDEFINED, type, candidateTask, true /* reuseCandidate */); - assertGetOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, type, candidateTask, + assertGetOrCreateRootTask(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, type, candidateTask, true /* reuseCandidate */); - assertGetOrCreateStack(WINDOWING_MODE_FREEFORM, type, candidateTask, + assertGetOrCreateRootTask(WINDOWING_MODE_FREEFORM, type, candidateTask, true /* reuseCandidate */); - assertGetOrCreateStack(WINDOWING_MODE_MULTI_WINDOW, type, candidateTask, + assertGetOrCreateRootTask(WINDOWING_MODE_MULTI_WINDOW, type, candidateTask, true /* reuseCandidate */); - assertGetOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, type, candidateTask, + assertGetOrCreateRootTask(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, type, candidateTask, false /* reuseCandidate */); - assertGetOrCreateStack(WINDOWING_MODE_PINNED, type, candidateTask, + assertGetOrCreateRootTask(WINDOWING_MODE_PINNED, type, candidateTask, true /* reuseCandidate */); final int windowingMode = WINDOWING_MODE_FULLSCREEN; - assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_HOME, candidateTask, + assertGetOrCreateRootTask(windowingMode, ACTIVITY_TYPE_HOME, candidateTask, false /* reuseCandidate */); - assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_RECENTS, candidateTask, + assertGetOrCreateRootTask(windowingMode, ACTIVITY_TYPE_RECENTS, candidateTask, false /* reuseCandidate */); - assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_ASSISTANT, candidateTask, + assertGetOrCreateRootTask(windowingMode, ACTIVITY_TYPE_ASSISTANT, candidateTask, false /* reuseCandidate */); - assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_DREAM, candidateTask, + assertGetOrCreateRootTask(windowingMode, ACTIVITY_TYPE_DREAM, candidateTask, false /* reuseCandidate */); } @@ -250,9 +250,9 @@ public class TaskDisplayAreaTests extends WindowTestsBase { final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST); - final Task firstStack = firstTaskDisplayArea.createStack( + final Task firstStack = firstTaskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); - final Task secondStack = secondTaskDisplayArea.createStack( + final Task secondStack = secondTaskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); final ActivityRecord firstActivity = new ActivityBuilder(mAtm) .setTask(firstStack).build(); @@ -281,7 +281,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase { @Test public void testIgnoreOrientationRequest() { final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); - final Task stack = taskDisplayArea.createStack( + final Task stack = taskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build(); @@ -326,10 +326,10 @@ public class TaskDisplayAreaTests extends WindowTestsBase { assertFalse(defaultTaskDisplayArea.mChildren.contains(task)); } - private void assertGetOrCreateStack(int windowingMode, int activityType, Task candidateTask, + private void assertGetOrCreateRootTask(int windowingMode, int activityType, Task candidateTask, boolean reuseCandidate) { final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea(); - final Task stack = taskDisplayArea.getOrCreateStack(windowingMode, activityType, + final Task stack = taskDisplayArea.getOrCreateRootTask(windowingMode, activityType, false /* onTop */, null /* intent */, candidateTask /* candidateTask */); assertEquals(reuseCandidate, stack == candidateTask); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index 4f55322e2085..269ce5d833f2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -1566,13 +1566,13 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { private ActivityRecord createSourceActivity(TestDisplayContent display) { final Task stack = display.getDefaultTaskDisplayArea() - .createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true); + .createRootTask(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true); return new ActivityBuilder(mAtm).setTask(stack).build(); } private void addFreeformTaskTo(TestDisplayContent display, Rect bounds) { final Task stack = display.getDefaultTaskDisplayArea() - .createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true); + .createRootTask(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true); stack.setWindowingMode(WINDOWING_MODE_FREEFORM); final Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build(); // Just work around the unnecessary adjustments for bounds. diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java index 61d4a473215b..4a5ff58fca3c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java @@ -177,7 +177,7 @@ public class TaskRecordTests extends WindowTestsBase { public void testFitWithinBounds() { final Rect parentBounds = new Rect(10, 10, 200, 200); TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea(); - Task stack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM, + Task stack = taskDisplayArea.createRootTask(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build(); final Configuration parentConfig = stack.getConfiguration(); @@ -497,7 +497,7 @@ public class TaskRecordTests extends WindowTestsBase { @Test public void testInsetDisregardedWhenFreeformOverlapsNavBar() { TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea(); - Task stack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, + Task stack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); DisplayInfo displayInfo = new DisplayInfo(); mAtm.mContext.getDisplay().getDisplayInfo(displayInfo); @@ -1027,9 +1027,9 @@ public class TaskRecordTests extends WindowTestsBase { final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST); - final Task firstStack = firstTaskDisplayArea.createStack( + final Task firstStack = firstTaskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); - final Task secondStack = secondTaskDisplayArea.createStack( + final Task secondStack = secondTaskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); final ActivityRecord firstActivity = new ActivityBuilder(mAtm) .setTask(firstStack).build(); @@ -1083,7 +1083,7 @@ public class TaskRecordTests extends WindowTestsBase { Rect expectedConfigBounds) { TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea(); - Task stack = taskDisplayArea.createStack(windowingMode, ACTIVITY_TYPE_STANDARD, + Task stack = taskDisplayArea.createRootTask(windowingMode, ACTIVITY_TYPE_STANDARD, true /* onTop */); Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index 573da896eff3..c4bcfdbcf89d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -812,7 +812,7 @@ public class WindowContainerTests extends WindowTestsBase { final ActivityRecord activity = createActivityRecord(mDisplayContent, task); final DisplayContent newDc = createNewDisplay(); - stack.getDisplayArea().removeStack(stack); + stack.getDisplayArea().removeRootTask(stack); newDc.getDefaultTaskDisplayArea().addChild(stack, POSITION_TOP); verify(stack).onDisplayChanged(newDc); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 8fe65eb2747d..dba157e6ce06 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -387,7 +387,7 @@ public class WindowOrganizerTests extends WindowTestsBase { public void testSetIgnoreOrientationRequest_taskDisplayArea() { removeGlobalMinSizeRestriction(); final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); - final Task stack = taskDisplayArea.createStack( + final Task stack = taskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build(); taskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); @@ -425,7 +425,7 @@ public class WindowOrganizerTests extends WindowTestsBase { public void testSetIgnoreOrientationRequest_displayContent() { removeGlobalMinSizeRestriction(); final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); - final Task stack = taskDisplayArea.createStack( + final Task stack = taskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build(); mDisplayContent.setFocusedApp(activity); @@ -743,8 +743,8 @@ public class WindowOrganizerTests extends WindowTestsBase { private List<Task> getTasksCreatedByOrganizer(DisplayContent dc) { ArrayList<Task> out = new ArrayList<>(); dc.forAllTaskDisplayAreas(taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task t = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task t = taskDisplayArea.getRootTaskAt(sNdx); if (t.mCreatedByOrganizer) out.add(t); } }); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 6c046bda1444..14a62d1a4ff0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -27,6 +27,8 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.os.Process.SYSTEM_UID; import static android.view.View.VISIBLE; +import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; +import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; @@ -40,8 +42,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; -import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; -import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; @@ -64,7 +64,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; -import android.content.res.Configuration; import android.hardware.display.DisplayManager; import android.os.Build; import android.os.Bundle; @@ -797,7 +796,7 @@ class WindowTestsBase extends SystemServiceTestsBase { mTask = new TaskBuilder(mService.mTaskSupervisor) .setComponent(mComponent) .setParentTask(mParentTask).build(); - } else if (mTask == null && mParentTask != null && DisplayContent.alwaysCreateStack( + } else if (mTask == null && mParentTask != null && DisplayContent.alwaysCreateRootTask( mParentTask.getWindowingMode(), mParentTask.getActivityType())) { // The stack can be the task root. mTask = mParentTask; @@ -831,13 +830,14 @@ class WindowTestsBase extends SystemServiceTestsBase { if (mLaunchTaskBehind) { options = ActivityOptions.makeTaskLaunchBehind(); } + final ActivityRecord activity = new ActivityRecord.Builder(mService) + .setLaunchedFromPid(mLaunchedFromPid) + .setLaunchedFromUid(mLaunchedFromUid) + .setIntent(intent) + .setActivityInfo(aInfo) + .setActivityOptions(options) + .build(); - final ActivityRecord activity = new ActivityRecord(mService, null /* caller */, - mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */, - null, null, intent, null, aInfo /*aInfo*/, new Configuration(), - null /* resultTo */, null /* resultWho */, 0 /* reqCode */, - false /*componentSpecified*/, false /* rootVoiceInteraction */, - mService.mTaskSupervisor, options, null /* sourceRecord */); spyOn(activity); if (mTask != null) { // fullscreen value is normally read from resources in ctor, so for testing we need @@ -871,7 +871,7 @@ class WindowTestsBase extends SystemServiceTestsBase { activity.processName, activity.info.applicationInfo.uid); // Resume top activities to make sure all other signals in the system are connected. - mService.mRootWindowContainer.resumeFocusedStacksTopActivities(); + mService.mRootWindowContainer.resumeFocusedTasksTopActivities(); return activity; } } @@ -995,7 +995,7 @@ class WindowTestsBase extends SystemServiceTestsBase { // Create parent task. if (mParentTask == null && mCreateParentTask) { - mParentTask = mTaskDisplayArea.createStack( + mParentTask = mTaskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); } if (mParentTask != null && !Mockito.mockingDetails(mParentTask).isSpy()) { @@ -1020,9 +1020,9 @@ class WindowTestsBase extends SystemServiceTestsBase { } Task task; - final int taskId = mTaskId >= 0 ? mTaskId : mTaskDisplayArea.getNextStackId(); + final int taskId = mTaskId >= 0 ? mTaskId : mTaskDisplayArea.getNextRootTaskId(); if (mParentTask == null) { - task = mTaskDisplayArea.createStackUnchecked( + task = mTaskDisplayArea.createRootTaskUnchecked( mWindowingMode, mActivityType, taskId, mOnTop, mActivityInfo, mIntent, false /* createdByOrganizer */, false /* deferTaskAppear */, null /* launchCookie */); @@ -1114,8 +1114,8 @@ class WindowTestsBase extends SystemServiceTestsBase { mSecondary.mRemoteToken.toWindowContainerToken()); DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId); dc.forAllTaskDisplayAreas(taskDisplayArea -> { - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final Task stack = taskDisplayArea.getStackAt(sNdx); + for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) { + final Task stack = taskDisplayArea.getRootTaskAt(sNdx); if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) { stack.reparent(mSecondary, POSITION_BOTTOM); } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index c962932e7d44..baee4736b527 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2033,8 +2033,16 @@ public class CarrierConfigManager { "allow_hold_call_during_emergency_bool"; /** - * Flag indicating whether the carrier supports RCS presence indication for - * User Capability Exchange (UCE). When presence is supported, the device should use the + * Flag indicating whether or not the carrier supports the periodic exchange of phone numbers + * in the user's address book with the carrier's presence server in order to retrieve the RCS + * capabilities for each contact used in the RCS User Capability Exchange (UCE) procedure. See + * RCC.71, section 3 for more information. + * <p> + * The flag {@link Ims#KEY_ENABLE_PRESENCE_PUBLISH_BOOL} must also be enabled if this flag is + * enabled, as sending a periodic SIP PUBLISH with this device's RCS capabilities is a + * requirement for capability exchange to begin. + * <p> + * When presence is supported, the device should use the * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} bit mask and set the * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE_VT_CAPABLE} bit to indicate * whether each contact supports video calling. The UI is made aware that presence is enabled @@ -3850,12 +3858,27 @@ public class CarrierConfigManager { public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL = KEY_PREFIX + "ims_single_registration_required_bool"; + /** + * A boolean flag specifying whether or not this carrier supports the device notifying the + * network of its RCS capabilities using the SIP PUBLISH procedure defined for User + * Capability Exchange (UCE). See RCC.71, section 3 for more information. + * <p> + * If this key's value is set to false, the procedure for RCS contact capability exchange + * via SIP SUBSCRIBE/NOTIFY will also be disabled internally, and + * {@link #KEY_USE_RCS_PRESENCE_BOOL} must also be set to false to ensure apps do not + * improperly think that capability exchange via SIP PUBLISH is enabled. + * <p> The default value for this key is {@code false}. + */ + public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL = + KEY_PREFIX + "enable_presence_publish_bool"; + private Ims() {} private static PersistableBundle getDefaults() { PersistableBundle defaults = new PersistableBundle(); defaults.putInt(KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT, 4000); defaults.putBoolean(KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false); + defaults.putBoolean(KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false); return defaults; } } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 9288f7925eab..d963970a3d2b 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -8105,6 +8105,7 @@ public class TelephonyManager { * * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isInEmergencySmsMode() { try { diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index 1b51936e873b..aaa68d6f7d57 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -18,6 +18,7 @@ package android.telephony.ims; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; @@ -207,6 +208,42 @@ public final class ImsCallProfile implements Parcelable { "android.telephony.ims.extra.RETRY_CALL_FAIL_NETWORKTYPE"; /** + * Extra for the call composer call priority, either {@link ImsCallProfile#PRIORITY_NORMAL} or + * {@link ImsCallProfile#PRIORITY_URGENT}. It can be set via + * {@link #setCallExtraInt(String, int)}. + * + * Reference: RCC.20 Section 2.4.4.2 + */ + public static final String EXTRA_PRIORITY = "android.telephony.ims.extra.PRIORITY"; + + // TODO(hallliu) remove the reference to the maximum length and update it later. + /** + * Extra for the call composer call subject, a string of maximum length 60 characters. + * It can be set via {@link #setCallExtra(String, String)}. + * + * Reference: RCC.20 Section 2.4.3.2 + */ + public static final String EXTRA_CALL_SUBJECT = "android.telephony.ims.extra.CALL_SUBJECT"; + + /** + * Extra for the call composer call location, an {@Link android.location.Location} parcelable + * class to represent the geolocation as a latitude and longitude pair. It can be set via + * {@link #setCallExtraParcelable(String, Parcelable)}. + * + * Reference: RCC.20 Section 2.4.3.2 + */ + public static final String EXTRA_LOCATION = "android.telephony.ims.extra.LOCATION"; + + /** + * Extra for the call composer picture URL, a String that indicates the URL on the carrier’s + * server infrastructure to get the picture. It can be set via + * {@link #setCallExtra(String, String)}. + * + * Reference: RCC.20 Section 2.4.3.2 + */ + public static final String EXTRA_PICTURE_URL = "android.telephony.ims.extra.PICTURE_URL"; + + /** * Values for EXTRA_OIR / EXTRA_CNAP */ /** @@ -244,6 +281,21 @@ public final class ImsCallProfile implements Parcelable { */ public static final int DIALSTRING_USSD = 2; + // Values for EXTRA_PRIORITY + /** + * Indicates the call composer call priority is normal. + * + * Reference: RCC.20 Section 2.4.4.2 + */ + public static final int PRIORITY_NORMAL = 0; + + /** + * Indicates the call composer call priority is urgent. + * + * Reference: RCC.20 Section 2.4.4.2 + */ + public static final int PRIORITY_URGENT = 1; + /** * Call is not restricted on peer side and High Definition media is supported */ @@ -588,6 +640,19 @@ public final class ImsCallProfile implements Parcelable { return mCallExtras.getInt(name, defaultValue); } + /** + * Get the call extras (Parcelable), given the extra name. + * @param name call extra name + * @return the corresponding call extra Parcelable or null if not applicable + */ + @Nullable + public <T extends Parcelable> T getCallExtraParcelable(@Nullable String name) { + if (mCallExtras != null) { + return mCallExtras.getParcelable(name); + } + return null; + } + public void setCallExtra(String name, String value) { if (mCallExtras != null) { mCallExtras.putString(name, value); @@ -607,6 +672,17 @@ public final class ImsCallProfile implements Parcelable { } /** + * Set the call extra value (Parcelable), given the call extra name. + * @param name call extra name + * @param parcelable call extra value + */ + public void setCallExtraParcelable(@NonNull String name, @NonNull Parcelable parcelable) { + if (mCallExtras != null) { + mCallExtras.putParcelable(name, parcelable); + } + } + + /** * Set the call restrict cause, which provides the reason why a call has been restricted from * using High Definition media. */ 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 a20f96d17278..67deca4fe387 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,6 +16,7 @@ package com.android.server.wm.flicker.close +import androidx.test.filters.FlakyTest import android.view.Surface import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry @@ -54,6 +55,7 @@ import org.junit.runners.Parameterized @RequiresDevice @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@FlakyTest(bugId = 174635878) class CloseAppBackButtonTest( testName: String, flickerSpec: Flicker 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 4bbb38c4d71a..252ce2a32bf0 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,6 +16,7 @@ package com.android.server.wm.flicker.close +import androidx.test.filters.FlakyTest import android.view.Surface import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry @@ -54,6 +55,7 @@ import org.junit.runners.Parameterized @RequiresDevice @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@FlakyTest(bugId = 174635878) class CloseAppHomeButtonTest( testName: String, flickerSpec: Flicker diff --git a/tests/RollbackTest/RollbackTest/AndroidManifest.xml b/tests/RollbackTest/RollbackTest/AndroidManifest.xml index 9274da268735..590105b3209f 100644 --- a/tests/RollbackTest/RollbackTest/AndroidManifest.xml +++ b/tests/RollbackTest/RollbackTest/AndroidManifest.xml @@ -19,8 +19,6 @@ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <application> - <receiver android:name="com.android.cts.install.lib.LocalIntentSender" - android:exported="true" /> <uses-library android:name="android.test.runner" /> </application> diff --git a/tests/StagedInstallTest/app/AndroidManifest.xml b/tests/StagedInstallTest/app/AndroidManifest.xml index a678f1ec3691..d7ac9d0f9ce4 100644 --- a/tests/StagedInstallTest/app/AndroidManifest.xml +++ b/tests/StagedInstallTest/app/AndroidManifest.xml @@ -20,8 +20,6 @@ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <application> - <receiver android:name="com.android.cts.install.lib.LocalIntentSender" - android:exported="true" /> <uses-library android:name="android.test.runner" /> </application> diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index ba87dc50e246..5d4573716145 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -56,8 +56,10 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_IA; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; @@ -5398,6 +5400,106 @@ public class ConnectivityServiceTest { } @Test + public void testApplyUnderlyingCapabilities() throws Exception { + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mCellNetworkAgent.connect(false /* validated */); + mWiFiNetworkAgent.connect(false /* validated */); + + final NetworkCapabilities cellNc = new NetworkCapabilities() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_CONGESTED) + .setLinkDownstreamBandwidthKbps(10); + final NetworkCapabilities wifiNc = new NetworkCapabilities() + .addTransportType(TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_METERED) + .addCapability(NET_CAPABILITY_NOT_ROAMING) + .addCapability(NET_CAPABILITY_NOT_CONGESTED) + .addCapability(NET_CAPABILITY_NOT_SUSPENDED) + .setLinkUpstreamBandwidthKbps(20); + mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */); + mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */); + waitForIdle(); + + final Network mobile = mCellNetworkAgent.getNetwork(); + final Network wifi = mWiFiNetworkAgent.getNetwork(); + + final NetworkCapabilities initialCaps = new NetworkCapabilities(); + initialCaps.addCapability(NET_CAPABILITY_INTERNET); + initialCaps.removeCapability(NET_CAPABILITY_NOT_VPN); + + final NetworkCapabilities withNoUnderlying = new NetworkCapabilities(); + withNoUnderlying.addCapability(NET_CAPABILITY_INTERNET); + withNoUnderlying.addCapability(NET_CAPABILITY_NOT_CONGESTED); + withNoUnderlying.addCapability(NET_CAPABILITY_NOT_ROAMING); + withNoUnderlying.addCapability(NET_CAPABILITY_NOT_SUSPENDED); + withNoUnderlying.addTransportType(TRANSPORT_VPN); + withNoUnderlying.removeCapability(NET_CAPABILITY_NOT_VPN); + + final NetworkCapabilities withMobileUnderlying = new NetworkCapabilities(withNoUnderlying); + withMobileUnderlying.addTransportType(TRANSPORT_CELLULAR); + withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING); + withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_SUSPENDED); + withMobileUnderlying.setLinkDownstreamBandwidthKbps(10); + + final NetworkCapabilities withWifiUnderlying = new NetworkCapabilities(withNoUnderlying); + withWifiUnderlying.addTransportType(TRANSPORT_WIFI); + withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED); + withWifiUnderlying.setLinkUpstreamBandwidthKbps(20); + + final NetworkCapabilities withWifiAndMobileUnderlying = + new NetworkCapabilities(withNoUnderlying); + withWifiAndMobileUnderlying.addTransportType(TRANSPORT_CELLULAR); + withWifiAndMobileUnderlying.addTransportType(TRANSPORT_WIFI); + withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED); + withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING); + withWifiAndMobileUnderlying.setLinkDownstreamBandwidthKbps(10); + withWifiAndMobileUnderlying.setLinkUpstreamBandwidthKbps(20); + + NetworkCapabilities caps = new NetworkCapabilities(initialCaps); + final boolean notDeclaredMetered = false; + mService.applyUnderlyingCapabilities(new Network[]{}, caps, notDeclaredMetered); + assertEquals(withNoUnderlying, caps); + + caps = new NetworkCapabilities(initialCaps); + mService.applyUnderlyingCapabilities(new Network[]{null}, caps, notDeclaredMetered); + assertEquals(withNoUnderlying, caps); + + caps = new NetworkCapabilities(initialCaps); + mService.applyUnderlyingCapabilities(new Network[]{mobile}, caps, notDeclaredMetered); + assertEquals(withMobileUnderlying, caps); + + mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, notDeclaredMetered); + assertEquals(withWifiUnderlying, caps); + + final boolean isDeclaredMetered = true; + withWifiUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED); + caps = new NetworkCapabilities(initialCaps); + mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, isDeclaredMetered); + assertEquals(withWifiUnderlying, caps); + + caps = new NetworkCapabilities(initialCaps); + mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, caps, isDeclaredMetered); + assertEquals(withWifiAndMobileUnderlying, caps); + + withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED); + caps = new NetworkCapabilities(initialCaps); + mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi}, + caps, notDeclaredMetered); + assertEquals(withWifiAndMobileUnderlying, caps); + + caps = new NetworkCapabilities(initialCaps); + mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi}, + caps, notDeclaredMetered); + assertEquals(withWifiAndMobileUnderlying, caps); + + mService.applyUnderlyingCapabilities(null, caps, notDeclaredMetered); + assertEquals(withWifiUnderlying, caps); + } + + @Test public void testVpnConnectDisconnectUnderlyingNetwork() throws Exception { final TestNetworkCallback callback = new TestNetworkCallback(); final NetworkRequest request = new NetworkRequest.Builder() @@ -5947,17 +6049,28 @@ public class ConnectivityServiceTest { && caps.hasTransport(TRANSPORT_VPN) && caps.hasTransport(TRANSPORT_WIFI)); + // Change the VPN's capabilities somehow (specifically, disconnect wifi). + mWiFiNetworkAgent.disconnect(); + callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent); + callback.expectCapabilitiesThat(mMockVpn, (caps) + -> caps.getUids().size() == 2 + && caps.getUids().contains(new UidRange(uid, uid)) + && caps.getUids().contains(UidRange.createForUser(restrictedUserId)) + && caps.hasTransport(TRANSPORT_VPN) + && !caps.hasTransport(TRANSPORT_WIFI)); + // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user. final Intent removedIntent = new Intent(ACTION_USER_REMOVED); removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId); handler.post(() -> mServiceContext.sendBroadcast(removedIntent)); - // Expect that the VPN gains the UID range for the restricted user. + // Expect that the VPN gains the UID range for the restricted user, and that the capability + // change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved. callback.expectCapabilitiesThat(mMockVpn, (caps) -> caps.getUids().size() == 1 && caps.getUids().contains(new UidRange(uid, uid)) && caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_WIFI)); + && !caps.hasTransport(TRANSPORT_WIFI)); } @Test diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index d0db55f2bb13..337507ac1d46 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -21,15 +21,6 @@ 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.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; -import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; -import static android.net.NetworkCapabilities.TRANSPORT_VPN; -import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -621,102 +612,6 @@ public class VpnTest { order.verify(mNotificationManager).cancel(anyString(), anyInt()); } - @Test - public void testCapabilities() { - setMockedUsers(primaryUser); - - final Network mobile = new Network(1); - final Network wifi = new Network(2); - - final Map<Network, NetworkCapabilities> networks = new HashMap<>(); - networks.put( - mobile, - new NetworkCapabilities() - .addTransportType(TRANSPORT_CELLULAR) - .addCapability(NET_CAPABILITY_INTERNET) - .addCapability(NET_CAPABILITY_NOT_CONGESTED) - .setLinkDownstreamBandwidthKbps(10)); - networks.put( - wifi, - new NetworkCapabilities() - .addTransportType(TRANSPORT_WIFI) - .addCapability(NET_CAPABILITY_INTERNET) - .addCapability(NET_CAPABILITY_NOT_METERED) - .addCapability(NET_CAPABILITY_NOT_ROAMING) - .addCapability(NET_CAPABILITY_NOT_CONGESTED) - .addCapability(NET_CAPABILITY_NOT_SUSPENDED) - .setLinkUpstreamBandwidthKbps(20)); - setMockedNetworks(networks); - - final NetworkCapabilities caps = new NetworkCapabilities(); - - Vpn.applyUnderlyingCapabilities( - mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */); - assertTrue(caps.hasTransport(TRANSPORT_VPN)); - assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); - assertFalse(caps.hasTransport(TRANSPORT_WIFI)); - assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps()); - assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps()); - assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); - - Vpn.applyUnderlyingCapabilities( - mConnectivityManager, - new Network[] {mobile}, - caps, - false /* isAlwaysMetered */); - assertTrue(caps.hasTransport(TRANSPORT_VPN)); - assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); - assertFalse(caps.hasTransport(TRANSPORT_WIFI)); - assertEquals(10, caps.getLinkDownstreamBandwidthKbps()); - assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps()); - assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); - assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); - - Vpn.applyUnderlyingCapabilities( - mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */); - assertTrue(caps.hasTransport(TRANSPORT_VPN)); - assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); - assertTrue(caps.hasTransport(TRANSPORT_WIFI)); - assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps()); - assertEquals(20, caps.getLinkUpstreamBandwidthKbps()); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); - - Vpn.applyUnderlyingCapabilities( - mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */); - assertTrue(caps.hasTransport(TRANSPORT_VPN)); - assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); - assertTrue(caps.hasTransport(TRANSPORT_WIFI)); - assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps()); - assertEquals(20, caps.getLinkUpstreamBandwidthKbps()); - assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); - - Vpn.applyUnderlyingCapabilities( - mConnectivityManager, - new Network[] {mobile, wifi}, - caps, - false /* isAlwaysMetered */); - assertTrue(caps.hasTransport(TRANSPORT_VPN)); - assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); - assertTrue(caps.hasTransport(TRANSPORT_WIFI)); - assertEquals(10, caps.getLinkDownstreamBandwidthKbps()); - assertEquals(20, caps.getLinkUpstreamBandwidthKbps()); - assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); - assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); - } - /** * The profile name should NOT change between releases for backwards compatibility * diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h index 852b1244cd6e..768b4b2c7bfd 100644 --- a/tools/aapt2/cmd/Link.h +++ b/tools/aapt2/cmd/Link.h @@ -190,8 +190,11 @@ class LinkCommand : public Command { AddOptionalFlag("--version-name", "Version name to inject into the AndroidManifest.xml if none is present.", &options_.manifest_fixer_options.version_name_default); + AddOptionalFlag("--revision-code", + "Revision code (integer) to inject into the AndroidManifest.xml if none is\n" + "present.", &options_.manifest_fixer_options.revision_code_default); AddOptionalSwitch("--replace-version", - "If --version-code and/or --version-name are specified, these\n" + "If --version-code, --version-name, and/or --revision-code are specified, these\n" "values will replace any value already in the manifest. By\n" "default, nothing is changed if the manifest already defines\n" "these attributes.", diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index c03661ca2366..8abd9dec56be 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -367,6 +367,16 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, } } + if (options_.revision_code_default) { + if (options_.replace_version) { + el->RemoveAttribute(xml::kSchemaAndroid, "revisionCode"); + } + if (el->FindAttribute(xml::kSchemaAndroid, "revisionCode") == nullptr) { + el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, "revisionCode", + options_.revision_code_default.value()}); + } + } + return true; }); diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h index ec4367b450fb..34ad8d586df1 100644 --- a/tools/aapt2/link/ManifestFixer.h +++ b/tools/aapt2/link/ManifestFixer.h @@ -60,6 +60,10 @@ struct ManifestFixerOptions { // replace_version is set. Maybe<std::string> version_code_major_default; + // The revision code to set if 'android:revisionCode' is not defined in <manifest> or if + // replace_version is set. + Maybe<std::string> revision_code_default; + // The version of the framework being compiled against to set for 'android:compileSdkVersion' in // the <manifest> tag. Maybe<std::string> compile_sdk_version; diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp index 781ff7b51637..432f10bdab97 100644 --- a/tools/aapt2/link/ManifestFixer_test.cpp +++ b/tools/aapt2/link/ManifestFixer_test.cpp @@ -445,6 +445,66 @@ TEST_F(ManifestFixerTest, ReplaceVersionNameAndCode) { EXPECT_THAT(attr->value, StrEq("0x20000000")); } +TEST_F(ManifestFixerTest, UseDefaultRevisionCode) { + ManifestFixerOptions options; + options.revision_code_default = std::string("0x10000000"); + + std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( + <manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android" + android:versionCode="0x00000001" />)EOF", + options); + ASSERT_THAT(doc, NotNull()); + + xml::Element* manifest_el = doc->root.get(); + ASSERT_THAT(manifest_el, NotNull()); + + xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("0x10000000")); +} + +TEST_F(ManifestFixerTest, DontUseDefaultRevisionCode) { + ManifestFixerOptions options; + options.revision_code_default = std::string("0x10000000"); + + std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( + <manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android" + android:versionCode="0x00000001" + android:revisionCode="0x00000002" />)EOF", + options); + ASSERT_THAT(doc, NotNull()); + + xml::Element* manifest_el = doc->root.get(); + ASSERT_THAT(manifest_el, NotNull()); + + xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("0x00000002")); +} + +TEST_F(ManifestFixerTest, ReplaceRevisionCode) { + ManifestFixerOptions options; + options.replace_version = true; + options.revision_code_default = std::string("0x10000000"); + + std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( + <manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android" + android:versionCode="0x00000001" + android:revisionCode="0x00000002" />)EOF", + options); + ASSERT_THAT(doc, NotNull()); + + xml::Element* manifest_el = doc->root.get(); + ASSERT_THAT(manifest_el, NotNull()); + + xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("0x10000000")); +} + TEST_F(ManifestFixerTest, ReplaceVersionName) { ManifestFixerOptions options; options.replace_version = true; diff --git a/wifi/aidl-export/android/net/wifi/CoexUnsafeChannel.aidl b/wifi/aidl-export/android/net/wifi/CoexUnsafeChannel.aidl new file mode 100644 index 000000000000..cb359e9b2c1b --- /dev/null +++ b/wifi/aidl-export/android/net/wifi/CoexUnsafeChannel.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2020, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +parcelable CoexUnsafeChannel; diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt index 5e8fc0774cce..48d9fd453b05 100644 --- a/wifi/api/system-current.txt +++ b/wifi/api/system-current.txt @@ -1,6 +1,17 @@ // Signature format: 2.0 package android.net.wifi { + public final class CoexUnsafeChannel implements android.os.Parcelable { + ctor public CoexUnsafeChannel(int, int); + ctor public CoexUnsafeChannel(int, int, int); + method public int getBand(); + method public int getChannel(); + method public int getPowerCapDbm(); + method public boolean isPowerCapAvailable(); + method public void setPowerCapDbm(int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.CoexUnsafeChannel> CREATOR; + } + public abstract class EasyConnectStatusCallback { ctor public EasyConnectStatusCallback(); method public void onBootstrapUriGenerated(@NonNull String); @@ -456,6 +467,8 @@ package android.net.wifi { method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset(); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener); method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>); + method @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public int getCoexRestrictions(); + method @NonNull @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public java.util.Set<android.net.wifi.CoexUnsafeChannel> getCoexUnsafeChannels(); method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCountryCode(); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.Network getCurrentNetwork(); method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String[] getFactoryMacAddresses(); @@ -476,6 +489,7 @@ package android.net.wifi { method public boolean isVerboseLoggingEnabled(); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled(); method public boolean isWifiScannerSupported(); + method @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public void registerCoexCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.CoexCallback); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerNetworkRequestMatchCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback); @@ -487,6 +501,7 @@ package android.net.wifi { method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData(); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setAutoWakeupEnabled(boolean); + method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS) public void setCoexUnsafeChannels(@NonNull java.util.Set<android.net.wifi.CoexUnsafeChannel>, int); method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setPasspointMeteredOverride(@NonNull String, int); @@ -507,6 +522,7 @@ package android.net.wifi { method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession(); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean stopSoftAp(); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void stopTemporarilyDisablingAllNonCarrierMergedWifi(); + method @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public void unregisterCoexCallback(@NonNull android.net.wifi.WifiManager.CoexCallback); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterNetworkRequestMatchCallback(@NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback); @@ -520,6 +536,9 @@ package android.net.wifi { field public static final int CHANGE_REASON_ADDED = 0; // 0x0 field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2 field public static final int CHANGE_REASON_REMOVED = 1; // 0x1 + field public static final int COEX_RESTRICTION_SOFTAP = 2; // 0x2 + field public static final int COEX_RESTRICTION_WIFI_AWARE = 4; // 0x4 + field public static final int COEX_RESTRICTION_WIFI_DIRECT = 1; // 0x1 field public static final String CONFIGURED_NETWORKS_CHANGED_ACTION = "android.net.wifi.CONFIGURED_NETWORKS_CHANGE"; field public static final int DEVICE_MOBILITY_STATE_HIGH_MVMT = 1; // 0x1 field public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2; // 0x2 @@ -575,6 +594,11 @@ package android.net.wifi { method public void onSuccess(); } + public abstract static class WifiManager.CoexCallback { + ctor public WifiManager.CoexCallback(); + method public abstract void onCoexUnsafeChannelsChanged(); + } + public static interface WifiManager.NetworkRequestMatchCallback { method public default void onAbort(); method public default void onMatch(@NonNull java.util.List<android.net.wifi.ScanResult>); diff --git a/wifi/java/android/net/wifi/CoexUnsafeChannel.java b/wifi/java/android/net/wifi/CoexUnsafeChannel.java new file mode 100644 index 000000000000..3f9efa020d05 --- /dev/null +++ b/wifi/java/android/net/wifi/CoexUnsafeChannel.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ; +import static android.net.wifi.WifiScanner.WIFI_BAND_5_GHZ; +import static android.net.wifi.WifiScanner.WIFI_BAND_6_GHZ; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Data structure class representing a Wi-Fi channel that would cause interference to/receive + * interference from the active cellular channels and should be avoided. + * + * If {@link #isPowerCapAvailable()} is {@code true}, then a valid power cap value is available + * through {@link #getPowerCapDbm()} to be used if this channel cannot be avoided. If {@code false}, + * then {@link #getPowerCapDbm()} throws an IllegalStateException and the channel will not need to + * cap its power. + * + * @hide + */ +@SystemApi +public final class CoexUnsafeChannel implements Parcelable { + private @WifiAnnotations.WifiBandBasic int mBand; + private int mChannel; + private boolean mIsPowerCapAvailable = false; + private int mPowerCapDbm; + + /** + * Constructor for a CoexUnsafeChannel with no power cap specified. + * @param band One of {@link WifiAnnotations.WifiBandBasic} + * @param channel Channel number + */ + public CoexUnsafeChannel(@WifiAnnotations.WifiBandBasic int band, int channel) { + mBand = band; + mChannel = channel; + } + + /** + * Constructor for a CoexUnsafeChannel with power cap specified. + * @param band One of {@link WifiAnnotations.WifiBandBasic} + * @param channel Channel number + * @param powerCapDbm Power cap in dBm + */ + public CoexUnsafeChannel(@WifiAnnotations.WifiBandBasic int band, int channel, + int powerCapDbm) { + mBand = band; + mChannel = channel; + setPowerCapDbm(powerCapDbm); + } + + /** Returns the Wi-Fi band of this channel as one of {@link WifiAnnotations.WifiBandBasic} */ + public @WifiAnnotations.WifiBandBasic int getBand() { + return mBand; + } + + /** Returns the channel number of this channel. */ + public int getChannel() { + return mChannel; + } + + /** Returns {@code true} if {@link #getPowerCapDbm()} is a valid value, else {@code false} */ + public boolean isPowerCapAvailable() { + return mIsPowerCapAvailable; + } + + /** + * Returns the power cap of this channel in dBm. Throws IllegalStateException if + * {@link #isPowerCapAvailable()} is {@code false}. + */ + public int getPowerCapDbm() { + if (!mIsPowerCapAvailable) { + throw new IllegalStateException("getPowerCapDbm called but power cap is unavailable"); + } + return mPowerCapDbm; + } + + /** Set the power cap of this channel. */ + public void setPowerCapDbm(int powerCapDbm) { + mIsPowerCapAvailable = true; + mPowerCapDbm = powerCapDbm; + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CoexUnsafeChannel that = (CoexUnsafeChannel) o; + return mBand == that.mBand + && mChannel == that.mChannel + && mIsPowerCapAvailable == that.mIsPowerCapAvailable + && mPowerCapDbm == that.mPowerCapDbm; + } + + @Override + public int hashCode() { + return Objects.hash(mBand, mChannel, mIsPowerCapAvailable, mPowerCapDbm); + } + + @Override + public String toString() { + StringBuilder sj = new StringBuilder("CoexUnsafeChannel{"); + sj.append(mChannel); + sj.append(", "); + if (mBand == WIFI_BAND_24_GHZ) { + sj.append("2.4GHz"); + } else if (mBand == WIFI_BAND_5_GHZ) { + sj.append("5GHz"); + } else if (mBand == WIFI_BAND_6_GHZ) { + sj.append("6GHz"); + } else { + sj.append("UNKNOWN BAND"); + } + if (mIsPowerCapAvailable) { + sj.append(", ").append(mPowerCapDbm).append("dBm"); + } + sj.append('}'); + return sj.toString(); + } + + /** Implement the Parcelable interface {@hide} */ + @Override + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface {@hide} */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mBand); + dest.writeInt(mChannel); + dest.writeBoolean(mIsPowerCapAvailable); + if (mIsPowerCapAvailable) { + dest.writeInt(mPowerCapDbm); + } + } + + /** Implement the Parcelable interface */ + public static final @NonNull Creator<CoexUnsafeChannel> CREATOR = + new Creator<CoexUnsafeChannel>() { + public CoexUnsafeChannel createFromParcel(Parcel in) { + final int band = in.readInt(); + final int channel = in.readInt(); + final boolean isPowerCapAvailable = in.readBoolean(); + if (isPowerCapAvailable) { + final int powerCapDbm = in.readInt(); + return new CoexUnsafeChannel(band, channel, powerCapDbm); + } + return new CoexUnsafeChannel(band, channel); + } + + public CoexUnsafeChannel[] newArray(int size) { + return new CoexUnsafeChannel[size]; + } + }; +} diff --git a/wifi/java/android/net/wifi/ICoexCallback.aidl b/wifi/java/android/net/wifi/ICoexCallback.aidl new file mode 100644 index 000000000000..89e4c4b93013 --- /dev/null +++ b/wifi/java/android/net/wifi/ICoexCallback.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +/** + * Interface for Wi-Fi/cellular coex callback. + * @hide + */ +oneway interface ICoexCallback +{ + void onCoexUnsafeChannelsChanged(); +} diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 0b3c0575dabd..6dee751f5894 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -24,7 +24,9 @@ import android.net.wifi.hotspot2.IProvisioningCallback; import android.net.DhcpInfo; import android.net.Network; +import android.net.wifi.CoexUnsafeChannel; import android.net.wifi.IActionListener; +import android.net.wifi.ICoexCallback; import android.net.wifi.IDppCallback; import android.net.wifi.ILocalOnlyHotspotCallback; import android.net.wifi.INetworkRequestMatchCallback; @@ -144,6 +146,16 @@ interface IWifiManager void updateInterfaceIpState(String ifaceName, int mode); + void setCoexUnsafeChannels(in List<CoexUnsafeChannel> unsafeChannels, int mandatoryRestrictions); + + List<CoexUnsafeChannel> getCoexUnsafeChannels(); + + int getCoexRestrictions(); + + void registerCoexCallback(in ICoexCallback callback); + + void unregisterCoexCallback(in ICoexCallback callback); + boolean startSoftAp(in WifiConfiguration wifiConfig, String packageName); boolean startTetheredHotspot(in SoftApConfiguration softApConfig, String packageName); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index d089e1a86a68..b8fa1e18ed28 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -72,6 +72,7 @@ import java.net.InetAddress; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -3110,6 +3111,238 @@ public class WifiManager { } } + /* Wi-Fi/Cellular Coex */ + + /** + * Mandatory coex restriction flag for Wi-Fi Direct. + * + * @see #setCoexUnsafeChannels(Set, int) + * + * @hide + */ + @SystemApi + public static final int COEX_RESTRICTION_WIFI_DIRECT = 0x1 << 0; + + /** + * Mandatory coex restriction flag for SoftAP + * + * @see #setCoexUnsafeChannels(Set, int) + * + * @hide + */ + @SystemApi + public static final int COEX_RESTRICTION_SOFTAP = 0x1 << 1; + + /** + * Mandatory coex restriction flag for Wi-Fi Aware. + * + * @see #setCoexUnsafeChannels(Set, int) + * + * @hide + */ + @SystemApi + public static final int COEX_RESTRICTION_WIFI_AWARE = 0x1 << 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = {"COEX_RESTRICTION_"}, value = { + COEX_RESTRICTION_WIFI_DIRECT, + COEX_RESTRICTION_SOFTAP, + COEX_RESTRICTION_WIFI_AWARE + }) + public @interface CoexRestriction {} + + /** + * Specify the set of {@link CoexUnsafeChannel} to propagate through the framework for + * Wi-Fi/Cellular coex channel avoidance if the default algorithm is disabled via overlay + * (i.e. config_wifiCoexDefaultAlgorithmEnabled = false). Otherwise do nothing. + * + * @param unsafeChannels Set of {@link CoexUnsafeChannel} to avoid. + * @param restrictions Bitmap of {@link CoexRestriction} specifying the mandatory restricted + * uses of the specified channels. If any restrictions are set, then the + * supplied CoexUnsafeChannels will be completely avoided for the + * specified modes, rather than be avoided with best effort. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS) + public void setCoexUnsafeChannels(@NonNull Set<CoexUnsafeChannel> unsafeChannels, + int restrictions) { + if (unsafeChannels == null) { + throw new IllegalArgumentException("unsafeChannels must not be null"); + } + try { + mService.setCoexUnsafeChannels(new ArrayList<>(unsafeChannels), restrictions); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the set of current {@link CoexUnsafeChannel} being used for Wi-Fi/Cellular coex + * channel avoidance. + * + * This returns the set calculated by the default algorithm if + * config_wifiCoexDefaultAlgorithmEnabled is {@code true}. Otherwise, returns the set supplied + * in {@link #setCoexUnsafeChannels(Set, int)}. + * + * If any {@link CoexRestriction} flags are set in {@link #getCoexRestrictions()}, then the + * CoexUnsafeChannels should be totally avoided (i.e. not best effort) for the Wi-Fi modes + * specified by the flags. + * + * @return Set of current CoexUnsafeChannels. + * + * @hide + */ + @NonNull + @SystemApi + @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) + public Set<CoexUnsafeChannel> getCoexUnsafeChannels() { + try { + return new HashSet<>(mService.getCoexUnsafeChannels()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the current coex restrictions being used for Wi-Fi/Cellular coex + * channel avoidance. + * + * This returns the restrictions calculated by the default algorithm if + * config_wifiCoexDefaultAlgorithmEnabled is {@code true}. Otherwise, returns the value supplied + * in {@link #setCoexUnsafeChannels(Set, int)}. + * + * @return int containing a bitwise-OR combination of {@link CoexRestriction}. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) + public int getCoexRestrictions() { + try { + return mService.getCoexRestrictions(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Registers a CoexCallback to listen on the current CoexUnsafeChannels and restrictions being + * used for Wi-Fi/cellular coex channel avoidance. + * @param executor Executor to execute listener callback on + * @param callback CoexCallback to register + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) + public void registerCoexCallback( + @NonNull @CallbackExecutor Executor executor, @NonNull CoexCallback callback) { + if (executor == null) throw new IllegalArgumentException("executor must not be null"); + if (callback == null) throw new IllegalArgumentException("callback must not be null"); + CoexCallback.CoexCallbackProxy proxy = callback.getProxy(); + proxy.initProxy(executor, callback); + try { + mService.registerCoexCallback(proxy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Unregisters a CoexCallback from listening on the current CoexUnsafeChannels and restrictions + * being used for Wi-Fi/cellular coex channel avoidance. + * @param callback CoexCallback to unregister + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) + public void unregisterCoexCallback(@NonNull CoexCallback callback) { + if (callback == null) throw new IllegalArgumentException("callback must not be null"); + CoexCallback.CoexCallbackProxy proxy = callback.getProxy(); + try { + mService.unregisterCoexCallback(proxy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } finally { + proxy.cleanUpProxy(); + } + } + + /** + * Abstract callback class for applications to receive updates about current CoexUnsafeChannels + * for Wi-Fi/Cellular coex channel avoidance. + * + * @hide + */ + @SystemApi + public abstract static class CoexCallback { + private final CoexCallbackProxy mCoexCallbackProxy; + + public CoexCallback() { + mCoexCallbackProxy = new CoexCallbackProxy(); + } + + /*package*/ @NonNull + CoexCallbackProxy getProxy() { + return mCoexCallbackProxy; + } + + /** + * Indicates that the current CoexUnsafeChannels or restrictions have changed. + * Clients should call {@link #getCoexUnsafeChannels()} and {@link #getCoexRestrictions()} + * to get the updated values. + */ + public abstract void onCoexUnsafeChannelsChanged(); + + /** + * Callback proxy for CoexCallback objects. + */ + private static class CoexCallbackProxy extends ICoexCallback.Stub { + private final Object mLock = new Object(); + @Nullable @GuardedBy("mLock") private Executor mExecutor; + @Nullable @GuardedBy("mLock") private CoexCallback mCallback; + + CoexCallbackProxy() { + mExecutor = null; + mCallback = null; + } + + /*package*/ void initProxy(@NonNull Executor executor, + @NonNull CoexCallback callback) { + synchronized (mLock) { + mExecutor = executor; + mCallback = callback; + } + } + + /*package*/ void cleanUpProxy() { + synchronized (mLock) { + mExecutor = null; + mCallback = null; + } + } + + @Override + public void onCoexUnsafeChannelsChanged() { + Executor executor; + CoexCallback callback; + synchronized (mLock) { + executor = mExecutor; + callback = mCallback; + } + if (executor == null || callback == null) { + return; + } + Binder.clearCallingIdentity(); + executor.execute(callback::onCoexUnsafeChannelsChanged); + } + } + } + /** * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration. * Note that starting Soft AP mode may disable station mode operation if the device does not @@ -5991,7 +6224,6 @@ public class WifiManager { executor.execute(callback::onScanResultsAvailable); } } - } /** diff --git a/wifi/tests/src/android/net/wifi/CoexUnsafeChannelTest.java b/wifi/tests/src/android/net/wifi/CoexUnsafeChannelTest.java new file mode 100644 index 000000000000..320f25e715fe --- /dev/null +++ b/wifi/tests/src/android/net/wifi/CoexUnsafeChannelTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.Parcel; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Unit tests for {@link android.net.wifi.CoexUnsafeChannel}. + */ +@SmallTest +public class CoexUnsafeChannelTest { + /** + * Verifies {@link CoexUnsafeChannel#isPowerCapAvailable()} returns false if no cap is set. + */ + @Test + public void testIsPowerCapAvailable_noPowerCap_returnsFalse() { + CoexUnsafeChannel unsafeChannel = new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6); + + assertThat(unsafeChannel.isPowerCapAvailable()).isFalse(); + } + + /** + * Verifies {@link CoexUnsafeChannel#isPowerCapAvailable()} returns true if a cap is set, and + * {@link CoexUnsafeChannel#getPowerCapDbm()} returns the set value. + */ + @Test + public void testIsPowerCapAvailable_powerCapSet_returnsTrue() { + final int powerCapDbm = -50; + CoexUnsafeChannel unsafeChannel = new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6); + + unsafeChannel.setPowerCapDbm(powerCapDbm); + + assertThat(unsafeChannel.isPowerCapAvailable()).isTrue(); + assertThat(unsafeChannel.getPowerCapDbm()).isEqualTo(powerCapDbm); + } + + /** + * Verifies {@link CoexUnsafeChannel#getPowerCapDbm()} throws an IllegalStateException if + * {@link CoexUnsafeChannel#isPowerCapAvailable()} is {@code false}. + */ + @Test(expected = IllegalStateException.class) + public void testGetPowerCap_powerCapUnavailable_throwsException() { + CoexUnsafeChannel unsafeChannel = new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6); + + unsafeChannel.getPowerCapDbm(); + } + + /** + * Verify parcel read/write for CoexUnsafeChannel with or without power cap. + */ + @Test + public void testParcelReadWrite_withOrWithoutCap_readEqualsWritten() throws Exception { + CoexUnsafeChannel writeUnsafeChannelNoCap = + new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6); + CoexUnsafeChannel writeUnsafeChannelCapped = + new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6, -50); + + CoexUnsafeChannel readUnsafeChannelNoCap = parcelReadWrite(writeUnsafeChannelNoCap); + CoexUnsafeChannel readUnsafeChannelCapped = parcelReadWrite(writeUnsafeChannelCapped); + + assertThat(writeUnsafeChannelNoCap).isEqualTo(readUnsafeChannelNoCap); + assertThat(writeUnsafeChannelCapped).isEqualTo(readUnsafeChannelCapped); + } + + /** + * Write the provided {@link CoexUnsafeChannel} to a parcel and deserialize it. + */ + private static CoexUnsafeChannel parcelReadWrite(CoexUnsafeChannel writeResult) + throws Exception { + Parcel parcel = Parcel.obtain(); + writeResult.writeToParcel(parcel, 0); + parcel.setDataPosition(0); // Rewind data position back to the beginning for read. + return CoexUnsafeChannel.CREATOR.createFromParcel(parcel); + } +} diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index aefebbcec607..39f6f57b05b3 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -19,6 +19,9 @@ package android.net.wifi; import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_METERED; import static android.net.wifi.WifiManager.ActionListener; import static android.net.wifi.WifiManager.BUSY; +import static android.net.wifi.WifiManager.COEX_RESTRICTION_SOFTAP; +import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_AWARE; +import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_DIRECT; import static android.net.wifi.WifiManager.ERROR; import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC; import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE; @@ -43,6 +46,7 @@ import static android.net.wifi.WifiManager.WIFI_FEATURE_SCANNER; import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE; import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B; import static android.net.wifi.WifiManager.WpsCallback; +import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -74,6 +78,7 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.net.DhcpInfo; import android.net.MacAddress; +import android.net.wifi.WifiManager.CoexCallback; import android.net.wifi.WifiManager.LocalOnlyHotspotCallback; import android.net.wifi.WifiManager.LocalOnlyHotspotObserver; import android.net.wifi.WifiManager.LocalOnlyHotspotReservation; @@ -108,9 +113,11 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.concurrent.Executor; /** @@ -151,6 +158,7 @@ public class WifiManagerTest { private WifiManager mWifiManager; private WifiNetworkSuggestion mWifiNetworkSuggestion; private ScanResultsCallback mScanResultsCallback; + private CoexCallback mCoexCallback; private WifiActivityEnergyInfo mWifiActivityEnergyInfo; /** @@ -214,10 +222,149 @@ public class WifiManagerTest { mRunnable.run(); } }; + mCoexCallback = new CoexCallback() { + @Override + public void onCoexUnsafeChannelsChanged() { + mRunnable.run(); + } + }; mWifiActivityEnergyInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0); } /** + * Check the call to setCoexUnsafeChannels calls WifiServiceImpl to setCoexUnsafeChannels with + * the provided CoexUnsafeChannels and restrictions bitmask. + */ + @Test + public void testSetCoexUnsafeChannelsGoesToWifiServiceImpl() throws Exception { + Set<CoexUnsafeChannel> unsafeChannels = new HashSet<>(); + int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP + | COEX_RESTRICTION_WIFI_AWARE; + + mWifiManager.setCoexUnsafeChannels(unsafeChannels, restrictions); + + verify(mWifiService).setCoexUnsafeChannels(new ArrayList<>(unsafeChannels), restrictions); + } + + /** + * Verify an IllegalArgumentException if passed a null value for unsafeChannels. + */ + @Test + public void testSetCoexUnsafeChannelsThrowsIllegalArgumentExceptionOnNullUnsafeChannels() { + try { + mWifiManager.setCoexUnsafeChannels(null, 0); + fail("expected IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + } + } + + /** + * Check the call to getCoexUnsafeChannels calls WifiServiceImpl to return the values from + * getCoexUnsafeChannels. + */ + @Test + public void testGetCoexUnsafeChannelsGoesToWifiServiceImpl() throws Exception { + Set<CoexUnsafeChannel> unsafeChannels = new HashSet<>(); + unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6)); + when(mWifiService.getCoexUnsafeChannels()).thenReturn(new ArrayList<>(unsafeChannels)); + + assertEquals(mWifiManager.getCoexUnsafeChannels(), unsafeChannels); + } + + /** + * Verify call to getCoexRestrictions calls WifiServiceImpl to return the value from + * getCoexRestrictions. + */ + @Test + public void testGetCoexRestrictionsGoesToWifiServiceImpl() throws Exception { + int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP + | COEX_RESTRICTION_WIFI_AWARE; + when(mWifiService.getCoexRestrictions()).thenReturn(restrictions); + + assertEquals(mWifiService.getCoexRestrictions(), restrictions); + } + + + /** + * Verify an IllegalArgumentException is thrown if callback is not provided. + */ + @Test(expected = IllegalArgumentException.class) + public void testRegisterCoexCallbackWithNullCallback() throws Exception { + mWifiManager.registerCoexCallback(mExecutor, null); + } + + /** + * Verify an IllegalArgumentException is thrown if executor is not provided. + */ + @Test(expected = IllegalArgumentException.class) + public void testRegisterCoexCallbackWithNullExecutor() throws Exception { + mWifiManager.registerCoexCallback(null, mCoexCallback); + } + + /** + * Verify client provided callback is being called to the right callback. + */ + @Test + public void testAddCoexCallbackAndReceiveEvent() throws Exception { + ArgumentCaptor<ICoexCallback.Stub> callbackCaptor = + ArgumentCaptor.forClass(ICoexCallback.Stub.class); + mWifiManager.registerCoexCallback(new SynchronousExecutor(), mCoexCallback); + verify(mWifiService).registerCoexCallback(callbackCaptor.capture()); + callbackCaptor.getValue().onCoexUnsafeChannelsChanged(); + verify(mRunnable).run(); + } + + /** + * Verify client provided callback is being called to the right executor. + */ + @Test + public void testRegisterCoexCallbackWithTheTargetExecutor() throws Exception { + ArgumentCaptor<ICoexCallback.Stub> callbackCaptor = + ArgumentCaptor.forClass(ICoexCallback.Stub.class); + mWifiManager.registerCoexCallback(mExecutor, mCoexCallback); + verify(mWifiService).registerCoexCallback(callbackCaptor.capture()); + mWifiManager.registerCoexCallback(mAnotherExecutor, mCoexCallback); + callbackCaptor.getValue().onCoexUnsafeChannelsChanged(); + verify(mExecutor, never()).execute(any(Runnable.class)); + verify(mAnotherExecutor).execute(any(Runnable.class)); + } + + /** + * Verify client register unregister then register again, to ensure callback still works. + */ + @Test + public void testRegisterUnregisterThenRegisterAgainWithCoexCallback() throws Exception { + ArgumentCaptor<ICoexCallback.Stub> callbackCaptor = + ArgumentCaptor.forClass(ICoexCallback.Stub.class); + mWifiManager.registerCoexCallback(new SynchronousExecutor(), mCoexCallback); + verify(mWifiService).registerCoexCallback(callbackCaptor.capture()); + mWifiManager.unregisterCoexCallback(mCoexCallback); + callbackCaptor.getValue().onCoexUnsafeChannelsChanged(); + verify(mRunnable, never()).run(); + mWifiManager.registerCoexCallback(new SynchronousExecutor(), mCoexCallback); + callbackCaptor.getValue().onCoexUnsafeChannelsChanged(); + verify(mRunnable).run(); + } + + /** + * Verify client unregisterCoexCallback. + */ + @Test + public void testUnregisterCoexCallback() throws Exception { + mWifiManager.unregisterCoexCallback(mCoexCallback); + verify(mWifiService).unregisterCoexCallback(any()); + } + + /** + * Verify client unregisterCoexCallback with null callback will cause an exception. + */ + @Test(expected = IllegalArgumentException.class) + public void testUnregisterCoexCallbackWithNullCallback() throws Exception { + mWifiManager.unregisterCoexCallback(null); + } + + + /** * Check the call to startSoftAp calls WifiService to startSoftAp with the provided * WifiConfiguration. Verify that the return value is propagated to the caller. */ |