diff options
167 files changed, 3582 insertions, 2633 deletions
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java index 1d86595a4063..b7cd4f5f8bce 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java @@ -18,6 +18,7 @@ package android.app.appsearch; import android.annotation.CallbackExecutor; import android.annotation.NonNull; +import android.app.appsearch.exceptions.AppSearchException; import android.os.Bundle; import android.os.ParcelableException; import android.os.RemoteException; @@ -166,9 +167,9 @@ public final class AppSearchSession { * of the returned {@link AppSearchBatchResult} are the URIs of the input * documents. The values are {@code null} if they were successfully indexed, * or a failed {@link AppSearchResult} otherwise. - * Or {@link BatchResultCallback#onSystemError} will be invoked with a - * {@link Throwable} if an unexpected internal error occurred in AppSearch - * service. + * Or {@link BatchResultCallback#onSystemError} will be invoked with an + * {@link AppSearchException} if an error occurred in AppSearch initialization + * or a cause {@link Throwable} if other error occurred in AppSearch service. */ public void putDocuments( @NonNull PutDocumentsRequest request, @@ -209,9 +210,9 @@ public final class AppSearchSession { * {@link AppSearchResult} otherwise. URIs that are not found will return a * failed {@link AppSearchResult} with a result code of * {@link AppSearchResult#RESULT_NOT_FOUND}. - * Or {@link BatchResultCallback#onSystemError} will be invoked with a - * {@link Throwable} if an unexpected internal error occurred in AppSearch - * service. + * Or {@link BatchResultCallback#onSystemError} will be invoked with an + * {@link AppSearchException} if an error occurred in AppSearch initialization + * or a cause {@link Throwable} if other error occurred in AppSearch service. */ public void getByUri( @NonNull GetByUriRequest request, @@ -337,9 +338,9 @@ public final class AppSearchSession { * are {@code null} on success, or a failed {@link AppSearchResult} otherwise. * URIs that are not found will return a failed {@link AppSearchResult} with a * result code of {@link AppSearchResult#RESULT_NOT_FOUND}. - * Or {@link BatchResultCallback#onSystemError} will be invoked with a - * {@link Throwable} if an unexpected internal error occurred in AppSearch - * service. + * Or {@link BatchResultCallback#onSystemError} will be invoked with an + * {@link AppSearchException} if an error occurred in AppSearch initialization + * or a cause {@link Throwable} if other error occurred in AppSearch service. */ public void removeByUri( @NonNull RemoveByUriRequest request, 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 53d097e844c8..551347c5c202 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -77,7 +77,7 @@ public class AppSearchManagerService extends SystemService { for (int i = 0; i < schemaBundles.size(); i++) { schemas.add(new AppSearchSchema(schemaBundles.get(i))); } - AppSearchImpl impl = ImplInstanceManager.getInstance(callingUserId); + AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid); impl.setSchema(databaseName, schemas, schemasNotPlatformSurfaceable, forceOverride); invokeCallbackOnResult(callback, @@ -103,7 +103,7 @@ public class AppSearchManagerService extends SystemService { try { AppSearchBatchResult.Builder<String, Void> resultBuilder = new AppSearchBatchResult.Builder<>(); - AppSearchImpl impl = ImplInstanceManager.getInstance(callingUserId); + AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid); for (int i = 0; i < documentBundles.size(); i++) { GenericDocument document = new GenericDocument(documentBundles.get(i)); @@ -138,7 +138,7 @@ public class AppSearchManagerService extends SystemService { try { AppSearchBatchResult.Builder<String, Bundle> resultBuilder = new AppSearchBatchResult.Builder<>(); - AppSearchImpl impl = ImplInstanceManager.getInstance(callingUserId); + AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid); for (int i = 0; i < uris.size(); i++) { String uri = uris.get(i); @@ -172,7 +172,7 @@ public class AppSearchManagerService extends SystemService { int callingUserId = UserHandle.getUserId(callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { - AppSearchImpl impl = ImplInstanceManager.getInstance(callingUserId); + AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid); SearchResultPage searchResultPage = impl.query( databaseName, @@ -198,7 +198,7 @@ public class AppSearchManagerService extends SystemService { int callingUserId = UserHandle.getUserId(callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { - AppSearchImpl impl = ImplInstanceManager.getInstance(callingUserId); + AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); SearchResultPage searchResultPage = impl.globalQuery( queryExpression, new SearchSpec(searchSpecBundle)); @@ -221,7 +221,7 @@ public class AppSearchManagerService extends SystemService { // TODO(b/162450968) check nextPageToken is being advanced by the same uid as originally // opened it try { - AppSearchImpl impl = ImplInstanceManager.getInstance(callingUserId); + AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); SearchResultPage searchResultPage = impl.getNextPage(nextPageToken); invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(searchResultPage.getBundle())); @@ -238,7 +238,7 @@ public class AppSearchManagerService extends SystemService { int callingUserId = UserHandle.getUserId(callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { - AppSearchImpl impl = ImplInstanceManager.getInstance(callingUserId); + AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); impl.invalidateNextPageToken(nextPageToken); } catch (Throwable t) { Log.d(TAG, "Unable to invalidate the query page token", t); @@ -257,10 +257,10 @@ public class AppSearchManagerService extends SystemService { int callingUid = Binder.getCallingUidOrThrow(); int callingUserId = UserHandle.getUserId(callingUid); final long callingIdentity = Binder.clearCallingIdentity(); + AppSearchBatchResult.Builder<String, Void> resultBuilder = + new AppSearchBatchResult.Builder<>(); try { - AppSearchBatchResult.Builder<String, Void> resultBuilder = - new AppSearchBatchResult.Builder<>(); - AppSearchImpl impl = ImplInstanceManager.getInstance(callingUserId); + AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid); for (int i = 0; i < uris.size(); i++) { String uri = uris.get(i); @@ -293,7 +293,7 @@ public class AppSearchManagerService extends SystemService { int callingUserId = UserHandle.getUserId(callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { - AppSearchImpl impl = ImplInstanceManager.getInstance(callingUserId); + AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid); impl.removeByQuery(databaseName, queryExpression, new SearchSpec(searchSpecBundle)); @@ -312,7 +312,7 @@ public class AppSearchManagerService extends SystemService { int callingUserId = UserHandle.getUserId(callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { - ImplInstanceManager.getOrCreateInstance(getContext(), callingUserId); + ImplInstanceManager.getInstance(getContext(), callingUserId); invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null)); } catch (Throwable t) { invokeCallbackOnError(callback, t); @@ -374,14 +374,13 @@ public class AppSearchManagerService extends SystemService { } /** - * Invokes the {@link IAppSearchBatchResultCallback} with an unexpected internal throwable. + * Invokes the {@link IAppSearchBatchResultCallback} with an throwable. * * <p>The throwable is converted to {@link ParcelableException}. */ private void invokeCallbackOnError(IAppSearchBatchResultCallback callback, Throwable throwable) { try { - //TODO(b/175067650) verify ParcelableException could propagate throwable correctly. callback.onSystemError(new ParcelableException(throwable)); } catch (RemoteException e) { Log.d(TAG, "Unable to send error to the callback", e); diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java index d26269132c5a..2871eb622f11 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java @@ -41,7 +41,7 @@ public final class ImplInstanceManager { private ImplInstanceManager() {} /** - * Gets an instance of AppSearchImpl for the given user, or creates one if none exists. + * Gets an instance of AppSearchImpl for the given user. * * <p>If no AppSearchImpl instance exists for this user, Icing will be initialized and one will * be created. @@ -51,7 +51,7 @@ public final class ImplInstanceManager { * @return An initialized {@link AppSearchImpl} for this user */ @NonNull - public static AppSearchImpl getOrCreateInstance(@NonNull Context context, @UserIdInt int userId) + public static AppSearchImpl getInstance(@NonNull Context context, @UserIdInt int userId) throws AppSearchException { AppSearchImpl instance = sInstances.get(userId); if (instance == null) { @@ -66,28 +66,6 @@ public final class ImplInstanceManager { return instance; } - /** - * Gets an instance of AppSearchImpl for the given user. - * - * <p>This method should only be called by an initialized SearchSession, which has been already - * created the AppSearchImpl instance for the given user. - * - * @param userId The multi-user userId of the device user calling AppSearch - * @return An initialized {@link AppSearchImpl} for this user - */ - @NonNull - public static AppSearchImpl getInstance(@UserIdInt int userId) { - AppSearchImpl instance = sInstances.get(userId); - if (instance == null) { - // Impossible scenario, user cannot call an uninitialized SearchSession, - // getInstance should always find the instance for the given user and never try to - // create an instance for this user again. - throw new IllegalStateException( - "AppSearchImpl has never been created for this user: " + userId); - } - return instance; - } - private static AppSearchImpl createImpl(@NonNull Context context, @UserIdInt int userId) throws AppSearchException { File appSearchDir = getAppSearchDir(context, userId); diff --git a/core/api/current.txt b/core/api/current.txt index 026e155fa258..e88811569049 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -141,6 +141,7 @@ package android { field public static final String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES"; field public static final String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; field public static final String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES"; + field public static final String REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE = "android.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE"; field public static final String REQUEST_PASSWORD_COMPLEXITY = "android.permission.REQUEST_PASSWORD_COMPLEXITY"; field @Deprecated public static final String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES"; field public static final String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE"; @@ -9520,6 +9521,8 @@ package android.companion { method @NonNull public java.util.List<java.lang.String> getAssociations(); method public boolean hasNotificationAccess(android.content.ComponentName); method public void requestNotificationAccess(android.content.ComponentName); + method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void startObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException; + method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void stopObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException; field public static final String EXTRA_DEVICE = "android.companion.extra.DEVICE"; } @@ -9540,6 +9543,9 @@ package android.companion { public interface DeviceFilter<D extends android.os.Parcelable> extends android.os.Parcelable { } + public class DeviceNotAssociatedException extends java.lang.Exception { + } + public final class WifiDeviceFilter implements android.companion.DeviceFilter<android.net.wifi.ScanResult> { method public int describeContents(); method public void writeToParcel(@NonNull android.os.Parcel, int); @@ -41076,6 +41082,28 @@ package android.telephony { field public static final int IP_VERSION_MISMATCH = 2055; // 0x807 field public static final int IRAT_HANDOVER_FAILED = 2194; // 0x892 field public static final int IS707B_MAX_ACCESS_PROBES = 2089; // 0x829 + field public static final int IWLAN_AUTHORIZATION_REJECTED = 9003; // 0x232b + field public static final int IWLAN_DNS_RESOLUTION_NAME_FAILURE = 16388; // 0x4004 + field public static final int IWLAN_DNS_RESOLUTION_TIMEOUT = 16389; // 0x4005 + field public static final int IWLAN_IKEV2_AUTH_FAILURE = 16385; // 0x4001 + field public static final int IWLAN_IKEV2_CERT_INVALID = 16387; // 0x4003 + field public static final int IWLAN_IKEV2_CONFIG_FAILURE = 16384; // 0x4000 + field public static final int IWLAN_IKEV2_MSG_TIMEOUT = 16386; // 0x4002 + field public static final int IWLAN_ILLEGAL_ME = 9006; // 0x232e + field public static final int IWLAN_IMEI_NOT_ACCEPTED = 11005; // 0x2afd + field public static final int IWLAN_MAX_CONNECTION_REACHED = 8193; // 0x2001 + field public static final int IWLAN_NETWORK_FAILURE = 10500; // 0x2904 + field public static final int IWLAN_NON_3GPP_ACCESS_TO_EPC_NOT_ALLOWED = 9000; // 0x2328 + field public static final int IWLAN_NO_APN_SUBSCRIPTION = 9002; // 0x232a + field public static final int IWLAN_PDN_CONNECTION_REJECTION = 8192; // 0x2000 + field public static final int IWLAN_PLMN_NOT_ALLOWED = 11011; // 0x2b03 + field public static final int IWLAN_RAT_TYPE_NOT_ALLOWED = 11001; // 0x2af9 + field public static final int IWLAN_SEMANTIC_ERRORS_IN_PACKET_FILTERS = 8244; // 0x2034 + field public static final int IWLAN_SEMANTIC_ERROR_IN_THE_TFT_OPERATION = 8241; // 0x2031 + field public static final int IWLAN_SYNTACTICAL_ERRORS_IN_PACKET_FILTERS = 8245; // 0x2035 + field public static final int IWLAN_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION = 8242; // 0x2032 + field public static final int IWLAN_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED = 11055; // 0x2b2f + field public static final int IWLAN_USER_UNKNOWN = 9001; // 0x2329 field public static final int LIMITED_TO_IPV4 = 2234; // 0x8ba field public static final int LIMITED_TO_IPV6 = 2235; // 0x8bb field public static final int LLC_SNDCP = 25; // 0x19 diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index ed6dea815e4c..6d564a3ce61c 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -6681,8 +6681,7 @@ public final class ActivityThread extends ClientTransactionHandler { private InstrumentationInfo prepareInstrumentation(AppBindData data) { final InstrumentationInfo ii; try { - ii = new ApplicationPackageManager( - null, getPackageManager(), getPermissionManager()) + ii = new ApplicationPackageManager(null, getPackageManager()) .getInstrumentationInfo(data.instrumentationName, 0); } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException( diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 3642d318e820..186d1fede5e0 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -59,8 +59,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.PackageManager.Property; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; @@ -95,8 +93,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; -import android.permission.IOnPermissionsChangeListener; -import android.permission.IPermissionManager; import android.permission.PermissionManager; import android.provider.Settings; import android.system.ErrnoException; @@ -106,7 +102,6 @@ import android.system.StructStat; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.DebugUtils; import android.util.LauncherIcons; import android.util.Log; @@ -129,7 +124,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; @@ -137,14 +131,6 @@ import java.util.Set; public class ApplicationPackageManager extends PackageManager { private static final String TAG = "ApplicationPackageManager"; private static final boolean DEBUG_ICONS = false; - /** - * Note: Changing this won't do anything on it's own - you should also change the filtering in - * {@link #shouldTraceGrant} - * - * @hide - */ - public static final boolean DEBUG_TRACE_GRANTS = false; - public static final boolean DEBUG_TRACE_PERMISSION_UPDATES = false; private static final int DEFAULT_EPHEMERAL_COOKIE_MAX_SIZE_BYTES = 16384; // 16KB @@ -171,6 +157,8 @@ public class ApplicationPackageManager extends PackageManager { @GuardedBy("mLock") private UserManager mUserManager; @GuardedBy("mLock") + private PermissionManager mPermissionManager; + @GuardedBy("mLock") private PackageInstaller mInstaller; @GuardedBy("mLock") private ArtManager mArtManager; @@ -190,6 +178,15 @@ public class ApplicationPackageManager extends PackageManager { } } + private PermissionManager getPermissionManager() { + synchronized (mLock) { + if (mPermissionManager == null) { + mPermissionManager = mContext.getSystemService(PermissionManager.class); + } + return mPermissionManager; + } + } + @Override public int getUserId() { return mContext.getUserId(); @@ -355,66 +352,41 @@ public class ApplicationPackageManager extends PackageManager { @Override @SuppressWarnings("unchecked") public List<PermissionGroupInfo> getAllPermissionGroups(int flags) { - try { - final ParceledListSlice<PermissionGroupInfo> parceledList = - mPermissionManager.getAllPermissionGroups(flags); - if (parceledList == null) { - return Collections.emptyList(); - } - return parceledList.getList(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().getAllPermissionGroups(flags); } @Override public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) throws NameNotFoundException { - try { - final PermissionGroupInfo pgi = - mPermissionManager.getPermissionGroupInfo(groupName, flags); - if (pgi != null) { - return pgi; - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + final PermissionGroupInfo permissionGroupInfo = getPermissionManager() + .getPermissionGroupInfo(groupName, flags); + if (permissionGroupInfo == null) { + throw new NameNotFoundException(groupName); } - throw new NameNotFoundException(groupName); + return permissionGroupInfo; } @Override public PermissionInfo getPermissionInfo(String permName, int flags) throws NameNotFoundException { - try { - final String packageName = mContext.getOpPackageName(); - final PermissionInfo pi = - mPermissionManager.getPermissionInfo(permName, packageName, flags); - if (pi != null) { - return pi; - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + final PermissionInfo permissionInfo = getPermissionManager().getPermissionInfo(permName, + flags); + if (permissionInfo == null) { + throw new NameNotFoundException(permName); } - throw new NameNotFoundException(permName); + return permissionInfo; } @Override @SuppressWarnings("unchecked") public List<PermissionInfo> queryPermissionsByGroup(String groupName, int flags) throws NameNotFoundException { - try { - final ParceledListSlice<PermissionInfo> parceledList = - mPermissionManager.queryPermissionsByGroup(groupName, flags); - if (parceledList != null) { - final List<PermissionInfo> pi = parceledList.getList(); - if (pi != null) { - return pi; - } - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + final List<PermissionInfo> permissionInfos = getPermissionManager().queryPermissionsByGroup( + groupName, flags); + if (permissionInfos == null) { + throw new NameNotFoundException(groupName); } - throw new NameNotFoundException(groupName); + return permissionInfos; } @Override @@ -724,11 +696,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public boolean isPermissionRevokedByPolicy(String permName, String pkgName) { - try { - return mPermissionManager.isPermissionRevokedByPolicy(permName, pkgName, getUserId()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().isPermissionRevokedByPolicy(pkgName, permName); } /** @@ -750,50 +718,23 @@ public class ApplicationPackageManager extends PackageManager { @Override public boolean addPermission(PermissionInfo info) { - try { - return mPermissionManager.addPermission(info, false); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().addPermission(info, false); } @Override public boolean addPermissionAsync(PermissionInfo info) { - try { - return mPermissionManager.addPermission(info, true); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().addPermission(info, true); } @Override public void removePermission(String name) { - try { - mPermissionManager.removePermission(name); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + getPermissionManager().removePermission(name); } @Override public void grantRuntimePermission(String packageName, String permissionName, UserHandle user) { - if (DEBUG_TRACE_GRANTS - && shouldTraceGrant(packageName, permissionName, user.getIdentifier())) { - Log.i(TAG, "App " + mContext.getPackageName() + " is granting " + packageName + " " - + permissionName + " for user " + user.getIdentifier(), new RuntimeException()); - } - try { - mPM.grantRuntimePermission(packageName, permissionName, user.getIdentifier()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** @hide */ - public static boolean shouldTraceGrant(String packageName, String permissionName, int userId) { - // To be modified when debugging - return false; + getPermissionManager().grantRuntimePermission(packageName, permissionName, user); } @Override @@ -804,124 +745,55 @@ public class ApplicationPackageManager extends PackageManager { @Override public void revokeRuntimePermission(String packageName, String permName, UserHandle user, String reason) { - if (DEBUG_TRACE_PERMISSION_UPDATES - && shouldTraceGrant(packageName, permName, user.getIdentifier())) { - Log.i(TAG, "App " + mContext.getPackageName() + " is revoking " + packageName + " " - + permName + " for user " + user.getIdentifier() + " with reason " + reason, - new RuntimeException()); - } - try { - mPermissionManager - .revokeRuntimePermission(packageName, permName, user.getIdentifier(), reason); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + getPermissionManager().revokeRuntimePermission(packageName, permName, user, reason); } @Override public int getPermissionFlags(String permName, String packageName, UserHandle user) { - try { - return mPermissionManager - .getPermissionFlags(permName, packageName, user.getIdentifier()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().getPermissionFlags(packageName, permName, user); } @Override public void updatePermissionFlags(String permName, String packageName, int flagMask, int flagValues, UserHandle user) { - if (DEBUG_TRACE_PERMISSION_UPDATES - && shouldTraceGrant(packageName, permName, user.getIdentifier())) { - Log.i(TAG, "App " + mContext.getPackageName() + " is updating flags for " - + packageName + " " - + permName + " for user " + user.getIdentifier() + ": " - + DebugUtils.flagsToString(PackageManager.class, "FLAG_PERMISSION_", flagMask) - + " := " + DebugUtils.flagsToString( - PackageManager.class, "FLAG_PERMISSION_", flagValues), - new RuntimeException()); - } - try { - final boolean checkAdjustPolicyFlagPermission = - mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q; - mPermissionManager.updatePermissionFlags(permName, packageName, flagMask, - flagValues, checkAdjustPolicyFlagPermission, user.getIdentifier()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + getPermissionManager().updatePermissionFlags(packageName, permName, flagMask, flagValues, + user); } @Override public @NonNull Set<String> getWhitelistedRestrictedPermissions( @NonNull String packageName, @PermissionWhitelistFlags int flags) { - try { - final int userId = getUserId(); - final List<String> whitelist = mPermissionManager - .getWhitelistedRestrictedPermissions(packageName, flags, userId); - if (whitelist != null) { - return new ArraySet<>(whitelist); - } - return Collections.emptySet(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().getAllowlistedRestrictedPermissions(packageName, flags); } @Override public boolean addWhitelistedRestrictedPermission(@NonNull String packageName, @NonNull String permName, @PermissionWhitelistFlags int flags) { - try { - final int userId = getUserId(); - return mPermissionManager - .addWhitelistedRestrictedPermission(packageName, permName, flags, userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().addAllowlistedRestrictedPermission(packageName, permName, + flags); } @Override - public boolean setAutoRevokeWhitelisted( - @NonNull String packageName, boolean whitelisted) { - try { - final int userId = getUserId(); - return mPermissionManager.setAutoRevokeWhitelisted(packageName, whitelisted, userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + public boolean setAutoRevokeWhitelisted(@NonNull String packageName, boolean whitelisted) { + return getPermissionManager().setAutoRevokeExempted(packageName, whitelisted); } @Override public boolean isAutoRevokeWhitelisted(@NonNull String packageName) { - try { - final int userId = getUserId(); - return mPermissionManager.isAutoRevokeWhitelisted(packageName, userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().isAutoRevokeExempted(packageName); } @Override public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName, @NonNull String permName, @PermissionWhitelistFlags int flags) { - try { - final int userId = getUserId(); - return mPermissionManager - .removeWhitelistedRestrictedPermission(packageName, permName, flags, userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().removeAllowlistedRestrictedPermission(packageName, permName, + flags); } @Override @UnsupportedAppUsage public boolean shouldShowRequestPermissionRationale(String permName) { - try { - final String packageName = mContext.getPackageName(); - return mPermissionManager - .shouldShowRequestPermissionRationale(permName, packageName, getUserId()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getPermissionManager().shouldShowRequestPermissionRationale(permName); } @Override @@ -1880,34 +1752,12 @@ public class ApplicationPackageManager extends PackageManager { @Override public void addOnPermissionsChangeListener(OnPermissionsChangedListener listener) { - synchronized (mPermissionListeners) { - if (mPermissionListeners.get(listener) != null) { - return; - } - OnPermissionsChangeListenerDelegate delegate = - new OnPermissionsChangeListenerDelegate(listener, Looper.getMainLooper()); - try { - mPermissionManager.addOnPermissionsChangeListener(delegate); - mPermissionListeners.put(listener, delegate); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } + getPermissionManager().addOnPermissionsChangeListener(listener); } @Override public void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener) { - synchronized (mPermissionListeners) { - IOnPermissionsChangeListener delegate = mPermissionListeners.get(listener); - if (delegate != null) { - try { - mPermissionManager.removeOnPermissionsChangeListener(delegate); - mPermissionListeners.remove(listener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - } + getPermissionManager().removeOnPermissionsChangeListener(listener); } @UnsupportedAppUsage @@ -1918,11 +1768,9 @@ public class ApplicationPackageManager extends PackageManager { } } - protected ApplicationPackageManager(ContextImpl context, IPackageManager pm, - IPermissionManager permissionManager) { + protected ApplicationPackageManager(ContextImpl context, IPackageManager pm) { mContext = context; mPM = pm; - mPermissionManager = permissionManager; } /** @@ -3234,7 +3082,6 @@ public class ApplicationPackageManager extends PackageManager { private final ContextImpl mContext; @UnsupportedAppUsage private final IPackageManager mPM; - private final IPermissionManager mPermissionManager; /** Assume locked until we hear otherwise */ private volatile boolean mUserUnlocked = false; @@ -3245,41 +3092,6 @@ public class ApplicationPackageManager extends PackageManager { private static ArrayMap<ResourceName, WeakReference<CharSequence>> sStringCache = new ArrayMap<ResourceName, WeakReference<CharSequence>>(); - private final Map<OnPermissionsChangedListener, IOnPermissionsChangeListener> - mPermissionListeners = new ArrayMap<>(); - - public class OnPermissionsChangeListenerDelegate extends IOnPermissionsChangeListener.Stub - implements Handler.Callback{ - private static final int MSG_PERMISSIONS_CHANGED = 1; - - private final OnPermissionsChangedListener mListener; - private final Handler mHandler; - - - public OnPermissionsChangeListenerDelegate(OnPermissionsChangedListener listener, - Looper looper) { - mListener = listener; - mHandler = new Handler(looper, this); - } - - @Override - public void onPermissionsChanged(int uid) { - mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget(); - } - - @Override - public boolean handleMessage(Message msg) { - switch (msg.what) { - case MSG_PERMISSIONS_CHANGED: { - final int uid = msg.arg1; - mListener.onPermissionsChanged(uid); - return true; - } - } - return false; - } - } - @Override public boolean canRequestPackageInstalls() { try { diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 2fec9f79717a..124cf71edc9c 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -72,7 +72,6 @@ import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; -import android.permission.IPermissionManager; import android.permission.PermissionManager; import android.system.ErrnoException; import android.system.Os; @@ -370,10 +369,9 @@ class ContextImpl extends Context { } final IPackageManager pm = ActivityThread.getPackageManager(); - final IPermissionManager permissionManager = ActivityThread.getPermissionManager(); - if (pm != null && permissionManager != null) { + if (pm != null) { // Doesn't matter if we make more than one instance. - return (mPackageManager = new ApplicationPackageManager(this, pm, permissionManager)); + return (mPackageManager = new ApplicationPackageManager(this, pm)); } return null; diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index fe382a33a8c5..2da5e001a3e4 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -27,7 +27,6 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Point; -import android.graphics.Rect; import android.os.Build; import android.os.IBinder; import android.os.Parcel; @@ -187,22 +186,6 @@ public class TaskInfo { public boolean isResizeable; /** - * Activity bounds if this task or its top activity is presented in letterbox mode and - * {@code null} otherwise. - * @hide - */ - @Nullable - public Rect letterboxActivityBounds; - - /** - * Activity insets if this task or its top activity is presented in letterbox mode and - * {@code null} otherwise. - * @hide - */ - @Nullable - public Rect letterboxActivityInsets; - - /** * Relative position of the task's top left corner in the parent container. * @hide */ @@ -223,12 +206,6 @@ public class TaskInfo { public int parentTaskId; /** - * Parent bounds. - * @hide - */ - public Rect parentBounds; - - /** * Whether this task is focused. * @hide */ @@ -320,7 +297,6 @@ public class TaskInfo { return topActivityType == that.topActivityType && isResizeable == that.isResizeable && Objects.equals(positionInParent, that.positionInParent) - && equalsLetterboxParams(that) && Objects.equals(pictureInPictureParams, that.pictureInPictureParams) && getWindowingMode() == that.getWindowingMode() && Objects.equals(taskDescription, that.taskDescription) @@ -328,18 +304,6 @@ public class TaskInfo { && isVisible == that.isVisible; } - private boolean equalsLetterboxParams(TaskInfo that) { - return Objects.equals(letterboxActivityBounds, that.letterboxActivityBounds) - && Objects.equals( - getConfiguration().windowConfiguration.getBounds(), - that.getConfiguration().windowConfiguration.getBounds()) - && Objects.equals( - getConfiguration().windowConfiguration.getMaxBounds(), - that.getConfiguration().windowConfiguration.getMaxBounds()) - && Objects.equals(parentBounds, that.parentBounds) - && Objects.equals(letterboxActivityInsets, that.letterboxActivityInsets); - } - /** * Reads the TaskInfo from a parcel. */ @@ -368,13 +332,10 @@ public class TaskInfo { topActivityInfo = source.readTypedObject(ActivityInfo.CREATOR); isResizeable = source.readBoolean(); source.readBinderList(launchCookies); - letterboxActivityBounds = source.readTypedObject(Rect.CREATOR); positionInParent = source.readTypedObject(Point.CREATOR); parentTaskId = source.readInt(); - parentBounds = source.readTypedObject(Rect.CREATOR); isFocused = source.readBoolean(); isVisible = source.readBoolean(); - letterboxActivityInsets = source.readTypedObject(Rect.CREATOR); } /** @@ -406,13 +367,10 @@ public class TaskInfo { dest.writeTypedObject(topActivityInfo, flags); dest.writeBoolean(isResizeable); dest.writeBinderList(launchCookies); - dest.writeTypedObject(letterboxActivityBounds, flags); dest.writeTypedObject(positionInParent, flags); dest.writeInt(parentTaskId); - dest.writeTypedObject(parentBounds, flags); dest.writeBoolean(isFocused); dest.writeBoolean(isVisible); - dest.writeTypedObject(letterboxActivityInsets, flags); } @Override @@ -433,13 +391,10 @@ public class TaskInfo { + " pictureInPictureParams=" + pictureInPictureParams + " topActivityInfo=" + topActivityInfo + " launchCookies=" + launchCookies - + " letterboxActivityBounds=" + letterboxActivityBounds + " positionInParent=" + positionInParent + " parentTaskId=" + parentTaskId - + " parentBounds=" + parentBounds + " isFocused=" + isFocused + " isVisible=" + isVisible - + " letterboxActivityInsets=" + letterboxActivityInsets + "}"; } } diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index c3c270e52eb6..59646f106db5 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -34,6 +34,7 @@ import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.service.notification.NotificationListenerService; +import android.util.ExceptionUtils; import android.util.Log; import java.util.Collections; @@ -321,6 +322,77 @@ public final class CompanionDeviceManager { } } + /** + * Register to receive callbacks whenever the associated device comes in and out of range. + * + * The provided device must be {@link #associate associated} with the calling app before + * calling this method. + * + * Caller must implement a single {@link CompanionDeviceService} which will be bound to and + * receive callbacks to {@link CompanionDeviceService#onDeviceAppeared} and + * {@link CompanionDeviceService#onDeviceDisappeared}. + * The app doesn't need to remain running in order to receive its callbacks. + * + * Calling app must declare uses-permission + * {@link android.Manifest.permission#REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE}. + * + * Calling app must check for feature presence of + * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} before calling this API. + * + * @param deviceAddress a previously-associated companion device's address + * + * @throws DeviceNotAssociatedException if the given device was not previously associated + * with this app. + */ + @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) + public void startObservingDevicePresence(@NonNull String deviceAddress) + throws DeviceNotAssociatedException { + if (!checkFeaturePresent()) { + return; + } + Objects.requireNonNull(deviceAddress, "address cannot be null"); + try { + mService.registerDevicePresenceListenerService( + mContext.getPackageName(), deviceAddress); + } catch (RemoteException e) { + ExceptionUtils.propagateIfInstanceOf(e.getCause(), DeviceNotAssociatedException.class); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Unregister for receiving callbacks whenever the associated device comes in and out of range. + * + * The provided device must be {@link #associate associated} with the calling app before + * calling this method. + * + * Calling app must declare uses-permission + * {@link android.Manifest.permission#REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE}. + * + * Calling app must check for feature presence of + * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} before calling this API. + * + * @param deviceAddress a previously-associated companion device's address + * + * @throws DeviceNotAssociatedException if the given device was not previously associated + * with this app. + */ + @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) + public void stopObservingDevicePresence(@NonNull String deviceAddress) + throws DeviceNotAssociatedException { + if (!checkFeaturePresent()) { + return; + } + Objects.requireNonNull(deviceAddress, "address cannot be null"); + try { + mService.unregisterDevicePresenceListenerService( + mContext.getPackageName(), deviceAddress); + } catch (RemoteException e) { + ExceptionUtils.propagateIfInstanceOf(e.getCause(), DeviceNotAssociatedException.class); + throw e.rethrowFromSystemServer(); + } + } + private boolean checkFeaturePresent() { boolean featurePresent = mService != null; if (!featurePresent && DEBUG) { diff --git a/core/java/android/companion/DeviceNotAssociatedException.java b/core/java/android/companion/DeviceNotAssociatedException.java new file mode 100644 index 000000000000..bebb6c9ff7eb --- /dev/null +++ b/core/java/android/companion/DeviceNotAssociatedException.java @@ -0,0 +1,31 @@ +/* + * 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.companion; + +import android.annotation.Nullable; + +/** + * An exception for a case when a given device was not + * {@link CompanionDeviceManager#associate associated} to the calling app. + */ +public class DeviceNotAssociatedException extends Exception { + /** @hide */ + public DeviceNotAssociatedException(@Nullable String deviceName) { + super("Device not associated with the current app: " + deviceName); + } +} diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl index bcb9be80e6a4..527d8df94ea0 100644 --- a/core/java/android/companion/ICompanionDeviceManager.aidl +++ b/core/java/android/companion/ICompanionDeviceManager.aidl @@ -45,4 +45,8 @@ interface ICompanionDeviceManager { boolean isDeviceAssociatedForWifiConnection(in String packageName, in String macAddress, int userId); + + void registerDevicePresenceListenerService(in String packageName, in String deviceAddress); + + void unregisterDevicePresenceListenerService(in String packageName, in String deviceAddress); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index cf3f7069c63f..67a1ad676348 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -4438,6 +4438,7 @@ public abstract class PackageManager { * @throws NameNotFoundException if a package with the given name cannot be * found on the system. */ + //@Deprecated public abstract PermissionInfo getPermissionInfo(@NonNull String permName, @PermissionInfoFlags int flags) throws NameNotFoundException; @@ -4450,9 +4451,10 @@ public abstract class PackageManager { * @param flags Additional option flags to modify the data returned. * @return Returns a list of {@link PermissionInfo} containing information * about all of the permissions in the given group. - * @throws NameNotFoundException if a package with the given name cannot be + * @throws NameNotFoundException if a group with the given name cannot be * found on the system. */ + //@Deprecated @NonNull public abstract List<PermissionInfo> queryPermissionsByGroup(@NonNull String permissionGroup, @PermissionInfoFlags int flags) throws NameNotFoundException; @@ -4481,7 +4483,7 @@ public abstract class PackageManager { * Retrieve all of the information we know about a particular group of * permissions. * - * @param permName The fully qualified name (i.e. + * @param groupName The fully qualified name (i.e. * com.google.permission_group.APPS) of the permission you are * interested in. * @param flags Additional option flags to modify the data returned. @@ -4490,8 +4492,9 @@ public abstract class PackageManager { * @throws NameNotFoundException if a package with the given name cannot be * found on the system. */ + //@Deprecated @NonNull - public abstract PermissionGroupInfo getPermissionGroupInfo(@NonNull String permName, + public abstract PermissionGroupInfo getPermissionGroupInfo(@NonNull String groupName, @PermissionGroupInfoFlags int flags) throws NameNotFoundException; /** @@ -4501,6 +4504,7 @@ public abstract class PackageManager { * @return Returns a list of {@link PermissionGroupInfo} containing * information about all of the known permission groups. */ + //@Deprecated @NonNull public abstract List<PermissionGroupInfo> getAllPermissionGroups( @PermissionGroupInfoFlags int flags); @@ -4757,6 +4761,7 @@ public abstract class PackageManager { * @return Whether the permission is restricted by policy. */ @CheckResult + //@Deprecated public abstract boolean isPermissionRevokedByPolicy(@NonNull String permName, @NonNull String packageName); @@ -4805,6 +4810,7 @@ public abstract class PackageManager { * * @see #removePermission(String) */ + //@Deprecated public abstract boolean addPermission(@NonNull PermissionInfo info); /** @@ -4814,6 +4820,7 @@ public abstract class PackageManager { * expense of no guarantee the added permission will be retained if * the device is rebooted before it is written. */ + //@Deprecated public abstract boolean addPermissionAsync(@NonNull PermissionInfo info); /** @@ -4829,6 +4836,7 @@ public abstract class PackageManager { * * @see #addPermission(PermissionInfo) */ + //@Deprecated public abstract void removePermission(@NonNull String permName); /** @@ -4881,6 +4889,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @SystemApi @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) @@ -4908,6 +4917,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @SystemApi @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) @@ -4936,6 +4946,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermission(@NonNull String packageName, @@ -4953,6 +4964,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @SystemApi @RequiresPermission(anyOf = { @@ -4976,6 +4988,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @SystemApi @RequiresPermission(anyOf = { @@ -5040,6 +5053,7 @@ public abstract class PackageManager { * * @throws SecurityException if you try to access a whitelist that you have no access to. */ + //@Deprecated @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, conditional = true) public @NonNull Set<String> getWhitelistedRestrictedPermissions( @@ -5106,6 +5120,7 @@ public abstract class PackageManager { * * @throws SecurityException if you try to modify a whitelist that you have no access to. */ + //@Deprecated @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, conditional = true) public boolean addWhitelistedRestrictedPermission(@NonNull String packageName, @@ -5175,6 +5190,7 @@ public abstract class PackageManager { * * @throws SecurityException if you try to modify a whitelist that you have no access to. */ + //@Deprecated @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, conditional = true) public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName, @@ -5207,6 +5223,7 @@ public abstract class PackageManager { * * @throws SecurityException if you you have no access to modify this. */ + //@Deprecated @RequiresPermission(value = Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS, conditional = true) public boolean setAutoRevokeWhitelisted(@NonNull String packageName, boolean whitelisted) { @@ -5234,6 +5251,7 @@ public abstract class PackageManager { * * @throws SecurityException if you you have no access to this. */ + //@Deprecated @RequiresPermission(value = Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS, conditional = true) public boolean isAutoRevokeWhitelisted(@NonNull String packageName) { @@ -5252,6 +5270,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @UnsupportedAppUsage public abstract boolean shouldShowRequestPermissionRationale(@NonNull String permName); @@ -7554,6 +7573,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS) @@ -7567,6 +7587,7 @@ public abstract class PackageManager { * * @hide */ + //@Deprecated @SuppressWarnings("HiddenAbstractMethod") @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS) diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 7afba1a214b8..41cc12f3b2e3 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -2856,10 +2856,10 @@ public abstract class CameraMetadata<TKey> { * respective color channel provided in * {@link CaptureRequest#SENSOR_TEST_PATTERN_DATA android.sensor.testPatternData}.</p> * <p>For example:</p> - * <pre><code>android.testPatternData = [0, 0xFFFFFFFF, 0xFFFFFFFF, 0] + * <pre><code>android.control.testPatternData = [0, 0xFFFFFFFF, 0xFFFFFFFF, 0] * </code></pre> * <p>All green pixels are 100% green. All red/blue pixels are black.</p> - * <pre><code>android.testPatternData = [0xFFFFFFFF, 0, 0xFFFFFFFF, 0] + * <pre><code>android.control.testPatternData = [0xFFFFFFFF, 0, 0xFFFFFFFF, 0] * </code></pre> * <p>All red pixels are 100% red. Only the odd green pixels * are 100% green. All blue pixels are 100% black.</p> diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index e1d900528f07..25d84bab89e2 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -321,16 +321,6 @@ interface INetworkManagementService void setFirewallChainEnabled(int chain, boolean enable); /** - * Set all packets from users in ranges to go through VPN specified by netId. - */ - void addVpnUidRanges(int netId, in UidRange[] ranges); - - /** - * Clears the special VPN rules for users in ranges and VPN specified by netId. - */ - void removeVpnUidRanges(int netId, in UidRange[] ranges); - - /** * Start listening for mobile activity state changes. */ void registerNetworkActivityListener(INetworkActivityListener listener); @@ -361,7 +351,5 @@ interface INetworkManagementService void removeInterfaceFromLocalNetwork(String iface); int removeRoutesFromLocalNetwork(in List<RouteInfo> routes); - void setAllowOnlyVpnForUids(boolean enable, in UidRange[] uidRanges); - boolean isNetworkRestricted(int uid); } diff --git a/core/java/android/os/RemoteException.java b/core/java/android/os/RemoteException.java index 98c66d1beaf4..e9fc2f38072b 100644 --- a/core/java/android/os/RemoteException.java +++ b/core/java/android/os/RemoteException.java @@ -37,6 +37,11 @@ public class RemoteException extends AndroidException { super(message, cause, enableSuppression, writableStackTrace); } + /** @hide */ + public RemoteException(Throwable cause) { + this(cause.getMessage(), cause, true, false); + } + /** * Rethrow this as an unchecked runtime exception. * <p> diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 3940bd62950c..d31e0129fb27 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -19,6 +19,7 @@ package android.permission; import static android.os.Build.VERSION_CODES.S; import android.Manifest; +import android.annotation.CheckResult; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; @@ -36,11 +37,22 @@ import android.compat.annotation.EnabledAfter; import android.content.Context; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; +import android.content.pm.PermissionGroupInfo; +import android.content.pm.PermissionInfo; import android.content.pm.permission.SplitPermissionInfoParcelable; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.DebugUtils; +import android.util.Log; import android.util.Slog; import com.android.internal.annotations.Immutable; @@ -60,7 +72,7 @@ import java.util.Set; @SystemApi @SystemService(Context.PERMISSION_SERVICE) public final class PermissionManager { - private static final String TAG = PermissionManager.class.getName(); + private static final String LOG_TAG = PermissionManager.class.getName(); /** @hide */ public static final String KILL_APP_REASON_PERMISSIONS_REVOKED = @@ -80,6 +92,18 @@ public final class PermissionManager { @EnabledAfter(targetSdkVersion = S) public static final long CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS = 146211400; + /** + * Note: Changing this won't do anything on its own - you should also change the filtering in + * {@link #shouldTraceGrant}. + * + * @hide + */ + public static final boolean DEBUG_TRACE_GRANTS = false; + /** + * @hide + */ + public static final boolean DEBUG_TRACE_PERMISSION_UPDATES = false; + private final @NonNull Context mContext; private final IPackageManager mPackageManager; @@ -88,6 +112,9 @@ public final class PermissionManager { private final LegacyPermissionManager mLegacyPermissionManager; + private final ArrayMap<PackageManager.OnPermissionsChangedListener, + IOnPermissionsChangeListener> mPermissionListeners = new ArrayMap<>(); + private List<SplitPermissionInfo> mSplitPermissionInfos; /** @@ -107,6 +134,649 @@ public final class PermissionManager { } /** + * Retrieve all of the information we know about a particular permission. + * + * @param permissionName the fully qualified name (e.g. com.android.permission.LOGIN) of the + * permission you are interested in + * @param flags additional option flags to modify the data returned + * @return a {@link PermissionInfo} containing information about the permission, or {@code null} + * if not found + * + * @hide Pending API + */ + @Nullable + public PermissionInfo getPermissionInfo(@NonNull String permissionName, + @PackageManager.PermissionInfoFlags int flags) { + try { + final String packageName = mContext.getOpPackageName(); + return mPermissionManager.getPermissionInfo(permissionName, packageName, flags); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Query for all of the permissions associated with a particular group. + * + * @param groupName the fully qualified name (e.g. com.android.permission.LOGIN) of the + * permission group you are interested in. Use {@code null} to find all of the + * permissions not associated with a group + * @param flags additional option flags to modify the data returned + * @return a list of {@link PermissionInfo} containing information about all of the permissions + * in the given group, or {@code null} if the group is not found + * + * @hide Pending API + */ + @Nullable + public List<PermissionInfo> queryPermissionsByGroup(@NonNull String groupName, + @PackageManager.PermissionInfoFlags int flags) { + try { + final ParceledListSlice<PermissionInfo> parceledList = + mPermissionManager.queryPermissionsByGroup(groupName, flags); + if (parceledList == null) { + return null; + } + return parceledList.getList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Add a new dynamic permission to the system. For this to work, your package must have defined + * a permission tree through the + * {@link android.R.styleable#AndroidManifestPermissionTree <permission-tree>} tag in its + * manifest. A package can only add permissions to trees that were defined by either its own + * package or another with the same user id; a permission is in a tree if it matches the name of + * the permission tree + ".": for example, "com.foo.bar" is a member of the permission tree + * "com.foo". + * <p> + * It is good to make your permission tree name descriptive, because you are taking possession + * of that entire set of permission names. Thus, it must be under a domain you control, with a + * suffix that will not match any normal permissions that may be declared in any applications + * that are part of that domain. + * <p> + * New permissions must be added before any .apks are installed that use those permissions. + * Permissions you add through this method are remembered across reboots of the device. If the + * given permission already exists, the info you supply here will be used to update it. + * + * @param permissionInfo description of the permission to be added + * @param async whether the persistence of the permission should be asynchronous, allowing it to + * return quicker and batch a series of adds, at the expense of no guarantee the + * added permission will be retained if the device is rebooted before it is + * written. + * @return {@code true} if a new permission was created, {@code false} if an existing one was + * updated + * @throws SecurityException if you are not allowed to add the given permission name + * + * @see #removePermission(String) + * + * @hide Pending API + */ + public boolean addPermission(@NonNull PermissionInfo permissionInfo, boolean async) { + try { + return mPermissionManager.addPermission(permissionInfo, async); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Removes a permission that was previously added with + * {@link #addPermission(PermissionInfo, boolean)}. The same ownership rules apply -- you are + * only allowed to remove permissions that you are allowed to add. + * + * @param permissionName the name of the permission to remove + * @throws SecurityException if you are not allowed to remove the given permission name + * + * @see #addPermission(PermissionInfo, boolean) + * + * @hide Pending API + */ + public void removePermission(@NonNull String permissionName) { + try { + mPermissionManager.removePermission(permissionName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Retrieve all of the information we know about a particular group of permissions. + * + * @param groupName the fully qualified name (e.g. com.android.permission_group.APPS) of the + * permission you are interested in + * @param flags additional option flags to modify the data returned + * @return a {@link PermissionGroupInfo} containing information about the permission, or + * {@code null} if not found + * + * @hide Pending API + */ + @Nullable + public PermissionGroupInfo getPermissionGroupInfo(@NonNull String groupName, + @PackageManager.PermissionGroupInfoFlags int flags) { + try { + return mPermissionManager.getPermissionGroupInfo(groupName, flags); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Retrieve all of the known permission groups in the system. + * + * @param flags additional option flags to modify the data returned + * @return a list of {@link PermissionGroupInfo} containing information about all of the known + * permission groups + * + * @hide Pending API + */ + @NonNull + public List<PermissionGroupInfo> getAllPermissionGroups( + @PackageManager.PermissionGroupInfoFlags int flags) { + try { + final ParceledListSlice<PermissionGroupInfo> parceledList = + mPermissionManager.getAllPermissionGroups(flags); + if (parceledList == null) { + return Collections.emptyList(); + } + return parceledList.getList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Checks whether a particular permissions has been revoked for a package by policy. Typically + * the device owner or the profile owner may apply such a policy. The user cannot grant policy + * revoked permissions, hence the only way for an app to get such a permission is by a policy + * change. + * + * @param packageName the name of the package you are checking against + * @param permissionName the name of the permission you are checking for + * + * @return whether the permission is restricted by policy + * + * @hide Pending API + */ + @CheckResult + public boolean isPermissionRevokedByPolicy(@NonNull String packageName, + @NonNull String permissionName) { + try { + return mPermissionManager.isPermissionRevokedByPolicy(permissionName, packageName, + mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ + public static boolean shouldTraceGrant(String packageName, String permissionName, int userId) { + // To be modified when debugging + return false; + } + + /** + * Grant a runtime permission to an application which the application does not already have. The + * permission must have been requested by the application. If the application is not allowed to + * hold the permission, a {@link java.lang.SecurityException} is thrown. If the package or + * permission is invalid, a {@link java.lang.IllegalArgumentException} is thrown. + * <p> + * <strong>Note: </strong>Using this API requires holding + * {@code android.permission.GRANT_RUNTIME_PERMISSIONS} and if the user ID is not the current + * user {@code android.permission.INTERACT_ACROSS_USERS_FULL}. + * + * @param packageName the package to which to grant the permission + * @param permissionName the permission name to grant + * @param user the user for which to grant the permission + * + * @see #revokeRuntimePermission(String, String, android.os.UserHandle) + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) + //@SystemApi + public void grantRuntimePermission(@NonNull String packageName, + @NonNull String permissionName, @NonNull UserHandle user) { + if (DEBUG_TRACE_GRANTS + && shouldTraceGrant(packageName, permissionName, user.getIdentifier())) { + Log.i(LOG_TAG, "App " + mContext.getPackageName() + " is granting " + packageName + " " + + permissionName + " for user " + user.getIdentifier(), new RuntimeException()); + } + try { + mPermissionManager.grantRuntimePermission(packageName, permissionName, + user.getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Revoke a runtime permission that was previously granted by + * {@link #grantRuntimePermission(String, String, android.os.UserHandle)}. The permission must + * have been requested by and granted to the application. If the application is not allowed to + * hold the permission, a {@link java.lang.SecurityException} is thrown. If the package or + * permission is invalid, a {@link java.lang.IllegalArgumentException} is thrown. + * <p> + * <strong>Note: </strong>Using this API requires holding + * {@code android.permission.REVOKE_RUNTIME_PERMISSIONS} and if the user ID is not the current + * user {@code android.permission.INTERACT_ACROSS_USERS_FULL}. + * + * @param packageName the package from which to revoke the permission + * @param permName the permission name to revoke + * @param user the user for which to revoke the permission + * @param reason the reason for the revoke, or {@code null} for unspecified + * + * @see #grantRuntimePermission(String, String, android.os.UserHandle) + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) + //@SystemApi + public void revokeRuntimePermission(@NonNull String packageName, + @NonNull String permName, @NonNull UserHandle user, @Nullable String reason) { + if (DEBUG_TRACE_PERMISSION_UPDATES + && shouldTraceGrant(packageName, permName, user.getIdentifier())) { + Log.i(LOG_TAG, "App " + mContext.getPackageName() + " is revoking " + packageName + " " + + permName + " for user " + user.getIdentifier() + " with reason " + + reason, new RuntimeException()); + } + try { + mPermissionManager + .revokeRuntimePermission(packageName, permName, user.getIdentifier(), reason); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the state flags associated with a permission. + * + * @param packageName the package name for which to get the flags + * @param permissionName the permission for which to get the flags + * @param user the user for which to get permission flags + * @return the permission flags + * + * @hide + */ + @PackageManager.PermissionFlags + @RequiresPermission(anyOf = { + android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, + android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, + android.Manifest.permission.GET_RUNTIME_PERMISSIONS + }) + //@SystemApi + public int getPermissionFlags(@NonNull String packageName, @NonNull String permissionName, + @NonNull UserHandle user) { + try { + return mPermissionManager.getPermissionFlags(permissionName, packageName, + user.getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Updates the flags associated with a permission by replacing the flags in the specified mask + * with the provided flag values. + * + * @param packageName The package name for which to update the flags + * @param permissionName The permission for which to update the flags + * @param flagMask The flags which to replace + * @param flagValues The flags with which to replace + * @param user The user for which to update the permission flags + * + * @hide + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, + android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS + }) + //@SystemApi + public void updatePermissionFlags(@NonNull String packageName, @NonNull String permissionName, + @PackageManager.PermissionFlags int flagMask, + @PackageManager.PermissionFlags int flagValues, @NonNull UserHandle user) { + if (DEBUG_TRACE_PERMISSION_UPDATES && shouldTraceGrant(packageName, permissionName, + user.getIdentifier())) { + Log.i(LOG_TAG, "App " + mContext.getPackageName() + " is updating flags for " + + packageName + " " + permissionName + " for user " + + user.getIdentifier() + ": " + DebugUtils.flagsToString( + PackageManager.class, "FLAG_PERMISSION_", flagMask) + " := " + + DebugUtils.flagsToString(PackageManager.class, "FLAG_PERMISSION_", + flagValues), new RuntimeException()); + } + try { + final boolean checkAdjustPolicyFlagPermission = + mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q; + mPermissionManager.updatePermissionFlags(permissionName, packageName, flagMask, + flagValues, checkAdjustPolicyFlagPermission, user.getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the restricted permissions that have been allowlisted and the app is allowed to have + * them granted in their full form. + * <p> + * Permissions can be hard restricted which means that the app cannot hold them or soft + * restricted where the app can hold the permission but in a weaker form. Whether a permission + * is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard restricted} or + * {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted} depends on the permission + * declaration. Allowlisting a hard restricted permission allows for the to hold that permission + * and allowlisting a soft restricted permission allows the app to hold the permission in its + * full, unrestricted form. + * <p> + * There are four allowlists: + * <ol> + * <li> + * One for cases where the system permission policy allowlists a permission. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM} flag. Can only be + * accessed by pre-installed holders of a dedicated permission. + * <li> + * One for cases where the system allowlists the permission when upgrading from an OS version in + * which the permission was not restricted to an OS version in which the permission is + * restricted. This list corresponds to the + * {@link PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE} flag. Can be accessed by + * pre-installed holders of a dedicated permission or the installer on record. + * <li> + * One for cases where the installer of the package allowlists a permission. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER} flag. Can be + * accessed by pre-installed holders of a dedicated permission or the installer on record. + * <li> + * One for cases where the system exempts the permission when granting a role. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can be + * accessed by pre-installed holders of a dedicated permission. + * </ol> + * + * @param packageName the app for which to get allowlisted permissions + * @param allowlistFlag the flag to determine which allowlist to query. Only one flag can be + * passed. + * @return the allowlisted permissions that are on any of the allowlists you query for + * @throws SecurityException if you try to access a allowlist that you have no access to + * + * @see #addAllowlistedRestrictedPermission(String, String, int) + * @see #removeAllowlistedRestrictedPermission(String, String, int) + * @see PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM + * @see PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE + * @see PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER + * @see PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE + * + * @hide Pending API + */ + @NonNull + @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, + conditional = true) + public Set<String> getAllowlistedRestrictedPermissions(@NonNull String packageName, + @PackageManager.PermissionWhitelistFlags int allowlistFlag) { + try { + final List<String> allowlist = mPermissionManager.getWhitelistedRestrictedPermissions( + packageName, allowlistFlag, mContext.getUserId()); + if (allowlist == null) { + return Collections.emptySet(); + } + return new ArraySet<>(allowlist); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Adds a allowlisted restricted permission for an app. + * <p> + * Permissions can be hard restricted which means that the app cannot hold them or soft + * restricted where the app can hold the permission but in a weaker form. Whether a permission + * is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard restricted} or + * {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted} depends on the permission + * declaration. Allowlisting a hard restricted permission allows for the to hold that permission + * and allowlisting a soft restricted permission allows the app to hold the permission in its + * full, unrestricted form. + * <p>There are four allowlists: + * <ol> + * <li> + * One for cases where the system permission policy allowlists a permission. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM} flag. Can only be + * accessed by pre-installed holders of a dedicated permission. + * <li> + * One for cases where the system allowlists the permission when upgrading from an OS version in + * which the permission was not restricted to an OS version in which the permission is + * restricted. This list corresponds to the + * {@link PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE} flag. Can be accessed by + * pre-installed holders of a dedicated permission or the installer on record. + * <li> + * One for cases where the installer of the package allowlists a permission. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER} flag. Can be + * accessed by pre-installed holders of a dedicated permission or the installer on record. + * <li> + * One for cases where the system exempts the permission when granting a role. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can be + * accessed by pre-installed holders of a dedicated permission. + * </ol> + * <p> + * You need to specify the allowlists for which to set the allowlisted permissions which will + * clear the previous allowlisted permissions and replace them with the provided ones. + * + * @param packageName the app for which to get allowlisted permissions + * @param permissionName the allowlisted permission to add + * @param allowlistFlags the allowlists to which to add. Passing multiple flags updates all + * specified allowlists. + * @return whether the permission was added to the allowlist + * @throws SecurityException if you try to modify a allowlist that you have no access to. + * + * @see #getAllowlistedRestrictedPermissions(String, int) + * @see #removeAllowlistedRestrictedPermission(String, String, int) + * @see PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM + * @see PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE + * @see PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER + * @see PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE + * + * @hide Pending API + */ + @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, + conditional = true) + public boolean addAllowlistedRestrictedPermission(@NonNull String packageName, + @NonNull String permissionName, + @PackageManager.PermissionWhitelistFlags int allowlistFlags) { + try { + return mPermissionManager.addWhitelistedRestrictedPermission(packageName, + permissionName, allowlistFlags, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Removes a allowlisted restricted permission for an app. + * <p> + * Permissions can be hard restricted which means that the app cannot hold them or soft + * restricted where the app can hold the permission but in a weaker form. Whether a permission + * is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard restricted} or + * {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted} depends on the permission + * declaration. Allowlisting a hard restricted permission allows for the to hold that permission + * and allowlisting a soft restricted permission allows the app to hold the permission in its + * full, unrestricted form. + * <p>There are four allowlists: + * <ol> + * <li> + * One for cases where the system permission policy allowlists a permission. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM} flag. Can only be + * accessed by pre-installed holders of a dedicated permission. + * <li> + * One for cases where the system allowlists the permission when upgrading from an OS version in + * which the permission was not restricted to an OS version in which the permission is + * restricted. This list corresponds to the + * {@link PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE} flag. Can be accessed by + * pre-installed holders of a dedicated permission or the installer on record. + * <li> + * One for cases where the installer of the package allowlists a permission. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER} flag. Can be + * accessed by pre-installed holders of a dedicated permission or the installer on record. + * <li> + * One for cases where the system exempts the permission when granting a role. This list + * corresponds to the {@link PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can be + * accessed by pre-installed holders of a dedicated permission. + * </ol> + * <p> + * You need to specify the allowlists for which to set the allowlisted permissions which will + * clear the previous allowlisted permissions and replace them with the provided ones. + * + * @param packageName the app for which to get allowlisted permissions + * @param permissionName the allowlisted permission to remove + * @param allowlistFlags the allowlists from which to remove. Passing multiple flags updates all + * specified allowlists. + * @return whether the permission was removed from the allowlist + * @throws SecurityException if you try to modify a allowlist that you have no access to. + * + * @see #getAllowlistedRestrictedPermissions(String, int) + * @see #addAllowlistedRestrictedPermission(String, String, int) + * @see PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM + * @see PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE + * @see PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER + * @see PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE + * + * @hide Pending API + */ + @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, + conditional = true) + public boolean removeAllowlistedRestrictedPermission(@NonNull String packageName, + @NonNull String permissionName, + @PackageManager.PermissionWhitelistFlags int allowlistFlags) { + try { + return mPermissionManager.removeWhitelistedRestrictedPermission(packageName, + permissionName, allowlistFlags, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Checks whether an application is exempted from having its permissions be automatically + * revoked when the app is unused for an extended period of time. + * <p> + * Only the installer on record that installed the given package, or a holder of + * {@code WHITELIST_AUTO_REVOKE_PERMISSIONS} is allowed to call this. + * + * @param packageName the app for which to set exemption + * @return whether the app is exempted + * @throws SecurityException if you you have no access to this + * + * @see #setAutoRevokeExempted + * + * @hide Pending API + */ + @RequiresPermission(value = Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS, + conditional = true) + public boolean isAutoRevokeExempted(@NonNull String packageName) { + try { + return mPermissionManager.isAutoRevokeWhitelisted(packageName, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Marks an application exempted from having its permissions be automatically revoked when the + * app is unused for an extended period of time. + * <p> + * Only the installer on record that installed the given package is allowed to call this. + * <p> + * Packages start in exempted state, and it is the installer's responsibility to un-exempt the + * packages it installs, unless auto-revoking permissions from that package would cause + * breakages beyond having to re-request the permission(s). + * + * @param packageName the app for which to set exemption + * @param exempted whether the app should be exempted + * @return whether any change took effect + * @throws SecurityException if you you have no access to modify this + * + * @see #isAutoRevokeExempted + * + * @hide Pending API + */ + @RequiresPermission(value = Manifest.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS, + conditional = true) + public boolean setAutoRevokeExempted(@NonNull String packageName, boolean exempted) { + try { + return mPermissionManager.setAutoRevokeWhitelisted(packageName, exempted, + mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get whether you should show UI with rationale for requesting a permission. You should do this + * only if you do not have the permission and the context in which the permission is requested + * does not clearly communicate to the user what would be the benefit from grating this + * permission. + * + * @param permissionName a permission your app wants to request + * @return whether you can show permission rationale UI + * + * @hide + */ + //@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public boolean shouldShowRequestPermissionRationale(@NonNull String permissionName) { + try { + final String packageName = mContext.getPackageName(); + return mPermissionManager.shouldShowRequestPermissionRationale(permissionName, + packageName, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Add a listener for permission changes for installed packages. + * + * @param listener the listener to add + * + * @hide + */ + //@SystemApi + @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS) + public void addOnPermissionsChangeListener( + @NonNull PackageManager.OnPermissionsChangedListener listener) { + synchronized (mPermissionListeners) { + if (mPermissionListeners.get(listener) != null) { + return; + } + final OnPermissionsChangeListenerDelegate delegate = + new OnPermissionsChangeListenerDelegate(listener, Looper.getMainLooper()); + try { + mPermissionManager.addOnPermissionsChangeListener(delegate); + mPermissionListeners.put(listener, delegate); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Remove a listener for permission changes for installed packages. + * + * @param listener the listener to remove + * + * @hide + */ + //@SystemApi + @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS) + public void removeOnPermissionsChangeListener( + @NonNull PackageManager.OnPermissionsChangedListener listener) { + synchronized (mPermissionListeners) { + final IOnPermissionsChangeListener delegate = mPermissionListeners.get(listener); + if (delegate != null) { + try { + mPermissionManager.removeOnPermissionsChangeListener(delegate); + mPermissionListeners.remove(listener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + } + + /** * Gets the version of the runtime permission database. * * @return The database version, -1 when this is an upgrade from pre-Q, 0 when this is a fresh @@ -174,7 +844,7 @@ public final class PermissionManager { try { parcelableList = ActivityThread.getPermissionManager().getSplitPermissions(); } catch (RemoteException e) { - Slog.e(TAG, "Error getting split permissions", e); + Slog.e(LOG_TAG, "Error getting split permissions", e); return Collections.emptyList(); } @@ -403,10 +1073,11 @@ public final class PermissionManager { // permission this is. final int appId = UserHandle.getAppId(uid); if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) { - Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission); + Slog.w(LOG_TAG, "Missing ActivityManager; assuming " + uid + " holds " + + permission); return PackageManager.PERMISSION_GRANTED; } - Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold " + Slog.w(LOG_TAG, "Missing ActivityManager; assuming " + uid + " does not hold " + permission); return PackageManager.PERMISSION_DENIED; } @@ -586,4 +1257,35 @@ public final class PermissionManager { sPackageNamePermissionCache.disableLocal(); } + private final class OnPermissionsChangeListenerDelegate + extends IOnPermissionsChangeListener.Stub implements Handler.Callback{ + private static final int MSG_PERMISSIONS_CHANGED = 1; + + private final PackageManager.OnPermissionsChangedListener mListener; + private final Handler mHandler; + + public OnPermissionsChangeListenerDelegate( + PackageManager.OnPermissionsChangedListener listener, Looper looper) { + mListener = listener; + mHandler = new Handler(looper, this); + } + + @Override + public void onPermissionsChanged(int uid) { + mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget(); + } + + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_PERMISSIONS_CHANGED: { + final int uid = msg.arg1; + mListener.onPermissionsChanged(uid); + return true; + } + default: + return false; + } + } + } } diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index 6ef9e7e3d9b8..017f40521a81 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -16,18 +16,18 @@ package android.security.keymaster; -import android.hardware.keymint.Algorithm; -import android.hardware.keymint.BlockMode; -import android.hardware.keymint.Digest; -import android.hardware.keymint.ErrorCode; -import android.hardware.keymint.HardwareAuthenticatorType; -import android.hardware.keymint.KeyFormat; -import android.hardware.keymint.KeyOrigin; -import android.hardware.keymint.KeyPurpose; -import android.hardware.keymint.PaddingMode; -import android.hardware.keymint.SecurityLevel; -import android.hardware.keymint.Tag; -import android.hardware.keymint.TagType; +import android.hardware.security.keymint.Algorithm; +import android.hardware.security.keymint.BlockMode; +import android.hardware.security.keymint.Digest; +import android.hardware.security.keymint.ErrorCode; +import android.hardware.security.keymint.HardwareAuthenticatorType; +import android.hardware.security.keymint.KeyFormat; +import android.hardware.security.keymint.KeyOrigin; +import android.hardware.security.keymint.KeyPurpose; +import android.hardware.security.keymint.PaddingMode; +import android.hardware.security.keymint.SecurityLevel; +import android.hardware.security.keymint.Tag; +import android.hardware.security.keymint.TagType; import java.util.HashMap; import java.util.Map; diff --git a/core/java/android/service/textservice/OWNERS b/core/java/android/service/textservice/OWNERS index a637754ba17a..10b8b7637431 100644 --- a/core/java/android/service/textservice/OWNERS +++ b/core/java/android/service/textservice/OWNERS @@ -1,5 +1,3 @@ # Bug component: 34867 -ogunwale@google.com -roosa@google.com -yukawa@google.com +include ../../inputmethodservice/OWNERS
\ No newline at end of file diff --git a/core/java/android/util/ExceptionUtils.java b/core/java/android/util/ExceptionUtils.java index 1a397b39ef3c..4b511acc280f 100644 --- a/core/java/android/util/ExceptionUtils.java +++ b/core/java/android/util/ExceptionUtils.java @@ -98,4 +98,6 @@ public class ExceptionUtils { } return t; } + + }
\ No newline at end of file diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl index f209d88ac825..cac91a9f07d7 100644 --- a/core/java/android/view/IRecentsAnimationController.aidl +++ b/core/java/android/view/IRecentsAnimationController.aidl @@ -136,4 +136,13 @@ interface IRecentsAnimationController { * @return {@code true} when target removed successfully, {@code false} otherwise. */ boolean removeTask(int taskId); + + /** + * Detach navigation bar from app. + * + * The system reparents the leash of navigation bar to the app when the recents animation starts + * and Launcher should call this method to let system restore the navigation bar to its + * original position when the quick switch gesture is finished. + */ + void detachNavigationBarFromApp(); } diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS index 5196c3e88eec..72fa4c39f1bc 100644 --- a/core/java/android/view/OWNERS +++ b/core/java/android/view/OWNERS @@ -8,6 +8,7 @@ nduca@google.com sumir@google.com ogunwale@google.com jjaggi@google.com +roosa@google.com # Display per-file Display*.java = file:/services/core/java/com/android/server/display/OWNERS diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 607888c81357..15adc5a0ec2f 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -239,7 +239,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall private static boolean useBlastAdapter(Context context) { ContentResolver contentResolver = context.getContentResolver(); return Settings.Global.getInt(contentResolver, - Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV, 1 /* default */) == 1; + Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV, 0 /* default */) == 1; } private final boolean mUseBlastAdapter; diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index 16fd383fa7ff..3c18b6b89af8 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -43,6 +43,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.IBinder.DeathRecipient; import android.os.RemoteException; +import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; import android.util.TimeUtils; @@ -334,15 +335,22 @@ public final class MainContentCaptureSession extends ContentCaptureSession { if (!mEvents.isEmpty() && eventType == TYPE_VIEW_TEXT_CHANGED) { final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1); - // TODO(b/121045053): check if flags match + // We merge two consecutive text change event, unless one of them clears the text. if (lastEvent.getType() == TYPE_VIEW_TEXT_CHANGED && lastEvent.getId().equals(event.getId())) { - if (sVerbose) { + boolean bothNonEmpty = !TextUtils.isEmpty(lastEvent.getText()) + && !TextUtils.isEmpty(event.getText()); + boolean equalContent = TextUtils.equals(lastEvent.getText(), event.getText()); + if (equalContent) { + addEvent = false; + } else if (bothNonEmpty) { + lastEvent.mergeEvent(event); + addEvent = false; + } + if (!addEvent && sVerbose) { Log.v(TAG, "Buffering VIEW_TEXT_CHANGED event, updated text=" + getSanitizedString(event.getText())); } - lastEvent.mergeEvent(event); - addEvent = false; } } diff --git a/core/java/android/view/textservice/OWNERS b/core/java/android/view/textservice/OWNERS index a637754ba17a..582be8dc4594 100644 --- a/core/java/android/view/textservice/OWNERS +++ b/core/java/android/view/textservice/OWNERS @@ -1,5 +1,3 @@ # Bug component: 34867 -ogunwale@google.com -roosa@google.com -yukawa@google.com +include ../inputmethod/OWNERS diff --git a/core/java/android/widget/OWNERS b/core/java/android/widget/OWNERS index fbb975b806f1..718076b49f77 100644 --- a/core/java/android/widget/OWNERS +++ b/core/java/android/widget/OWNERS @@ -7,3 +7,5 @@ aurimas@google.com siyamed@google.com per-file TextView.java, EditText.java, Editor.java = siyamed@google.com, nona@google.com, clarabayarri@google.com + +per-file SpellChecker.java = file:../view/inputmethod/OWNERS diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java index 8012540ed314..254c2997fa65 100644 --- a/core/java/com/android/internal/util/LatencyTracker.java +++ b/core/java/com/android/internal/util/LatencyTracker.java @@ -86,6 +86,11 @@ public class LatencyTracker { */ public static final int ACTION_FACE_WAKE_AND_UNLOCK = 7; + /** + * Time between the swipe-up gesture and window drawn of recents activity. + */ + public static final int ACTION_START_RECENTS_ANIMATION = 8; + private static final String[] NAMES = new String[]{ "expand panel", "toggle recents", @@ -94,7 +99,9 @@ public class LatencyTracker { "check credential unlocked", "turn on screen", "rotate the screen", - "face wake-and-unlock"}; + "face wake-and-unlock", + "start recents-animation", + }; private static final int[] STATSD_ACTION = new int[]{ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL, @@ -105,6 +112,7 @@ public class LatencyTracker { FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TURN_ON_SCREEN, FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN, FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK, + FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION, }; private static LatencyTracker sLatencyTracker; @@ -170,6 +178,8 @@ public class LatencyTracker { return "ACTION_ROTATE_SCREEN"; case 8: return "ACTION_FACE_WAKE_AND_UNLOCK"; + case 9: + return "ACTION_START_RECENTS_ANIMATION"; default: throw new IllegalArgumentException("Invalid action"); } diff --git a/core/java/com/android/internal/view/OWNERS b/core/java/com/android/internal/view/OWNERS new file mode 100644 index 000000000000..99a76861c542 --- /dev/null +++ b/core/java/com/android/internal/view/OWNERS @@ -0,0 +1,5 @@ +# Bug component: 25700 + +file:/core/java/android/view/OWNERS + +per-file *Input* = file:/services/core/java/com/android/server/inputmethod/OWNERS
\ No newline at end of file diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 648ea390369f..ef7edc2f2dd2 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3969,6 +3969,12 @@ <permission android:name="android.permission.MANAGE_COMPANION_DEVICES" android:protectionLevel="signature" /> + <!-- Allows an application to subscribe to notifications about the presence status change + of their associated companion device + --> + <permission android:name="android.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE" + android:protectionLevel="normal" /> + <!-- @SystemApi Allows an application to use SurfaceFlinger's low level features. <p>Not for use by third-party applications. @hide diff --git a/core/res/res/drawable-car/car_switch_thumb.xml b/core/res/res/drawable-car/car_switch_thumb.xml index 03efc189aa95..66cf4438418d 100644 --- a/core/res/res/drawable-car/car_switch_thumb.xml +++ b/core/res/res/drawable-car/car_switch_thumb.xml @@ -14,12 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. --> - -<shape - xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="oval"> - <solid android:color="@color/car_switch"/> - <size - android:width="@dimen/car_seekbar_thumb_size" - android:height="@dimen/car_seekbar_thumb_size"/> -</shape> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:gravity="center_vertical|fill_horizontal" + android:top="@dimen/car_switch_thumb_margin_size" + android:bottom="@dimen/car_switch_thumb_margin_size"> + <shape android:shape="oval"> + <solid android:color="@color/car_switch"/> + <size + android:width="@dimen/car_switch_thumb_size" + android:height="@dimen/car_switch_thumb_size"/> + </shape> + </item> +</layer-list> diff --git a/core/res/res/drawable-car/car_switch_track.xml b/core/res/res/drawable-car/car_switch_track.xml new file mode 100644 index 000000000000..cb0b9beeeab6 --- /dev/null +++ b/core/res/res/drawable-car/car_switch_track.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:height="@dimen/car_touch_target_size_minus_one" + android:width="@dimen/car_touch_target_size_minus_one" + android:gravity="center"> + <selector> + <item android:state_focused="true" android:state_pressed="true"> + <shape android:shape="oval"> + <solid android:color="#8A94CBFF"/> + <stroke android:width="4dp" + android:color="#94CBFF"/> + </shape> + </item> + <item android:state_focused="true"> + <shape android:shape="oval"> + <solid android:color="#3D94CBFF"/> + <stroke android:width="8dp" + android:color="#94CBFF"/> + </shape> + </item> + </selector> + </item> + <item android:gravity="center_vertical|fill_horizontal" + android:left="@dimen/car_switch_track_margin_size" + android:right="@dimen/car_switch_track_margin_size"> + <shape + android:shape="rectangle" + android:tint="@color/switch_track_material"> + <corners android:radius="7dp" /> + <solid android:color="@color/white_disabled_material" /> + <size android:height="14dp" /> + <padding + android:right="@dimen/car_switch_track_margin_size" + android:left="@dimen/car_switch_track_margin_size"/> + </shape> + </item> +</layer-list> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 03ba83c6bd2e..cddb8b5802d0 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4574,6 +4574,6 @@ <!-- Indicates that default fitness tracker app needs to request sensor and location permissions. --> <bool name="config_trackerAppNeedsPermissions">false</bool> - <!-- Component with platform query permissions for AppSearch --> - <string name="config_defaultAppSearchPlatformQuerierComponent" translatable="false"></string> + <!-- Package with global data query permissions for AppSearch --> + <string name="config_globalAppSearchDataQuerierPackage" translatable="false"></string> </resources> diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml index 2c4f4c89ab81..c3cd80b1edda 100644 --- a/core/res/res/values/dimens_car.xml +++ b/core/res/res/values/dimens_car.xml @@ -84,6 +84,14 @@ <dimen name="car_button_radius">@dimen/car_radius_1</dimen> <dimen name="car_pill_button_size">56dp</dimen> <dimen name="car_touch_target_size">76dp</dimen> + <dimen name="car_touch_target_size_minus_one">75dp</dimen> + + <!-- Switch. --> + <!-- Thumb size + 2*thumb margin size must equal car_touch_target_size --> + <!-- 2 * Thumb size + 2*track margin size must equal car_touch_target_size --> + <dimen name="car_switch_thumb_size">24dp</dimen> + <dimen name="car_switch_thumb_margin_size">26dp</dimen> + <dimen name="car_switch_track_margin_size">14dp</dimen> <!-- Seekbar --> <dimen name="car_seekbar_height">6dp</dimen> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index aff0695bb14e..a2556a112941 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4116,8 +4116,8 @@ <java-symbol type="bool" name="config_trackerAppNeedsPermissions"/> - <!-- Component with platform query permissions for AppSearch --> - <java-symbol type="string" name="config_defaultAppSearchPlatformQuerierComponent" /> + <!-- Package with global data query permissions for AppSearch --> + <java-symbol type="string" name="config_globalAppSearchDataQuerierPackage" /> <!-- Color used by the accessibility focus rectangle --> <java-symbol type="color" name="accessibility_focus_highlight_color" /> diff --git a/core/tests/powertests/PowerStatsLoadTests/Android.bp b/core/tests/batterystatstests/BatteryStatsLoadTests/Android.bp index 66c91adc6540..ade97b81e775 100644 --- a/core/tests/powertests/PowerStatsLoadTests/Android.bp +++ b/core/tests/batterystatstests/BatteryStatsLoadTests/Android.bp @@ -1,5 +1,5 @@ android_test { - name: "PowerStatsLoadTests", + name: "BatteryStatsLoadTests", srcs: ["src/**/*.java"], static_libs: [ "androidx.test.rules", diff --git a/core/tests/powertests/PowerStatsLoadTests/AndroidManifest.xml b/core/tests/batterystatstests/BatteryStatsLoadTests/AndroidManifest.xml index 9cecaedf1380..adc20c6ae496 100644 --- a/core/tests/powertests/PowerStatsLoadTests/AndroidManifest.xml +++ b/core/tests/batterystatstests/BatteryStatsLoadTests/AndroidManifest.xml @@ -16,7 +16,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.core.powerstatsloadtests"> + package="com.android.frameworks.core.batterystatsloadtests"> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> @@ -27,7 +27,7 @@ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.frameworks.core.powerstatsloadtests" + android:targetPackage="com.android.frameworks.core.batterystatsloadtests" android:label="Power Stats Load Tests" /> <queries> diff --git a/core/tests/powertests/PowerStatsLoadTests/src/com/android/frameworks/core/powerstatsloadtests/ConnectivitySetupRule.java b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/ConnectivitySetupRule.java index ca2942647f08..1afc22b7406d 100644 --- a/core/tests/powertests/PowerStatsLoadTests/src/com/android/frameworks/core/powerstatsloadtests/ConnectivitySetupRule.java +++ b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/ConnectivitySetupRule.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.frameworks.core.powerstatsloadtests; +package com.android.frameworks.core.batterystatsloadtests; import static org.junit.Assert.assertEquals; diff --git a/core/tests/powertests/PowerStatsLoadTests/src/com/android/frameworks/core/powerstatsloadtests/PowerMetrics.java b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java index 88cb719add60..dbe5773a3107 100644 --- a/core/tests/powertests/PowerStatsLoadTests/src/com/android/frameworks/core/powerstatsloadtests/PowerMetrics.java +++ b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.frameworks.core.powerstatsloadtests; +package com.android.frameworks.core.batterystatsloadtests; import android.os.Process; diff --git a/core/tests/powertests/PowerStatsLoadTests/src/com/android/frameworks/core/powerstatsloadtests/PowerMetricsCollector.java b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java index a71559b5ad6b..254458cc8935 100644 --- a/core/tests/powertests/PowerStatsLoadTests/src/com/android/frameworks/core/powerstatsloadtests/PowerMetricsCollector.java +++ b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.frameworks.core.powerstatsloadtests; +package com.android.frameworks.core.batterystatsloadtests; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -106,6 +106,7 @@ public class PowerMetricsCollector implements TestRule { mContext = instrumentation.getContext(); mUid = Process.myUid(); mUserManager = mContext.getSystemService(UserManager.class); + // TODO(b/175324611): Use BatteryUsageStats instead mStatsHelper = new BatteryStatsHelper(mContext, false /* collectBatteryBroadcast */); mStatsHelper.create((Bundle) null); } diff --git a/core/tests/powertests/PowerStatsLoadTests/src/com/android/frameworks/core/powerstatsloadtests/SystemServiceCallLoadTest.java b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/SystemServiceCallLoadTest.java index 911ccba3ac78..488469d54f29 100644 --- a/core/tests/powertests/PowerStatsLoadTests/src/com/android/frameworks/core/powerstatsloadtests/SystemServiceCallLoadTest.java +++ b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/SystemServiceCallLoadTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.frameworks.core.powerstatsloadtests; +package com.android.frameworks.core.batterystatsloadtests; import static org.junit.Assert.assertNotNull; diff --git a/core/tests/powertests/PowerStatsLoadTests/src/com/android/frameworks/core/powerstatsloadtests/WiFiLoadTest.java b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/WiFiLoadTest.java index 90627192946d..27495da8d839 100644 --- a/core/tests/powertests/PowerStatsLoadTests/src/com/android/frameworks/core/powerstatsloadtests/WiFiLoadTest.java +++ b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/WiFiLoadTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.frameworks.core.powerstatsloadtests; +package com.android.frameworks.core.batterystatsloadtests; import android.util.Log; diff --git a/core/tests/powertests/PowerStatsViewer/Android.bp b/core/tests/batterystatstests/BatteryStatsViewer/Android.bp index a3dc4fb4ff74..1e0498be5800 100644 --- a/core/tests/powertests/PowerStatsViewer/Android.bp +++ b/core/tests/batterystatstests/BatteryStatsViewer/Android.bp @@ -1,5 +1,5 @@ android_test { - name: "PowerStatsViewer", + name: "BatteryStatsViewer", srcs: ["src/**/*.java"], defaults: ["SettingsLibDefaults"], static_libs: [ diff --git a/core/tests/powertests/PowerStatsViewer/AndroidManifest.xml b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml index 28ea05fca61e..edb1b108b7bc 100644 --- a/core/tests/powertests/PowerStatsViewer/AndroidManifest.xml +++ b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml @@ -16,7 +16,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.core.powerstatsviewer" + package="com.android.frameworks.core.batterystatsviewer" android:sharedUserId="android.uid.system"> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> @@ -24,9 +24,9 @@ <application android:theme="@style/Theme" - android:label="Power Stats Viewer"> - <activity android:name=".PowerStatsViewerActivity" - android:label="Power Stats Viewer" + android:label="Battery Stats Viewer"> + <activity android:name=".BatteryStatsViewerActivity" + android:label="Battery Stats Viewer" android:launchMode="singleTop" android:exported="true"> <intent-filter> @@ -35,7 +35,7 @@ </intent-filter> </activity> - <activity android:name=".PowerConsumerPickerActivity" - android:label="Select a power consumer"/> + <activity android:name=".BatteryConsumerPickerActivity" + android:label="Select a battery consumer"/> </application> </manifest> diff --git a/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_entry_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml index 1ced825adf31..1ced825adf31 100644 --- a/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_entry_layout.xml +++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml diff --git a/core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_info_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_info_layout.xml index fbd0ebd61bc7..fbd0ebd61bc7 100644 --- a/core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_info_layout.xml +++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_info_layout.xml diff --git a/core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_picker_activity_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_activity_layout.xml index ecc89f0cb33e..ecc89f0cb33e 100644 --- a/core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_picker_activity_layout.xml +++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_activity_layout.xml diff --git a/core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_picker_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_layout.xml index bea38c18c20b..bea38c18c20b 100644 --- a/core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_picker_layout.xml +++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_layout.xml diff --git a/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_viewer_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml index 238e238deeaa..e58a08fd362c 100644 --- a/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_viewer_layout.xml +++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml @@ -42,13 +42,13 @@ android:paddingStart="10dp" android:paddingEnd="10dp"> - <include layout="@layout/power_consumer_info_layout"/> + <include layout="@layout/battery_consumer_info_layout"/> </LinearLayout> </androidx.cardview.widget.CardView> <androidx.recyclerview.widget.RecyclerView - android:id="@+id/power_stats_data_view" + android:id="@+id/battery_consumer_data_view" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> @@ -59,7 +59,7 @@ android:layout_height="match_parent" android:gravity="center" android:visibility="gone" - android:text="No power stats available"/> + android:text="No battery stats available"/> </LinearLayout> <FrameLayout diff --git a/core/tests/powertests/PowerStatsViewer/res/values/styles.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/values/styles.xml index 629d729e7b9a..629d729e7b9a 100644 --- a/core/tests/powertests/PowerStatsViewer/res/values/styles.xml +++ b/core/tests/batterystatstests/BatteryStatsViewer/res/values/styles.xml diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java index 6d8e2c59be97..b077ea313b9d 100644 --- a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java +++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.frameworks.core.powerstatsviewer; +package com.android.frameworks.core.batterystatsviewer; import android.content.Context; import android.os.BatteryConsumer; @@ -30,7 +30,7 @@ import com.android.internal.os.BatteryStatsHelper; import java.util.ArrayList; import java.util.List; -public class PowerStatsData { +public class BatteryConsumerData { private static final String PACKAGE_CALENDAR_PROVIDER = "com.android.providers.calendar"; private static final String PACKAGE_MEDIA_PROVIDER = "com.android.providers.media"; private static final String PACKAGE_SYSTEMUI = "com.android.systemui"; @@ -58,11 +58,11 @@ public class PowerStatsData { public double total; } - private final PowerConsumerInfoHelper.PowerConsumerInfo mPowerConsumerInfo; + private final BatteryConsumerInfoHelper.BatteryConsumerInfo mBatteryConsumerInfo; private final List<Entry> mEntries = new ArrayList<>(); - public PowerStatsData(Context context, BatteryStatsHelper batteryStatsHelper, - BatteryUsageStats batteryUsageStats, String powerConsumerId) { + public BatteryConsumerData(Context context, BatteryStatsHelper batteryStatsHelper, + BatteryUsageStats batteryUsageStats, String batteryConsumerId) { List<BatterySipper> usageList = batteryStatsHelper.getUsageList(); BatteryStats batteryStats = batteryStatsHelper.getStats(); @@ -102,7 +102,7 @@ public class PowerStatsData { totalScreenPower = sipper.sumPower(); } - if (powerConsumerId(sipper).equals(powerConsumerId)) { + if (batteryConsumerId(sipper).equals(batteryConsumerId)) { requestedBatterySipper = sipper; } @@ -143,21 +143,20 @@ public class PowerStatsData { BatteryConsumer requestedBatteryConsumer = null; for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) { - if (powerConsumerId(consumer).equals(powerConsumerId)) { + if (batteryConsumerId(consumer).equals(batteryConsumerId)) { requestedBatteryConsumer = consumer; break; } } if (requestedBatterySipper == null) { - mPowerConsumerInfo = null; + mBatteryConsumerInfo = null; return; } - long totalScreenMeasuredEnergyUJ = batteryStats.getScreenOnEnergy(); - - mPowerConsumerInfo = PowerConsumerInfoHelper.makePowerConsumerInfo( + mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo( context.getPackageManager(), requestedBatterySipper); + long totalScreenMeasuredEnergyUJ = batteryStats.getScreenOnEnergy(); addEntry("Total power", EntryType.POWER, requestedBatterySipper.totalSmearedPowerMah, totalSmearedPowerMah); @@ -279,19 +278,19 @@ public class PowerStatsData { } } - public PowerConsumerInfoHelper.PowerConsumerInfo getPowerConsumerInfo() { - return mPowerConsumerInfo; + public BatteryConsumerInfoHelper.BatteryConsumerInfo getBatteryConsumerInfo() { + return mBatteryConsumerInfo; } public List<Entry> getEntries() { return mEntries; } - public static String powerConsumerId(BatterySipper sipper) { + public static String batteryConsumerId(BatterySipper sipper) { return sipper.drainType + "|" + sipper.userId + "|" + sipper.getUid(); } - public static String powerConsumerId(BatteryConsumer consumer) { + public static String batteryConsumerId(BatteryConsumer consumer) { if (consumer instanceof UidBatteryConsumer) { return BatterySipper.DrainType.APP + "|" + UserHandle.getUserId(((UidBatteryConsumer) consumer).getUid()) + "|" diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerInfoHelper.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java index 6fec2405b0c6..8ee6c604cb3e 100644 --- a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerInfoHelper.java +++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.frameworks.core.powerstatsviewer; +package com.android.frameworks.core.batterystatsviewer; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -26,11 +26,11 @@ import com.android.internal.os.BatterySipper; import java.util.Locale; -class PowerConsumerInfoHelper { +class BatteryConsumerInfoHelper { private static final String SYSTEM_SERVER_PACKAGE_NAME = "android"; - public static class PowerConsumerInfo { + public static class BatteryConsumerInfo { public String id; public CharSequence label; public double powerMah; @@ -40,10 +40,10 @@ class PowerConsumerInfoHelper { } @NonNull - public static PowerConsumerInfo makePowerConsumerInfo(PackageManager packageManager, + public static BatteryConsumerInfo makeBatteryConsumerInfo(PackageManager packageManager, @NonNull BatterySipper sipper) { - PowerConsumerInfo info = new PowerConsumerInfo(); - info.id = PowerStatsData.powerConsumerId(sipper); + BatteryConsumerInfo info = new BatteryConsumerInfo(); + info.id = BatteryConsumerData.batteryConsumerId(sipper); sipper.sumPower(); info.powerMah = sipper.totalSmearedPowerMah; switch (sipper.drainType) { diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerPickerActivity.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java index f56d113980c8..2db848b084a6 100644 --- a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerPickerActivity.java +++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.frameworks.core.powerstatsviewer; +package com.android.frameworks.core.batterystatsviewer; import android.content.Context; import android.content.Intent; @@ -34,14 +34,14 @@ import com.google.android.material.tabs.TabLayout; * Picker, showing a sorted lists of applications and other types of entities consuming power. * Returns the selected entity ID or null. */ -public class PowerConsumerPickerActivity extends FragmentActivity { +public class BatteryConsumerPickerActivity extends FragmentActivity { public static final ActivityResultContract<Void, String> CONTRACT = new ActivityResultContract<Void, String>() { @NonNull @Override public Intent createIntent(@NonNull Context context, Void aVoid) { - return new Intent(context, PowerConsumerPickerActivity.class); + return new Intent(context, BatteryConsumerPickerActivity.class); } @Override @@ -58,7 +58,7 @@ public class PowerConsumerPickerActivity extends FragmentActivity { super.onCreate(icicle); getActionBar().setDisplayHomeAsUpEnabled(true); - setContentView(R.layout.power_consumer_picker_activity_layout); + setContentView(R.layout.battery_consumer_picker_activity_layout); ViewPager viewPager = findViewById(R.id.pager); @@ -75,12 +75,12 @@ public class PowerConsumerPickerActivity extends FragmentActivity { public Fragment getItem(int position) { switch (position) { case 0: - return new PowerConsumerPickerFragment( - PowerConsumerPickerFragment.PICKER_TYPE_APP); + return new BatteryConsumerPickerFragment( + BatteryConsumerPickerFragment.PICKER_TYPE_APP); case 1: default: - return new PowerConsumerPickerFragment( - PowerConsumerPickerFragment.PICKER_TYPE_DRAIN); + return new BatteryConsumerPickerFragment( + BatteryConsumerPickerFragment.PICKER_TYPE_DRAIN); } } @@ -101,9 +101,9 @@ public class PowerConsumerPickerActivity extends FragmentActivity { tabLayout.setupWithViewPager(viewPager); } - public void setSelectedPowerConsumer(String id) { + public void setSelectedBatteryConsumer(String batteryConsumerId) { Intent intent = new Intent(); - intent.putExtra(Intent.EXTRA_RETURN_RESULT, id); + intent.putExtra(Intent.EXTRA_RETURN_RESULT, batteryConsumerId); setResult(RESULT_OK, intent); finish(); } diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerPickerFragment.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java index 25225b87f602..bb11fd598511 100644 --- a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerPickerFragment.java +++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.frameworks.core.powerstatsviewer; +package com.android.frameworks.core.batterystatsviewer; import android.content.Context; import android.content.pm.PackageManager; @@ -36,7 +36,7 @@ import androidx.loader.content.Loader; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.android.frameworks.core.powerstatsviewer.PowerConsumerInfoHelper.PowerConsumerInfo; +import com.android.frameworks.core.batterystatsviewer.BatteryConsumerInfoHelper.BatteryConsumerInfo; import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; import com.android.settingslib.utils.AsyncLoaderCompat; @@ -50,7 +50,7 @@ import java.util.Locale; * Picker, showing a sorted lists of applications or other types of entities consuming power. * Returns the selected entity ID or null. */ -public class PowerConsumerPickerFragment extends Fragment { +public class BatteryConsumerPickerFragment extends Fragment { private static final String TAG = "AppPicker"; public static final String PICKER_TYPE = "pickertype"; @@ -58,53 +58,53 @@ public class PowerConsumerPickerFragment extends Fragment { public static final int PICKER_TYPE_APP = 0; public static final int PICKER_TYPE_DRAIN = 1; - private PowerConsumerListAdapter mPowerConsumerListAdapter; + private BatteryConsumerListAdapter mBatteryConsumerListAdapter; private RecyclerView mAppList; private View mLoadingView; - private interface OnPowerConsumerSelectedListener { - void onPowerConsumerSelected(String uid); + private interface OnBatteryConsumerSelectedListener { + void onBatteryConsumerSelected(String batteryConsumerId); } - public PowerConsumerPickerFragment(int pickerType) { + public BatteryConsumerPickerFragment(int pickerType) { Bundle args = new Bundle(); args.putInt(PICKER_TYPE, pickerType); setArguments(args); } - public PowerConsumerPickerFragment() { + public BatteryConsumerPickerFragment() { } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.power_consumer_picker_layout, container, false); + View view = inflater.inflate(R.layout.battery_consumer_picker_layout, container, false); mLoadingView = view.findViewById(R.id.loading_view); mAppList = view.findViewById(R.id.list_view); mAppList.setLayoutManager(new LinearLayoutManager(getContext())); - mPowerConsumerListAdapter = new PowerConsumerListAdapter( - PowerConsumerPickerFragment.this::setSelectedPowerConsumer); - mAppList.setAdapter(mPowerConsumerListAdapter); + mBatteryConsumerListAdapter = new BatteryConsumerListAdapter( + BatteryConsumerPickerFragment.this::setSelectedBatteryConsumer); + mAppList.setAdapter(mBatteryConsumerListAdapter); LoaderManager.getInstance(this).initLoader(0, getArguments(), - new PowerConsumerListLoaderCallbacks()); + new BatteryConsumerListLoaderCallbacks()); return view; } - public void setSelectedPowerConsumer(String id) { - ((PowerConsumerPickerActivity) getActivity()).setSelectedPowerConsumer(id); + public void setSelectedBatteryConsumer(String id) { + ((BatteryConsumerPickerActivity) getActivity()).setSelectedBatteryConsumer(id); } - private static class PowerConsumerListLoader extends - AsyncLoaderCompat<List<PowerConsumerInfo>> { + private static class BatteryConsumerListLoader extends + AsyncLoaderCompat<List<BatteryConsumerInfo>> { private final BatteryStatsHelper mStatsHelper; private final int mPickerType; private final UserManager mUserManager; private final PackageManager mPackageManager; - PowerConsumerListLoader(Context context, int pickerType) { + BatteryConsumerListLoader(Context context, int pickerType) { super(context); mUserManager = context.getSystemService(UserManager.class); mStatsHelper = new BatteryStatsHelper(context, false /* collectBatteryBroadcast */); @@ -115,8 +115,8 @@ public class PowerConsumerPickerFragment extends Fragment { } @Override - public List<PowerConsumerInfo> loadInBackground() { - List<PowerConsumerInfoHelper.PowerConsumerInfo> powerConsumerList = new ArrayList<>(); + public List<BatteryConsumerInfo> loadInBackground() { + List<BatteryConsumerInfo> batteryConsumerList = new ArrayList<>(); mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId()); @@ -135,74 +135,75 @@ public class PowerConsumerPickerFragment extends Fragment { } } - powerConsumerList.add( - PowerConsumerInfoHelper.makePowerConsumerInfo(mPackageManager, sipper)); + batteryConsumerList.add( + BatteryConsumerInfoHelper.makeBatteryConsumerInfo(mPackageManager, sipper)); } - powerConsumerList.sort( - Comparator.comparing((PowerConsumerInfo a) -> a.powerMah).reversed()); - return powerConsumerList; + batteryConsumerList.sort( + Comparator.comparing((BatteryConsumerInfo a) -> a.powerMah).reversed()); + return batteryConsumerList; } @Override - protected void onDiscardResult(List<PowerConsumerInfo> result) { + protected void onDiscardResult(List<BatteryConsumerInfo> result) { } } - private class PowerConsumerListLoaderCallbacks implements - LoaderManager.LoaderCallbacks<List<PowerConsumerInfo>> { + private class BatteryConsumerListLoaderCallbacks implements + LoaderManager.LoaderCallbacks<List<BatteryConsumerInfo>> { @NonNull @Override - public Loader<List<PowerConsumerInfo>> onCreateLoader(int id, Bundle args) { - return new PowerConsumerListLoader(getContext(), args.getInt(PICKER_TYPE)); + public Loader<List<BatteryConsumerInfo>> onCreateLoader(int id, Bundle args) { + return new BatteryConsumerListLoader(getContext(), args.getInt(PICKER_TYPE)); } @Override - public void onLoadFinished(@NonNull Loader<List<PowerConsumerInfo>> loader, - List<PowerConsumerInfoHelper.PowerConsumerInfo> powerConsumerList) { - mPowerConsumerListAdapter.setPowerConsumerList(powerConsumerList); + public void onLoadFinished(@NonNull Loader<List<BatteryConsumerInfo>> loader, + List<BatteryConsumerInfo> batteryConsumerList) { + mBatteryConsumerListAdapter.setBatteryConsumerList(batteryConsumerList); mAppList.setVisibility(View.VISIBLE); mLoadingView.setVisibility(View.GONE); } @Override public void onLoaderReset( - @NonNull Loader<List<PowerConsumerInfoHelper.PowerConsumerInfo>> loader) { + @NonNull Loader<List<BatteryConsumerInfo>> loader) { } } - public class PowerConsumerListAdapter extends RecyclerView.Adapter<PowerConsumerViewHolder> { - private final OnPowerConsumerSelectedListener mListener; - private List<PowerConsumerInfo> mPowerConsumerList; + public class BatteryConsumerListAdapter extends + RecyclerView.Adapter<BatteryConsumerViewHolder> { + private final OnBatteryConsumerSelectedListener mListener; + private List<BatteryConsumerInfo> mBatteryConsumerList; - public PowerConsumerListAdapter(OnPowerConsumerSelectedListener listener) { + public BatteryConsumerListAdapter(OnBatteryConsumerSelectedListener listener) { mListener = listener; } - void setPowerConsumerList(List<PowerConsumerInfo> powerConsumerList) { - mPowerConsumerList = powerConsumerList; + void setBatteryConsumerList(List<BatteryConsumerInfo> batteryConsumerList) { + mBatteryConsumerList = batteryConsumerList; notifyDataSetChanged(); } @Override public int getItemCount() { - return mPowerConsumerList.size(); + return mBatteryConsumerList.size(); } @NonNull @Override - public PowerConsumerViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, + public BatteryConsumerViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) { LayoutInflater layoutInflater = LayoutInflater.from(viewGroup.getContext()); - View view = layoutInflater.inflate(R.layout.power_consumer_info_layout, viewGroup, + View view = layoutInflater.inflate(R.layout.battery_consumer_info_layout, viewGroup, false); - return new PowerConsumerViewHolder(view, mListener); + return new BatteryConsumerViewHolder(view, mListener); } @Override - public void onBindViewHolder(@NonNull PowerConsumerViewHolder viewHolder, int position) { - PowerConsumerInfoHelper.PowerConsumerInfo item = mPowerConsumerList.get(position); + public void onBindViewHolder(@NonNull BatteryConsumerViewHolder viewHolder, int position) { + BatteryConsumerInfo item = mBatteryConsumerList.get(position); viewHolder.id = item.id; viewHolder.titleView.setText(item.label); if (item.details != null) { @@ -225,9 +226,9 @@ public class PowerConsumerPickerFragment extends Fragment { } // View Holder used when displaying apps - public static class PowerConsumerViewHolder extends RecyclerView.ViewHolder + public static class BatteryConsumerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { - private final OnPowerConsumerSelectedListener mListener; + private final OnBatteryConsumerSelectedListener mListener; public String id; public TextView titleView; @@ -236,7 +237,7 @@ public class PowerConsumerPickerFragment extends Fragment { public TextView packagesView; public TextView powerView; - PowerConsumerViewHolder(View view, OnPowerConsumerSelectedListener listener) { + BatteryConsumerViewHolder(View view, OnBatteryConsumerSelectedListener listener) { super(view); mListener = listener; view.setOnClickListener(this); @@ -250,7 +251,7 @@ public class PowerConsumerPickerFragment extends Fragment { @Override public void onClick(View v) { - mListener.onPowerConsumerSelected(id); + mListener.onBatteryConsumerSelected(id); } } } diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java index 91533913e35d..4978010f8591 100644 --- a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java +++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.frameworks.core.powerstatsviewer; +package com.android.frameworks.core.batterystatsviewer; import android.content.Context; import android.content.SharedPreferences; @@ -47,25 +47,25 @@ import java.util.Collections; import java.util.List; import java.util.Locale; -public class PowerStatsViewerActivity extends ComponentActivity { - private static final int POWER_STATS_REFRESH_RATE_MILLIS = 60 * 1000; - public static final String PREF_SELECTED_POWER_CONSUMER = "powerConsumerId"; +public class BatteryStatsViewerActivity extends ComponentActivity { + private static final int BATTERY_STATS_REFRESH_RATE_MILLIS = 60 * 1000; + public static final String PREF_SELECTED_BATTERY_CONSUMER = "batteryConsumerId"; public static final int LOADER_BATTERY_STATS_HELPER = 0; public static final int LOADER_BATTERY_USAGE_STATS = 1; - private PowerStatsDataAdapter mPowerStatsDataAdapter; - private Runnable mPowerStatsRefresh = this::periodicPowerStatsRefresh; + private BatteryStatsDataAdapter mBatteryStatsDataAdapter; + private Runnable mBatteryStatsRefresh = this::periodicBatteryStatsRefresh; private SharedPreferences mSharedPref; - private String mPowerConsumerId; + private String mBatteryConsumerId; private TextView mTitleView; private TextView mDetailsView; private ImageView mIconView; private TextView mPackagesView; - private RecyclerView mPowerStatsDataView; + private RecyclerView mBatteryConsumerDataView; private View mLoadingView; private View mEmptyView; private ActivityResultLauncher<Void> mStartAppPicker = registerForActivityResult( - PowerConsumerPickerActivity.CONTRACT, this::onApplicationSelected); + BatteryConsumerPickerActivity.CONTRACT, this::onApplicationSelected); private BatteryStatsHelper mBatteryStatsHelper; private BatteryUsageStats mBatteryUsageStats; @@ -75,7 +75,7 @@ public class PowerStatsViewerActivity extends ComponentActivity { mSharedPref = getPreferences(Context.MODE_PRIVATE); - setContentView(R.layout.power_stats_viewer_layout); + setContentView(R.layout.battery_stats_viewer_layout); View appCard = findViewById(R.id.app_card); appCard.setOnClickListener((e) -> startAppPicker()); @@ -85,17 +85,17 @@ public class PowerStatsViewerActivity extends ComponentActivity { mIconView = findViewById(android.R.id.icon); mPackagesView = findViewById(R.id.packages); - mPowerStatsDataView = findViewById(R.id.power_stats_data_view); - mPowerStatsDataView.setLayoutManager(new LinearLayoutManager(this)); - mPowerStatsDataAdapter = new PowerStatsDataAdapter(); - mPowerStatsDataView.setAdapter(mPowerStatsDataAdapter); + mBatteryConsumerDataView = findViewById(R.id.battery_consumer_data_view); + mBatteryConsumerDataView.setLayoutManager(new LinearLayoutManager(this)); + mBatteryStatsDataAdapter = new BatteryStatsDataAdapter(); + mBatteryConsumerDataView.setAdapter(mBatteryStatsDataAdapter); mLoadingView = findViewById(R.id.loading_view); mEmptyView = findViewById(R.id.empty_view); - mPowerConsumerId = mSharedPref.getString(PREF_SELECTED_POWER_CONSUMER, null); - loadPowerStats(); - if (mPowerConsumerId == null) { + mBatteryConsumerId = mSharedPref.getString(PREF_SELECTED_BATTERY_CONSUMER, null); + loadBatteryStats(); + if (mBatteryConsumerId == null) { startAppPicker(); } } @@ -103,38 +103,40 @@ public class PowerStatsViewerActivity extends ComponentActivity { @Override protected void onResume() { super.onResume(); - periodicPowerStatsRefresh(); + periodicBatteryStatsRefresh(); } @Override protected void onPause() { super.onPause(); - getMainThreadHandler().removeCallbacks(mPowerStatsRefresh); + getMainThreadHandler().removeCallbacks(mBatteryStatsRefresh); } private void startAppPicker() { mStartAppPicker.launch(null); } - private void onApplicationSelected(String powerConsumerId) { - if (powerConsumerId == null) { - if (mPowerConsumerId == null) { + private void onApplicationSelected(String batteryConsumerId) { + if (batteryConsumerId == null) { + if (mBatteryConsumerId == null) { finish(); } } else { - mPowerConsumerId = powerConsumerId; - mSharedPref.edit().putString(PREF_SELECTED_POWER_CONSUMER, mPowerConsumerId).apply(); + mBatteryConsumerId = batteryConsumerId; + mSharedPref.edit() + .putString(PREF_SELECTED_BATTERY_CONSUMER, mBatteryConsumerId) + .apply(); mLoadingView.setVisibility(View.VISIBLE); - loadPowerStats(); + loadBatteryStats(); } } - private void periodicPowerStatsRefresh() { - loadPowerStats(); - getMainThreadHandler().postDelayed(mPowerStatsRefresh, POWER_STATS_REFRESH_RATE_MILLIS); + private void periodicBatteryStatsRefresh() { + loadBatteryStats(); + getMainThreadHandler().postDelayed(mBatteryStatsRefresh, BATTERY_STATS_REFRESH_RATE_MILLIS); } - private void loadPowerStats() { + private void loadBatteryStats() { LoaderManager loaderManager = LoaderManager.getInstance(this); loaderManager.restartLoader(LOADER_BATTERY_STATS_HELPER, null, new BatteryStatsHelperLoaderCallbacks()); @@ -171,7 +173,7 @@ public class PowerStatsViewerActivity extends ComponentActivity { @NonNull @Override public Loader<BatteryStatsHelper> onCreateLoader(int id, Bundle args) { - return new BatteryStatsHelperLoader(PowerStatsViewerActivity.this); + return new BatteryStatsHelperLoader(BatteryStatsViewerActivity.this); } @Override @@ -207,7 +209,7 @@ public class PowerStatsViewerActivity extends ComponentActivity { @NonNull @Override public Loader<BatteryUsageStats> onCreateLoader(int id, Bundle args) { - return new BatteryUsageStatsLoader(PowerStatsViewerActivity.this); + return new BatteryUsageStatsLoader(BatteryStatsViewerActivity.this); } @Override @@ -223,60 +225,60 @@ public class PowerStatsViewerActivity extends ComponentActivity { public void onBatteryStatsHelperLoaded(BatteryStatsHelper batteryStatsHelper) { mBatteryStatsHelper = batteryStatsHelper; - onPowerStatsDataLoaded(); + onBatteryStatsDataLoaded(); } private void onBatteryUsageStatsLoaded(BatteryUsageStats batteryUsageStats) { mBatteryUsageStats = batteryUsageStats; - onPowerStatsDataLoaded(); + onBatteryStatsDataLoaded(); } - public void onPowerStatsDataLoaded() { + public void onBatteryStatsDataLoaded() { if (mBatteryStatsHelper == null || mBatteryUsageStats == null) { return; } - PowerStatsData powerStatsData = new PowerStatsData(this, mBatteryStatsHelper, - mBatteryUsageStats, mPowerConsumerId); + BatteryConsumerData batteryConsumerData = new BatteryConsumerData(this, mBatteryStatsHelper, + mBatteryUsageStats, mBatteryConsumerId); - PowerConsumerInfoHelper.PowerConsumerInfo - powerConsumerInfo = powerStatsData.getPowerConsumerInfo(); - if (powerConsumerInfo == null) { - mTitleView.setText("Power consumer not found"); + BatteryConsumerInfoHelper.BatteryConsumerInfo + batteryConsumerInfo = batteryConsumerData.getBatteryConsumerInfo(); + if (batteryConsumerInfo == null) { + mTitleView.setText("Battery consumer not found"); mPackagesView.setVisibility(View.GONE); } else { - mTitleView.setText(powerConsumerInfo.label); - if (powerConsumerInfo.details != null) { - mDetailsView.setText(powerConsumerInfo.details); + mTitleView.setText(batteryConsumerInfo.label); + if (batteryConsumerInfo.details != null) { + mDetailsView.setText(batteryConsumerInfo.details); mDetailsView.setVisibility(View.VISIBLE); } else { mDetailsView.setVisibility(View.GONE); } mIconView.setImageDrawable( - powerConsumerInfo.iconInfo.loadIcon(getPackageManager())); + batteryConsumerInfo.iconInfo.loadIcon(getPackageManager())); - if (powerConsumerInfo.packages != null) { - mPackagesView.setText(powerConsumerInfo.packages); + if (batteryConsumerInfo.packages != null) { + mPackagesView.setText(batteryConsumerInfo.packages); mPackagesView.setVisibility(View.VISIBLE); } else { mPackagesView.setVisibility(View.GONE); } } - mPowerStatsDataAdapter.setEntries(powerStatsData.getEntries()); - if (powerStatsData.getEntries().isEmpty()) { + mBatteryStatsDataAdapter.setEntries(batteryConsumerData.getEntries()); + if (batteryConsumerData.getEntries().isEmpty()) { mEmptyView.setVisibility(View.VISIBLE); - mPowerStatsDataView.setVisibility(View.GONE); + mBatteryConsumerDataView.setVisibility(View.GONE); } else { mEmptyView.setVisibility(View.GONE); - mPowerStatsDataView.setVisibility(View.VISIBLE); + mBatteryConsumerDataView.setVisibility(View.VISIBLE); } mLoadingView.setVisibility(View.GONE); } - private static class PowerStatsDataAdapter extends - RecyclerView.Adapter<PowerStatsDataAdapter.ViewHolder> { + private static class BatteryStatsDataAdapter extends + RecyclerView.Adapter<BatteryStatsDataAdapter.ViewHolder> { public static class ViewHolder extends RecyclerView.ViewHolder { public TextView titleTextView; public TextView amountTextView; @@ -291,9 +293,9 @@ public class PowerStatsViewerActivity extends ComponentActivity { } } - private List<PowerStatsData.Entry> mEntries = Collections.emptyList(); + private List<BatteryConsumerData.Entry> mEntries = Collections.emptyList(); - public void setEntries(List<PowerStatsData.Entry> entries) { + public void setEntries(List<BatteryConsumerData.Entry> entries) { mEntries = entries; notifyDataSetChanged(); } @@ -307,14 +309,14 @@ public class PowerStatsViewerActivity extends ComponentActivity { @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int position) { LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); - View itemView = layoutInflater.inflate(R.layout.power_stats_entry_layout, parent, + View itemView = layoutInflater.inflate(R.layout.battery_consumer_entry_layout, parent, false); return new ViewHolder(itemView); } @Override public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) { - PowerStatsData.Entry entry = mEntries.get(position); + BatteryConsumerData.Entry entry = mEntries.get(position); switch (entry.entryType) { case POWER: viewHolder.titleTextView.setText(entry.title); diff --git a/core/tests/powertests/OWNERS b/core/tests/batterystatstests/OWNERS index c22f6a4bbbf6..c22f6a4bbbf6 100644 --- a/core/tests/powertests/OWNERS +++ b/core/tests/batterystatstests/OWNERS diff --git a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java index 95da532045ac..4b0ed65e5fde 100644 --- a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java +++ b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java @@ -90,7 +90,7 @@ public class ApplicationPackageManagerTest extends TestCase { private boolean mAllow3rdPartyOnInternal = true; public MockedApplicationPackageManager() { - super(null, null, null); + super(null, null); } public void setForceAllowOnExternal(boolean forceAllowOnExternal) { diff --git a/data/etc/car/com.android.car.provision.xml b/data/etc/car/com.android.car.provision.xml index 7e77848ec337..4fd9cae53bd7 100644 --- a/data/etc/car/com.android.car.provision.xml +++ b/data/etc/car/com.android.car.provision.xml @@ -19,6 +19,7 @@ <permission name="android.car.permission.CAR_POWERTRAIN"/> <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.INTERACT_ACROSS_USERS_FULL"/> + <permission name="android.permission.MANAGE_USERS"/> <permission name="android.permission.MASTER_CLEAR"/> <permission name="android.permission.QUERY_ALL_PACKAGES"/> <permission name="android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"/> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 75b3babbc3a2..d8a735c78ca3 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1063,6 +1063,12 @@ "group": "WM_DEBUG_TASKS", "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" }, + "-856590985": { + "message": "dcTarget: %s mImeRequester: %s", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + }, "-856025122": { "message": "SURFACE transparentRegionHint=%s: %s", "level": "INFO", @@ -1711,12 +1717,6 @@ "group": "WM_SHOW_TRANSACTIONS", "at": "com\/android\/server\/wm\/Session.java" }, - "-49129622": { - "message": "performLayout: Activity exiting now removed %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/TaskDisplayArea.java" - }, "-33096143": { "message": "applyAnimation: transition animation is disabled or skipped. container=%s", "level": "VERBOSE", @@ -1771,6 +1771,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "44438983": { + "message": "performLayout: Activity exiting now removed %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "45285419": { "message": "startingWindow was set but startingSurface==null, couldn't remove", "level": "VERBOSE", @@ -1831,12 +1837,6 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowContextListenerController.java" }, - "91350919": { - "message": "Attempted to set IME flag to a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, "94402792": { "message": "Moving to RESUMED: %s (in existing)", "level": "VERBOSE", @@ -2383,12 +2383,6 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "632168013": { - "message": "dcTarget: %s mImeTargetFromIme: %s", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" - }, "633654009": { "message": "SURFACE POS (setPositionInTransaction) @ (%f,%f): %s", "level": "INFO", diff --git a/keystore/java/android/security/KeyStoreOperation.java b/keystore/java/android/security/KeyStoreOperation.java index 49a48871fd30..7ea9e1438845 100644 --- a/keystore/java/android/security/KeyStoreOperation.java +++ b/keystore/java/android/security/KeyStoreOperation.java @@ -17,7 +17,7 @@ package android.security; import android.annotation.NonNull; -import android.hardware.keymint.KeyParameter; +import android.hardware.security.keymint.KeyParameter; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.security.keymaster.KeymasterDefs; diff --git a/keystore/java/android/security/KeyStoreSecurityLevel.java b/keystore/java/android/security/KeyStoreSecurityLevel.java index 7c3de8bee475..3ef4aa5b7ec3 100644 --- a/keystore/java/android/security/KeyStoreSecurityLevel.java +++ b/keystore/java/android/security/KeyStoreSecurityLevel.java @@ -18,7 +18,7 @@ package android.security; import android.annotation.NonNull; import android.app.compat.CompatChanges; -import android.hardware.keymint.KeyParameter; +import android.hardware.security.keymint.KeyParameter; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.security.keystore.BackendBusyException; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java index 69c7a2589d6f..0775a1a99886 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java @@ -17,7 +17,7 @@ package android.security.keystore2; import android.annotation.NonNull; -import android.hardware.keymint.KeyParameter; +import android.hardware.security.keymint.KeyParameter; import android.security.keymaster.KeymasterDefs; import android.security.keystore.ArrayUtils; import android.security.keystore.KeyProperties; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java index 2b5f6c31607b..bc56f015f3bd 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java @@ -18,7 +18,7 @@ package android.security.keystore2; import android.annotation.NonNull; import android.annotation.Nullable; -import android.hardware.keymint.KeyParameter; +import android.hardware.security.keymint.KeyParameter; import android.security.KeyStoreException; import android.security.KeyStoreOperation; import android.security.keymaster.KeymasterDefs; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java index 18d26922f1ae..a3b04abfba3f 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java @@ -19,7 +19,7 @@ package android.security.keystore2; import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; -import android.hardware.keymint.KeyParameter; +import android.hardware.security.keymint.KeyParameter; import android.security.KeyStoreException; import android.security.KeyStoreOperation; import android.security.keymaster.KeymasterDefs; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java index 2250c89aac41..d1ef1df817e6 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java @@ -17,7 +17,7 @@ package android.security.keystore2; import android.annotation.NonNull; -import android.hardware.keymint.KeyParameter; +import android.hardware.security.keymint.KeyParameter; import android.security.KeyStoreException; import android.security.KeyStoreOperation; import android.security.keymaster.KeymasterDefs; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java index eea45c287622..8475ad9fd57b 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java @@ -16,7 +16,7 @@ package android.security.keystore2; -import android.hardware.keymint.KeyParameter; +import android.hardware.security.keymint.KeyParameter; import android.security.KeyStoreException; import android.security.KeyStoreOperation; import android.security.keymaster.KeymasterDefs; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java index 479fd8a6a73a..233f352989ab 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java @@ -16,8 +16,8 @@ package android.security.keystore2; -import android.hardware.keymint.KeyParameter; -import android.hardware.keymint.SecurityLevel; +import android.hardware.security.keymint.KeyParameter; +import android.hardware.security.keymint.SecurityLevel; import android.security.KeyStore2; import android.security.KeyStoreSecurityLevel; import android.security.keymaster.KeymasterArguments; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java index 61725e3e8c24..df0e1462a492 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -18,8 +18,8 @@ package android.security.keystore2; import android.annotation.NonNull; import android.annotation.Nullable; -import android.hardware.keymint.KeyParameter; -import android.hardware.keymint.SecurityLevel; +import android.hardware.security.keymint.KeyParameter; +import android.hardware.security.keymint.SecurityLevel; import android.os.Build; import android.security.KeyPairGeneratorSpec; import android.security.KeyStore2; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java index 2686ddc20c1d..951f91887894 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java @@ -18,7 +18,7 @@ package android.security.keystore2; import android.annotation.NonNull; import android.annotation.Nullable; -import android.hardware.keymint.KeyParameter; +import android.hardware.security.keymint.KeyParameter; import android.security.keymaster.KeymasterDefs; import android.security.keystore.KeyProperties; import android.security.keystore.KeymasterUtils; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java index 444dad4cffbe..ab7559116a41 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java @@ -17,7 +17,7 @@ package android.security.keystore2; import android.annotation.NonNull; -import android.hardware.keymint.KeyParameter; +import android.hardware.security.keymint.KeyParameter; import android.security.keymaster.KeymasterDefs; import android.security.keystore.KeyProperties; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java index a168f8feb3db..9b4f01e744f7 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java @@ -18,7 +18,7 @@ package android.security.keystore2; import android.annotation.CallSuper; import android.annotation.NonNull; -import android.hardware.keymint.KeyParameter; +import android.hardware.security.keymint.KeyParameter; import android.security.KeyStoreException; import android.security.KeyStoreOperation; import android.security.keymaster.KeymasterDefs; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java index 9790a4ae5b65..aca531458382 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java @@ -18,9 +18,9 @@ package android.security.keystore2; import android.annotation.NonNull; import android.hardware.biometrics.BiometricManager; -import android.hardware.keymint.HardwareAuthenticatorType; -import android.hardware.keymint.KeyParameter; -import android.hardware.keymint.SecurityLevel; +import android.hardware.security.keymint.HardwareAuthenticatorType; +import android.hardware.security.keymint.KeyParameter; +import android.hardware.security.keymint.SecurityLevel; import android.security.GateKeeper; import android.security.KeyStore2; import android.security.KeyStoreParameter; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java index a2d4528b99fd..4d4b0d8f183b 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java @@ -18,7 +18,7 @@ package android.security.keystore2; import android.annotation.NonNull; import android.annotation.Nullable; -import android.hardware.keymint.KeyParameter; +import android.hardware.security.keymint.KeyParameter; import android.security.keymaster.KeymasterDefs; import android.security.keystore.ArrayUtils; import android.security.keystore.KeyProperties; diff --git a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java index 8fa532b6e188..18c786aa3093 100644 --- a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java +++ b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java @@ -18,8 +18,8 @@ package android.security.keystore2; import android.annotation.NonNull; import android.hardware.biometrics.BiometricManager; -import android.hardware.keymint.KeyParameter; -import android.hardware.keymint.SecurityLevel; +import android.hardware.security.keymint.KeyParameter; +import android.hardware.security.keymint.SecurityLevel; import android.security.GateKeeper; import android.security.keymaster.KeymasterDefs; import android.security.keystore.KeyProperties; diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml index f0eae97b107e..807e5afae890 100644 --- a/libs/WindowManager/Shell/res/values/config.xml +++ b/libs/WindowManager/Shell/res/values/config.xml @@ -42,16 +42,4 @@ <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows, when the PIP menu is shown in center. --> <string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string> - - <!-- Gravity of letterboxed apps in portrait screen orientation. - Can be Gravity.TOP, Gravity.CENTER or Gravity.BOTTOM. - Any other value will result in runtime exception for a letterboxed activity. - Default is Gravity.TOP. --> - <integer name="config_letterboxPortraitGravity">0x00000030</integer> - - <!-- Gravity of letterboxed apps in landscape screen orientation. - Can be Gravity.LEFT, Gravity.CENTER or Gravity.RIGHT. - Any other value will result in runtime exception for a letterboxed activity. - Default is Gravity.CENTER. --> - <integer name="config_letterboxLandscapeGravity">0x00000011</integer> </resources> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java index 4f13b83bc29d..63d31182a748 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java @@ -20,8 +20,9 @@ import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCR import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString; import android.app.ActivityManager; -import android.util.ArraySet; +import android.graphics.Point; import android.util.Slog; +import android.util.SparseArray; import android.view.SurfaceControl; import androidx.annotation.NonNull; @@ -40,7 +41,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { private final SyncTransactionQueue mSyncQueue; - private final ArraySet<Integer> mTasks = new ArraySet<>(); + private final SparseArray<SurfaceControl> mLeashByTaskId = new SparseArray<>(); public FullscreenTaskListener(SyncTransactionQueue syncQueue) { mSyncQueue = syncQueue; @@ -48,39 +49,44 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { - synchronized (mTasks) { - if (mTasks.contains(taskInfo.taskId)) { - throw new RuntimeException("Task appeared more than once: #" + taskInfo.taskId); - } - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d", - taskInfo.taskId); - mTasks.add(taskInfo.taskId); - mSyncQueue.runInSync(t -> { - // Reset several properties back to fullscreen (PiP, for example, leaves all these - // properties in a bad state). - t.setWindowCrop(leash, null); - t.setPosition(leash, 0, 0); - // TODO(shell-transitions): Eventually set everything in transition so there's no - // SF Transaction here. - if (!Transitions.ENABLE_SHELL_TRANSITIONS) { - t.setAlpha(leash, 1f); - t.setMatrix(leash, 1, 0, 0, 1); - t.show(leash); - } - }); + if (mLeashByTaskId.get(taskInfo.taskId) != null) { + throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId); } + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d", + taskInfo.taskId); + mLeashByTaskId.put(taskInfo.taskId, leash); + final Point positionInParent = taskInfo.positionInParent; + mSyncQueue.runInSync(t -> { + // Reset several properties back to fullscreen (PiP, for example, leaves all these + // properties in a bad state). + t.setWindowCrop(leash, null); + t.setPosition(leash, positionInParent.x, positionInParent.y); + // TODO(shell-transitions): Eventually set everything in transition so there's no + // SF Transaction here. + if (!Transitions.ENABLE_SHELL_TRANSITIONS) { + t.setAlpha(leash, 1f); + t.setMatrix(leash, 1, 0, 0, 1); + t.show(leash); + } + }); + } + + @Override + public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { + final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId); + final Point positionInParent = taskInfo.positionInParent; + mSyncQueue.runInSync(t -> t.setPosition(leash, positionInParent.x, positionInParent.y)); } @Override public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { - synchronized (mTasks) { - if (!mTasks.remove(taskInfo.taskId)) { - Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId); - return; - } - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d", - taskInfo.taskId); + if (mLeashByTaskId.get(taskInfo.taskId) == null) { + Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId); + return; } + mLeashByTaskId.remove(taskInfo.taskId); + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d", + taskInfo.taskId); } @Override @@ -88,7 +94,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { final String innerPrefix = prefix + " "; final String childPrefix = innerPrefix + " "; pw.println(prefix + this); - pw.println(innerPrefix + mTasks.size() + " Tasks"); + pw.println(innerPrefix + mLeashByTaskId.size() + " Tasks"); } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandler.java index 45948dd9e800..20850428d3bd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandler.java @@ -16,12 +16,9 @@ package com.android.wm.shell; -import android.view.Gravity; - import com.android.wm.shell.apppairs.AppPairs; import com.android.wm.shell.common.annotations.ExternalThread; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout; -import com.android.wm.shell.letterbox.LetterboxConfigController; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.splitscreen.SplitScreen; @@ -42,7 +39,6 @@ public final class ShellCommandHandler { private final Optional<HideDisplayCutout> mHideDisplayCutout; private final ShellTaskOrganizer mShellTaskOrganizer; private final Optional<AppPairs> mAppPairsOptional; - private final LetterboxConfigController mLetterboxConfigController; public ShellCommandHandler( ShellTaskOrganizer shellTaskOrganizer, @@ -50,15 +46,13 @@ public final class ShellCommandHandler { Optional<Pip> pipOptional, Optional<OneHanded> oneHandedOptional, Optional<HideDisplayCutout> hideDisplayCutout, - Optional<AppPairs> appPairsOptional, - LetterboxConfigController letterboxConfigController) { + Optional<AppPairs> appPairsOptional) { mShellTaskOrganizer = shellTaskOrganizer; mSplitScreenOptional = splitScreenOptional; mPipOptional = pipOptional; mOneHandedOptional = oneHandedOptional; mHideDisplayCutout = hideDisplayCutout; mAppPairsOptional = appPairsOptional; - mLetterboxConfigController = letterboxConfigController; } /** Dumps WM Shell internal state. */ @@ -85,14 +79,6 @@ public final class ShellCommandHandler { return false; } switch (args[1]) { - case "set-letterbox-portrait-gravity": - return runSetLetterboxPortraitGravity(args, pw); - case "get-letterbox-portrait-gravity": - return runGetLetterboxPortraitGravity(pw); - case "set-letterbox-landscape-gravity": - return runSetLetterboxLandscapeGravity(args, pw); - case "get-letterbox-landscape-gravity": - return runGetLetterboxLandscapeGravity(pw); case "pair": return runPair(args, pw); case "unpair": @@ -104,92 +90,6 @@ public final class ShellCommandHandler { } } - private boolean runSetLetterboxPortraitGravity(String[] args, PrintWriter pw) { - if (args.length < 3) { - // First two arguments are "WMShell" and command name. - pw.println("Error: reset, TOP, CENTER or BOTTOM should be provided as an argument"); - return true; - } - switch (args[2]) { - case "reset": - mLetterboxConfigController.resetPortraitGravity(); - break; - case "TOP": - mLetterboxConfigController.setPortraitGravity(Gravity.TOP); - break; - case "CENTER": - mLetterboxConfigController.setPortraitGravity(Gravity.CENTER); - break; - case "BOTTOM": - mLetterboxConfigController.setPortraitGravity(Gravity.BOTTOM); - break; - default: - pw.println("Error: expected reset, TOP, CENTER or BOTTOM but got " + args[2]); - } - return true; - } - - private boolean runGetLetterboxPortraitGravity(PrintWriter pw) { - final int gravity = mLetterboxConfigController.getPortraitGravity(); - switch (gravity) { - case Gravity.TOP: - pw.println("TOP"); - break; - case Gravity.CENTER: - pw.println("CENTER"); - break; - case Gravity.BOTTOM: - pw.println("BOTTOM"); - break; - default: - throw new AssertionError("Unexpected gravity: " + gravity); - } - return true; - } - - private boolean runSetLetterboxLandscapeGravity(String[] args, PrintWriter pw) { - if (args.length < 3) { - // First two arguments are "WMShell" and command name. - pw.println("Error: reset, LEFT, CENTER or RIGHT should be provided as an argument"); - return false; - } - switch (args[2]) { - case "reset": - mLetterboxConfigController.resetLandscapeGravity(); - break; - case "LEFT": - mLetterboxConfigController.setLandscapeGravity(Gravity.LEFT); - break; - case "CENTER": - mLetterboxConfigController.setLandscapeGravity(Gravity.CENTER); - break; - case "RIGHT": - mLetterboxConfigController.setLandscapeGravity(Gravity.RIGHT); - break; - default: - pw.println( - "Error: expected reset, LEFT, CENTER or RIGHT but got " + args[2]); - } - return true; - } - - private boolean runGetLetterboxLandscapeGravity(PrintWriter pw) { - final int gravity = mLetterboxConfigController.getLandscapeGravity(); - switch (gravity) { - case Gravity.LEFT: - pw.println("LEFT"); - break; - case Gravity.CENTER: - pw.println("CENTER"); - break; - case Gravity.RIGHT: - pw.println("RIGHT"); - break; - default: - throw new AssertionError("Unexpected gravity: " + gravity); - } - return true; - } private boolean runPair(String[] args, PrintWriter pw) { if (args.length < 4) { @@ -220,12 +120,6 @@ public final class ShellCommandHandler { pw.println(" Print this help text."); pw.println(" <no arguments provided>"); pw.println(" Dump Window Manager Shell internal state"); - pw.println(" set-letterbox-portrait-gravity [reset|TOP|CENTER|BOTTOM]"); - pw.println(" get-letterbox-portrait-gravity"); - pw.println(" Set, reset or print letterbox gravity for portrait screen mode."); - pw.println(" set-letterbox-landscape-gravity [reset|LEFT|CENTER|RIGHT]"); - pw.println(" get-letterbox-landscape-gravity"); - pw.println(" Set, reset or print letterbox gravity for landscape screen mode."); pw.println(" pair <taskId1> <taskId2>"); pw.println(" unpair <taskId>"); pw.println(" Pairs/unpairs tasks with given ids."); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInit.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInit.java index 6c08079e586e..f8956030936c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInit.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInit.java @@ -17,13 +17,11 @@ package com.android.wm.shell; import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN; -import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_LETTERBOX; import com.android.wm.shell.apppairs.AppPairs; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.annotations.ExternalThread; import com.android.wm.shell.draganddrop.DragAndDropController; -import com.android.wm.shell.letterbox.LetterboxTaskListener; import com.android.wm.shell.splitscreen.SplitScreen; import java.util.Optional; @@ -38,7 +36,6 @@ public class ShellInit { private final ShellTaskOrganizer mShellTaskOrganizer; private final Optional<SplitScreen> mSplitScreenOptional; private final Optional<AppPairs> mAppPairsOptional; - private final LetterboxTaskListener mLetterboxTaskListener; private final FullscreenTaskListener mFullscreenTaskListener; private final Transitions mTransitions; @@ -47,7 +44,6 @@ public class ShellInit { ShellTaskOrganizer shellTaskOrganizer, Optional<SplitScreen> splitScreenOptional, Optional<AppPairs> appPairsOptional, - LetterboxTaskListener letterboxTaskListener, FullscreenTaskListener fullscreenTaskListener, Transitions transitions) { mDisplayImeController = displayImeController; @@ -55,7 +51,6 @@ public class ShellInit { mShellTaskOrganizer = shellTaskOrganizer; mSplitScreenOptional = splitScreenOptional; mAppPairsOptional = appPairsOptional; - mLetterboxTaskListener = letterboxTaskListener; mFullscreenTaskListener = fullscreenTaskListener; mTransitions = transitions; } @@ -66,8 +61,6 @@ public class ShellInit { mDisplayImeController.startMonitorDisplays(); mShellTaskOrganizer.addListenerForType( - mLetterboxTaskListener, TASK_LISTENER_TYPE_LETTERBOX); - mShellTaskOrganizer.addListenerForType( mFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN); // Register the shell organizer mShellTaskOrganizer.registerOrganizer(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index 62d265aab38f..10cec6d59cbe 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -62,14 +62,12 @@ public class ShellTaskOrganizer extends TaskOrganizer { public static final int TASK_LISTENER_TYPE_FULLSCREEN = -2; public static final int TASK_LISTENER_TYPE_MULTI_WINDOW = -3; public static final int TASK_LISTENER_TYPE_PIP = -4; - public static final int TASK_LISTENER_TYPE_LETTERBOX = -5; @IntDef(prefix = {"TASK_LISTENER_TYPE_"}, value = { TASK_LISTENER_TYPE_UNDEFINED, TASK_LISTENER_TYPE_FULLSCREEN, TASK_LISTENER_TYPE_MULTI_WINDOW, TASK_LISTENER_TYPE_PIP, - TASK_LISTENER_TYPE_LETTERBOX, }) public @interface TaskListenerType {} @@ -371,9 +369,7 @@ public class ShellTaskOrganizer extends TaskOrganizer { static @TaskListenerType int taskInfoToTaskListenerType(RunningTaskInfo runningTaskInfo) { switch (runningTaskInfo.getWindowingMode()) { case WINDOWING_MODE_FULLSCREEN: - return runningTaskInfo.letterboxActivityBounds != null - ? TASK_LISTENER_TYPE_LETTERBOX - : TASK_LISTENER_TYPE_FULLSCREEN; + return TASK_LISTENER_TYPE_FULLSCREEN; case WINDOWING_MODE_MULTI_WINDOW: return TASK_LISTENER_TYPE_MULTI_WINDOW; case WINDOWING_MODE_PINNED: @@ -389,8 +385,6 @@ public class ShellTaskOrganizer extends TaskOrganizer { switch (type) { case TASK_LISTENER_TYPE_FULLSCREEN: return "TASK_LISTENER_TYPE_FULLSCREEN"; - case TASK_LISTENER_TYPE_LETTERBOX: - return "TASK_LISTENER_TYPE_LETTERBOX"; case TASK_LISTENER_TYPE_MULTI_WINDOW: return "TASK_LISTENER_TYPE_MULTI_WINDOW"; case TASK_LISTENER_TYPE_PIP: diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index 4c70b5d32108..e1a94b071bf4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -123,14 +123,16 @@ public class SplitLayout { mBounds1.set(mRootBounds); mBounds2.set(mRootBounds); if (isLandscape(mRootBounds)) { + position += mRootBounds.left; mDividerBounds.left = position - mDividerInsets; mDividerBounds.right = mDividerBounds.left + mDividerWindowWidth; - mBounds1.right = mBounds1.left + position; + mBounds1.right = position; mBounds2.left = mBounds1.right + mDividerSize; } else { + position += mRootBounds.top; mDividerBounds.top = position - mDividerInsets; mDividerBounds.bottom = mDividerBounds.top + mDividerWindowWidth; - mBounds1.bottom = mBounds1.top + position; + mBounds1.bottom = position; mBounds2.top = mBounds1.bottom + mDividerSize; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxConfigController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxConfigController.java deleted file mode 100644 index 0a549c6aa7d9..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxConfigController.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.letterbox; - -import android.content.Context; -import android.view.Gravity; - -import com.android.wm.shell.R; - -/** - * Controls access to and overrides of resource config values used by {@link - * LetterboxTaskOrganizer}. - */ -public final class LetterboxConfigController { - - private final Context mContext; - - /** {@link Gravity} of letterboxed apps in portrait screen orientation. */ - private int mLetterboxPortraitGravity; - - /** {@link Gravity} of letterboxed apps in landscape screen orientation. */ - private int mLetterboxLandscapeGravity; - - public LetterboxConfigController(Context context) { - mContext = context; - mLetterboxPortraitGravity = - mContext.getResources().getInteger(R.integer.config_letterboxPortraitGravity); - mLetterboxLandscapeGravity = - mContext.getResources().getInteger(R.integer.config_letterboxLandscapeGravity); - } - - /** - * Overrides {@link Gravity} of letterboxed apps in portrait screen orientation. - * - * @throws IllegalArgumentException if gravity isn't equal to {@link Gravity#TOP}, {@link - * Gravity#CENTER} or {@link Gravity#BOTTOM}. - */ - public void setPortraitGravity(int gravity) { - if (gravity != Gravity.TOP && gravity != Gravity.CENTER && gravity != Gravity.BOTTOM) { - throw new IllegalArgumentException( - "Expected Gravity#TOP, Gravity#CENTER or Gravity#BOTTOM but got" - + gravity); - } - mLetterboxPortraitGravity = gravity; - } - - /** - * Resets {@link Gravity} of letterboxed apps in portrait screen orientation to {@link - * R.integer.config_letterboxPortraitGravity}. - */ - public void resetPortraitGravity() { - mLetterboxPortraitGravity = - mContext.getResources().getInteger(R.integer.config_letterboxPortraitGravity); - } - - /** - * Gets {@link Gravity} of letterboxed apps in portrait screen orientation. - */ - public int getPortraitGravity() { - return mLetterboxPortraitGravity; - } - - /** - * Overrides {@link Gravity} of letterboxed apps in landscape screen orientation. - * - * @throws IllegalArgumentException if gravity isn't equal to {@link Gravity#RIGHT}, {@link - * Gravity#CENTER} or {@link Gravity#LEFT}. - */ - public void setLandscapeGravity(int gravity) { - if (gravity != Gravity.LEFT && gravity != Gravity.CENTER && gravity != Gravity.RIGHT) { - throw new IllegalArgumentException( - "Expected Gravity#LEFT, Gravity#CENTER or Gravity#RIGHT but got" - + gravity); - } - mLetterboxLandscapeGravity = gravity; - } - - /** - * Resets {@link Gravity} of letterboxed apps in landscape screen orientation to {@link - * R.integer.config_letterboxLandscapeGravity}. - */ - public void resetLandscapeGravity() { - mLetterboxLandscapeGravity = - mContext.getResources().getInteger(R.integer.config_letterboxLandscapeGravity); - } - - /** - * Gets {@link Gravity} of letterboxed apps in landscape screen orientation. - */ - public int getLandscapeGravity() { - return mLetterboxLandscapeGravity; - } - -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java deleted file mode 100644 index 490ef3296be6..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.letterbox; - -import android.app.ActivityManager; -import android.graphics.Insets; -import android.graphics.Point; -import android.graphics.Rect; -import android.util.Slog; -import android.util.SparseArray; -import android.view.Gravity; -import android.view.SurfaceControl; -import android.view.WindowInsets; -import android.view.WindowManager; - -import com.android.internal.protolog.common.ProtoLog; -import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.Transitions; -import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.protolog.ShellProtoLogGroup; - -/** - * Organizes a task in {@link android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN} when - * it's presented in the letterbox mode either because orientations of a top activity and a device - * don't match or because a top activity is in a size compat mode. - */ -public class LetterboxTaskListener implements ShellTaskOrganizer.TaskListener { - private static final String TAG = "LetterboxTaskListener"; - - private final SyncTransactionQueue mSyncQueue; - private final LetterboxConfigController mLetterboxConfigController; - private final WindowManager mWindowManager; - private final SparseArray<SurfaceControl> mLeashByTaskId = new SparseArray<>(); - - public LetterboxTaskListener( - SyncTransactionQueue syncQueue, - LetterboxConfigController letterboxConfigController, - WindowManager windowManager) { - mSyncQueue = syncQueue; - mLetterboxConfigController = letterboxConfigController; - mWindowManager = windowManager; - } - - @Override - public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { - if (mLeashByTaskId.get(taskInfo.taskId) != null) { - throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId); - } - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Letterbox Task Appeared: #%d", - taskInfo.taskId); - mLeashByTaskId.put(taskInfo.taskId, leash); - Point positionInParent = new Point(); - Rect crop = new Rect(); - resolveTaskPositionAndCrop(taskInfo, positionInParent, crop); - mSyncQueue.runInSync(t -> { - setPositionAndWindowCrop(t, leash, positionInParent, crop); - if (!Transitions.ENABLE_SHELL_TRANSITIONS) { - t.setAlpha(leash, 1f); - t.setMatrix(leash, 1, 0, 0, 1); - t.show(leash); - } - }); - } - - @Override - public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { - if (mLeashByTaskId.get(taskInfo.taskId) == null) { - Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId); - return; - } - mLeashByTaskId.remove(taskInfo.taskId); - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Letterbox Task Vanished: #%d", - taskInfo.taskId); - } - - @Override - public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Letterbox Task Changed: #%d", - taskInfo.taskId); - final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId); - Point positionInParent = new Point(); - Rect crop = new Rect(); - resolveTaskPositionAndCrop(taskInfo, positionInParent, crop); - mSyncQueue.runInSync(t -> setPositionAndWindowCrop(t, leash, positionInParent, crop)); - } - - private static void setPositionAndWindowCrop( - SurfaceControl.Transaction transaction, - SurfaceControl leash, - final Point positionInParent, - final Rect crop) { - transaction.setPosition(leash, positionInParent.x, positionInParent.y); - transaction.setWindowCrop(leash, crop); - } - - // TODO(b/173440321): Correct presentation of letterboxed activities in One-handed mode. - private void resolveTaskPositionAndCrop( - ActivityManager.RunningTaskInfo taskInfo, - Point positionInParent, - Rect crop) { - // In screen coordinates - Rect parentBounds = new Rect(taskInfo.parentBounds); - // Intersect parent and max bounds. This is required for situations when parent bounds - // go beyond display bounds, for example, in One-handed mode. - final Rect maxBounds = taskInfo.getConfiguration().windowConfiguration.getMaxBounds(); - if (!parentBounds.intersect(maxBounds)) { - Slog.w(TAG, "Task parent and max bounds don't intersect: #" + taskInfo.taskId); - } - - // In screen coordinates - final Rect taskBounds = taskInfo.getConfiguration().windowConfiguration.getBounds(); - final Rect activityBounds = taskInfo.letterboxActivityBounds; - - Insets insets = getInsets(); - Rect displayBoundsWithInsets = - new Rect(mWindowManager.getMaximumWindowMetrics().getBounds()); - displayBoundsWithInsets.inset(insets); - - Rect taskBoundsWithInsets = new Rect(taskBounds); - taskBoundsWithInsets.intersect(displayBoundsWithInsets); - - Rect activityBoundsWithInsets = new Rect(activityBounds); - activityBoundsWithInsets.intersect(displayBoundsWithInsets); - - Rect parentBoundsWithInsets = new Rect(parentBounds); - parentBoundsWithInsets.intersect(displayBoundsWithInsets); - - // Crop need to be in the task coordinates. - crop.set(activityBoundsWithInsets); - crop.offset(-taskBounds.left, -taskBounds.top); - - // Account for insets since coordinates calculations below are done with them. - positionInParent.x = parentBoundsWithInsets.left - parentBounds.left - - (taskBoundsWithInsets.left - taskBounds.left); - positionInParent.y = parentBoundsWithInsets.top - parentBounds.top - - (taskBoundsWithInsets.top - taskBounds.top); - - // Calculating a position of task bounds (without insets) in parent coordinates (without - // insets) to align activity bounds (without insets) as requested in config. Activity - // accounts for insets that overlap with its bounds (this overlap can be partial) so - // ignoring overlap with insets when computing the position. Also, cropping unwanted insets - // while keeping the top one if the activity is aligned at the top of the window to show - // status bar decor view. - if (parentBounds.height() >= parentBounds.width()) { - final int gravity = mLetterboxConfigController.getPortraitGravity(); - // Center activity horizontally. - positionInParent.x += - (parentBoundsWithInsets.width() - activityBoundsWithInsets.width()) / 2 - + taskBoundsWithInsets.left - activityBoundsWithInsets.left; - switch (gravity) { - case Gravity.TOP: - positionInParent.y += taskBoundsWithInsets.top - activityBoundsWithInsets.top; - break; - case Gravity.CENTER: - positionInParent.y += - taskBoundsWithInsets.top - activityBoundsWithInsets.top - + (parentBoundsWithInsets.height() - - activityBoundsWithInsets.height()) / 2; - break; - case Gravity.BOTTOM: - positionInParent.y += - parentBoundsWithInsets.height() - activityBoundsWithInsets.bottom - + taskBoundsWithInsets.top; - break; - default: - throw new AssertionError( - "Unexpected portrait gravity " + gravity - + " for task: #" + taskInfo.taskId); - } - } else { - final int gravity = mLetterboxConfigController.getLandscapeGravity(); - // Align activity to the top. - positionInParent.y += taskBoundsWithInsets.top - activityBoundsWithInsets.top; - switch (gravity) { - case Gravity.LEFT: - positionInParent.x += taskBoundsWithInsets.left - activityBoundsWithInsets.left; - break; - case Gravity.CENTER: - positionInParent.x += - (parentBoundsWithInsets.width() - activityBoundsWithInsets.width()) / 2 - + taskBoundsWithInsets.left - activityBoundsWithInsets.left; - break; - case Gravity.RIGHT: - positionInParent.x += - parentBoundsWithInsets.width() - - activityBoundsWithInsets.right + taskBoundsWithInsets.left; - break; - default: - throw new AssertionError( - "Unexpected landscape gravity " + gravity - + " for task: #" + taskInfo.taskId); - } - } - - // New bounds of the activity after it's repositioned with required gravity. - Rect newActivityBounds = new Rect(activityBounds); - // Task's surfce will be repositioned to positionInParent together with the activity - // inside it so the new activity bounds are the original activity bounds offset by - // the task's offset. - newActivityBounds.offset( - positionInParent.x - taskBounds.left, positionInParent.y - taskBounds.top); - Rect newActivityBoundsWithInsets = new Rect(newActivityBounds); - newActivityBoundsWithInsets.intersect(displayBoundsWithInsets); - // Activity handles insets on its own (e.g. under status bar or navigation bar). - // crop that is calculated above crops all insets from an activity and below insets that - // can be shown are added back to the crop bounds (e.g. if activity is still shown at the - // top of the display then the top inset won't be cropped). - // After task's surface is repositioned, intersection between an activity and insets can - // change but if it doesn't, the activity should be shown under insets to maximize visible - // area. - // Also, an activity can use area under insets and insets shouldn't be cropped in this case - // regardless of a position on the screen. - final Rect activityInsetsFromCore = taskInfo.letterboxActivityInsets; - if (newActivityBounds.top - newActivityBoundsWithInsets.top - == activityBounds.top - activityBoundsWithInsets.top - // Check whether an activity is shown under inset. If it is, then the inset from - // WM Core and the inset computed here will be different because local insets - // doesn't take into account visibility of insets requested by the activity. - || activityBoundsWithInsets.top - activityBounds.top - != activityInsetsFromCore.top) { - crop.top -= activityBoundsWithInsets.top - activityBounds.top; - } - if (newActivityBounds.bottom - newActivityBoundsWithInsets.bottom - == activityBounds.bottom - activityBoundsWithInsets.bottom - || activityBounds.bottom - activityBoundsWithInsets.bottom - != activityInsetsFromCore.bottom) { - crop.bottom += activityBounds.bottom - activityBoundsWithInsets.bottom; - } - if (newActivityBounds.left - newActivityBoundsWithInsets.left - == activityBounds.left - activityBoundsWithInsets.left - || activityBoundsWithInsets.left - activityBounds.left - != activityInsetsFromCore.left) { - crop.left -= activityBoundsWithInsets.left - activityBounds.left; - } - if (newActivityBounds.right - newActivityBoundsWithInsets.right - == activityBounds.right - activityBoundsWithInsets.right - || activityBounds.right - activityBoundsWithInsets.right - != activityInsetsFromCore.right) { - crop.right += activityBounds.right - activityBoundsWithInsets.right; - } - } - - private Insets getInsets() { - return mWindowManager - .getMaximumWindowMetrics() - .getWindowInsets() - .getInsets( - WindowInsets.Type.navigationBars() - | WindowInsets.Type.statusBars() - | WindowInsets.Type.displayCutout()); - } - -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java index 3b1e6cbe5ccd..951a68884e11 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java @@ -75,6 +75,7 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, @Nullable OneHandedGestureEventCallback mGestureEventCallback; private Rect mGestureRegion = new Rect(); + private boolean mIsStopGesture; /** * Constructor of OneHandedGestureHandler, we only handle the gesture of @@ -153,20 +154,20 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, float distance = (float) Math.hypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y); if (distance > mDragDistThreshold) { - mGestureEventCallback.onStop(); + mIsStopGesture = true; } } break; case MotionEvent.ACTION_UP: if (mLastPos.y >= mDownPos.y && mPassedSlop) { mGestureEventCallback.onStart(); + } else if (mIsStopGesture) { + mGestureEventCallback.onStop(); } - mPassedSlop = false; - mAllowGesture = false; + clearState(); break; case MotionEvent.ACTION_CANCEL: - mPassedSlop = false; - mAllowGesture = false; + clearState(); break; default: break; @@ -174,6 +175,11 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, } } + private void clearState() { + mPassedSlop = false; + mIsStopGesture = false; + } + private void disposeInputChannel() { if (mInputEventReceiver != null) { mInputEventReceiver.dispose(); diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt index 1638d72f9914..c5b54bc4abcb 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt @@ -16,8 +16,10 @@ package com.android.wm.shell.flicker +import android.graphics.Region import com.android.server.wm.flicker.dsl.EventLogAssertion import com.android.server.wm.flicker.dsl.LayersAssertion +import com.android.server.wm.flicker.helpers.WindowUtils @JvmOverloads fun LayersAssertion.appPairsDividerIsVisible( @@ -59,6 +61,50 @@ fun LayersAssertion.dockedStackDividerIsInvisible( } } +@JvmOverloads +fun LayersAssertion.dockedStackPrimaryBoundsIsVisible( + rotation: Int, + primaryLayerName: String, + bugId: Int = 0, + enabled: Boolean = bugId == 0 +) { + end("PrimaryAppBounds", bugId, enabled) { + val entry = this.trace.entries.firstOrNull() + ?: throw IllegalStateException("Trace is empty") + val dividerRegion = entry.getVisibleBounds(FlickerTestBase.DOCKED_STACK_DIVIDER) + this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation)) + } +} + +@JvmOverloads +fun LayersAssertion.dockedStackSecondaryBoundsIsVisible( + rotation: Int, + secondaryLayerName: String, + bugId: Int = 0, + enabled: Boolean = bugId == 0 +) { + end("SecondaryAppBounds", bugId, enabled) { + val entry = this.trace.entries.firstOrNull() + ?: throw IllegalStateException("Trace is empty") + val dividerRegion = entry.getVisibleBounds(FlickerTestBase.DOCKED_STACK_DIVIDER) + this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation)) + } +} + +fun getPrimaryRegion(dividerRegion: Region, rotation: Int): Region { + val displayBounds = WindowUtils.getDisplayBounds(rotation) + return Region(0, 0, displayBounds.getBounds().right, + dividerRegion.getBounds().bottom - WindowUtils.dockedStackDividerInset) +} + +fun getSecondaryRegion(dividerRegion: Region, rotation: Int): Region { + val displayBounds = WindowUtils.getDisplayBounds(rotation) + return Region(0, + dividerRegion.getBounds().bottom - WindowUtils.dockedStackDividerInset, + displayBounds.getBounds().right, + displayBounds.getBounds().bottom - WindowUtils.navigationBarHeight) +} + fun EventLogAssertion.focusChanges( vararg windows: String, bugId: Int = 0, diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt index 96234fcc8570..5125a3972cf4 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt @@ -37,3 +37,4 @@ const val TEST_APP_FIXED_ACTIVITY_LABEL = "FixedApp" // Test App > SplitScreen Activity const val TEST_APP_SPLITSCREEN_PRIMARY_LABEL = "SplitScreenPrimaryApp" const val TEST_APP_SPLITSCREEN_SECONDARY_LABEL = "SplitScreenSecondaryApp" +const val TEST_APP_NONRESIZEABLE_LABEL = "NonResizeableApp" diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt index 0f8d30a94ec6..379ec95b6792 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt @@ -61,10 +61,9 @@ class AppPairsTest( setup { eachRun { uiDevice.wakeUpAndGoToHomeScreen() - primaryApp.open() - uiDevice.pressHome() - secondaryApp.open() - uiDevice.pressHome() + primaryApp.launchViaIntent() + secondaryApp.launchViaIntent() + nonResizeableApp.launchViaIntent() updateTaskId() } } @@ -90,7 +89,7 @@ class AppPairsTest( @Test fun testAppPairs_pairPrimaryAndSecondaryApps() { - val testTag = "testAppPaired_pairPrimaryAndSecondary" + val testTag = "testAppPairs_pairPrimaryAndSecondaryApps" runWithFlicker(appPairsSetup) { withTestName { testTag } repeat { @@ -176,6 +175,36 @@ class AppPairsTest( } } + @Test + fun testAppPairs_canNotPairNonResizeableApps() { + val testTag = "testAppPairs_canNotPairNonResizeableApps" + runWithFlicker(appPairsSetup) { + withTestName { testTag } + repeat { + TEST_REPETITIONS + } + transitions { + nonResizeableApp.launchViaIntent() + // TODO pair apps through normal UX flow + executeShellCommand(composePairsCommand( + primaryTaskId, nonResizeableTaskId, true /* pair */)) + SystemClock.sleep(AppPairsHelper.TIMEOUT_MS) + } + assertions { + layersTrace { + appPairsDividerIsInvisible() + } + windowManagerTrace { + end { + showsAppWindow(nonResizeableApp.defaultWindowName) + .and() + .hidesAppWindow(primaryApp.defaultWindowName) + } + } + } + } + } + private fun composePairsCommand( primaryApp: String, secondaryApp: String, @@ -202,6 +231,7 @@ class AppPairsTest( private fun updateTaskId() { val primaryAppComponent = primaryApp.openAppIntent.component val secondaryAppComponent = secondaryApp.openAppIntent.component + val nonResizeableAppComponent = nonResizeableApp.openAppIntent.component if (primaryAppComponent != null) { primaryTaskId = appPairsHelper.getTaskIdForActivity( primaryAppComponent.packageName, primaryAppComponent.className).toString() @@ -210,11 +240,17 @@ class AppPairsTest( secondaryTaskId = appPairsHelper.getTaskIdForActivity( secondaryAppComponent.packageName, secondaryAppComponent.className).toString() } + if (nonResizeableAppComponent != null) { + nonResizeableTaskId = appPairsHelper.getTaskIdForActivity( + nonResizeableAppComponent.packageName, + nonResizeableAppComponent.className).toString() + } } companion object { var primaryTaskId = "" var secondaryTaskId = "" + var nonResizeableTaskId = "" @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<Array<Any>> { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestBase.kt index f32cd8842074..4d46f2856704 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestBase.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.apppairs import com.android.wm.shell.flicker.NonRotationTestBase +import com.android.wm.shell.flicker.TEST_APP_NONRESIZEABLE_LABEL import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_LABEL import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_SECONDARY_LABEL import com.android.wm.shell.flicker.helpers.AppPairsHelper @@ -36,4 +37,7 @@ abstract class AppPairsTestBase( protected val secondaryApp = SplitScreenHelper(instrumentation, TEST_APP_SPLITSCREEN_SECONDARY_LABEL, Components.SplitScreenSecondaryActivity()) + protected val nonResizeableApp = SplitScreenHelper(instrumentation, + TEST_APP_NONRESIZEABLE_LABEL, + Components.NonResizeableActivity()) } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt index e67fc97dad2e..fb795c72b106 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt @@ -17,9 +17,7 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.graphics.Region import android.os.SystemClock -import com.android.server.wm.flicker.helpers.WindowUtils import com.android.wm.shell.flicker.testapp.Components class SplitScreenHelper( @@ -43,20 +41,6 @@ class SplitScreenHelper( SystemClock.sleep(TIMEOUT_MS) } - fun getPrimaryBounds(dividerBounds: Region): android.graphics.Region { - val primaryAppBounds = Region(0, 0, dividerBounds.bounds.right, - dividerBounds.bounds.bottom + WindowUtils.dockedStackDividerInset) - return primaryAppBounds - } - - fun getSecondaryBounds(dividerBounds: Region): android.graphics.Region { - val displayBounds = WindowUtils.displayBounds - val secondaryAppBounds = Region(0, - dividerBounds.bounds.bottom - WindowUtils.dockedStackDividerInset, - displayBounds.right, displayBounds.bottom - WindowUtils.navigationBarHeight) - return secondaryAppBounds - } - companion object { const val TEST_REPETITIONS = 1 const val TIMEOUT_MS = 3_000L diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt index 5570a562a515..348676189524 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt @@ -21,14 +21,23 @@ import android.view.Surface import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.dsl.runWithFlicker +import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.server.wm.flicker.helpers.canSplitScreen +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.openQuickstep import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.wm.shell.flicker.dockedStackDividerIsInvisible import com.android.wm.shell.flicker.dockedStackDividerIsVisible import com.android.wm.shell.flicker.helpers.SplitScreenHelper.Companion.TEST_REPETITIONS import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible +import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible +import org.junit.Assert import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -56,14 +65,16 @@ class EnterSplitScreenTest( setup { eachRun { uiDevice.wakeUpAndGoToHomeScreen() - splitScreenApp.open() - uiDevice.pressHome() } } teardown { eachRun { + if (uiDevice.isInSplitScreen()) { + uiDevice.exitSplitScreen() + } splitScreenApp.exit() secondaryApp.exit() + nonResizeableApp.exit() } } assertions { @@ -87,18 +98,14 @@ class EnterSplitScreenTest( TEST_REPETITIONS } transitions { + splitScreenApp.launchViaIntent() uiDevice.launchSplitScreen() } assertions { layersTrace { dockedStackDividerIsVisible() - end("appsEndingBounds", enabled = false) { - val entry = this.trace.entries.firstOrNull() - ?: throw IllegalStateException("Trace is empty") - this.hasVisibleRegion(splitScreenApp.defaultWindowName, - splitScreenApp.getPrimaryBounds( - entry.getVisibleBounds(DOCKED_STACK_DIVIDER))) - } + dockedStackPrimaryBoundsIsVisible( + rotation, splitScreenApp.defaultWindowName, 169271943) } windowManagerTrace { end { @@ -118,27 +125,18 @@ class EnterSplitScreenTest( TEST_REPETITIONS } transitions { - secondaryApp.open() - uiDevice.pressHome() - splitScreenApp.open() - uiDevice.pressHome() + secondaryApp.launchViaIntent() + splitScreenApp.launchViaIntent() uiDevice.launchSplitScreen() splitScreenApp.reopenAppFromOverview() } assertions { layersTrace { dockedStackDividerIsVisible() - end("appsEndingBounds", enabled = false) { - val entry = this.trace.entries.firstOrNull() - ?: throw IllegalStateException("Trace is empty") - this.hasVisibleRegion(splitScreenApp.defaultWindowName, - splitScreenApp.getPrimaryBounds( - entry.getVisibleBounds(DOCKED_STACK_DIVIDER))) - .and() - .hasVisibleRegion(secondaryApp.defaultWindowName, - splitScreenApp.getSecondaryBounds( - entry.getVisibleBounds(DOCKED_STACK_DIVIDER))) - } + dockedStackPrimaryBoundsIsVisible( + rotation, splitScreenApp.defaultWindowName, 169271943) + dockedStackSecondaryBoundsIsVisible( + rotation, secondaryApp.defaultWindowName, 169271943) } windowManagerTrace { end { @@ -150,6 +148,98 @@ class EnterSplitScreenTest( } } + @Test + fun testNonResizeableNotDocked() { + val testTag = "testNonResizeableNotDocked" + runWithFlicker(splitScreenSetup) { + withTestName { testTag } + repeat { + TEST_REPETITIONS + } + transitions { + nonResizeableApp.launchViaIntent() + uiDevice.openQuickstep() + if (uiDevice.canSplitScreen()) { + Assert.fail("Non-resizeable app should not enter split screen") + } + } + assertions { + layersTrace { + dockedStackDividerIsInvisible() + } + windowManagerTrace { + end { + hidesAppWindow(nonResizeableApp.defaultWindowName) + } + } + } + } + } + + @Test + fun testNonResizeableWhenAlreadyInSplitScreenPrimary() { + val testTag = "testNonResizeableWhenAlreadyInSplitScreenPrimary" + runWithFlicker(splitScreenSetup) { + withTestName { testTag } + repeat { + TEST_REPETITIONS + } + transitions { + nonResizeableApp.launchViaIntent() + splitScreenApp.launchViaIntent() + uiDevice.launchSplitScreen() + nonResizeableApp.reopenAppFromOverview() + } + assertions { + layersTrace { + dockedStackDividerIsInvisible() + end("appsEndingBounds", enabled = false) { + val displayBounds = WindowUtils.getDisplayBounds(rotation) + this.hasVisibleRegion(nonResizeableApp.defaultWindowName, displayBounds) + } + } + windowManagerTrace { + end { + showsAppWindow(nonResizeableApp.defaultWindowName) + hidesAppWindow(splitScreenApp.defaultWindowName) + } + } + } + } + } + + @Test + fun testNonResizeableWhenAlreadyInSplitScreenSecondary() { + val testTag = "testNonResizeableWhenAlreadyInSplitScreenSecondary" + runWithFlicker(splitScreenSetup) { + withTestName { testTag } + repeat { + TEST_REPETITIONS + } + transitions { + splitScreenApp.launchViaIntent() + uiDevice.launchSplitScreen() + uiDevice.pressBack() + nonResizeableApp.launchViaIntent() + } + assertions { + layersTrace { + dockedStackDividerIsInvisible() + end("appsEndingBounds", enabled = false) { + val displayBounds = WindowUtils.getDisplayBounds(rotation) + this.hasVisibleRegion(nonResizeableApp.defaultWindowName, displayBounds) + } + } + windowManagerTrace { + end { + showsAppWindow(nonResizeableApp.defaultWindowName) + hidesAppWindow(splitScreenApp.defaultWindowName) + } + } + } + } + } + companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/RotateOneLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/RotateOneLaunchedAppTest.kt new file mode 100644 index 000000000000..be8f9bcdedb6 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/RotateOneLaunchedAppTest.kt @@ -0,0 +1,146 @@ +/* + * 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 android.view.Surface +import androidx.test.filters.RequiresDevice +import com.android.server.wm.flicker.dsl.FlickerBuilder +import com.android.server.wm.flicker.dsl.runWithFlicker +import com.android.server.wm.flicker.helpers.exitSplitScreen +import com.android.server.wm.flicker.helpers.isInSplitScreen +import com.android.server.wm.flicker.helpers.launchSplitScreen +import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.server.wm.flicker.navBarLayerRotatesAndScales +import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.statusBarLayerRotatesScales +import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import com.android.wm.shell.flicker.dockedStackDividerIsVisible +import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible +import com.android.wm.shell.flicker.helpers.SplitScreenHelper +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test open app to split screen. + * To run this test: `atest WMShellFlickerTests:RotateOneLaunchedAppTest` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class RotateOneLaunchedAppTest( + rotationName: String, + rotation: Int +) : SplitScreenTestBase(rotationName, rotation) { + private val splitScreenRotationSetup: FlickerBuilder + get() = FlickerBuilder(instrumentation).apply { + val testSetupRotation = "testSetupRotation" + withTestName { + testSetupRotation + } + setup { + test { + device.wakeUpAndGoToHomeScreen() + } + } + teardown { + eachRun { + if (uiDevice.isInSplitScreen()) { + uiDevice.exitSplitScreen() + } + setRotation(Surface.ROTATION_0) + splitScreenApp.exit() + secondaryApp.exit() + } + } + } + + @Test + fun testRotateInSplitScreenMode() { + val testTag = "testEnterSplitScreen_launchToSide" + runWithFlicker(splitScreenRotationSetup) { + withTestName { testTag } + repeat { + SplitScreenHelper.TEST_REPETITIONS + } + transitions { + splitScreenApp.launchViaIntent() + device.launchSplitScreen() + setRotation(rotation) + } + assertions { + layersTrace { + navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation, 169271943) + statusBarLayerRotatesScales(Surface.ROTATION_0, rotation, 169271943) + dockedStackDividerIsVisible() + dockedStackPrimaryBoundsIsVisible( + rotation, splitScreenApp.defaultWindowName, 169271943) + } + windowManagerTrace { + navBarWindowIsAlwaysVisible() + statusBarWindowIsAlwaysVisible() + end { + showsAppWindow(splitScreenApp.defaultWindowName) + } + } + } + } + } + + @Test + fun testRotateAndEnterSplitScreenMode() { + val testTag = "testRotateAndEnterSplitScreenMode" + runWithFlicker(splitScreenRotationSetup) { + withTestName { testTag } + repeat { + SplitScreenHelper.TEST_REPETITIONS + } + transitions { + splitScreenApp.launchViaIntent() + setRotation(rotation) + device.launchSplitScreen() + } + assertions { + layersTrace { + navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation, 169271943) + statusBarLayerRotatesScales(Surface.ROTATION_0, rotation, 169271943) + dockedStackDividerIsVisible() + dockedStackPrimaryBoundsIsVisible( + rotation, splitScreenApp.defaultWindowName, 169271943) + } + windowManagerTrace { + navBarWindowIsAlwaysVisible() + statusBarWindowIsAlwaysVisible() + end { + showsAppWindow(splitScreenApp.defaultWindowName) + } + } + } + } + } + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<Array<Any>> { + val supportedRotations = intArrayOf(Surface.ROTATION_90, Surface.ROTATION_270) + return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) } + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/RotateTwoLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/RotateTwoLaunchedAppTest.kt new file mode 100644 index 000000000000..2e05c2a99273 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/RotateTwoLaunchedAppTest.kt @@ -0,0 +1,157 @@ +/* + * 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 android.view.Surface +import androidx.test.filters.RequiresDevice +import com.android.server.wm.flicker.dsl.FlickerBuilder +import com.android.server.wm.flicker.dsl.runWithFlicker +import com.android.server.wm.flicker.helpers.exitSplitScreen +import com.android.server.wm.flicker.helpers.isInSplitScreen +import com.android.server.wm.flicker.helpers.launchSplitScreen +import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.server.wm.flicker.navBarLayerRotatesAndScales +import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.statusBarLayerRotatesScales +import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import com.android.wm.shell.flicker.dockedStackDividerIsVisible +import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible +import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible +import com.android.wm.shell.flicker.helpers.SplitScreenHelper +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test open app to split screen. + * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppTest` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class RotateTwoLaunchedAppTest( + rotationName: String, + rotation: Int +) : SplitScreenTestBase(rotationName, rotation) { + private val splitScreenRotationSetup: FlickerBuilder + get() = FlickerBuilder(instrumentation).apply { + val testSetupRotation = "testSetupRotation" + withTestName { + testSetupRotation + } + setup { + test { + device.wakeUpAndGoToHomeScreen() + } + } + teardown { + eachRun { + if (uiDevice.isInSplitScreen()) { + uiDevice.exitSplitScreen() + } + setRotation(Surface.ROTATION_0) + splitScreenApp.exit() + secondaryApp.exit() + } + } + } + + @Test + fun testRotateInSplitScreenMode() { + val testTag = "testRotateInSplitScreenMode" + runWithFlicker(splitScreenRotationSetup) { + withTestName { testTag } + repeat { + SplitScreenHelper.TEST_REPETITIONS + } + transitions { + secondaryApp.launchViaIntent() + splitScreenApp.launchViaIntent() + device.launchSplitScreen() + splitScreenApp.reopenAppFromOverview() + setRotation(rotation) + } + assertions { + layersTrace { + navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation, 169271943) + statusBarLayerRotatesScales(Surface.ROTATION_0, rotation, 169271943) + dockedStackDividerIsVisible() + dockedStackPrimaryBoundsIsVisible( + rotation, splitScreenApp.defaultWindowName, 169271943) + dockedStackSecondaryBoundsIsVisible( + rotation, secondaryApp.defaultWindowName, 169271943) + } + windowManagerTrace { + navBarWindowIsAlwaysVisible() + statusBarWindowIsAlwaysVisible() + end { + showsAppWindow(splitScreenApp.defaultWindowName) + .and().showsAppWindow(secondaryApp.defaultWindowName) + } + } + } + } + } + + @Test + fun testRotateAndEnterSplitScreenMode() { + val testTag = "testRotateAndEnterSplitScreenMode" + runWithFlicker(splitScreenRotationSetup) { + withTestName { testTag } + repeat { + SplitScreenHelper.TEST_REPETITIONS + } + transitions { + secondaryApp.launchViaIntent() + splitScreenApp.launchViaIntent() + setRotation(rotation) + device.launchSplitScreen() + splitScreenApp.reopenAppFromOverview() + } + assertions { + layersTrace { + navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation, 169271943) + statusBarLayerRotatesScales(Surface.ROTATION_0, rotation, 169271943) + dockedStackDividerIsVisible() + dockedStackPrimaryBoundsIsVisible( + rotation, splitScreenApp.defaultWindowName, 169271943) + dockedStackSecondaryBoundsIsVisible( + rotation, secondaryApp.defaultWindowName, 169271943) + } + windowManagerTrace { + navBarWindowIsAlwaysVisible() + statusBarWindowIsAlwaysVisible() + end { + showsAppWindow(splitScreenApp.defaultWindowName) + .and().showsAppWindow(secondaryApp.defaultWindowName) + } + } + } + } + } + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<Array<Any>> { + val supportedRotations = intArrayOf(Surface.ROTATION_90, Surface.ROTATION_270) + return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) } + } + } +}
\ No newline at end of file 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 deleted file mode 100644 index d2371bd766f5..000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateOneLaunchedAppTest.kt +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.flicker.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 deleted file mode 100644 index 67346424acd2..000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateTwoLaunchedAppTest.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.flicker.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/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenTestBase.kt index a3440df9ddf8..42c509d6eba8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenTestBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenTestBase.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen import com.android.wm.shell.flicker.NonRotationTestBase +import com.android.wm.shell.flicker.TEST_APP_NONRESIZEABLE_LABEL import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_LABEL import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_SECONDARY_LABEL import com.android.wm.shell.flicker.helpers.SplitScreenHelper @@ -32,4 +33,7 @@ abstract class SplitScreenTestBase( protected val secondaryApp = SplitScreenHelper(instrumentation, TEST_APP_SPLITSCREEN_SECONDARY_LABEL, Components.SplitScreenSecondaryActivity()) + protected val nonResizeableApp = SplitScreenHelper(instrumentation, + TEST_APP_NONRESIZEABLE_LABEL, + Components.NonResizeableActivity()) } diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml index a583b725899b..28ed3431db62 100644 --- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml @@ -86,6 +86,17 @@ </intent-filter> </activity> + <activity android:name=".NonResizeableActivity" + android:resizeableActivity="false" + android:taskAffinity="com.android.wm.shell.flicker.testapp.NonResizeableActivity" + android:label="NonResizeableApp" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + <activity android:name=".SimpleActivity" android:taskAffinity="com.android.wm.shell.flicker.testapp.SimpleActivity" android:label="SimpleApp" diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_non_resizeable.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_non_resizeable.xml new file mode 100644 index 000000000000..45d5917f86d6 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_non_resizeable.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:background="@android:color/holo_orange_light"> + + <TextView + android:id="@+id/NonResizeableTest" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:gravity="center_vertical|center_horizontal" + android:text="NonResizeableActivity" + android:textAppearance="?android:attr/textAppearanceLarge"/> + +</LinearLayout> diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java index 8e9b4cb2d53e..f729ea554072 100644 --- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/Components.java @@ -38,6 +38,13 @@ public class Components { } } + public static class NonResizeableActivity extends ComponentsInfo { + @Override + public String getActivityName() { + return NonResizeableActivity.class.getSimpleName(); + } + } + public static class PipActivity extends ComponentsInfo { // Intent action that this activity dynamically registers to enter picture-in-picture public static final String ACTION_ENTER_PIP = PACKAGE_NAME + ".PipActivity.ENTER_PIP"; diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/NonResizeableActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/NonResizeableActivity.java new file mode 100644 index 000000000000..24275e002c7f --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/NonResizeableActivity.java @@ -0,0 +1,29 @@ +/* + * 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.testapp; + +import android.app.Activity; +import android.os.Bundle; + +public class NonResizeableActivity extends Activity { + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + setContentView(R.layout.activity_non_resizeable); + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java index 3ff750af7ec9..862776ec7df2 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java @@ -16,18 +16,14 @@ package com.android.wm.shell; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; -import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN; -import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_LETTERBOX; import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_MULTI_WINDOW; import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -38,7 +34,6 @@ import static org.mockito.Mockito.verify; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; import android.content.pm.ParceledListSlice; -import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; @@ -47,7 +42,6 @@ import android.window.ITaskOrganizer; import android.window.ITaskOrganizerController; import android.window.TaskAppearedInfo; -import androidx.annotation.Nullable; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -263,28 +257,6 @@ public class ShellTaskOrganizerTests { assertTrue(mwListener.appeared.contains(task2)); } - @Test - public void testTaskInfoToTaskListenerType_whenLetterboxBoundsPassed_returnsLetterboxType() { - RunningTaskInfo taskInfo = createTaskInfo( - /* taskId */ 1, - WINDOWING_MODE_FULLSCREEN, - /* letterboxActivityBounds */ new Rect(1, 1, 1, 1)); - - assertEquals( - ShellTaskOrganizer.taskInfoToTaskListenerType(taskInfo), - TASK_LISTENER_TYPE_LETTERBOX); - } - - @Test - public void testTaskInfoToTaskListenerType_whenLetterboxBoundsIsNull_returnsFullscreenType() { - RunningTaskInfo taskInfo = createTaskInfo( - /* taskId */ 1, WINDOWING_MODE_FULLSCREEN, /* letterboxActivityBounds */ null); - - assertEquals( - ShellTaskOrganizer.taskInfoToTaskListenerType(taskInfo), - TASK_LISTENER_TYPE_FULLSCREEN); - } - private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode) { RunningTaskInfo taskInfo = new RunningTaskInfo(); taskInfo.taskId = taskId; @@ -292,12 +264,4 @@ public class ShellTaskOrganizerTests { return taskInfo; } - private static RunningTaskInfo createTaskInfo( - int taskId, int windowingMode, @Nullable Rect letterboxActivityBounds) { - RunningTaskInfo taskInfo = new RunningTaskInfo(); - taskInfo.taskId = taskId; - taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode); - taskInfo.letterboxActivityBounds = Rect.copyOrNull(letterboxActivityBounds); - return taskInfo; - } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxConfigControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxConfigControllerTest.java deleted file mode 100644 index 29233366d4f3..000000000000 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxConfigControllerTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.letterbox; - -import static org.junit.Assert.assertEquals; - -import android.view.Gravity; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import com.android.wm.shell.R; -import com.android.wm.shell.ShellTestCase; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Tests for {@link LetterboxConfigController}. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public final class LetterboxConfigControllerTest extends ShellTestCase { - - private LetterboxConfigController mLetterboxConfigController; - - @Before - public void setUp() { - mLetterboxConfigController = new LetterboxConfigController(getContext()); - } - - @Test - public void testGetPortraitGravity_noOverrides_returnConfigValue() { - assertEquals( - mLetterboxConfigController.getPortraitGravity(), - getContext().getResources().getInteger(R.integer.config_letterboxPortraitGravity)); - } - - @Test - public void testGetLandscapeGravity_noOverrides_returnConfigValue() { - assertEquals( - mLetterboxConfigController.getLandscapeGravity(), - getContext().getResources().getInteger(R.integer.config_letterboxLandscapeGravity)); - } - - @Test - public void testSetPortraitGravity_validValue_savesValue() { - mLetterboxConfigController.setPortraitGravity(Gravity.BOTTOM); - assertEquals(mLetterboxConfigController.getPortraitGravity(), Gravity.BOTTOM); - - mLetterboxConfigController.setPortraitGravity(Gravity.CENTER); - assertEquals(mLetterboxConfigController.getPortraitGravity(), Gravity.CENTER); - - mLetterboxConfigController.setPortraitGravity(Gravity.TOP); - assertEquals(mLetterboxConfigController.getPortraitGravity(), Gravity.TOP); - } - - @Test - public void testSetLandscapeGravity_validValue_savesValue() { - mLetterboxConfigController.setLandscapeGravity(Gravity.LEFT); - assertEquals(mLetterboxConfigController.getLandscapeGravity(), Gravity.LEFT); - - mLetterboxConfigController.setLandscapeGravity(Gravity.CENTER); - assertEquals(mLetterboxConfigController.getLandscapeGravity(), Gravity.CENTER); - - mLetterboxConfigController.setLandscapeGravity(Gravity.RIGHT); - assertEquals(mLetterboxConfigController.getLandscapeGravity(), Gravity.RIGHT); - } - - @Test(expected = IllegalArgumentException.class) - public void testSetPortraitGravity_invalidValue_throwsException() { - mLetterboxConfigController.setPortraitGravity(Gravity.RIGHT); - } - - @Test(expected = IllegalArgumentException.class) - public void testSetLandscapeGravity_invalidValue_throwsException() { - mLetterboxConfigController.setLandscapeGravity(Gravity.TOP); - } - - @Test - public void testResetPortraitGravity() { - int defaultGravity = - getContext().getResources().getInteger(R.integer.config_letterboxPortraitGravity); - - mLetterboxConfigController.setPortraitGravity(Gravity.BOTTOM); - mLetterboxConfigController.resetPortraitGravity(); - assertEquals(mLetterboxConfigController.getPortraitGravity(), defaultGravity); - - mLetterboxConfigController.setPortraitGravity(Gravity.CENTER); - mLetterboxConfigController.resetPortraitGravity(); - assertEquals(mLetterboxConfigController.getPortraitGravity(), defaultGravity); - - mLetterboxConfigController.setPortraitGravity(Gravity.TOP); - mLetterboxConfigController.resetPortraitGravity(); - assertEquals(mLetterboxConfigController.getPortraitGravity(), defaultGravity); - } - - @Test - public void testResetLandscapeGravity() { - int defaultGravity = - getContext().getResources().getInteger(R.integer.config_letterboxLandscapeGravity); - - mLetterboxConfigController.setLandscapeGravity(Gravity.RIGHT); - mLetterboxConfigController.resetLandscapeGravity(); - assertEquals(mLetterboxConfigController.getLandscapeGravity(), defaultGravity); - - mLetterboxConfigController.setLandscapeGravity(Gravity.CENTER); - mLetterboxConfigController.resetLandscapeGravity(); - assertEquals(mLetterboxConfigController.getLandscapeGravity(), defaultGravity); - - mLetterboxConfigController.setLandscapeGravity(Gravity.LEFT); - mLetterboxConfigController.resetLandscapeGravity(); - assertEquals(mLetterboxConfigController.getLandscapeGravity(), defaultGravity); - } - -} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java deleted file mode 100644 index 5cbc7d927d61..000000000000 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.letterbox; - -import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; - -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -import android.app.ActivityManager.RunningTaskInfo; -import android.graphics.Insets; -import android.graphics.Rect; -import android.os.Handler; -import android.os.Looper; -import android.view.Gravity; -import android.view.SurfaceControl; -import android.view.WindowInsets; -import android.view.WindowManager; -import android.view.WindowMetrics; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import com.android.wm.shell.ShellTestCase; -import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.common.TransactionPool; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Tests for {@link LetterboxTaskListener}. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public final class LetterboxTaskListenerTest extends ShellTestCase { - - @Mock private SurfaceControl mLeash; - @Mock private SurfaceControl.Transaction mTransaction; - @Mock private WindowManager mWindowManager; - @Mock private WindowMetrics mWindowMetrics; - @Mock private WindowInsets mWindowInsets; - private LetterboxTaskListener mLetterboxTaskListener; - private LetterboxConfigController mLetterboxConfigController; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - mLetterboxConfigController = new LetterboxConfigController(getContext()); - mLetterboxTaskListener = new LetterboxTaskListener( - new SyncTransactionQueue( - new TransactionPool() { - @Override - public SurfaceControl.Transaction acquire() { - return mTransaction; - } - - @Override - public void release(SurfaceControl.Transaction t) { - } - }, - new Handler(Looper.getMainLooper())), - mLetterboxConfigController, - mWindowManager); - - when(mWindowManager.getMaximumWindowMetrics()).thenReturn(mWindowMetrics); - when(mWindowMetrics.getWindowInsets()).thenReturn(mWindowInsets); - } - - @Test - public void testOnTaskInfoChanged_updatesPositionAndCrop() { - setWindowBoundsAndInsets( - /* windowBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds - Insets.NONE); - - mLetterboxConfigController.setLandscapeGravity(Gravity.CENTER); - mLetterboxTaskListener.onTaskAppeared( - createTaskInfo( - /* taskId */ 1, - /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds - /* parentBounds */ new Rect(0, 0, 200, 100), - /* activityBounds */ new Rect(75, 0, 125, 75), - /* taskBounds */ new Rect(50, 0, 125, 100), - /* activityInsets */ new Rect(0, 0, 0, 0)), - mLeash); - - // Task doesn't need to repositioned - verifySetPosition(50, 0); - // Should return activity coordinates offset by task coordinates - verifySetWindowCrop(new Rect(25, 0, 75, 75)); - - mLetterboxTaskListener.onTaskInfoChanged( - createTaskInfo( - /* taskId */ 1, - /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds - /* parentBounds */ new Rect(0, 0, 200, 100), - // Activity is offset by 25 to the left - /* activityBounds */ new Rect(50, 0, 100, 75), - /* taskBounds */ new Rect(50, 0, 125, 100), - /* activityInsets */ new Rect(0, 0, 0, 0))); - - // Task needs to be repositioned by 25 to the left - verifySetPosition(75, 0); - // Should return activity coordinates offset by task coordinates - verifySetWindowCrop(new Rect(0, 0, 50, 75)); - } - - @Test - public void testOnTaskInfoAppeared_landscapeWithLeftGravity() { - mLetterboxConfigController.setLandscapeGravity(Gravity.LEFT); - setWindowBoundsAndInsets( - /* windowBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds - Insets.of(/* left= */ 10, /* top= */ 10, /* right= */ 10, /* bottom= */ 10)); - - mLetterboxTaskListener.onTaskAppeared( - createTaskInfo( - /* taskId */ 1, - /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds - /* parentBounds */ new Rect(0, 0, 200, 100), - /* activityBounds */ new Rect(150, 0, 200, 75), - /* taskBounds */ new Rect(125, 0, 200, 100), - /* activityInsets */ new Rect(0, 10, 10, 0)), - mLeash); - - verifySetPosition(-15, 0); - // Should return activity coordinates offset by task coordinates minus unwanted right inset - verifySetWindowCrop(new Rect(25, 0, 65, 75)); - } - - @Test - public void testOnTaskInfoAppeared_landscapeWithCenterGravity() { - mLetterboxConfigController.setLandscapeGravity(Gravity.CENTER); - setWindowBoundsAndInsets( - /* windowBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds - Insets.of(/* left= */ 10, /* top= */ 10, /* right= */ 10, /* bottom= */ 10)); - - mLetterboxTaskListener.onTaskAppeared( - createTaskInfo( - /* taskId */ 1, - /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds - /* parentBounds */ new Rect(0, 0, 200, 100), - /* activityBounds */ new Rect(150, 0, 200, 75), - /* taskBounds */ new Rect(125, 0, 200, 100), - /* activityInsets */ new Rect(0, 10, 10, 0)), - mLeash); - - verifySetPosition(55, 0); - // Should return activity coordinates offset by task coordinates minus unwanted right inset - verifySetWindowCrop(new Rect(25, 0, 65, 75)); - } - - @Test - public void testOnTaskInfoAppeared_landscapeWithRightGravity() { - mLetterboxConfigController.setLandscapeGravity(Gravity.RIGHT); - setWindowBoundsAndInsets( - /* windowBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds - Insets.of(/* left= */ 10, /* top= */ 10, /* right= */ 10, /* bottom= */ 10)); - - mLetterboxTaskListener.onTaskAppeared( - createTaskInfo( - /* taskId */ 1, - /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds - /* parentBounds */ new Rect(0, 0, 200, 100), - /* activityBounds */ new Rect(50, 0, 100, 75), - /* taskBounds */ new Rect(25, 0, 100, 100), - /* activityInsets */ new Rect(0, 10, 10, 0)), - mLeash); - - verifySetPosition(115, 0); - // Should return activity coordinates offset by task coordinates - verifySetWindowCrop(new Rect(25, 0, 75, 75)); - } - - @Test - public void testOnTaskInfoAppeared_portraitWithTopGravity() { - mLetterboxConfigController.setPortraitGravity(Gravity.TOP); - setWindowBoundsAndInsets( - /* windowBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds - Insets.of(/* left= */ 10, /* top= */ 10, /* right= */ 10, /* bottom= */ 20)); - - mLetterboxTaskListener.onTaskAppeared( - createTaskInfo( - /* taskId */ 1, - /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds - /* parentBounds */ new Rect(0, 0, 100, 150), - /* activityBounds */ new Rect(0, 75, 50, 125), - /* taskBounds */ new Rect(0, 50, 100, 125), - /* activityInsets */ new Rect(10, 0, 0, 0)), - mLeash); - - verifySetPosition(20, -15); - // Should return activity coordinates offset by task coordinates minus unwanted left inset - verifySetWindowCrop(new Rect(10, 25, 50, 75)); - } - - @Test - public void testOnTaskInfoAppeared_portraitWithCenterGravity() { - mLetterboxConfigController.setPortraitGravity(Gravity.CENTER); - setWindowBoundsAndInsets( - /* windowBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds - Insets.of(/* left= */ 10, /* top= */ 10, /* right= */ 10, /* bottom= */ 20)); - - mLetterboxTaskListener.onTaskAppeared( - createTaskInfo( - /* taskId */ 1, - /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds - /* parentBounds */ new Rect(0, 0, 100, 150), - /* activityBounds */ new Rect(0, 75, 50, 125), - /* taskBounds */ new Rect(0, 50, 100, 125), - /* activityInsets */ new Rect(10, 0, 0, 0)), - mLeash); - - verifySetPosition(20, 20); - // Should return activity coordinates offset by task coordinates minus unwanted left inset - verifySetWindowCrop(new Rect(10, 25, 50, 75)); - } - - @Test - public void testOnTaskInfoAppeared_portraitWithCenterGravity_visibleLeftInset() { - mLetterboxConfigController.setPortraitGravity(Gravity.CENTER); - setWindowBoundsAndInsets( - /* windowBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds - Insets.of(/* left= */ 10, /* top= */ 10, /* right= */ 10, /* bottom= */ 20)); - - mLetterboxTaskListener.onTaskAppeared( - createTaskInfo( - /* taskId */ 1, - /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds - /* parentBounds */ new Rect(0, 0, 100, 150), - /* activityBounds */ new Rect(0, 75, 50, 125), - /* taskBounds */ new Rect(0, 50, 100, 125), - // Activity is drawn under the left inset. - /* activityInsets */ new Rect(0, 0, 0, 0)), - mLeash); - - verifySetPosition(20, 20); - // Should return activity coordinates offset by task coordinates - verifySetWindowCrop(new Rect(0, 25, 50, 75)); - } - - @Test - public void testOnTaskInfoAppeared_portraitWithBottomGravity() { - mLetterboxConfigController.setPortraitGravity(Gravity.BOTTOM); - setWindowBoundsAndInsets( - /* windowBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds - Insets.of(/* left= */ 10, /* top= */ 10, /* right= */ 10, /* bottom= */ 20)); - - mLetterboxTaskListener.onTaskAppeared( - createTaskInfo( - /* taskId */ 1, - /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds - /* parentBounds */ new Rect(0, 0, 100, 150), - /* activityBounds */ new Rect(0, 75, 50, 125), - /* taskBounds */ new Rect(0, 50, 100, 125), - /* activityInsets */ new Rect(10, 0, 0, 0)), - mLeash); - - verifySetPosition(20, 55); - // Should return activity coordinates offset by task coordinates minus unwanted left inset - verifySetWindowCrop(new Rect(10, 25, 50, 75)); - } - - @Test - public void testOnTaskInfoAppeared_partlyOverlapsWithAllInsets() { - mLetterboxConfigController.setPortraitGravity(Gravity.TOP); - setWindowBoundsAndInsets( - /* windowBounds= */ new Rect(0, 0, 200, 125), // equal to parent bounds - Insets.of(/* left= */ 25, /* top= */ 25, /* right= */ 35, /* bottom= */ 15)); - - mLetterboxTaskListener.onTaskAppeared( - createTaskInfo( - /* taskId */ 1, - /* maxBounds= */ new Rect(0, 0, 200, 125), // equal to parent bounds - /* parentBounds */ new Rect(0, 0, 200, 125), - /* activityBounds */ new Rect(15, 0, 175, 120), - /* taskBounds */ new Rect(0, 0, 200, 125), - /* activityInsets */ new Rect(10, 25, 10, 10)), // equal to parent bounds - mLeash); - - // Activity fully covers parent bounds with insets so doesn't need to be moved. - verifySetPosition(0, 0); - // Should return activity coordinates offset by task coordinates - verifySetWindowCrop(new Rect(15, 0, 175, 120)); - } - - @Test - public void testOnTaskInfoAppeared_parentShiftedLikeInOneHandedMode() { - mLetterboxConfigController.setPortraitGravity(Gravity.TOP); - setWindowBoundsAndInsets( - /* windowBounds= */ new Rect(0, 0, 100, 150), - Insets.of(/* left= */ 0, /* top= */ 10, /* right= */ 0, /* bottom= */ 0)); - - mLetterboxTaskListener.onTaskAppeared( - createTaskInfo( - /* taskId */ 1, - /* maxBounds= */ new Rect(0, 0, 100, 150), - /* parentBounds */ new Rect(0, 75, 100, 225), - /* activityBounds */ new Rect(25, 75, 75, 125), - /* taskBounds */ new Rect(0, 75, 100, 125), - /* activityInsets */ new Rect(10, 0, 0, 0)), - mLeash); - - verifySetPosition(0, 0); - verifySetWindowCrop(new Rect(25, 0, 75, 50)); - } - - @Test(expected = IllegalStateException.class) - public void testOnTaskAppeared_calledSecondTimeWithSameTaskId_throwsException() { - setWindowBoundsAndInsets(new Rect(), Insets.NONE); - RunningTaskInfo taskInfo = - createTaskInfo(/* taskId */ 1, new Rect(), new Rect(), new Rect(), new Rect(), - new Rect()); - mLetterboxTaskListener.onTaskAppeared(taskInfo, mLeash); - mLetterboxTaskListener.onTaskAppeared(taskInfo, mLeash); - } - - private void setWindowBoundsAndInsets(Rect windowBounds, Insets insets) { - when(mWindowMetrics.getBounds()).thenReturn(windowBounds); - when(mWindowInsets.getInsets(anyInt())).thenReturn(insets); - } - - private void verifySetPosition(int x, int y) { - verify(mTransaction).setPosition(eq(mLeash), eq((float) x), eq((float) y)); - } - - private void verifySetWindowCrop(final Rect crop) { - // Should return activty coordinates offset by task coordinates - verify(mTransaction).setWindowCrop(eq(mLeash), eq(crop)); - } - - private static RunningTaskInfo createTaskInfo( - int taskId, - final Rect maxBounds, - final Rect parentBounds, - final Rect activityBounds, - final Rect taskBounds, - final Rect activityInsets) { - RunningTaskInfo taskInfo = new RunningTaskInfo(); - taskInfo.taskId = taskId; - taskInfo.configuration.windowConfiguration.setMaxBounds(maxBounds); - taskInfo.parentBounds = parentBounds; - taskInfo.configuration.windowConfiguration.setBounds(taskBounds); - taskInfo.letterboxActivityBounds = Rect.copyOrNull(activityBounds); - taskInfo.letterboxActivityInsets = Rect.copyOrNull(activityInsets); - - return taskInfo; - } -} diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index 068f9689d06f..4b8a8adade1f 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -73,6 +73,8 @@ interface IMediaRouterService { void unregisterManager(IMediaRouter2Manager manager); void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId, in MediaRoute2Info route, int volume); + void startScan(IMediaRouter2Manager manager); + void stopScan(IMediaRouter2Manager manager); void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId, in RoutingSessionInfo oldSession, in @nullable MediaRoute2Info route); diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index c2168f12a351..e7e83ebb001f 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -25,6 +25,7 @@ import android.annotation.SuppressLint; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; +import android.os.Process; import android.os.SystemProperties; import android.util.Log; import android.util.Pair; @@ -188,13 +189,14 @@ public final class MediaCodecInfo { // COMMON CONSTANTS private static final Range<Integer> POSITIVE_INTEGERS = - Range.create(1, Integer.MAX_VALUE); + Range.create(1, Integer.MAX_VALUE); private static final Range<Long> POSITIVE_LONGS = - Range.create(1l, Long.MAX_VALUE); + Range.create(1L, Long.MAX_VALUE); private static final Range<Rational> POSITIVE_RATIONALS = - Range.create(new Rational(1, Integer.MAX_VALUE), - new Rational(Integer.MAX_VALUE, 1)); - private static final Range<Integer> SIZE_RANGE = Range.create(1, 32768); + Range.create(new Rational(1, Integer.MAX_VALUE), + new Rational(Integer.MAX_VALUE, 1)); + private static final Range<Integer> SIZE_RANGE = + Process.is64Bit() ? Range.create(1, 32768) : Range.create(1, 4096); private static final Range<Integer> FRAME_RATE_RANGE = Range.create(0, 960); private static final Range<Integer> BITRATE_RANGE = Range.create(0, 500000000); private static final int DEFAULT_MAX_SUPPORTED_INSTANCES = 32; @@ -1399,6 +1401,9 @@ public final class MediaCodecInfo { /** * Returns the range of supported video widths. + * <p class=note> + * 32-bit processes will not support resolutions larger than 4096x4096 due to + * the limited address space. */ public Range<Integer> getSupportedWidths() { return mWidthRange; @@ -1406,6 +1411,9 @@ public final class MediaCodecInfo { /** * Returns the range of supported video heights. + * <p class=note> + * 32-bit processes will not support resolutions larger than 4096x4096 due to + * the limited address space. */ public Range<Integer> getSupportedHeights() { return mHeightRange; @@ -1857,6 +1865,10 @@ public final class MediaCodecInfo { && aligned.mMaxMacroBlockRate >= otherAligned.mMaxMacroBlockRate); } + /* package private */ boolean isEqualDimension(@NonNull PerformancePoint other) { + return mWidth == other.mWidth && mHeight == other.mHeight; + } + private @NonNull Size getCommonBlockSize(@NonNull PerformancePoint other) { return new Size( Math.max(mBlockSize.getWidth(), other.mBlockSize.getWidth()) * 16, @@ -1997,6 +2009,9 @@ public final class MediaCodecInfo { * Performance points assume a single active codec. For use cases where multiple * codecs are active, should use that highest pixel count, and add the frame rates of * each individual codec. + * <p class=note> + * Supported resolution could be further restricted for 32-bit processes due to + * the limited virtual memory space. */ @Nullable public List<PerformancePoint> getSupportedPerformancePoints() { @@ -2164,6 +2179,12 @@ public final class MediaCodecInfo { if (size == null || size.getWidth() * size.getHeight() <= 0) { continue; } + if (size.getWidth() > SIZE_RANGE.getUpper() + || size.getHeight() > SIZE_RANGE.getUpper()) { + size = new Size( + Math.min(size.getWidth(), SIZE_RANGE.getUpper()), + Math.min(size.getHeight(), SIZE_RANGE.getUpper())); + } Range<Long> range = Utils.parseLongRange(map.get(key), null); if (range == null || range.getLower() < 0 || range.getUpper() < 0) { continue; @@ -2193,6 +2214,29 @@ public final class MediaCodecInfo { (a.getMaxMacroBlockRate() < b.getMaxMacroBlockRate() ? -1 : 1) : (a.getMaxFrameRate() != b.getMaxFrameRate()) ? (a.getMaxFrameRate() < b.getMaxFrameRate() ? -1 : 1) : 0)); + + // remove redundant points + for (int i = 1; i < ret.size(); ++i) { + PerformancePoint a = ret.get(i); + for (int j = 0; j < i; ++j) { + PerformancePoint b = ret.get(j); + if (b.isEqualDimension(a) && b.covers(a)) { + ret.set(i, null); + break; + } + } + } + int newSize = 0; + for (int i = 0; i < ret.size(); ++i) { + PerformancePoint a = ret.get(i); + if (a == null) { + continue; + } + ret.set(newSize, a); + ++newSize; + } + ret.setSize(newSize); + return Collections.unmodifiableList(ret); } diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java index 4b09a5f19fb0..68237de2ca98 100644 --- a/media/java/android/media/MediaRouter2Manager.java +++ b/media/java/android/media/MediaRouter2Manager.java @@ -147,6 +147,36 @@ public final class MediaRouter2Manager { } /** + * Starts scanning remote routes. + * @see #stopScan(String) + */ + public void startScan() { + Client client = getOrCreateClient(); + if (client != null) { + try { + mMediaRouterService.startScan(client); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to get sessions. Service probably died.", ex); + } + } + } + + /** + * Stops scanning remote routes to reduce resource consumption. + * @see #startScan(String) + */ + public void stopScan() { + Client client = getOrCreateClient(); + if (client != null) { + try { + mMediaRouterService.stopScan(client); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to get sessions. Service probably died.", ex); + } + } + } + + /** * Gets a {@link android.media.session.MediaController} associated with the * given routing session. * If there is no matching media session, {@code null} is returned. diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java index 68f2964dbeb2..2f952474b7f0 100644 --- a/media/java/android/media/RouteDiscoveryPreference.java +++ b/media/java/android/media/RouteDiscoveryPreference.java @@ -153,6 +153,7 @@ public final class RouteDiscoveryPreference implements Parcelable { return false; } RouteDiscoveryPreference other = (RouteDiscoveryPreference) o; + //TODO: Make this order-free return Objects.equals(mPreferredFeatures, other.mPreferredFeatures) && mShouldPerformActiveScan == other.mShouldPerformActiveScan; } diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index d094c2cd3c63..20f02a46ea63 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -279,6 +279,7 @@ public class Tuner implements AutoCloseable { @Nullable private FrontendInfo mFrontendInfo; private Integer mFrontendHandle; + private Boolean mIsSharedFrontend = false; private int mFrontendType = FrontendSettings.TYPE_UNDEFINED; private int mUserId; private Lnb mLnb; @@ -441,8 +442,11 @@ public class Tuner implements AutoCloseable { */ public void shareFrontendFromTuner(@NonNull Tuner tuner) { mTunerResourceManager.shareFrontend(mClientId, tuner.mClientId); - mFrontendHandle = tuner.mFrontendHandle; - mFrontend = nativeOpenFrontendByHandle(mFrontendHandle); + synchronized (mIsSharedFrontend) { + mFrontendHandle = tuner.mFrontendHandle; + mFrontend = tuner.mFrontend; + mIsSharedFrontend = true; + } } /** @@ -473,14 +477,19 @@ public class Tuner implements AutoCloseable { private void releaseAll() { if (mFrontendHandle != null) { - int res = nativeCloseFrontend(mFrontendHandle); - if (res != Tuner.RESULT_SUCCESS) { - TunerUtils.throwExceptionForResult(res, "failed to close frontend"); + synchronized (mIsSharedFrontend) { + if (!mIsSharedFrontend) { + int res = nativeCloseFrontend(mFrontendHandle); + if (res != Tuner.RESULT_SUCCESS) { + TunerUtils.throwExceptionForResult(res, "failed to close frontend"); + } + } + mIsSharedFrontend = false; } mTunerResourceManager.releaseFrontend(mFrontendHandle, mClientId); FrameworkStatsLog .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId, - FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__UNKNOWN); + FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__UNKNOWN); mFrontendHandle = null; mFrontend = null; } diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp index 948ebcd9fdd5..6a622c5a1566 100644 --- a/media/jni/android_media_MediaExtractor.cpp +++ b/media/jni/android_media_MediaExtractor.cpp @@ -68,7 +68,7 @@ JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz) mClass = (jclass)env->NewGlobalRef(clazz); mObject = env->NewWeakGlobalRef(thiz); - mImpl = new NuMediaExtractor; + mImpl = new NuMediaExtractor(NuMediaExtractor::EntryPoint::SDK); } JMediaExtractor::~JMediaExtractor() { diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 126897a908f8..ddc51cdb861c 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -464,11 +464,13 @@ static jobject android_media_MediaMetadataRetriever_getThumbnailImageAtIndex( || thumbPixels * 6 >= maxPixels) { frameMemory = retriever->getImageAtIndex( index, colorFormat, false /*metaOnly*/, true /*thumbnail*/); - // TODO: Using unsecurePointer() has some associated security pitfalls - // (see declaration for details). - // Either document why it is safe in this case or address the - // issue (e.g. by copying). - videoFrame = static_cast<VideoFrame *>(frameMemory->unsecurePointer()); + if (frameMemory != 0) { + // TODO: Using unsecurePointer() has some associated security pitfalls + // (see declaration for details). + // Either document why it is safe in this case or address the + // issue (e.g. by copying). + videoFrame = static_cast<VideoFrame *>(frameMemory->unsecurePointer()); + } if (thumbPixels > maxPixels) { int downscale = ceil(sqrt(thumbPixels / (float)maxPixels)); diff --git a/media/native/midi/amidi.cpp b/media/native/midi/amidi.cpp index 35c4d42a0aa8..923377c8180e 100644 --- a/media/native/midi/amidi.cpp +++ b/media/native/midi/amidi.cpp @@ -131,7 +131,7 @@ static media_status_t AMIDI_getDeviceInfo(const AMidiDevice *device, MidiDeviceInfo deviceInfo; Status txResult = device->server->getDeviceInfo(&deviceInfo); if (!txResult.isOk()) { - ALOGE("AMIDI_getDeviceInfo transaction error: %d", txResult.transactionError()); + ALOGE("%s server exception code: %d", __func__, txResult.exceptionCode()); return AMEDIA_ERROR_UNKNOWN; } @@ -253,7 +253,7 @@ static media_status_t AMIDI_openPort(const AMidiDevice *device, int32_t portNumb ? device->server->openOutputPort(portToken, portNumber, &ufd) : device->server->openInputPort(portToken, portNumber, &ufd); if (!txResult.isOk()) { - ALOGE("AMIDI_openPort transaction error: %d", txResult.transactionError()); + ALOGE("%s server exception code: %d", __func__, txResult.exceptionCode()); return AMEDIA_ERROR_UNKNOWN; } @@ -282,7 +282,7 @@ static void AMIDI_closePort(AMIDI_Port *port) { Status txResult = port->device->server->closePort(port->binderToken); if (!txResult.isOk()) { - ALOGE("Transaction error closing MIDI port:%d", txResult.transactionError()); + ALOGE("%s server exception code: %d", __func__, txResult.exceptionCode()); } delete port; diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 4e9721218a02..ca0686751873 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1112,7 +1112,7 @@ <string name="power_remaining_charging_duration_only"><xliff:g id="time">%1$s</xliff:g> left until charged</string> <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration --> <string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="time">%2$s</xliff:g> until charged</string> - <!-- [CHAR_LIMIT=40] Label for battery level chart when charge been limited --> + <!-- [CHAR_LIMIT=80] Label for battery level chart when charge been limited --> <string name="power_charging_limited"><xliff:g id="level">%1$s</xliff:g> - Optimizing for battery health</string> <!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed --> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java index 611c4b766b4e..fa2f8b97b039 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java @@ -137,4 +137,15 @@ public class RecentsAnimationControllerCompat { return false; } } + + /** + * @see IRecentsAnimationController#detachNavigationBarFromApp + */ + public void detachNavigationBarFromApp() { + try { + mAnimationController.detachNavigationBarFromApp(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to detach the navigation bar from app", e); + } + } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java index eb86128a82a5..9e2538977fab 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java @@ -24,6 +24,7 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.media.MediaMetadata; import android.media.MediaRoute2Info; +import android.media.MediaRouter2Manager; import android.media.RoutingSessionInfo; import android.media.session.MediaController; import android.media.session.MediaSessionManager; @@ -76,6 +77,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>(); private final boolean mAboveStatusbar; private final NotificationEntryManager mNotificationEntryManager; + private final MediaRouter2Manager mRouterManager; @VisibleForTesting final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>(); @@ -104,6 +106,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName); mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName); mUiEventLogger = uiEventLogger; + mRouterManager = MediaRouter2Manager.getInstance(mContext); } void start(@NonNull Callback cb) { @@ -134,6 +137,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { mLocalMediaManager.stopScan(); mLocalMediaManager.registerCallback(this); mLocalMediaManager.startScan(); + mRouterManager.startScan(); } void stop() { @@ -144,6 +148,9 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { mLocalMediaManager.unregisterCallback(this); mLocalMediaManager.stopScan(); } + if (mRouterManager != null) { + mRouterManager.stopScan(); + } mMediaDevices.clear(); } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index 654e92270c9a..ee58947a691c 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -57,8 +57,6 @@ import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController; -import com.android.wm.shell.letterbox.LetterboxConfigController; -import com.android.wm.shell.letterbox.LetterboxTaskListener; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.pip.Pip; @@ -173,7 +171,6 @@ public abstract class WMShellBaseModule { ShellTaskOrganizer shellTaskOrganizer, Optional<SplitScreen> splitScreenOptional, Optional<AppPairs> appPairsOptional, - LetterboxTaskListener letterboxTaskListener, FullscreenTaskListener fullscreenTaskListener, Transitions transitions) { return new ShellInit(displayImeController, @@ -181,7 +178,6 @@ public abstract class WMShellBaseModule { shellTaskOrganizer, splitScreenOptional, appPairsOptional, - letterboxTaskListener, fullscreenTaskListener, transitions); } @@ -198,11 +194,9 @@ public abstract class WMShellBaseModule { Optional<Pip> pipOptional, Optional<OneHanded> oneHandedOptional, Optional<HideDisplayCutout> hideDisplayCutout, - Optional<AppPairs> appPairsOptional, - LetterboxConfigController letterboxConfigController) { + Optional<AppPairs> appPairsOptional) { return Optional.of(new ShellCommandHandler(shellTaskOrganizer, splitScreenOptional, - pipOptional, oneHandedOptional, hideDisplayCutout, appPairsOptional, - letterboxConfigController)); + pipOptional, oneHandedOptional, hideDisplayCutout, appPairsOptional)); } @WMSingleton @@ -338,21 +332,6 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides - static LetterboxTaskListener provideLetterboxTaskListener( - SyncTransactionQueue syncQueue, - LetterboxConfigController letterboxConfigController, - WindowManager windowManager) { - return new LetterboxTaskListener(syncQueue, letterboxConfigController, windowManager); - } - - @WMSingleton - @Provides - static LetterboxConfigController provideLetterboxConfigController(Context context) { - return new LetterboxConfigController(context); - } - - @WMSingleton - @Provides static Transitions provideTransitions(ShellTaskOrganizer organizer, TransactionPool pool, @ShellMainThread ShellExecutor mainExecutor, @ShellAnimationThread ShellExecutor animExecutor) { diff --git a/services/autofill/java/com/android/server/autofill/TEST_MAPPING b/services/autofill/java/com/android/server/autofill/TEST_MAPPING index cf058add0262..d8a69177387d 100644 --- a/services/autofill/java/com/android/server/autofill/TEST_MAPPING +++ b/services/autofill/java/com/android/server/autofill/TEST_MAPPING @@ -1,5 +1,5 @@ { - "presubmit": [ + "presubmit-large": [ { "name": "CtsAutoFillServiceTestCases", "options": [ diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 0a80b02a964c..e6e52de0440f 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -40,6 +40,7 @@ import android.bluetooth.BluetoothDevice; import android.companion.Association; import android.companion.AssociationRequest; import android.companion.CompanionDeviceManager; +import android.companion.DeviceNotAssociatedException; import android.companion.ICompanionDeviceDiscoveryService; import android.companion.ICompanionDeviceManager; import android.companion.IFindDeviceCallback; @@ -486,6 +487,43 @@ public class CompanionDeviceManagerService extends SystemService implements Bind a -> Objects.equals(a.getDeviceMacAddress(), macAddress)); } + @Override + public void registerDevicePresenceListenerService( + String packageName, String deviceAddress) + throws RemoteException { + checkCanRegisterObserverService(packageName, deviceAddress); + + //TODO(eugenesusla) implement + } + + @Override + public void unregisterDevicePresenceListenerService( + String packageName, String deviceAddress) + throws RemoteException { + checkCanRegisterObserverService(packageName, deviceAddress); + + //TODO(eugenesusla) implement + } + + private void checkCanRegisterObserverService(String packageName, String deviceAddress) + throws RemoteException { + getContext().enforceCallingOrSelfPermission( + android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE, + "[un]registerDevicePresenceListenerService"); + checkCallerIsSystemOr(packageName); + + int userId = getCallingUserId(); + Set<Association> deviceAssociations = CollectionUtils.filter( + getAllAssociations(userId, packageName), + association -> deviceAddress.equals(association.getDeviceMacAddress())); + + if (deviceAssociations.isEmpty()) { + throw new RemoteException(new DeviceNotAssociatedException("App " + packageName + + " is not associated with device " + deviceAddress + + " for user " + userId)); + } + } + private void checkCanCallNotificationApi(String callingPackage) throws RemoteException { checkCallerIsSystemOr(callingPackage); int userId = getCallingUserId(); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index f87892950a00..a6559f9521e0 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -129,6 +129,7 @@ import android.net.RouteInfoParcel; import android.net.SocketKeepalive; import android.net.TetheringManager; import android.net.UidRange; +import android.net.UidRangeParcel; import android.net.Uri; import android.net.VpnManager; import android.net.VpnService; @@ -2822,6 +2823,7 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED: { + // TODO: prevent loops, e.g., if a network declares itself as underlying. if (!nai.supportsUnderlyingNetworks()) { Log.wtf(TAG, "Non-virtual networks cannot have underlying networks"); break; @@ -3421,6 +3423,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } nai.clearLingerState(); + propagateUnderlyingNetworkCapabilities(nai.network); if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) { mDefaultNetworkNai = null; updateDataActivityTracking(null /* newNetwork */, nai); @@ -3428,9 +3431,6 @@ public class ConnectivityService extends IConnectivityManager.Stub ensureNetworkTransitionWakelock(nai.toShortString()); } mLegacyTypeTracker.remove(nai, wasDefault); - if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) { - propagateUnderlyingNetworkCapabilities(); - } rematchAllNetworksAndRequests(); mLingerMonitor.noteDisconnect(nai); if (nai.created) { @@ -4819,17 +4819,35 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private Network[] underlyingNetworksOrDefault(Network[] underlyingNetworks) { + final Network defaultNetwork = getNetwork(getDefaultNetwork()); + if (underlyingNetworks == null && defaultNetwork != null) { + // null underlying networks means to track the default. + underlyingNetworks = new Network[] { defaultNetwork }; + } + return underlyingNetworks; + } + + // Returns true iff |network| is an underlying network of |nai|. + private boolean hasUnderlyingNetwork(NetworkAgentInfo nai, Network network) { + // TODO: support more than one level of underlying networks, either via a fixed-depth search + // (e.g., 2 levels of underlying networks), or via loop detection, or.... + if (!nai.supportsUnderlyingNetworks()) return false; + final Network[] underlying = underlyingNetworksOrDefault(nai.declaredUnderlyingNetworks); + return ArrayUtils.contains(underlying, network); + } + /** - * Ask all networks with underlying networks to recompute and update their capabilities. + * Recompute the capabilities for any networks that had a specific network as underlying. * * When underlying networks change, such networks may have to update capabilities to reflect * things like the metered bit, their transports, and so on. The capabilities are calculated * immediately. This method runs on the ConnectivityService thread. */ - private void propagateUnderlyingNetworkCapabilities() { + private void propagateUnderlyingNetworkCapabilities(Network updatedNetwork) { ensureRunningOnConnectivityServiceThread(); for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { - if (nai.supportsUnderlyingNetworks()) { + if (updatedNetwork == null || hasUnderlyingNetwork(nai, updatedNetwork)) { updateCapabilitiesForNetwork(nai); } } @@ -5152,7 +5170,7 @@ public class ConnectivityService extends IConnectivityManager.Stub loge("Starting user already has a VPN"); return; } - userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, userId, mKeyStore); + userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore); mVpns.put(userId, userVpn); if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) { updateLockdownVpn(); @@ -6368,27 +6386,28 @@ public class ConnectivityService extends IConnectivityManager.Stub * This method should never alter the agent's NetworkCapabilities, only store data in |nai|. */ private void processCapabilitiesFromAgent(NetworkAgentInfo nai, NetworkCapabilities nc) { - nai.declaredMetered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED); + // Note: resetting the owner UID before storing the agent capabilities in NAI means that if + // the agent attempts to change the owner UID, then nai.declaredCapabilities will not + // actually be the same as the capabilities sent by the agent. Still, it is safer to reset + // the owner UID here and behave as if the agent had never tried to change it. if (nai.networkCapabilities.getOwnerUid() != nc.getOwnerUid()) { Log.e(TAG, nai.toShortString() + ": ignoring attempt to change owner from " + nai.networkCapabilities.getOwnerUid() + " to " + nc.getOwnerUid()); nc.setOwnerUid(nai.networkCapabilities.getOwnerUid()); } + nai.declaredCapabilities = new NetworkCapabilities(nc); } - /** Modifies |caps| based on the capabilities of the specified underlying networks. */ + /** Modifies |newNc| based on the capabilities of |underlyingNetworks| and |agentCaps|. */ @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 }; + @NonNull NetworkCapabilities agentCaps, @NonNull NetworkCapabilities newNc) { + underlyingNetworks = underlyingNetworksOrDefault(underlyingNetworks); + int[] transportTypes = agentCaps.getTransportTypes(); int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; - boolean metered = declaredMetered; // metered if any underlying is metered, or agentMetered + // metered if any underlying is metered, or originally declared metered by the agent. + boolean metered = !agentCaps.hasCapability(NET_CAPABILITY_NOT_METERED); 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 @@ -6434,13 +6453,13 @@ public class ConnectivityService extends IConnectivityManager.Stub 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); + newNc.setTransportTypes(transportTypes); + newNc.setLinkDownstreamBandwidthKbps(downKbps); + newNc.setLinkUpstreamBandwidthKbps(upKbps); + newNc.setCapability(NET_CAPABILITY_NOT_METERED, !metered); + newNc.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming); + newNc.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested); + newNc.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended); } /** @@ -6497,7 +6516,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } if (nai.supportsUnderlyingNetworks()) { - applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, newNc, nai.declaredMetered); + applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, nai.declaredCapabilities, + newNc); } return newNc; @@ -6576,11 +6596,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - if (!newNc.hasTransport(TRANSPORT_VPN)) { - // Tell VPNs about updated capabilities, since they may need to - // bubble those changes through. - propagateUnderlyingNetworkCapabilities(); - } + // This network might have been underlying another network. Propagate its capabilities. + propagateUnderlyingNetworkCapabilities(nai.network); if (!newNc.equalsTransportTypes(prevNc)) { mDnsManager.updateTransportsForNetwork( @@ -6622,6 +6639,16 @@ public class ConnectivityService extends IConnectivityManager.Stub && (lp.hasIpv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute()); } + private static UidRangeParcel[] toUidRangeStableParcels(final @NonNull Set<UidRange> ranges) { + final UidRangeParcel[] stableRanges = new UidRangeParcel[ranges.size()]; + int index = 0; + for (UidRange range : ranges) { + stableRanges[index] = new UidRangeParcel(range.start, range.stop); + index++; + } + return stableRanges; + } + private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc, NetworkCapabilities newNc) { Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids(); @@ -6641,14 +6668,11 @@ public class ConnectivityService extends IConnectivityManager.Stub // removing old range works because, unlike the filtering rules below, it's possible to // add duplicate UID routing rules. if (!newRanges.isEmpty()) { - final UidRange[] addedRangesArray = new UidRange[newRanges.size()]; - newRanges.toArray(addedRangesArray); - mNMS.addVpnUidRanges(nai.network.getNetId(), addedRangesArray); + mNetd.networkAddUidRanges(nai.network.netId, toUidRangeStableParcels(newRanges)); } if (!prevRanges.isEmpty()) { - final UidRange[] removedRangesArray = new UidRange[prevRanges.size()]; - prevRanges.toArray(removedRangesArray); - mNMS.removeVpnUidRanges(nai.network.getNetId(), removedRangesArray); + mNetd.networkRemoveUidRanges( + nai.network.netId, toUidRangeStableParcels(prevRanges)); } final boolean wasFiltering = requiresVpnIsolation(nai, prevNc, nai.linkProperties); final boolean shouldFilter = requiresVpnIsolation(nai, newNc, nai.linkProperties); @@ -6903,8 +6927,10 @@ public class ConnectivityService extends IConnectivityManager.Stub updateTcpBufferSizes(null != newNetwork ? newNetwork.linkProperties.getTcpBufferSizes() : null); notifyIfacesChangedForNetworkStats(); - // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks. - propagateUnderlyingNetworkCapabilities(); + // Fix up the NetworkCapabilities of any networks that have this network as underlying. + if (newNetwork != null) { + propagateUnderlyingNetworkCapabilities(newNetwork.network); + } } private void processListenRequests(@NonNull final NetworkAgentInfo nai) { @@ -7360,13 +7386,11 @@ public class ConnectivityService extends IConnectivityManager.Stub networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND); if (!createNativeNetwork(networkAgent)) return; - if (networkAgent.isVPN()) { - // Initialize the VPN capabilities to their starting values according to the - // underlying networks. This will avoid a spurious callback to - // onCapabilitiesUpdated being sent in updateAllVpnCapabilities below as - // the VPN would switch from its default, blank capabilities to those - // that reflect the capabilities of its underlying networks. - propagateUnderlyingNetworkCapabilities(); + if (networkAgent.supportsUnderlyingNetworks()) { + // Initialize the network's capabilities to their starting values according to the + // underlying networks. This ensures that the capabilities are correct before + // anything happens to the network. + updateCapabilitiesForNetwork(networkAgent); } networkAgent.created = true; } @@ -7408,10 +7432,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // doing. updateSignalStrengthThresholds(networkAgent, "CONNECT", null); - if (networkAgent.supportsUnderlyingNetworks()) { - propagateUnderlyingNetworkCapabilities(); - } - // Consider network even though it is not yet validated. rematchAllNetworksAndRequests(); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 5e86f855c1e7..086cc1ca32ed 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -60,7 +60,6 @@ import android.net.NetworkStack; import android.net.NetworkStats; import android.net.RouteInfo; import android.net.TetherStatsParcel; -import android.net.UidRange; import android.net.UidRangeParcel; import android.net.shared.NetdUtils; import android.net.shared.RouteUtils; @@ -1393,38 +1392,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } } - private static UidRangeParcel makeUidRangeParcel(int start, int stop) { - UidRangeParcel range = new UidRangeParcel(); - range.start = start; - range.stop = stop; - return range; - } - - private static UidRangeParcel[] toStableParcels(UidRange[] ranges) { - UidRangeParcel[] stableRanges = new UidRangeParcel[ranges.length]; - for (int i = 0; i < ranges.length; i++) { - stableRanges[i] = makeUidRangeParcel(ranges[i].start, ranges[i].stop); - } - return stableRanges; - } - - @Override - public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges) - throws ServiceSpecificException { - NetworkStack.checkNetworkStackPermission(mContext); - try { - mNetdService.networkRejectNonSecureVpn(add, toStableParcels(uidRanges)); - } catch (ServiceSpecificException e) { - Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")" - + ": netd command failed", e); - throw e; - } catch (RemoteException e) { - Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")" - + ": netd command failed", e); - throw e.rethrowAsRuntimeException(); - } - } - private void applyUidCleartextNetworkPolicy(int uid, int policy) { final int policyValue; switch (policy) { @@ -1553,27 +1520,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } @Override - public void addVpnUidRanges(int netId, UidRange[] ranges) { - NetworkStack.checkNetworkStackPermission(mContext); - - try { - mNetdService.networkAddUidRanges(netId, toStableParcels(ranges)); - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override - public void removeVpnUidRanges(int netId, UidRange[] ranges) { - NetworkStack.checkNetworkStackPermission(mContext); - try { - mNetdService.networkRemoveUidRanges(netId, toStableParcels(ranges)); - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override public void setFirewallEnabled(boolean enabled) { enforceSystemUid(); try { @@ -1616,7 +1562,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { ranges = new UidRangeParcel[] { // TODO: is there a better way of finding all existing users? If so, we could // specify their ranges here. - makeUidRangeParcel(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE), + new UidRangeParcel(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE), }; // ... except for the UIDs that have allow rules. synchronized (mRulesLock) { @@ -1647,7 +1593,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { for (int i = 0; i < ranges.length; i++) { if (rules.valueAt(i) == FIREWALL_RULE_DENY) { int uid = rules.keyAt(i); - ranges[numUids] = makeUidRangeParcel(uid, uid); + ranges[numUids] = new UidRangeParcel(uid, uid); numUids++; } } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index c95bfd031af4..730c64e6968c 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -4488,10 +4488,13 @@ class StorageManagerService extends IStorageManager.Stub // When using FUSE, we may need to kill the app if the op changes switch(code) { case OP_REQUEST_INSTALL_PACKAGES: - if (previousMode == MODE_ALLOWED || mode == MODE_ALLOWED) { - // If we transition to/from MODE_ALLOWED, kill the app to make - // sure it has the correct view of /storage. Changing between - // MODE_DEFAULT / MODE_ERRORED is a no-op + // In R, we used to kill the app here if it transitioned to/from + // MODE_ALLOWED, to make sure the app had the correct (writable) OBB + // view. But the majority of apps don't handle OBBs anyway, and for those + // that do, they can restart themselves. Therefore, starting from S, + // only kill the app when it transitions away from MODE_ALLOWED (eg, + // when the permission is taken away). + if (previousMode == MODE_ALLOWED && mode != MODE_ALLOWED) { killAppForOpChange(code, uid); } return; diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 4872efdce88b..7d6e54243d89 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -19,7 +19,6 @@ package com.android.server.am; import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND; import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; -import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST; import static android.os.Process.NFC_UID; @@ -168,6 +167,7 @@ public final class ActiveServices { public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION = 16; public static final int FGS_FEATURE_ALLOWED_BY_FGS_BINDING = 17; public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE = 18; + public static final int FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD = 19; @IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = { FGS_FEATURE_DENIED, @@ -187,7 +187,8 @@ public final class ActiveServices { FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST, FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION, FGS_FEATURE_ALLOWED_BY_FGS_BINDING, - FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE + FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE, + FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD }) @Retention(RetentionPolicy.SOURCE) public @interface FgsFeatureRetCode {} @@ -5244,10 +5245,14 @@ public final class ActiveServices { if (ret == FGS_FEATURE_DENIED) { for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) { final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i); - if (pr.uid == callingUid - && pr.mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { - ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE; - break; + if (pr.uid == callingUid) { + if (pr.mAllowStartFgs) { + ret = FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD; + break; + } else if (pr.isAllowedStartFgsState()) { + ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE; + break; + } } } } @@ -5286,7 +5291,7 @@ public final class ActiveServices { } if (ret == FGS_FEATURE_DENIED) { - if (mAm.isWhitelistedForFgsStartLocked(r.appInfo.uid)) { + if (mAm.isWhitelistedForFgsStartLocked(callingUid)) { // uid is on DeviceIdleController's user/system allowlist // or AMS's FgsStartTempAllowList. ret = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST; @@ -5354,6 +5359,8 @@ public final class ActiveServices { return "ALLOWED_BY_FGS_BINDING"; case FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE: return "ALLOWED_BY_DEVICE_DEMO_MODE"; + case FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD: + return "ALLOWED_BY_PROCESS_RECORD"; default: return ""; } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 0b4d27f4990b..f2c1e90e2476 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -756,8 +756,9 @@ class AppErrors { boolean handleAppCrashLocked(ProcessRecord app, String reason, String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) { final long now = SystemClock.uptimeMillis(); - final boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; + final boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ANR_SHOW_BACKGROUND, 0, + mService.mUserController.getCurrentUserId()) != 0; final boolean procIsBoundForeground = (app.getCurProcState() == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE); @@ -889,8 +890,9 @@ class AppErrors { void handleShowAppErrorUi(Message msg) { AppErrorDialog.Data data = (AppErrorDialog.Data) msg.obj; - boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; + boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ANR_SHOW_BACKGROUND, 0, + mService.mUserController.getCurrentUserId()) != 0; final int userId; synchronized (mService) { @@ -982,8 +984,9 @@ class AppErrors { return; } - boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; + boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ANR_SHOW_BACKGROUND, 0, + mService.mUserController.getCurrentUserId()) != 0; if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) { proc.getDialogController().showAnrDialogs(data); } else { diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 771f273781fa..5b3e6514c6a6 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1329,7 +1329,7 @@ public final class OomAdjuster { app.setCached(false); app.shouldNotFreeze = false; - app.mAllowStartFgsState = PROCESS_STATE_NONEXISTENT; + app.resetAllowStartFgs(); final int appUid = app.info.uid; final int logUid = mService.mCurOomAdjUid; @@ -1351,7 +1351,6 @@ public final class OomAdjuster { app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT); app.curCapability = PROCESS_CAPABILITY_ALL; app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT); - app.bumpAllowStartFgsState(PROCESS_STATE_PERSISTENT); // System processes can do UI, and when they do we want to have // them trim their memory after the user leaves the UI. To // facilitate this, here we need to determine whether or not it @@ -1382,6 +1381,8 @@ public final class OomAdjuster { app.setCurRawProcState(app.getCurProcState()); app.curAdj = app.maxAdj; app.completedAdjSeq = app.adjSeq; + app.bumpAllowStartFgsState(app.getCurProcState()); + app.setAllowStartFgs(); // if curAdj is less than prevAppAdj, then this process was promoted return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState; } @@ -1773,6 +1774,11 @@ public final class OomAdjuster { int clientAdj = client.getCurRawAdj(); int clientProcState = client.getCurRawProcState(); + // pass client's mAllowStartFgs to the app if client is not persistent process. + if (client.mAllowStartFgs && client.maxAdj >= ProcessList.FOREGROUND_APP_ADJ) { + app.mAllowStartFgs = true; + } + if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) { if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) { continue; @@ -2236,7 +2242,7 @@ public final class OomAdjuster { app.setCurRawProcState(procState); app.setHasForegroundActivities(foregroundActivities); app.completedAdjSeq = mAdjSeq; - + app.setAllowStartFgs(); // if curAdj or curProcState improved, then this process was promoted return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState || app.curCapability != prevCapability ; diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index cf4adc65a7fc..255badd3239f 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -16,7 +16,16 @@ package com.android.server.am; +import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; +import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND; +import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; +import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.Process.NFC_UID; +import static android.os.Process.ROOT_UID; +import static android.os.Process.SHELL_UID; +import static android.os.Process.SYSTEM_UID; import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; @@ -361,6 +370,17 @@ class ProcessRecord implements WindowProcessListener { private final ArraySet<Binder> mBackgroundFgsStartTokens = new ArraySet<>(); + // The list of permissions that can start FGS from background. + private static String[] ALLOW_BG_START_FGS_PERMISSIONS = + {START_ACTIVITIES_FROM_BACKGROUND, START_FOREGROUND_SERVICES_FROM_BACKGROUND, + SYSTEM_ALERT_WINDOW}; + // Does the process has permission to start FGS from background. + boolean mAllowStartFgsByPermission; + // Can this process start FGS from background? + // If this process has the ability to start FGS from background, this ability can be passed to + // another process through service binding. + boolean mAllowStartFgs; + void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo, long startTime) { this.startUid = startUid; @@ -476,6 +496,9 @@ class ProcessRecord implements WindowProcessListener { pw.println(); pw.print(prefix); pw.print("allowStartFgsState="); pw.println(mAllowStartFgsState); + if (mAllowStartFgs) { + pw.print(prefix); pw.print("allowStartFgs="); pw.println(mAllowStartFgs); + } if (hasShownUi || mPendingUiClean || hasAboveClient || treatLikeActivity) { pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi); pw.print(" pendingUiClean="); pw.print(mPendingUiClean); @@ -672,6 +695,7 @@ class ProcessRecord implements WindowProcessListener { mWindowProcessController = new WindowProcessController( mService.mActivityTaskManager, info, processName, uid, userId, this, this); pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode)); + setAllowStartFgsByPermission(); } public void setPid(int _pid) { @@ -1983,12 +2007,78 @@ class ProcessRecord implements WindowProcessListener { return mDialogController; } + void resetAllowStartFgs() { + mAllowStartFgsState = PROCESS_STATE_NONEXISTENT; + mAllowStartFgs = mAllowStartFgsByPermission; + } + void bumpAllowStartFgsState(int newProcState) { if (newProcState < mAllowStartFgsState) { mAllowStartFgsState = newProcState; } } + void setAllowStartFgsByPermission() { + boolean ret = false; + if (!ret) { + boolean isSystem = false; + final int uid = UserHandle.getAppId(info.uid); + switch (uid) { + case ROOT_UID: + case SYSTEM_UID: + case NFC_UID: + case SHELL_UID: + isSystem = true; + break; + default: + isSystem = false; + break; + } + + if (isSystem) { + ret = true; + } + } + + if (!ret) { + for (int i = 0; i < ALLOW_BG_START_FGS_PERMISSIONS.length; ++i) { + if (ActivityManager.checkComponentPermission(ALLOW_BG_START_FGS_PERMISSIONS[i], + info.uid, -1, true) + == PERMISSION_GRANTED) { + ret = true; + break; + } + } + } + mAllowStartFgs = mAllowStartFgsByPermission = ret; + } + + boolean isAllowedStartFgsState() { + return mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE; + } + + void setAllowStartFgs() { + if (mAllowStartFgs) { + return; + } + if (!mAllowStartFgs) { + mAllowStartFgs = isAllowedStartFgsState(); + } + + if (!mAllowStartFgs) { + // Is the calling UID a device owner app? + if (mService.mInternal != null) { + mAllowStartFgs = mService.mInternal.isDeviceOwner(info.uid); + } + } + + if (!mAllowStartFgs) { + // uid is on DeviceIdleController's user/system allowlist + // or AMS's FgsStartTempAllowList. + mAllowStartFgs = mService.isWhitelistedForFgsStartLocked(info.uid); + } + } + /** A controller to generate error dialogs in {@link ProcessRecord} */ class ErrorDialogController { /** dialogs being displayed due to crash */ diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index ccd1f3bb16f6..52b9f5c15c50 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -138,9 +138,10 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // not guaranteed to be current or correct, or even to exist. public @Nullable Network[] declaredUnderlyingNetworks; - // Whether this network is always metered even if its underlying networks are unmetered. - // Only relevant if #supportsUnderlyingNetworks is true. - public boolean declaredMetered; + // The capabilities originally announced by the NetworkAgent, regardless of any capabilities + // that were added or removed due to this network's underlying networks. + // Only set if #supportsUnderlyingNetworks is true. + public @Nullable NetworkCapabilities declaredCapabilities; // Indicates if netd has been told to create this Network. From this point on the appropriate // routing rules are setup and routes are added so packets can begin flowing over the Network. diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 66bb4d704e80..cabfbc02491c 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -48,6 +48,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.net.ConnectivityManager; import android.net.DnsResolver; +import android.net.INetd; import android.net.INetworkManagementEventObserver; import android.net.Ikev2VpnProfile; import android.net.IpPrefix; @@ -68,6 +69,7 @@ import android.net.NetworkProvider; import android.net.NetworkRequest; import android.net.RouteInfo; import android.net.UidRange; +import android.net.UidRangeParcel; import android.net.VpnManager; import android.net.VpnService; import android.net.ipsec.ike.ChildSessionCallback; @@ -188,7 +190,8 @@ public class Vpn { private PendingIntent mStatusIntent; private volatile boolean mEnableTeardown = true; - private final INetworkManagementService mNetd; + private final INetworkManagementService mNms; + private final INetd mNetd; @VisibleForTesting protected VpnConfig mConfig; private final NetworkProvider mNetworkProvider; @@ -234,7 +237,7 @@ public class Vpn { * @see mLockdown */ @GuardedBy("this") - private final Set<UidRange> mBlockedUidsAsToldToNetd = new ArraySet<>(); + private final Set<UidRangeParcel> mBlockedUidsAsToldToNetd = new ArraySet<>(); // The user id of initiating VPN. private final int mUserId; @@ -363,22 +366,23 @@ public class Vpn { } } - public Vpn(Looper looper, Context context, INetworkManagementService netService, + public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd, @UserIdInt int userId, @NonNull KeyStore keyStore) { - this(looper, context, new Dependencies(), netService, userId, keyStore, + this(looper, context, new Dependencies(), netService, netd, userId, keyStore, new SystemServices(context), new Ikev2SessionCreator()); } @VisibleForTesting protected Vpn(Looper looper, Context context, Dependencies deps, - INetworkManagementService netService, + INetworkManagementService netService, INetd netd, int userId, @NonNull KeyStore keyStore, SystemServices systemServices, Ikev2SessionCreator ikev2SessionCreator) { mContext = context; mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */); mDeps = deps; - mNetd = netService; + mNms = netService; + mNetd = netd; mUserId = userId; mLooper = looper; mSystemServices = systemServices; @@ -912,7 +916,7 @@ public class Vpn { } try { - mNetd.denyProtect(mOwnerUID); + mNms.denyProtect(mOwnerUID); } catch (Exception e) { Log.wtf(TAG, "Failed to disallow UID " + mOwnerUID + " to call protect() " + e); } @@ -922,7 +926,7 @@ public class Vpn { mOwnerUID = getAppUid(newPackage, mUserId); mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(newPackage); try { - mNetd.allowProtect(mOwnerUID); + mNms.allowProtect(mOwnerUID); } catch (Exception e) { Log.wtf(TAG, "Failed to allow UID " + mOwnerUID + " to call protect() " + e); } @@ -1579,24 +1583,25 @@ public class Vpn { exemptedPackages = new ArrayList<>(mLockdownAllowlist); exemptedPackages.add(mPackage); } - final Set<UidRange> rangesToTellNetdToRemove = new ArraySet<>(mBlockedUidsAsToldToNetd); + final Set<UidRangeParcel> rangesToTellNetdToRemove = + new ArraySet<>(mBlockedUidsAsToldToNetd); - final Set<UidRange> rangesToTellNetdToAdd; + final Set<UidRangeParcel> rangesToTellNetdToAdd; if (enforce) { - final Set<UidRange> rangesThatShouldBeBlocked = + final Set<UidRange> restrictedProfilesRanges = createUserAndRestrictedProfilesRanges(mUserId, - /* allowedApplications */ null, - /* disallowedApplications */ exemptedPackages); + /* allowedApplications */ null, + /* disallowedApplications */ exemptedPackages); + final Set<UidRangeParcel> rangesThatShouldBeBlocked = new ArraySet<>(); // The UID range of the first user (0-99999) would block the IPSec traffic, which comes // directly from the kernel and is marked as uid=0. So we adjust the range to allow // it through (b/69873852). - for (UidRange range : rangesThatShouldBeBlocked) { - if (range.start == 0) { - rangesThatShouldBeBlocked.remove(range); - if (range.stop != 0) { - rangesThatShouldBeBlocked.add(new UidRange(1, range.stop)); - } + for (UidRange range : restrictedProfilesRanges) { + if (range.start == 0 && range.stop != 0) { + rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.stop)); + } else if (range.start != 0) { + rangesThatShouldBeBlocked.add(new UidRangeParcel(range.start, range.stop)); } } @@ -1628,13 +1633,13 @@ public class Vpn { * including added ranges that already existed or removed ones that didn't. */ @GuardedBy("this") - private boolean setAllowOnlyVpnForUids(boolean enforce, Collection<UidRange> ranges) { + private boolean setAllowOnlyVpnForUids(boolean enforce, Collection<UidRangeParcel> ranges) { if (ranges.size() == 0) { return true; } - final UidRange[] rangesArray = ranges.toArray(new UidRange[ranges.size()]); + final UidRangeParcel[] stableRanges = ranges.toArray(new UidRangeParcel[ranges.size()]); try { - mNetd.setAllowOnlyVpnForUids(enforce, rangesArray); + mNetd.networkRejectNonSecureVpn(enforce, stableRanges); } catch (RemoteException | RuntimeException e) { Log.e(TAG, "Updating blocked=" + enforce + " for UIDs " + Arrays.toString(ranges.toArray()) + " failed", e); @@ -1849,10 +1854,20 @@ public class Vpn { if (mNetworkInfo.isConnected()) { return !appliesToUid(uid); } else { - return UidRange.containsUid(mBlockedUidsAsToldToNetd, uid); + return containsUid(mBlockedUidsAsToldToNetd, uid); } } + private boolean containsUid(Collection<UidRangeParcel> ranges, int uid) { + if (ranges == null) return false; + for (UidRangeParcel range : ranges) { + if (range.start <= uid && uid <= range.stop) { + return true; + } + } + return false; + } + private void updateAlwaysOnNotification(DetailedState networkState) { final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED); @@ -2495,7 +2510,7 @@ public class Vpn { address /* unused */, address /* unused */, network); - mNetd.setInterfaceUp(mTunnelIface.getInterfaceName()); + mNms.setInterfaceUp(mTunnelIface.getInterfaceName()); mSession = mIkev2SessionCreator.createIkeSession( mContext, diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java index 0b3cdae9231e..7afa81aa047d 100644 --- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java +++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java @@ -165,11 +165,13 @@ class BluetoothRouteProvider { private void buildBluetoothRoutes() { mBluetoothRoutes.clear(); - for (BluetoothDevice device : mBluetoothAdapter.getBondedDevices()) { - if (device.isConnected()) { - BluetoothRouteInfo newBtRoute = createBluetoothRoute(device); - if (newBtRoute.connectedProfiles.size() > 0) { - mBluetoothRoutes.put(device.getAddress(), newBtRoute); + if (mBluetoothAdapter.getBondedDevices() != null) { + for (BluetoothDevice device : mBluetoothAdapter.getBondedDevices()) { + if (device.isConnected()) { + BluetoothRouteInfo newBtRoute = createBluetoothRoute(device); + if (newBtRoute.connectedProfiles.size() > 0) { + mBluetoothRoutes.put(device.getAddress(), newBtRoute); + } } } } diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java index f882c57e49ba..edc9d7c64146 100644 --- a/services/core/java/com/android/server/media/MediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java @@ -77,7 +77,7 @@ abstract class MediaRoute2Provider { @NonNull public List<RoutingSessionInfo> getSessionInfos() { synchronized (mLock) { - return mSessionInfos; + return new ArrayList<>(mSessionInfos); } } diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java index 85af346aa88a..ab38dca2387d 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java @@ -108,8 +108,8 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider mLastDiscoveryPreference = discoveryPreference; if (mConnectionReady) { mActiveConnection.updateDiscoveryPreference(discoveryPreference); - updateBinding(); } + updateBinding(); } @Override @@ -205,9 +205,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider } private boolean shouldBind() { - //TODO: Binding could be delayed until it's necessary. if (mRunning) { - return true; + // Bind when there is a discovery preference or an active route session. + return (mLastDiscoveryPreference != null + && !mLastDiscoveryPreference.getPreferredFeatures().isEmpty()) + || !getSessionInfos().isEmpty(); } return false; } diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 1114fe0d9bf8..31edf43679e9 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -16,6 +16,7 @@ package com.android.server.media; +import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR; import static android.media.MediaRouter2Utils.getOriginalId; import static android.media.MediaRouter2Utils.getProviderId; @@ -73,10 +74,12 @@ class MediaRouter2ServiceImpl { // TODO: (In Android S or later) if we add callback methods for generic failures // in MediaRouter2, remove this constant and replace the usages with the real request IDs. private static final long DUMMY_REQUEST_ID = -1; + private static final int PACKAGE_IMPORTANCE_FOR_DISCOVERY = IMPORTANCE_FOREGROUND; private final Context mContext; private final Object mLock = new Object(); final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1); + final ActivityManager mActivityManager; @GuardedBy("mLock") private final SparseArray<UserRecord> mUserRecords = new SparseArray<>(); @@ -87,8 +90,21 @@ class MediaRouter2ServiceImpl { @GuardedBy("mLock") private int mCurrentUserId = -1; + private final ActivityManager.OnUidImportanceListener mOnUidImportanceListener = + (uid, importance) -> { + synchronized (mLock) { + final int count = mUserRecords.size(); + for (int i = 0; i < count; i++) { + mUserRecords.valueAt(i).mHandler.maybeUpdateDiscoveryPreferenceForUid(uid); + } + } + }; + MediaRouter2ServiceImpl(Context context) { mContext = context; + mActivityManager = mContext.getSystemService(ActivityManager.class); + mActivityManager.addOnUidImportanceListener(mOnUidImportanceListener, + PACKAGE_IMPORTANCE_FOR_DISCOVERY); } //////////////////////////////////////////////////////////////// @@ -388,6 +404,30 @@ class MediaRouter2ServiceImpl { } } + public void startScan(IMediaRouter2Manager manager) { + Objects.requireNonNull(manager, "manager must not be null"); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + startScanLocked(manager); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + public void stopScan(IMediaRouter2Manager manager) { + Objects.requireNonNull(manager, "manager must not be null"); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + stopScanLocked(manager); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId, MediaRoute2Info route, int volume) { Objects.requireNonNull(manager, "manager must not be null"); @@ -839,6 +879,24 @@ class MediaRouter2ServiceImpl { disposeUserIfNeededLocked(userRecord); // since manager removed from user } + private void startScanLocked(@NonNull IMediaRouter2Manager manager) { + final IBinder binder = manager.asBinder(); + ManagerRecord managerRecord = mAllManagerRecords.get(binder); + if (managerRecord == null) { + return; + } + managerRecord.startScan(); + } + + private void stopScanLocked(@NonNull IMediaRouter2Manager manager) { + final IBinder binder = manager.asBinder(); + ManagerRecord managerRecord = mAllManagerRecords.get(binder); + if (managerRecord == null) { + return; + } + managerRecord.stopScan(); + } + private void setRouteVolumeWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager, @NonNull MediaRoute2Info route, int volume) { @@ -1122,6 +1180,7 @@ class MediaRouter2ServiceImpl { public final String mPackageName; public final int mManagerId; public SessionCreationRequest mLastSessionCreationRequest; + public boolean mIsScanning; ManagerRecord(UserRecord userRecord, IMediaRouter2Manager manager, int uid, int pid, String packageName) { @@ -1146,6 +1205,24 @@ class MediaRouter2ServiceImpl { pw.println(prefix + this); } + public void startScan() { + if (mIsScanning) { + return; + } + mIsScanning = true; + mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage( + UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler)); + } + + public void stopScan() { + if (!mIsScanning) { + return; + } + mIsScanning = false; + mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage( + UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler)); + } + @Override public String toString() { return "Manager " + mPackageName + " (pid " + mPid + ")"; @@ -1262,6 +1339,24 @@ class MediaRouter2ServiceImpl { return null; } + public void maybeUpdateDiscoveryPreferenceForUid(int uid) { + MediaRouter2ServiceImpl service = mServiceRef.get(); + if (service == null) { + return; + } + boolean isUidRelevant; + synchronized (service.mLock) { + isUidRelevant = mUserRecord.mRouterRecords.stream().anyMatch( + router -> router.mUid == uid) + | mUserRecord.mManagerRecords.stream().anyMatch( + manager -> manager.mUid == uid); + } + if (isUidRelevant) { + sendMessage(PooledLambda.obtainMessage( + UserHandler::updateDiscoveryPreferenceOnHandler, this)); + } + } + private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) { int providerInfoIndex = getLastProviderInfoIndex(provider.getUniqueId()); MediaRoute2ProviderInfo currentInfo = provider.getProviderInfo(); @@ -1767,6 +1862,16 @@ class MediaRouter2ServiceImpl { return managers; } + private List<RouterRecord> getRouterRecords() { + MediaRouter2ServiceImpl service = mServiceRef.get(); + if (service == null) { + return Collections.emptyList(); + } + synchronized (service.mLock) { + return new ArrayList<>(mUserRecord.mRouterRecords); + } + } + private List<ManagerRecord> getManagerRecords() { MediaRouter2ServiceImpl service = mServiceRef.get(); if (service == null) { @@ -2001,13 +2106,28 @@ class MediaRouter2ServiceImpl { return; } List<RouteDiscoveryPreference> discoveryPreferences = new ArrayList<>(); - synchronized (service.mLock) { - for (RouterRecord routerRecord : mUserRecord.mRouterRecords) { + List<RouterRecord> routerRecords = getRouterRecords(); + List<ManagerRecord> managerRecords = getManagerRecords(); + boolean isAnyManagerScanning = + managerRecords.stream().anyMatch(manager -> manager.mIsScanning + && service.mActivityManager.getPackageImportance(manager.mPackageName) + <= PACKAGE_IMPORTANCE_FOR_DISCOVERY); + + for (RouterRecord routerRecord : routerRecords) { + if (isAnyManagerScanning + || service.mActivityManager.getPackageImportance(routerRecord.mPackageName) + <= PACKAGE_IMPORTANCE_FOR_DISCOVERY) { discoveryPreferences.add(routerRecord.mDiscoveryPreference); } - mUserRecord.mCompositeDiscoveryPreference = - new RouteDiscoveryPreference.Builder(discoveryPreferences) - .build(); + } + + synchronized (service.mLock) { + RouteDiscoveryPreference newPreference = + new RouteDiscoveryPreference.Builder(discoveryPreferences).build(); + if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)) { + return; + } + mUserRecord.mCompositeDiscoveryPreference = newPreference; } for (MediaRoute2Provider provider : mRouteProviders) { provider.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference); diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 0e52a67c8d39..b6d6cc48d0cd 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -544,6 +544,18 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override + public void startScan(IMediaRouter2Manager manager) { + mService2.startScan(manager); + } + + // Binder call + @Override + public void stopScan(IMediaRouter2Manager manager) { + mService2.stopScan(manager); + } + + // Binder call + @Override public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId, MediaRoute2Info route, int volume) { mService2.setRouteVolumeWithManager(manager, requestId, route, volume); diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 0ac0c8d95423..9f07695fcecf 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -737,7 +737,7 @@ class ShortcutPackage extends ShortcutPackageItem { || ((pinnedByCallerSet != null) && pinnedByCallerSet.contains(si.getId())); if (!getPinnedByAnyLauncher) { - if (si.isFloating()) { + if (si.isFloating() && !si.isCached()) { if (!isPinnedByCaller) { continue; } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 708e050f8a8c..1dbf8396bcfb 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -66,7 +66,6 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppOpsManager; -import android.app.ApplicationPackageManager; import android.app.IActivityManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.role.RoleManager; @@ -795,8 +794,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { private void updatePermissionFlagsInternal(String permName, String packageName, int flagMask, int flagValues, int callingUid, int userId, boolean overridePolicy, PermissionCallback callback) { - if (ApplicationPackageManager.DEBUG_TRACE_PERMISSION_UPDATES - && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) { + if (PermissionManager.DEBUG_TRACE_PERMISSION_UPDATES + && PermissionManager.shouldTraceGrant(packageName, permName, userId)) { Log.i(TAG, "System is updating flags for " + packageName + " " + permName + " for user " + userId + " " + DebugUtils.flagsToString( @@ -1456,8 +1455,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { // TODO swap permission name and package name private void grantRuntimePermissionInternal(String permName, String packageName, boolean overridePolicy, int callingUid, final int userId, PermissionCallback callback) { - if (ApplicationPackageManager.DEBUG_TRACE_GRANTS - && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) { + if (PermissionManager.DEBUG_TRACE_GRANTS + && PermissionManager.shouldTraceGrant(packageName, permName, userId)) { Log.i(TAG, "System is granting " + packageName + " " + permName + " for user " + userId + " on behalf of uid " + callingUid + " " + mPackageManagerInt.getNameForUid(callingUid), @@ -1633,8 +1632,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { private void revokeRuntimePermissionInternal(String permName, String packageName, boolean overridePolicy, int callingUid, final int userId, String reason, PermissionCallback callback) { - if (ApplicationPackageManager.DEBUG_TRACE_PERMISSION_UPDATES - && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) { + if (PermissionManager.DEBUG_TRACE_PERMISSION_UPDATES + && PermissionManager.shouldTraceGrant(packageName, permName, userId)) { Log.i(TAG, "System is revoking " + packageName + " " + permName + " for user " + userId + " on behalf of uid " + callingUid + " " + mPackageManagerInt.getNameForUid(callingUid), diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 6a50b793de0f..b0847879f456 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -631,6 +631,10 @@ class ActivityMetricsLogger { if (info.mLoggedTransitionStarting && info.allDrawn()) { done(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs); } + if (r.mWmService.isRecentsAnimationTarget(r)) { + r.mWmService.getRecentsAnimationController().logRecentsAnimationStartTime( + info.mSourceEventDelayMs + info.mWindowsDrawnDelayMs); + } return infoSnapshot; } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5daf1c4679be..4c18310df226 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1366,19 +1366,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } else if (mLetterbox != null) { mLetterbox.hide(); } - maybeUpdateLetterboxInTaskOrganizer(w); - } - - private void maybeUpdateLetterboxInTaskOrganizer(WindowState w) { - boolean isLetterboxed = w.isLetterboxedAppWindow() && fillsParent(); - if (!isLetterboxed) { - task.maybeUpdateLetterboxInTaskOrganizer( - this, /* activityBounds= */ null, /* activityInsets= */ null); - return; - } - final Rect insets = w.getInsetsStateWithVisibilityOverride().calculateInsets( - getBounds(), Type.systemBars(), false /* ignoreVisibility */); - task.maybeUpdateLetterboxInTaskOrganizer(this, getBounds(), insets); } void updateLetterboxSurface(WindowState winHint) { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index e60f2e70f25c..8d6d981be2b8 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -80,6 +80,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.window.DisplayAreaOrganizer.FEATURE_ROOT; import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; @@ -552,24 +553,56 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * This just indicates the window the input method is on top of, not * necessarily the window its input is going to. */ - WindowState mInputMethodTarget; + private WindowState mImeLayeringTarget; /** * The window which receives input from the input method. This is also a candidate of the * input method control target. */ - WindowState mInputMethodInputTarget; + private WindowState mImeInputTarget; /** * This controls the visibility and animation of the input method window. */ - InsetsControlTarget mInputMethodControlTarget; + private InsetsControlTarget mImeControlTarget; + + /** + * Used by {@link #getImeTarget} to return the IME target which the input method window on + * top of for adjusting input method window surface layer Z-Ordering. + * + * @see #mImeLayeringTarget + */ + static final int IME_TARGET_LAYERING = 0; + + /** + * Used by {@link #getImeTarget} to return the IME target which received the input connection + * from IME. + * + * @see #mImeInputTarget + */ + static final int IME_TARGET_INPUT = 1; + + /** + * Used by {@link #getImeTarget} to return the IME target which controls the IME insets + * visibility and animation. + * + * @see #mImeControlTarget + */ + static final int IME_TARGET_CONTROL = 2; + + @IntDef(flag = false, prefix = { "IME_TARGET_" }, value = { + IME_TARGET_LAYERING, + IME_TARGET_INPUT, + IME_TARGET_CONTROL, + }) + @Retention(RetentionPolicy.SOURCE) + @interface InputMethodTarget {} /** The surface parent of the IME container. */ private SurfaceControl mInputMethodSurfaceParent; - /** If true hold off on modifying the animation layer of mInputMethodTarget */ - boolean mInputMethodTargetWaitingAnim; + /** If {@code true} hold off on modifying the animation layer of {@link #mImeLayeringTarget} */ + boolean mImeLayeringTargetWaitingAnim; private final PointerEventDispatcher mPointerEventDispatcher; @@ -814,7 +847,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp private final Consumer<WindowState> mApplyPostLayoutPolicy = w -> getDisplayPolicy().applyPostLayoutPolicyLw(w, w.mAttrs, w.getParentWindow(), - mInputMethodTarget); + mImeLayeringTarget); private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> { final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked; @@ -2256,8 +2289,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @Nullable Task getRootTask(int rootTaskId) { - return getItemFromTaskDisplayAreas(taskDisplayArea -> - taskDisplayArea.getRootTask(rootTaskId)); + return getRootTask(rootTask -> rootTask.getRootTaskId() == rootTaskId); } int getRootTaskCount() { @@ -2834,7 +2866,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } void prepareFreezingTaskBounds() { - forAllTaskDisplayAreas(TaskDisplayArea::prepareFreezingTaskBounds); + forAllRootTasks(Task::prepareFreezingTaskBounds); } void rotateBounds(int oldRotation, int newRotation, Rect bounds) { @@ -2943,15 +2975,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp proto.write(FOCUSED_ROOT_TASK_ID, INVALID_TASK_ID); } proto.write(DISPLAY_READY, isReady()); - if (mInputMethodTarget != null) { - mInputMethodTarget.dumpDebug(proto, INPUT_METHOD_TARGET, logLevel); + if (mImeLayeringTarget != null) { + mImeLayeringTarget.dumpDebug(proto, INPUT_METHOD_TARGET, logLevel); } - if (mInputMethodInputTarget != null) { - mInputMethodInputTarget.dumpDebug(proto, INPUT_METHOD_INPUT_TARGET, logLevel); + if (mImeInputTarget != null) { + mImeInputTarget.dumpDebug(proto, INPUT_METHOD_INPUT_TARGET, logLevel); } - if (mInputMethodControlTarget != null - && mInputMethodControlTarget.getWindow() != null) { - mInputMethodControlTarget.getWindow().dumpDebug(proto, INPUT_METHOD_CONTROL_TARGET, + if (mImeControlTarget != null + && mImeControlTarget.getWindow() != null) { + mImeControlTarget.getWindow().dumpDebug(proto, INPUT_METHOD_CONTROL_TARGET, logLevel); } if (mCurrentFocus != null) { @@ -3207,7 +3239,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp boolean imWindowChanged = false; final WindowState imWindow = mInputMethodWindow; if (imWindow != null) { - final WindowState prevTarget = mInputMethodTarget; + final WindowState prevTarget = mImeLayeringTarget; final WindowState newTarget = computeImeTarget(true /* updateImeTarget*/); imWindowChanged = prevTarget != newTarget; @@ -3461,7 +3493,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } /** - * Determine and return the window that should be the IME target. + * Determine and return the window that should be the IME target for layering the IME window. * @param updateImeTarget If true the system IME target will be updated to match what we found. * @return The window that should be used as the IME target or null if there isn't any. */ @@ -3470,13 +3502,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // There isn't an IME so there shouldn't be a target...That was easy! if (updateImeTarget) { if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " - + mInputMethodTarget + " to null since mInputMethodWindow is null"); - setInputMethodTarget(null, mInputMethodTargetWaitingAnim); + + mImeLayeringTarget + " to null since mInputMethodWindow is null"); + setImeLayeringTarget(null, mImeLayeringTargetWaitingAnim); } return null; } - final WindowState curTarget = mInputMethodTarget; + final WindowState curTarget = mImeLayeringTarget; if (!canUpdateImeTarget()) { if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Defer updating IME target"); return curTarget; @@ -3531,7 +3563,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget + " to null." + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : "")); - setInputMethodTarget(null, mInputMethodTargetWaitingAnim); + setImeLayeringTarget(null, mImeLayeringTargetWaitingAnim); } return null; @@ -3558,7 +3590,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (mAppTransition.isTransitionSet()) { // If we are currently setting up for an animation, hold everything until we // can find out what will happen. - setInputMethodTarget(highestTarget, true); + setImeLayeringTarget(highestTarget, true); return highestTarget; } } @@ -3566,7 +3598,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget + " to " + target + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : "")); - setInputMethodTarget(target, false); + setImeLayeringTarget(target, false); } return target; @@ -3577,24 +3609,24 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * the candidate app window token if needed. */ void computeImeTargetIfNeeded(ActivityRecord candidate) { - if (mInputMethodTarget != null && mInputMethodTarget.mActivityRecord == candidate) { + if (mImeLayeringTarget != null && mImeLayeringTarget.mActivityRecord == candidate) { computeImeTarget(true /* updateImeTarget */); } } private boolean isImeControlledByApp() { - return mInputMethodInputTarget != null && !WindowConfiguration.isSplitScreenWindowingMode( - mInputMethodInputTarget.getWindowingMode()); + return mImeInputTarget != null && !WindowConfiguration.isSplitScreenWindowingMode( + mImeInputTarget.getWindowingMode()); } boolean isImeAttachedToApp() { return isImeControlledByApp() - && mInputMethodTarget != null - && mInputMethodTarget.mActivityRecord != null - && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN + && mImeLayeringTarget != null + && mImeLayeringTarget.mActivityRecord != null + && mImeLayeringTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN // An activity with override bounds should be letterboxed inside its parent bounds, // so it doesn't fill the screen. - && mInputMethodTarget.mActivityRecord.matchParentBounds(); + && mImeLayeringTarget.mActivityRecord.matchParentBounds(); } /** @@ -3621,6 +3653,24 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return statusBar != null ? statusBar : defaultDc.mRemoteInsetsControlTarget; } + /** + * Returns the corresponding IME insets control target according the IME target type. + * + * @param type The type of the IME target. + * @see #IME_TARGET_LAYERING + * @see #IME_TARGET_INPUT + * @see #IME_TARGET_CONTROL + */ + InsetsControlTarget getImeTarget(@InputMethodTarget int type) { + switch (type) { + case IME_TARGET_LAYERING: return mImeLayeringTarget; + case IME_TARGET_INPUT: return mImeInputTarget; + case IME_TARGET_CONTROL: return mImeControlTarget; + default: + return null; + } + } + @DisplayImePolicy int getImePolicy() { if (!isTrusted()) { return DISPLAY_IME_POLICY_FALLBACK_DISPLAY; @@ -3638,6 +3688,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return mWmService.mForceDesktopModeOnExternalDisplays && !isDefaultDisplay && !isPrivate(); } + @VisibleForTesting + void setImeLayeringTarget(WindowState target) { + mImeLayeringTarget = target; + } + /** * Sets the window the IME is on top of. * @param target window to place the IME surface on top of. If {@code null}, the IME will be @@ -3645,13 +3700,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * @param targetWaitingAnim if {@code true}, hold off on modifying the animation layer of * the target. */ - private void setInputMethodTarget(@Nullable WindowState target, boolean targetWaitingAnim) { - if (target == mInputMethodTarget && mInputMethodTargetWaitingAnim == targetWaitingAnim) { + private void setImeLayeringTarget(@Nullable WindowState target, boolean targetWaitingAnim) { + if (target == mImeLayeringTarget && mImeLayeringTargetWaitingAnim == targetWaitingAnim) { return; } ProtoLog.i(WM_DEBUG_IME, "setInputMethodTarget %s", target); - mInputMethodTarget = target; - mInputMethodTargetWaitingAnim = targetWaitingAnim; + mImeLayeringTarget = target; + mImeLayeringTargetWaitingAnim = targetWaitingAnim; // 1. Reparent the IME container window to the target root DA to get the correct bounds and // config. (Only happens when the target window is in a different root DA) @@ -3673,23 +3728,33 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp updateImeControlTarget(); } + @VisibleForTesting + void setImeInputTarget(WindowState target) { + mImeInputTarget = target; + } + + @VisibleForTesting + void setImeControlTarget(InsetsControlTarget target) { + mImeControlTarget = target; + } + /** * The IME input target is the window which receives input from IME. It is also a candidate * which controls the visibility and animation of the input method window. */ - void setInputMethodInputTarget(WindowState target) { - if (mInputMethodInputTarget != target) { + void updateImeInputAndControlTarget(WindowState target) { + if (mImeInputTarget != target) { ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target); - mInputMethodInputTarget = target; + mImeInputTarget = target; updateImeControlTarget(); } } void updateImeControlTarget() { - mInputMethodControlTarget = computeImeControlTarget(); - mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget); + mImeControlTarget = computeImeControlTarget(); + mInsetsStateController.onImeControlTargetChanged(mImeControlTarget); - final WindowState win = InsetsControlTarget.asWindowOrNull(mInputMethodControlTarget); + final WindowState win = InsetsControlTarget.asWindowOrNull(mImeControlTarget); final IBinder token = win != null ? win.mClient.asBinder() : null; // Note: not allowed to call into IMMS with the WM lock held, hence the post. mWmService.mH.post(() -> @@ -3712,12 +3777,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @VisibleForTesting InsetsControlTarget computeImeControlTarget() { if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null - || (mInputMethodInputTarget != null - && getImeHostOrFallback(mInputMethodInputTarget.getWindow()) + || (mImeInputTarget != null + && getImeHostOrFallback(mImeInputTarget.getWindow()) == mRemoteInsetsControlTarget)) { return mRemoteInsetsControlTarget; } else { - return mInputMethodInputTarget; + return mImeInputTarget; } } @@ -3734,7 +3799,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // screen. If it's not covering the entire screen the IME might extend beyond the apps // bounds. if (allowAttachToApp && isImeAttachedToApp()) { - return mInputMethodTarget.mActivityRecord.getSurfaceControl(); + return mImeLayeringTarget.mActivityRecord.getSurfaceControl(); } // Otherwise, we just attach it to where the display area policy put it. @@ -4191,8 +4256,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } // Initialize state of exiting applications. - forAllTaskDisplayAreas(taskDisplayArea -> { - taskDisplayArea.setExitingTokensHasVisible(hasVisible); + forAllRootTasks(task -> { + final ArrayList<ActivityRecord> activities = task.mExitingActivities; + for (int j = activities.size() - 1; j >= 0; --j) { + activities.get(j).hasVisible = hasVisible; + } }); } @@ -4205,7 +4273,22 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } // Time to remove any exiting applications? - forAllTaskDisplayAreas(TaskDisplayArea::removeExistingAppTokensIfPossible); + forAllRootTasks(task -> { + final ArrayList<ActivityRecord> activities = task.mExitingActivities; + for (int j = activities.size() - 1; j >= 0; --j) { + final ActivityRecord activity = activities.get(j); + if (!activity.hasVisible && !mDisplayContent.mClosingApps.contains(activity) + && (!activity.mIsExiting || activity.isEmpty())) { + // Make sure there is no animation running on this activity, so any windows + // associated with it will be removed as soon as their animations are + // complete. + cancelAnimation(); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, + "performLayout: Activity exiting now removed %s", activity); + activity.removeIfPossible(); + } + } + }); } @Override @@ -4355,7 +4438,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp private boolean skipImeWindowsDuringTraversal(DisplayContent dc) { // We skip IME windows so they're processed just above their target, except // in split-screen mode where we process the IME containers above the docked divider. - return dc.mInputMethodTarget != null + return dc.getImeTarget(IME_TARGET_LAYERING) != null && !dc.getDefaultTaskDisplayArea().isSplitScreenModeActivated(); } @@ -4470,7 +4553,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @Override void assignChildLayers(SurfaceControl.Transaction t) { mImeWindowsContainers.setNeedsLayer(); - final WindowState imeTarget = mInputMethodTarget; + final WindowState imeTarget = mImeLayeringTarget; // In the case where we have an IME target that is not in split-screen mode IME // assignment is easy. We just need the IME to go directly above the target. This way // children of the target will naturally go above the IME and everyone is happy. @@ -5128,15 +5211,56 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED */ void removeRootTasksInWindowingModes(int... windowingModes) { - forAllTaskDisplayAreas(taskDisplayArea -> { - taskDisplayArea.removeRootTasksInWindowingModes(windowingModes); + if (windowingModes == null || windowingModes.length == 0) { + return; + } + + // Collect the root tasks that are necessary to be removed instead of performing the removal + // by looping the children, so that we don't miss any root tasks after the children size + // changed or reordered. + final ArrayList<Task> rootTasks = new ArrayList<>(); + forAllRootTasks(rootTask -> { + for (int windowingMode : windowingModes) { + if (rootTask.mCreatedByOrganizer + || rootTask.getWindowingMode() != windowingMode + || !rootTask.isActivityTypeStandardOrUndefined()) { + continue; + } + rootTasks.add(rootTask); + } }); + for (int i = rootTasks.size() - 1; i >= 0; --i) { + mRootWindowContainer.mTaskSupervisor.removeRootTask(rootTasks.get(i)); + } } void removeRootTasksWithActivityTypes(int... activityTypes) { - forAllTaskDisplayAreas(taskDisplayArea -> { - taskDisplayArea.removeRootTasksWithActivityTypes(activityTypes); + if (activityTypes == null || activityTypes.length == 0) { + return; + } + + // Collect the root tasks that are necessary to be removed instead of performing the removal + // by looping the children, so that we don't miss any root tasks after the children size + // changed or reordered. + final ArrayList<Task> rootTasks = new ArrayList<>(); + forAllRootTasks(rootTask -> { + for (int activityType : activityTypes) { + // Collect the root tasks that are currently being organized. + if (rootTask.mCreatedByOrganizer) { + for (int k = rootTask.getChildCount() - 1; k >= 0; --k) { + final Task task = (Task) rootTask.getChildAt(k); + if (task.getActivityType() == activityType) { + rootTasks.add(task); + } + } + } else if (rootTask.getActivityType() == activityType) { + rootTasks.add(rootTask); + } + } }); + for (int i = rootTasks.size() - 1; i >= 0; --i) { + mRootWindowContainer.mTaskSupervisor.removeRootTask(rootTasks.get(i)); + } } ActivityRecord topRunningActivity() { diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index 91106eff9805..17c3b20c9e40 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -19,10 +19,14 @@ package com.android.server.wm; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL; +import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT; +import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.ImeInsetsSourceProviderProto.IME_TARGET_FROM_IME; import static com.android.server.wm.ImeInsetsSourceProviderProto.INSETS_SOURCE_PROVIDER; import static com.android.server.wm.ImeInsetsSourceProviderProto.IS_IME_LAYOUT_DRAWN; +import android.annotation.NonNull; import android.os.Trace; import android.util.proto.ProtoOutputStream; import android.view.InsetsSource; @@ -37,9 +41,9 @@ import java.io.PrintWriter; * Controller for IME inset source on the server. It's called provider as it provides the * {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}. */ -class ImeInsetsSourceProvider extends InsetsSourceProvider { +final class ImeInsetsSourceProvider extends InsetsSourceProvider { - private InsetsControlTarget mImeTargetFromIme; + private InsetsControlTarget mImeRequester; private Runnable mShowImeRunner; private boolean mIsImeLayoutDrawn; private boolean mImeShowing; @@ -56,12 +60,8 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { * @param imeTarget imeTarget on which IME request is coming from. */ void scheduleShowImePostLayout(InsetsControlTarget imeTarget) { - boolean targetChanged = mImeTargetFromIme != imeTarget - && mImeTargetFromIme != null && imeTarget != null && mShowImeRunner != null - && imeTarget.getWindow() != null && mImeTargetFromIme.getWindow() != null - && mImeTargetFromIme.getWindow().mActivityRecord - == imeTarget.getWindow().mActivityRecord; - mImeTargetFromIme = imeTarget; + boolean targetChanged = isTargetChangedWithinActivity(imeTarget); + mImeRequester = imeTarget; if (targetChanged) { // target changed, check if new target can show IME. ProtoLog.d(WM_DEBUG_IME, "IME target changed within ActivityRecord"); @@ -72,24 +72,24 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { return; } - ProtoLog.d(WM_DEBUG_IME, "Schedule IME show for %s", mImeTargetFromIme.getWindow() == null - ? mImeTargetFromIme : mImeTargetFromIme.getWindow().getName()); + ProtoLog.d(WM_DEBUG_IME, "Schedule IME show for %s", mImeRequester.getWindow() == null + ? mImeRequester : mImeRequester.getWindow().getName()); mShowImeRunner = () -> { ProtoLog.d(WM_DEBUG_IME, "Run showImeRunner"); // Target should still be the same. - if (isImeTargetFromDisplayContentAndImeSame()) { - final InsetsControlTarget target = mDisplayContent.mInputMethodControlTarget; + if (isReadyToShowIme()) { + final InsetsControlTarget target = mDisplayContent.getImeTarget(IME_TARGET_CONTROL); ProtoLog.i(WM_DEBUG_IME, "call showInsets(ime) on %s", target.getWindow() != null ? target.getWindow().getName() : ""); setImeShowing(true); target.showInsets(WindowInsets.Type.ime(), true /* fromIme */); Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "WMS.showImePostLayout", 0); - if (target != mImeTargetFromIme && mImeTargetFromIme != null) { + if (target != mImeRequester && mImeRequester != null) { ProtoLog.w(WM_DEBUG_IME, "showInsets(ime) was requested by different window: %s ", - (mImeTargetFromIme.getWindow() != null - ? mImeTargetFromIme.getWindow().getName() : "")); + (mImeRequester.getWindow() != null + ? mImeRequester.getWindow().getName() : "")); } } abortShowImePostLayout(); @@ -100,8 +100,7 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { void checkShowImePostLayout() { // check if IME is drawn if (mIsImeLayoutDrawn - || (mImeTargetFromIme != null - && isImeTargetFromDisplayContentAndImeSame() + || (isReadyToShowIme() && mWin != null && mWin.isDrawn() && !mWin.mGivenInsetsPending)) { @@ -118,13 +117,13 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { */ void abortShowImePostLayout() { ProtoLog.d(WM_DEBUG_IME, "abortShowImePostLayout"); - mImeTargetFromIme = null; + mImeRequester = null; mIsImeLayoutDrawn = false; mShowImeRunner = null; } @VisibleForTesting - boolean isImeTargetFromDisplayContentAndImeSame() { + boolean isReadyToShowIme() { // IMMS#mLastImeTargetWindow always considers focused window as // IME target, however DisplayContent#computeImeTarget() can compute // a different IME target. @@ -134,35 +133,75 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { // Also, if imeTarget is closing, it would be considered as outdated target. // TODO(b/139861270): Remove the child & sublayer check once IMMS is aware of // actual IME target. - final WindowState dcTarget = mDisplayContent.mInputMethodTarget; - final InsetsControlTarget controlTarget = mDisplayContent.mInputMethodControlTarget; - if (dcTarget == null || mImeTargetFromIme == null) { + final InsetsControlTarget dcTarget = mDisplayContent.getImeTarget(IME_TARGET_LAYERING); + if (dcTarget == null || mImeRequester == null) { return false; } - ProtoLog.d(WM_DEBUG_IME, "dcTarget: %s mImeTargetFromIme: %s", - dcTarget.getName(), mImeTargetFromIme.getWindow() == null - ? mImeTargetFromIme : mImeTargetFromIme.getWindow().getName()); - - return (!dcTarget.isClosing() && mImeTargetFromIme == dcTarget) - || (mImeTargetFromIme != null && mImeTargetFromIme.getWindow() != null - && dcTarget.getParentWindow() == mImeTargetFromIme - && dcTarget.mSubLayer > mImeTargetFromIme.getWindow().mSubLayer) - || mImeTargetFromIme == mDisplayContent.getImeFallback() - || mImeTargetFromIme == mDisplayContent.mInputMethodInputTarget - || controlTarget == mImeTargetFromIme - && (mImeTargetFromIme.getWindow() == null - || !mImeTargetFromIme.getWindow().isClosing()); + ProtoLog.d(WM_DEBUG_IME, "dcTarget: %s mImeRequester: %s", + dcTarget.getWindow().getName(), mImeRequester.getWindow() == null + ? mImeRequester : mImeRequester.getWindow().getName()); + + return isImeLayeringTarget(mImeRequester, dcTarget) + || isAboveImeLayeringTarget(mImeRequester, dcTarget) + || isImeFallbackTarget(mImeRequester) + || isImeInputTarget(mImeRequester) + || sameAsImeControlTarget(); } + // --------------------------------------------------------------------------------------- + // Methods for checking IME insets target changing state. + // + private static boolean isImeLayeringTarget(@NonNull InsetsControlTarget target, + @NonNull InsetsControlTarget dcTarget) { + return !dcTarget.getWindow().isClosing() && target == dcTarget; + } + + private static boolean isAboveImeLayeringTarget(@NonNull InsetsControlTarget target, + @NonNull InsetsControlTarget dcTarget) { + return target.getWindow() != null + && dcTarget.getWindow().getParentWindow() == target + && dcTarget.getWindow().mSubLayer > target.getWindow().mSubLayer; + } + + private boolean isImeFallbackTarget(InsetsControlTarget target) { + return target == mDisplayContent.getImeFallback(); + } + + private boolean isImeInputTarget(InsetsControlTarget target) { + return target == mDisplayContent.getImeTarget(IME_TARGET_INPUT); + } + + private boolean sameAsImeControlTarget() { + final InsetsControlTarget target = mDisplayContent.getImeTarget(IME_TARGET_CONTROL); + return target == mImeRequester + && (mImeRequester.getWindow() == null + || !mImeRequester.getWindow().isClosing()); + } + + private boolean isTargetChangedWithinActivity(InsetsControlTarget target) { + // We don't consider the target out of the activity. + if (target == null || target.getWindow() == null) { + return false; + } + return mImeRequester != target + && mImeRequester != null && mShowImeRunner != null + && mImeRequester.getWindow() != null + && mImeRequester.getWindow().mActivityRecord + == target.getWindow().mActivityRecord; + } + // --------------------------------------------------------------------------------------- + @Override public void dump(PrintWriter pw, String prefix) { super.dump(pw, prefix); pw.print(prefix); pw.print("mImeShowing="); pw.print(mImeShowing); - if (mImeTargetFromIme != null) { - pw.print(" showImePostLayout pending for mImeTargetFromIme="); - pw.print(mImeTargetFromIme); + if (mImeRequester != null) { + pw.print(prefix); + pw.print("showImePostLayout pending for mImeRequester="); + pw.print(mImeRequester); + pw.println(); } pw.println(); } @@ -171,8 +210,8 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { final long token = proto.start(fieldId); super.dumpDebug(proto, INSETS_SOURCE_PROVIDER, logLevel); - if (mImeTargetFromIme != null) { - mImeTargetFromIme.getWindow().dumpDebug(proto, IME_TARGET_FROM_IME, logLevel); + if (mImeRequester != null) { + mImeRequester.getWindow().dumpDebug(proto, IME_TARGET_FROM_IME, logLevel); } proto.write(IS_IME_LAYOUT_DRAWN, mIsImeLayoutDrawn); proto.end(token); diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 40315f98a98f..edd01ebee42f 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -57,7 +57,9 @@ import android.view.WindowInsets.Type; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.SoftInputShowHideReason; +import com.android.internal.os.BackgroundThread; import com.android.internal.protolog.common.ProtoLog; +import com.android.internal.util.LatencyTracker; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; @@ -84,6 +86,11 @@ import java.util.stream.Collectors; public class RecentsAnimationController implements DeathRecipient { private static final String TAG = RecentsAnimationController.class.getSimpleName(); private static final long FAILSAFE_DELAY = 1000; + /** + * If the recents animation is canceled before the delay since the window drawn, do not log the + * action because the duration is too small that may be just a mistouch, + */ + private static final long LATENCY_TRACKER_LOG_DELAY_MS = 300; public static final int REORDER_KEEP_IN_PLACE = 0; public static final int REORDER_MOVE_TO_TOP = 1; @@ -123,7 +130,7 @@ public class RecentsAnimationController implements DeathRecipient { private boolean mPendingStart = true; // Set when the animation has been canceled - private boolean mCanceled; + private volatile boolean mCanceled; // Whether or not the input consumer is enabled. The input consumer must be both registered and // enabled for it to start intercepting touch events. @@ -364,6 +371,9 @@ public class RecentsAnimationController implements DeathRecipient { Binder.restoreCallingIdentity(token); } } + + @Override + public void detachNavigationBarFromApp() {} }; /** @@ -592,6 +602,15 @@ public class RecentsAnimationController implements DeathRecipient { return adapter.createRemoteAnimationTarget(); } + void logRecentsAnimationStartTime(int durationMs) { + BackgroundThread.getHandler().postDelayed(() -> { + if (!mCanceled) { + mService.mLatencyTracker.logAction(LatencyTracker.ACTION_START_RECENTS_ANIMATION, + durationMs); + } + }, LATENCY_TRACKER_LOG_DELAY_MS); + } + private boolean removeTaskInternal(int taskId) { boolean result = false; for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 378638f82c37..69723ff99d06 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -514,16 +514,6 @@ class Task extends WindowContainer<WindowContainer> { // {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag of the root activity. boolean mSupportsPictureInPicture; - // Activity bounds if this task or its top activity is presented in letterbox mode and - // {@code null} otherwise. - @Nullable - private Rect mLetterboxActivityBounds; - - // Activity insets if this task or its top activity is presented in letterbox mode and - // {@code null} otherwise. - @Nullable - private Rect mLetterboxActivityInsets; - // Whether the task is currently being drag-resized private boolean mDragResizing; private int mDragResizeMode; @@ -4116,16 +4106,10 @@ class Task extends WindowContainer<WindowContainer> { info.resizeMode = top != null ? top.mResizeMode : mResizeMode; info.topActivityType = top.getActivityType(); info.isResizeable = isResizeable(); - // Don't query getTopNonFinishingActivity().getBounds() directly because when fillTaskInfo - // is triggered for the first time after activities change, getBounds() may return non final - // bounds, e.g. fullscreen bounds instead of letterboxed bounds. To work around this, - // assigning bounds from ActivityRecord#layoutLetterbox when they are ready. - info.letterboxActivityBounds = Rect.copyOrNull(mLetterboxActivityBounds); - info.letterboxActivityInsets = Rect.copyOrNull(mLetterboxActivityInsets); + info.positionInParent = getRelativePosition(); - info.parentBounds = getParentBounds(); - info.pictureInPictureParams = getPictureInPictureParams(); + info.pictureInPictureParams = getPictureInPictureParams(top); info.topActivityInfo = mReuseActivitiesReport.top != null ? mReuseActivitiesReport.top.info : null; @@ -4142,34 +4126,16 @@ class Task extends WindowContainer<WindowContainer> { } @Nullable PictureInPictureParams getPictureInPictureParams() { - final Task top = getTopMostTask(); + return getPictureInPictureParams(getTopMostTask()); + } + + private @Nullable PictureInPictureParams getPictureInPictureParams(Task top) { if (top == null) return null; final ActivityRecord rootActivity = top.getRootActivity(); return (rootActivity == null || rootActivity.pictureInPictureArgs.empty()) ? null : new PictureInPictureParams(rootActivity.pictureInPictureArgs); } - void maybeUpdateLetterboxInTaskOrganizer( - ActivityRecord activityRecord, - @Nullable Rect activityBounds, - @Nullable Rect activityInsets) { - if (isOrganized() - && mReuseActivitiesReport.top == activityRecord - // Want to force update only if letterbox bounds have changed. - && (!Objects.equals(mLetterboxActivityBounds, activityBounds) - || !Objects.equals(mLetterboxActivityInsets, activityInsets))) { - mLetterboxActivityBounds = Rect.copyOrNull(activityBounds); - mLetterboxActivityInsets = Rect.copyOrNull(activityInsets); - // Forcing update to reduce visual jank during the transition. - dispatchTaskInfoChangedIfNeeded(true /* force */); - } - } - - private Rect getParentBounds() { - final WindowContainer parent = getParent(); - return parent != null ? new Rect(parent.getBounds()) : new Rect(); - } - /** * Returns a {@link TaskInfo} with information from this task. */ diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 5522eeb6d900..7fed84015e8b 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -33,7 +33,6 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; 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; @@ -610,34 +609,6 @@ final class TaskDisplayArea extends DisplayArea<Task> { return false; } - void setExitingTokensHasVisible(boolean hasVisible) { - for (int i = mChildren.size() - 1; i >= 0; --i) { - final ArrayList<ActivityRecord> activities = mChildren.get(i).mExitingActivities; - for (int j = activities.size() - 1; j >= 0; --j) { - activities.get(j).hasVisible = hasVisible; - } - } - } - - void removeExistingAppTokensIfPossible() { - for (int i = mChildren.size() - 1; i >= 0; --i) { - final ArrayList<ActivityRecord> activities = mChildren.get(i).mExitingActivities; - for (int j = activities.size() - 1; j >= 0; --j) { - final ActivityRecord activity = activities.get(j); - if (!activity.hasVisible && !mDisplayContent.mClosingApps.contains(activity) - && (!activity.mIsExiting || activity.isEmpty())) { - // Make sure there is no animation running on this activity, so any windows - // associated with it will be removed as soon as their animations are - // complete. - cancelAnimation(); - ProtoLog.v(WM_DEBUG_ADD_REMOVE, - "performLayout: Activity exiting now removed %s", activity); - activity.removeIfPossible(); - } - } - } - } - @Override int getOrientation(int candidate) { mLastOrientationSource = null; @@ -894,11 +865,6 @@ final class TaskDisplayArea extends DisplayArea<Task> { } } - @Nullable - Task getRootTask(int rootTaskId) { - return getRootTask(stack -> stack.getRootTaskId() == rootTaskId); - } - /** * Returns an existing stack compatible with the windowing mode and activity type or creates one * if a compatible stack doesn't exist. @@ -1296,69 +1262,6 @@ final class TaskDisplayArea extends DisplayArea<Task> { } } - /** - * Removes root tasks in the input windowing modes from the system if they are of activity type - * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED - */ - void removeRootTasksInWindowingModes(int... windowingModes) { - if (windowingModes == null || windowingModes.length == 0) { - return; - } - - // Collect the root tasks that are necessary to be removed instead of performing the removal - // by looping the children, so that we don't miss any root tasks after the children size - // changed or reordered. - final ArrayList<Task> rootTasks = new ArrayList<>(); - for (int j = windowingModes.length - 1; j >= 0; --j) { - final int windowingMode = windowingModes[j]; - for (int i = mChildren.size() - 1; i >= 0; --i) { - final Task rootTask = mChildren.get(i); - if (rootTask.mCreatedByOrganizer - || !rootTask.isActivityTypeStandardOrUndefined() - || rootTask.getWindowingMode() != windowingMode) { - continue; - } - rootTasks.add(rootTask); - } - } - - for (int i = rootTasks.size() - 1; i >= 0; --i) { - mRootWindowContainer.mTaskSupervisor.removeRootTask(rootTasks.get(i)); - } - } - - void removeRootTasksWithActivityTypes(int... activityTypes) { - if (activityTypes == null || activityTypes.length == 0) { - return; - } - - // Collect the root tasks that are necessary to be removed instead of performing the removal - // by looping the children, so that we don't miss any root tasks after the children size - // changed or reordered. - final ArrayList<Task> rootTasks = new ArrayList<>(); - for (int j = activityTypes.length - 1; j >= 0; --j) { - final int activityType = activityTypes[j]; - for (int i = mChildren.size() - 1; i >= 0; --i) { - final Task rootTask = mChildren.get(i); - // Collect the root tasks that are currently being organized. - if (rootTask.mCreatedByOrganizer) { - for (int k = rootTask.getChildCount() - 1; k >= 0; --k) { - final Task task = (Task) rootTask.getChildAt(k); - if (task.getActivityType() == activityType) { - rootTasks.add(task); - } - } - } else if (rootTask.getActivityType() == activityType) { - rootTasks.add(rootTask); - } - } - } - - for (int i = rootTasks.size() - 1; i >= 0; --i) { - mRootWindowContainer.mTaskSupervisor.removeRootTask(rootTasks.get(i)); - } - } - void onSplitScreenModeDismissed() { // 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 @@ -1842,13 +1745,6 @@ final class TaskDisplayArea extends DisplayArea<Task> { } } - void prepareFreezingTaskBounds() { - for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final Task stack = getChildAt(stackNdx); - stack.prepareFreezingTaskBounds(); - } - } - /** * Removes the stacks in the node applying the content removal node from the display. * diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index ca44f0d60226..58aca20af926 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; +import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS; import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS; @@ -580,11 +581,11 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { synchronized (mGlobalLock) { DisplayContent dc = mService.mWindowManager.mRoot .getDisplayContent(displayId); - if (dc == null || dc.mInputMethodTarget == null) { + if (dc == null || dc.getImeTarget(IME_TARGET_LAYERING) == null) { return null; } // Avoid WindowState#getRootTask() so we don't attribute system windows to a task. - final Task task = dc.mInputMethodTarget.getTask(); + final Task task = dc.getImeTarget(IME_TARGET_LAYERING).getWindow().getTask(); if (task == null) { return null; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index f23319936536..6f10edfc59e5 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -105,6 +105,9 @@ import static com.android.internal.util.LatencyTracker.ACTION_ROTATE_SCREEN; import static com.android.server.LockGuard.INDEX_WINDOW; import static com.android.server.LockGuard.installLock; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; +import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL; +import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT; +import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -1037,7 +1040,7 @@ public class WindowManagerService extends IWindowManager.Stub private WindowContentFrameStats mTempWindowRenderStats; - private final LatencyTracker mLatencyTracker; + final LatencyTracker mLatencyTracker; /** * Whether the UI is currently running in touch mode (not showing @@ -1121,18 +1124,16 @@ public class WindowManagerService extends IWindowManager.Stub // While running a recents animation, this will get called early because we show the // recents animation target activity immediately when the animation starts. Defer the // mLaunchTaskBehind updates until recents animation finishes. - final boolean isRecentsAnimationTarget = getRecentsAnimationController() != null - && getRecentsAnimationController().isTargetApp(atoken); - if (atoken.mLaunchTaskBehind && !isRecentsAnimationTarget) { + if (atoken.mLaunchTaskBehind && !isRecentsAnimationTarget(atoken)) { mAtmService.mTaskSupervisor.scheduleLaunchTaskBehindComplete(atoken.token); atoken.mLaunchTaskBehind = false; } else { atoken.updateReportedVisibilityLocked(); // We should also defer sending the finished callback until the recents animation // successfully finishes. - if (atoken.mEnteringAnimation && !isRecentsAnimationTarget) { + if (atoken.mEnteringAnimation && !isRecentsAnimationTarget(atoken)) { atoken.mEnteringAnimation = false; - if (atoken != null && atoken.attachedToProcess()) { + if (atoken.attachedToProcess()) { try { atoken.app.getThread().scheduleEnterAnimationComplete(atoken.appToken); } catch (RemoteException e) { @@ -2969,6 +2970,10 @@ public class WindowManagerService extends IWindowManager.Stub } } + boolean isRecentsAnimationTarget(ActivityRecord r) { + return mRecentsAnimationController != null && mRecentsAnimationController.isTargetApp(r); + } + void setWindowOpaqueLocked(IBinder token, boolean isOpaque) { final ActivityRecord wtoken = mRoot.getActivityRecord(token); if (wtoken != null) { @@ -6322,20 +6327,20 @@ public class WindowManagerService extends IWindowManager.Stub mRoot.dumpTopFocusedDisplayId(pw); mRoot.forAllDisplays(dc -> { final int displayId = dc.getDisplayId(); - final WindowState inputMethodTarget = dc.mInputMethodTarget; - final WindowState inputMethodInputTarget = dc.mInputMethodInputTarget; - final InsetsControlTarget inputMethodControlTarget = dc.mInputMethodControlTarget; - if (inputMethodTarget != null) { - pw.print(" mInputMethodTarget in display# "); pw.print(displayId); - pw.print(' '); pw.println(inputMethodTarget); + final InsetsControlTarget imeLayeringTarget = dc.getImeTarget(IME_TARGET_LAYERING); + final InsetsControlTarget imeInputTarget = dc.getImeTarget(IME_TARGET_INPUT); + final InsetsControlTarget imeControlTarget = dc.getImeTarget(IME_TARGET_CONTROL); + if (imeLayeringTarget != null) { + pw.print(" imeLayeringTarget in display# "); pw.print(displayId); + pw.print(' '); pw.println(imeLayeringTarget); } - if (inputMethodInputTarget != null) { - pw.print(" mInputMethodInputTarget in display# "); pw.print(displayId); - pw.print(' '); pw.println(inputMethodInputTarget); + if (imeInputTarget != null) { + pw.print(" imeInputTarget in display# "); pw.print(displayId); + pw.print(' '); pw.println(imeInputTarget); } - if (inputMethodControlTarget != null) { - pw.print(" inputMethodControlTarget in display# "); pw.print(displayId); - pw.print(' '); pw.println(inputMethodControlTarget); + if (imeControlTarget != null) { + pw.print(" imeControlTarget in display# "); pw.print(displayId); + pw.print(' '); pw.println(imeControlTarget); } }); pw.print(" mInTouchMode="); pw.println(mInTouchMode); @@ -7630,7 +7635,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final WindowState imeTarget = mWindowMap.get(imeTargetWindowToken); if (imeTarget != null) { - imeTarget.getDisplayContent().setInputMethodInputTarget(imeTarget); + imeTarget.getDisplayContent().updateImeInputAndControlTarget(imeTarget); } } } @@ -7773,10 +7778,10 @@ public class WindowManagerService extends IWindowManager.Stub // requested to be hidden. dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout(); } - if (dc != null && dc.mInputMethodControlTarget != null) { + if (dc != null && dc.getImeTarget(IME_TARGET_CONTROL) != null) { ProtoLog.d(WM_DEBUG_IME, "hideIme Control target: %s ", - dc.mInputMethodControlTarget); - dc.mInputMethodControlTarget.hideInsets( + dc.getImeTarget(IME_TARGET_CONTROL)); + dc.getImeTarget(IME_TARGET_CONTROL).hideInsets( WindowInsets.Type.ime(), true /* fromIme */); } if (dc != null) { @@ -7900,7 +7905,7 @@ public class WindowManagerService extends IWindowManager.Stub if (dc == null) { return null; } - final InsetsControlTarget target = dc.mInputMethodControlTarget; + final InsetsControlTarget target = dc.getImeTarget(IME_TARGET_CONTROL); if (target == null) { return null; } @@ -7913,10 +7918,10 @@ public class WindowManagerService extends IWindowManager.Stub public String getImeTargetNameForLogging(int displayId) { synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(displayId); - if (dc == null) { + if (dc == null || dc.getImeTarget(IME_TARGET_LAYERING) == null) { return null; } - return dc.mInputMethodTarget != null ? dc.mInputMethodTarget.getName() : null; + return dc.getImeTarget(IME_TARGET_LAYERING).getWindow().getName(); } } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 3bbdcb8dfedd..32b84a8d0a2c 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -119,6 +119,8 @@ import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE; import static com.android.server.wm.AnimationSpecProto.MOVE; +import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT; +import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.DisplayContent.logsGestureExclusionRestrictions; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; @@ -1112,9 +1114,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final int layoutXDiff; final int layoutYDiff; final WindowState imeWin = mWmService.mRoot.getCurrentInputMethodWindow(); + final InsetsControlTarget imeTarget = dc.getImeTarget(IME_TARGET_LAYERING); final boolean isInputMethodAdjustTarget = windowsAreFloating - ? dc.mInputMethodTarget != null && task == dc.mInputMethodTarget.getTask() - : isInputMethodTarget(); + ? imeTarget != null && task == imeTarget.getWindow().getTask() + : isImeLayeringTarget(); final boolean isImeTarget = imeWin != null && imeWin.isVisibleNow() && isInputMethodAdjustTarget; if (isFullscreenAndFillsDisplay || layoutInParentFrame()) { @@ -1451,9 +1454,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override void onDisplayChanged(DisplayContent dc) { if (dc != null && mDisplayContent != null && dc != mDisplayContent - && mDisplayContent.mInputMethodInputTarget == this) { - dc.setInputMethodInputTarget(mDisplayContent.mInputMethodInputTarget); - mDisplayContent.mInputMethodInputTarget = null; + && getImeInputTarget() == this) { + dc.updateImeInputAndControlTarget(getImeInputTarget()); + mDisplayContent.setImeInputTarget(null); } super.onDisplayChanged(dc); // Window was not laid out for this display yet, so make sure mLayoutSeq does not match. @@ -2158,14 +2161,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } final DisplayContent dc = getDisplayContent(); - if (isInputMethodTarget()) { - // Make sure to set mInputMethodTarget as null when the removed window is the IME - // target, in case computeImeTarget may use the outdated target. - dc.mInputMethodTarget = null; + if (isImeLayeringTarget()) { + // Make sure to set mImeLayeringTarget as null when the removed window is the + // IME target, in case computeImeTarget may use the outdated target. + dc.setImeLayeringTarget(null); dc.computeImeTarget(true /* updateImeTarget */); } - if (dc.mInputMethodInputTarget == this) { - dc.setInputMethodInputTarget(null); + if (dc.getImeTarget(IME_TARGET_INPUT) == this) { + dc.updateImeInputAndControlTarget(null); } final int type = mAttrs.type; @@ -4615,7 +4618,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // directly above it. The exception is if we are in split screen // in which case we process the IME at the DisplayContent level to // ensure it is above the docked divider. - if (isInputMethodTarget() && !inSplitScreenWindowingMode()) { + if (isImeLayeringTarget() && !inSplitScreenWindowingMode()) { if (getDisplayContent().forAllImeWindows(callback, traverseTopToBottom)) { return true; } @@ -5211,9 +5214,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override boolean needsZBoost() { - final WindowState inputMethodTarget = getDisplayContent().mInputMethodTarget; - if (mIsImWindow && inputMethodTarget != null) { - final ActivityRecord activity = inputMethodTarget.mActivityRecord; + final InsetsControlTarget target = getDisplayContent().getImeTarget(IME_TARGET_LAYERING); + if (mIsImWindow && target != null) { + final ActivityRecord activity = target.getWindow().mActivityRecord; if (activity != null) { return activity.needsZBoost(); } @@ -5365,14 +5368,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (isChildWindow()) { // If we are a child of the input method target we need this promotion. - if (getParentWindow().isInputMethodTarget()) { + if (getParentWindow().isImeLayeringTarget()) { return true; } } else if (mActivityRecord != null) { // Likewise if we share a token with the Input method target and are ordered // above it but not necessarily a child (e.g. a Dialog) then we also need // this promotion. - final WindowState imeTarget = getDisplayContent().mInputMethodTarget; + final WindowState imeTarget = getImeLayeringTarget(); boolean inTokenWithAndAboveImeTarget = imeTarget != null && imeTarget != this && imeTarget.mToken == mToken && mAttrs.type != TYPE_APPLICATION_STARTING @@ -5499,8 +5502,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return !mTapExcludeRegion.isEmpty(); } - boolean isInputMethodTarget() { - return getDisplayContent().mInputMethodTarget == this; + boolean isImeLayeringTarget() { + return getDisplayContent().getImeTarget(IME_TARGET_LAYERING) == this; + } + + WindowState getImeLayeringTarget() { + final InsetsControlTarget target = getDisplayContent().getImeTarget(IME_TARGET_LAYERING); + return target != null ? target.getWindow() : null; + } + + WindowState getImeInputTarget() { + final InsetsControlTarget target = mDisplayContent.getImeTarget(IME_TARGET_INPUT); + return target != null ? target.getWindow() : null; } long getFrameNumber() { diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp index 4ca5b9e4b14f..1ecf850adb1f 100644 --- a/services/tests/wmtests/Android.bp +++ b/services/tests/wmtests/Android.bp @@ -47,7 +47,6 @@ android_test { "testables", "ub-uiautomator", "hamcrest-library", - "compatibility-device-util-axt", ], libs: [ 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 2053bfb45884..b451d9f4aaf0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -62,6 +62,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.same; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT; +import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; @@ -168,7 +170,7 @@ public class DisplayContentTests extends WindowTestsBase { final WindowState imeAppTarget = createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget"); - mDisplayContent.mInputMethodTarget = imeAppTarget; + mDisplayContent.setImeLayeringTarget(imeAppTarget); assertForAllWindowsOrder(Arrays.asList( mWallpaperWindow, @@ -187,7 +189,7 @@ public class DisplayContentTests extends WindowTestsBase { @UseTestDisplay(addAllCommonWindows = true) @Test public void testForAllWindows_WithChildWindowImeTarget() throws Exception { - mDisplayContent.mInputMethodTarget = mChildAppWindowAbove; + mDisplayContent.setImeLayeringTarget(mChildAppWindowAbove); assertForAllWindowsOrder(Arrays.asList( mWallpaperWindow, @@ -205,7 +207,7 @@ public class DisplayContentTests extends WindowTestsBase { @UseTestDisplay(addAllCommonWindows = true) @Test public void testForAllWindows_WithStatusBarImeTarget() throws Exception { - mDisplayContent.mInputMethodTarget = mStatusBarWindow; + mDisplayContent.setImeLayeringTarget(mStatusBarWindow); assertForAllWindowsOrder(Arrays.asList( mWallpaperWindow, @@ -223,7 +225,7 @@ public class DisplayContentTests extends WindowTestsBase { @UseTestDisplay(addAllCommonWindows = true) @Test public void testForAllWindows_WithNotificationShadeImeTarget() throws Exception { - mDisplayContent.mInputMethodTarget = mNotificationShadeWindow; + mDisplayContent.setImeLayeringTarget(mNotificationShadeWindow); assertForAllWindowsOrder(Arrays.asList( mWallpaperWindow, @@ -855,15 +857,17 @@ public class DisplayContentTests extends WindowTestsBase { mDisplayContent.setInputMethodWindowLocked(mImeWindow); newDisplay.setInputMethodWindowLocked(null); assertEquals("appWin should be IME target window", - appWin, mDisplayContent.mInputMethodTarget); - assertNull("newDisplay Ime target: ", newDisplay.mInputMethodTarget); + appWin, mDisplayContent.getImeTarget(IME_TARGET_LAYERING)); + assertNull("newDisplay Ime target: ", newDisplay.getImeTarget(IME_TARGET_LAYERING)); // Switch input method window on new display & make sure the input method target also // switched as expected. newDisplay.setInputMethodWindowLocked(mImeWindow); mDisplayContent.setInputMethodWindowLocked(null); - assertEquals("appWin1 should be IME target window", appWin1, newDisplay.mInputMethodTarget); - assertNull("default display Ime target: ", mDisplayContent.mInputMethodTarget); + assertEquals("appWin1 should be IME target window", appWin1, + newDisplay.getImeTarget(IME_TARGET_LAYERING)); + assertNull("default display Ime target: ", + mDisplayContent.getImeTarget(IME_TARGET_LAYERING)); } @Test @@ -937,17 +941,17 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testComputeImeParent_app() throws Exception { final DisplayContent dc = createNewDisplay(); - dc.mInputMethodTarget = createWindow(null, TYPE_BASE_APPLICATION, "app"); - dc.mInputMethodInputTarget = dc.mInputMethodTarget; - assertEquals(dc.mInputMethodTarget.mActivityRecord.getSurfaceControl(), - dc.computeImeParent()); + dc.setImeLayeringTarget(createWindow(null, TYPE_BASE_APPLICATION, "app")); + dc.setImeInputTarget(dc.getImeTarget(IME_TARGET_LAYERING).getWindow()); + assertEquals(dc.getImeTarget(IME_TARGET_LAYERING).getWindow() + .mActivityRecord.getSurfaceControl(), dc.computeImeParent()); } @Test public void testComputeImeParent_app_notFullscreen() throws Exception { final DisplayContent dc = createNewDisplay(); - dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "app"); - dc.mInputMethodTarget.setWindowingMode( + dc.setImeLayeringTarget(createWindow(null, TYPE_STATUS_BAR, "app")); + dc.getImeTarget(IME_TARGET_LAYERING).getWindow().setWindowingMode( WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent()); } @@ -957,7 +961,7 @@ public class DisplayContentTests extends WindowTestsBase { public void testComputeImeParent_app_notMatchParentBounds() { spyOn(mAppWindow.mActivityRecord); doReturn(false).when(mAppWindow.mActivityRecord).matchParentBounds(); - mDisplayContent.mInputMethodTarget = mAppWindow; + mDisplayContent.setImeLayeringTarget(mAppWindow); // The surface parent of IME should be the display instead of app window. assertEquals(mDisplayContent.getImeContainer().getParentSurfaceControl(), mDisplayContent.computeImeParent()); @@ -966,7 +970,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testComputeImeParent_noApp() throws Exception { final DisplayContent dc = createNewDisplay(); - dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "statusBar"); + dc.setImeLayeringTarget(createWindow(null, TYPE_STATUS_BAR, "statusBar")); assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent()); } @@ -976,12 +980,12 @@ public class DisplayContentTests extends WindowTestsBase { WindowState app = createWindow(null, TYPE_BASE_APPLICATION, dc, "app"); - dc.mInputMethodInputTarget = app; + dc.setImeInputTarget(app); assertEquals(app, dc.computeImeControlTarget()); app.removeImmediately(); - assertNull(dc.mInputMethodInputTarget); + assertNull(dc.getImeTarget(IME_TARGET_INPUT)); assertNull(dc.computeImeControlTarget()); } @@ -989,20 +993,21 @@ public class DisplayContentTests extends WindowTestsBase { public void testComputeImeControlTarget() throws Exception { final DisplayContent dc = createNewDisplay(); dc.setRemoteInsetsController(createDisplayWindowInsetsController()); - dc.mInputMethodInputTarget = createWindow(null, TYPE_BASE_APPLICATION, "app"); - dc.mInputMethodTarget = dc.mInputMethodInputTarget; - assertEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget()); + dc.setImeInputTarget(createWindow(null, TYPE_BASE_APPLICATION, "app")); + dc.setImeLayeringTarget(dc.getImeTarget(IME_TARGET_INPUT).getWindow()); + assertEquals(dc.getImeTarget(IME_TARGET_INPUT).getWindow(), dc.computeImeControlTarget()); } @Test public void testComputeImeControlTarget_splitscreen() throws Exception { final DisplayContent dc = createNewDisplay(); - dc.mInputMethodInputTarget = createWindow(null, TYPE_BASE_APPLICATION, "app"); - dc.mInputMethodInputTarget.setWindowingMode( + dc.setImeInputTarget(createWindow(null, TYPE_BASE_APPLICATION, "app")); + dc.getImeTarget(IME_TARGET_INPUT).getWindow().setWindowingMode( WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - dc.mInputMethodTarget = dc.mInputMethodInputTarget; + dc.setImeLayeringTarget(dc.getImeTarget(IME_TARGET_INPUT).getWindow()); dc.setRemoteInsetsController(createDisplayWindowInsetsController()); - assertNotEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget()); + assertNotEquals(dc.getImeTarget(IME_TARGET_INPUT).getWindow(), + dc.computeImeControlTarget()); } @UseTestDisplay(addWindows = W_ACTIVITY) @@ -1010,8 +1015,9 @@ public class DisplayContentTests extends WindowTestsBase { public void testComputeImeControlTarget_notMatchParentBounds() throws Exception { spyOn(mAppWindow.mActivityRecord); doReturn(false).when(mAppWindow.mActivityRecord).matchParentBounds(); - mDisplayContent.mInputMethodInputTarget = mAppWindow; - mDisplayContent.mInputMethodTarget = mDisplayContent.mInputMethodInputTarget; + mDisplayContent.setImeInputTarget(mAppWindow); + mDisplayContent.setImeLayeringTarget( + mDisplayContent.getImeTarget(IME_TARGET_INPUT).getWindow()); mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController()); assertEquals(mAppWindow, mDisplayContent.computeImeControlTarget()); } @@ -1637,7 +1643,7 @@ public class DisplayContentTests extends WindowTestsBase { TYPE_BASE_APPLICATION, "nextImeTargetApp"); spyOn(child1); doReturn(true).when(child1).inSplitScreenWindowingMode(); - mDisplayContent.mInputMethodTarget = child1; + mDisplayContent.setImeLayeringTarget(child1); spyOn(nextImeTargetApp); spyOn(mAppWindow); @@ -1648,7 +1654,7 @@ public class DisplayContentTests extends WindowTestsBase { child1.removeImmediately(); verify(mDisplayContent).computeImeTarget(true); - assertNull(mDisplayContent.mInputMethodInputTarget); + assertNull(mDisplayContent.getImeTarget(IME_TARGET_INPUT)); verify(child1, never()).needsRelativeLayeringToIme(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java index 59d195b670a8..5f9626711896 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java @@ -52,19 +52,19 @@ public class ImeInsetsSourceProviderTest extends WindowTestsBase { public void testTransparentControlTargetWindowCanShowIme() { final WindowState appWin = createWindow(null, TYPE_APPLICATION, "app"); final WindowState popup = createWindow(appWin, TYPE_APPLICATION, "popup"); - mDisplayContent.mInputMethodControlTarget = popup; - mDisplayContent.mInputMethodTarget = appWin; + mDisplayContent.setImeControlTarget(popup); + mDisplayContent.setImeLayeringTarget(appWin); popup.mAttrs.format = PixelFormat.TRANSPARENT; mImeProvider.scheduleShowImePostLayout(appWin); - assertTrue(mImeProvider.isImeTargetFromDisplayContentAndImeSame()); + assertTrue(mImeProvider.isReadyToShowIme()); } @Test public void testInputMethodInputTargetCanShowIme() { WindowState target = createWindow(null, TYPE_APPLICATION, "app"); - mDisplayContent.mInputMethodTarget = target; + mDisplayContent.setImeLayeringTarget(target); mImeProvider.scheduleShowImePostLayout(target); - assertTrue(mImeProvider.isImeTargetFromDisplayContentAndImeSame()); + assertTrue(mImeProvider.isReadyToShowIme()); } @Test @@ -74,8 +74,8 @@ public class ImeInsetsSourceProviderTest extends WindowTestsBase { mImeProvider.setWindow(ime, null, null); WindowState target = createWindow(null, TYPE_APPLICATION, "app"); - mDisplayContent.mInputMethodTarget = target; - mDisplayContent.mInputMethodControlTarget = target; + mDisplayContent.setImeLayeringTarget(target); + mDisplayContent.setImeControlTarget(target); mImeProvider.scheduleShowImePostLayout(target); assertFalse(mImeProvider.isImeShowing()); diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index 90caf35e2936..276643847712 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -31,6 +31,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -181,16 +182,18 @@ public class InsetsStateControllerTest extends WindowTestsBase { // This can be the IME z-order target while app cannot be the IME z-order target. // This is also the only IME control target in this test, so IME won't be invisible caused // by the control-target change. - mDisplayContent.mInputMethodInputTarget = createWindow(null, TYPE_APPLICATION, "base"); + mDisplayContent.updateImeInputAndControlTarget( + createWindow(null, TYPE_APPLICATION, "base")); // Make IME and stay visible during the test. mImeWindow.setHasSurface(true); getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null); - getController().onImeControlTargetChanged(mDisplayContent.mInputMethodInputTarget); + getController().onImeControlTargetChanged(mDisplayContent.getImeTarget(IME_TARGET_INPUT)); final InsetsState requestedState = new InsetsState(); requestedState.getSource(ITYPE_IME).setVisible(true); - mDisplayContent.mInputMethodInputTarget.updateRequestedVisibility(requestedState); - getController().onInsetsModified(mDisplayContent.mInputMethodInputTarget); + mDisplayContent.getImeTarget(IME_TARGET_INPUT).getWindow() + .updateRequestedVisibility(requestedState); + getController().onInsetsModified(mDisplayContent.getImeTarget(IME_TARGET_INPUT)); // Send our spy window (app) into the system so that we can detect the invocation. final WindowState win = createWindow(null, TYPE_APPLICATION, "app"); diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index dd6e490b8282..c7175a0c424d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -30,6 +30,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.Task.ActivityState.STOPPED; import static org.junit.Assert.assertEquals; @@ -270,7 +271,7 @@ public class SizeCompatTests extends WindowTestsBase { // The position should be horizontal centered. assertEquals((displayWidth - bounds.width()) / 2, bounds.left); - mActivity.mDisplayContent.mInputMethodTarget = addWindowToActivity(mActivity); + mActivity.mDisplayContent.setImeLayeringTarget(addWindowToActivity(mActivity)); // Make sure IME cannot attach to the app, otherwise IME window will also be shifted. assertFalse(mActivity.mDisplayContent.isImeAttachedToApp()); @@ -290,9 +291,9 @@ public class SizeCompatTests extends WindowTestsBase { assertFitted(); rotateDisplay(mActivity.mDisplayContent, ROTATION_90); - mActivity.mDisplayContent.mInputMethodTarget = addWindowToActivity(mActivity); - mActivity.mDisplayContent.mInputMethodInputTarget = - mActivity.mDisplayContent.mInputMethodTarget; + mActivity.mDisplayContent.setImeLayeringTarget(addWindowToActivity(mActivity)); + mActivity.mDisplayContent.setImeInputTarget( + mActivity.mDisplayContent.getImeTarget(IME_TARGET_LAYERING).getWindow()); // Because the aspect ratio of display doesn't exceed the max aspect ratio of activity. // The activity should still fill its parent container and IME can attach to the activity. assertTrue(mActivity.matchParentBounds()); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java index 788ef5ad2ec4..6046c9b2c2b1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java @@ -20,20 +20,19 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.android.server.wm.utils.CommonUtils.runWithShellPermissionIdentity; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.app.Activity; -import android.app.ActivityManager; import android.app.ActivityManager.TaskDescription; import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.ActivityView; -import android.app.IActivityManager; import android.app.ITaskStackListener; -import android.app.Instrumentation; import android.app.Instrumentation.ActivityMonitor; import android.app.TaskStackListener; import android.content.ComponentName; @@ -44,7 +43,6 @@ import android.os.Bundle; import android.os.RemoteException; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; -import android.support.test.uiautomator.UiDevice; import android.text.TextUtils; import android.view.Display; import android.view.ViewGroup; @@ -52,10 +50,7 @@ import android.view.ViewGroup; import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; -import com.android.compatibility.common.util.SystemUtil; - import org.junit.After; -import org.junit.Before; import org.junit.Test; import java.util.concurrent.ArrayBlockingQueue; @@ -70,17 +65,11 @@ import java.util.function.Predicate; @MediumTest public class TaskStackChangedListenerTest { - private IActivityManager mService; private ITaskStackListener mTaskStackListener; private static final int WAIT_TIMEOUT_MS = 5000; private static final Object sLock = new Object(); - @Before - public void setUp() throws Exception { - mService = ActivityManager.getService(); - } - @After public void tearDown() throws Exception { ActivityTaskManager.getService().unregisterTaskStackListener(mTaskStackListener); @@ -374,7 +363,7 @@ public class TaskStackChangedListenerTest { final ActivityMonitor monitor = new ActivityMonitor(activityClass.getName(), null, false); getInstrumentation().addMonitor(monitor); final Context context = getInstrumentation().getContext(); - SystemUtil.runWithShellPermissionIdentity(() -> context.startActivity( + runWithShellPermissionIdentity(() -> context.startActivity( new Intent(context, activityClass).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), options.toBundle())); final TestActivity activity = diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java index 78e873e2b0a3..f13847559aa0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java @@ -56,7 +56,7 @@ public class WindowContainerTraversalTests extends WindowTestsBase { WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenSecondaryWindow"); - mDisplayContent.mInputMethodTarget = splitScreenWindow; + mDisplayContent.setImeLayeringTarget(splitScreenWindow); Consumer<WindowState> c = mock(Consumer.class); mDisplayContent.forAllWindows(c, false); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java index d2be50d02ef3..4a6906b88710 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java @@ -292,7 +292,7 @@ public class WindowFrameTests extends WindowTestsBase { // Make IME attach to the window and can produce insets. final DisplayContent dc = mTestDisplayContent; - dc.mInputMethodTarget = w; + dc.setImeLayeringTarget(w); WindowState mockIme = mock(WindowState.class); Mockito.doReturn(true).when(mockIme).isVisibleNow(); dc.mInputMethodWindow = mockIme; diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index a57de094a210..76f8207b4ad8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -789,7 +789,7 @@ public class WindowStateTests extends WindowTestsBase { public void testNeedsRelativeLayeringToIme_notAttached() { WindowState sameTokenWindow = createWindow(null, TYPE_BASE_APPLICATION, mAppWindow.mToken, "SameTokenWindow"); - mDisplayContent.mInputMethodTarget = mAppWindow; + mDisplayContent.setImeLayeringTarget(mAppWindow); sameTokenWindow.mActivityRecord.getStack().setWindowingMode( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); assertTrue(sameTokenWindow.needsRelativeLayeringToIme()); @@ -802,7 +802,7 @@ public class WindowStateTests extends WindowTestsBase { public void testNeedsRelativeLayeringToIme_startingWindow() { WindowState sameTokenWindow = createWindow(null, TYPE_APPLICATION_STARTING, mAppWindow.mToken, "SameTokenWindow"); - mDisplayContent.mInputMethodTarget = mAppWindow; + mDisplayContent.setImeLayeringTarget(mAppWindow); sameTokenWindow.mActivityRecord.getStack().setWindowingMode( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); assertFalse(sameTokenWindow.needsRelativeLayeringToIme()); diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java index e44d47a59fe5..811a14666db9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java @@ -218,7 +218,7 @@ public class ZOrderingTests extends WindowTestsBase { @Test public void testAssignWindowLayers_ForImeWithNoTarget() { - mDisplayContent.mInputMethodTarget = null; + mDisplayContent.setImeLayeringTarget(null); mDisplayContent.assignChildLayers(mTransaction); // The Ime has an higher base layer than app windows and lower base layer than system @@ -236,7 +236,7 @@ public class ZOrderingTests extends WindowTestsBase { @Test public void testAssignWindowLayers_ForImeWithAppTarget() { final WindowState imeAppTarget = createWindow("imeAppTarget"); - mDisplayContent.mInputMethodTarget = imeAppTarget; + mDisplayContent.setImeLayeringTarget(imeAppTarget); mDisplayContent.assignChildLayers(mTransaction); @@ -262,7 +262,7 @@ public class ZOrderingTests extends WindowTestsBase { TYPE_APPLICATION_MEDIA_OVERLAY, imeAppTarget.mToken, "imeAppTargetChildBelowWindow"); - mDisplayContent.mInputMethodTarget = imeAppTarget; + mDisplayContent.setImeLayeringTarget(imeAppTarget); mDisplayContent.assignChildLayers(mTransaction); // Ime should be above all app windows except for child windows that are z-ordered above it @@ -284,7 +284,7 @@ public class ZOrderingTests extends WindowTestsBase { final WindowState imeAppTarget = createWindow("imeAppTarget"); final WindowState appAboveImeTarget = createWindow("appAboveImeTarget"); - mDisplayContent.mInputMethodTarget = imeAppTarget; + mDisplayContent.setImeLayeringTarget(imeAppTarget); mDisplayContent.assignChildLayers(mTransaction); // Ime should be above all app windows except for non-fullscreen app window above it and @@ -307,7 +307,7 @@ public class ZOrderingTests extends WindowTestsBase { mDisplayContent, "imeSystemOverlayTarget", true /* ownerCanAddInternalSystemWindow */); - mDisplayContent.mInputMethodTarget = imeSystemOverlayTarget; + mDisplayContent.setImeLayeringTarget(imeSystemOverlayTarget); mDisplayContent.assignChildLayers(mTransaction); // The IME target base layer is higher than all window except for the nav bar window, so the @@ -330,7 +330,7 @@ public class ZOrderingTests extends WindowTestsBase { @Test public void testAssignWindowLayers_ForStatusBarImeTarget() { - mDisplayContent.mInputMethodTarget = mStatusBarWindow; + mDisplayContent.setImeLayeringTarget(mStatusBarWindow); mDisplayContent.assignChildLayers(mTransaction); assertWindowHigher(mImeWindow, mChildAppWindowAbove); diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/CommonUtils.java b/services/tests/wmtests/src/com/android/server/wm/utils/CommonUtils.java new file mode 100644 index 000000000000..99d73cf5f7d3 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/utils/CommonUtils.java @@ -0,0 +1,37 @@ +/* + * 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.wm.utils; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import android.app.UiAutomation; + +/** Provides common utility functions. */ +public class CommonUtils { + public static UiAutomation getUiAutomation() { + return getInstrumentation().getUiAutomation(); + } + + public static void runWithShellPermissionIdentity(Runnable runnable) { + getUiAutomation().adoptShellPermissionIdentity(); + try { + runnable.run(); + } finally { + getUiAutomation().dropShellPermissionIdentity(); + } + } +} diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java index 8b7a243c30e6..d502da9fb9ec 100644 --- a/telephony/java/android/telephony/DataFailCause.java +++ b/telephony/java/android/telephony/DataFailCause.java @@ -916,6 +916,84 @@ public final class DataFailCause { /** System preference change back to SRAT during handoff */ public static final int HANDOFF_PREFERENCE_CHANGED = 0x8CB; + //IKE error notifications message as specified in 3GPP TS 24.302 (Section 8.1.2.2). + + /** The PDN connection corresponding to the requested APN has been rejected. */ + public static final int IWLAN_PDN_CONNECTION_REJECTION = 0x2000; + /** + * The PDN connection has been rejected. No additional PDN connections can be established + * for the UE due to the network policies or capabilities. + */ + public static final int IWLAN_MAX_CONNECTION_REACHED = 0x2001; + /** + * The PDN connection has been rejected due to a semantic error in TFT operation. + */ + public static final int IWLAN_SEMANTIC_ERROR_IN_THE_TFT_OPERATION = 0x2031; + /** + * The PDN connection has been rejected due to a syntactic error in TFT operation. + */ + public static final int IWLAN_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION = 0x2032; + /** + * The PDN connection has been rejected due to sematic errors in the packet filter. + */ + public static final int IWLAN_SEMANTIC_ERRORS_IN_PACKET_FILTERS = 0x2034; + /** + * The PDN connection has been rejected due to syntactic errors in the packet filter. + */ + public static final int IWLAN_SYNTACTICAL_ERRORS_IN_PACKET_FILTERS = 0x2035; + /** + * No non-3GPP subscription is associated with the IMSI. + * The UE is not allowed to use non-3GPP access to EPC. + */ + public static final int IWLAN_NON_3GPP_ACCESS_TO_EPC_NOT_ALLOWED = 0x2328; + /** The user identified by the IMSI is unknown. */ + public static final int IWLAN_USER_UNKNOWN = 0x2329; + /** + * The requested APN is not included in the user's profile, + * and therefore is not authorized for that user. + */ + public static final int IWLAN_NO_APN_SUBSCRIPTION = 0x232A; + /** The user is barred from using the non-3GPP access or the subscribed APN. */ + public static final int IWLAN_AUTHORIZATION_REJECTED = 0x232B; + /** The Mobile Equipment used is not acceptable to the network */ + public static final int IWLAN_ILLEGAL_ME = 0x232E; + /** + * The network has determined that the requested procedure cannot be completed successfully + * due to network failure. + */ + public static final int IWLAN_NETWORK_FAILURE = 0x2904; + /** The access type is restricted to the user. */ + public static final int IWLAN_RAT_TYPE_NOT_ALLOWED = 0x2AF9; + /** The network does not accept emergency PDN bringup request using an IMEI */ + public static final int IWLAN_IMEI_NOT_ACCEPTED = 0x2AFD; + /** + * The ePDG performs PLMN filtering (based on roaming agreements) and rejects + * the request from the UE. + * The UE requests service in a PLMN where the UE is not allowed to operate. + */ + public static final int IWLAN_PLMN_NOT_ALLOWED = 0x2B03; + /** The ePDG does not support un-authenticated IMSI based emergency PDN bringup **/ + public static final int IWLAN_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED = 0x2B2F; + + // Device is unable to establish an IPSec tunnel with the ePDG for any reason + // e.g authentication fail or certificate validation or DNS Resolution and timeout failure. + + /** IKE configuration error resulting in failure */ + public static final int IWLAN_IKEV2_CONFIG_FAILURE = 0x4000; + /** + * Sent in the response to an IKE_AUTH message when, for some reason, + * the authentication failed. + */ + public static final int IWLAN_IKEV2_AUTH_FAILURE = 0x4001; + /** IKE message timeout, tunnel setup failed due to no response from EPDG */ + public static final int IWLAN_IKEV2_MSG_TIMEOUT = 0x4002; + /** IKE Certification validation failure */ + public static final int IWLAN_IKEV2_CERT_INVALID = 0x4003; + /** Unable to resolve FQDN for the ePDG to an IP address */ + public static final int IWLAN_DNS_RESOLUTION_NAME_FAILURE = 0x4004; + /** No response received from the DNS Server due to a timeout*/ + public static final int IWLAN_DNS_RESOLUTION_TIMEOUT = 0x4005; + // OEM sepecific error codes. To be used by OEMs when they don't // want to reveal error code which would be replaced by ERROR_UNSPECIFIED public static final int OEM_DCFAILCAUSE_1 = 0x1001; @@ -1341,6 +1419,34 @@ public final class DataFailCause { sFailCauseMap.put(VSNCP_RECONNECT_NOT_ALLOWED, "VSNCP_RECONNECT_NOT_ALLOWED"); sFailCauseMap.put(IPV6_PREFIX_UNAVAILABLE, "IPV6_PREFIX_UNAVAILABLE"); sFailCauseMap.put(HANDOFF_PREFERENCE_CHANGED, "HANDOFF_PREFERENCE_CHANGED"); + sFailCauseMap.put(IWLAN_PDN_CONNECTION_REJECTION, "IWLAN_PDN_CONNECTION_REJECTION"); + sFailCauseMap.put(IWLAN_MAX_CONNECTION_REACHED, "IWLAN_MAX_CONNECTION_REACHED"); + sFailCauseMap.put(IWLAN_SEMANTIC_ERROR_IN_THE_TFT_OPERATION, + "IWLAN_SEMANTIC_ERROR_IN_THE_TFT_OPERATION"); + sFailCauseMap.put(IWLAN_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION, + "IWLAN_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION"); + sFailCauseMap.put(IWLAN_SEMANTIC_ERRORS_IN_PACKET_FILTERS, + "IWLAN_SEMANTIC_ERRORS_IN_PACKET_FILTERS"); + sFailCauseMap.put(IWLAN_SYNTACTICAL_ERRORS_IN_PACKET_FILTERS, + "IWLAN_SYNTACTICAL_ERRORS_IN_PACKET_FILTERS"); + sFailCauseMap.put(IWLAN_NON_3GPP_ACCESS_TO_EPC_NOT_ALLOWED, + "IWLAN_NON_3GPP_ACCESS_TO_EPC_NOT_ALLOWED"); + sFailCauseMap.put(IWLAN_USER_UNKNOWN, "IWLAN_USER_UNKNOWN"); + sFailCauseMap.put(IWLAN_NO_APN_SUBSCRIPTION, "IWLAN_NO_APN_SUBSCRIPTION"); + sFailCauseMap.put(IWLAN_AUTHORIZATION_REJECTED, "IWLAN_AUTHORIZATION_REJECTED"); + sFailCauseMap.put(IWLAN_ILLEGAL_ME, "IWLAN_ILLEGAL_ME"); + sFailCauseMap.put(IWLAN_NETWORK_FAILURE, "IWLAN_NETWORK_FAILURE"); + sFailCauseMap.put(IWLAN_RAT_TYPE_NOT_ALLOWED, "IWLAN_RAT_TYPE_NOT_ALLOWED"); + sFailCauseMap.put(IWLAN_IMEI_NOT_ACCEPTED, "IWLAN_IMEI_NOT_ACCEPTED"); + sFailCauseMap.put(IWLAN_PLMN_NOT_ALLOWED, "IWLAN_PLMN_NOT_ALLOWED"); + sFailCauseMap.put(IWLAN_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED, + "IWLAN_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED"); + sFailCauseMap.put(IWLAN_IKEV2_CONFIG_FAILURE, "IWLAN_IKEV2_CONFIG_FAILURE"); + sFailCauseMap.put(IWLAN_IKEV2_AUTH_FAILURE, "IWLAN_IKEV2_AUTH_FAILURE"); + sFailCauseMap.put(IWLAN_IKEV2_MSG_TIMEOUT, "IWLAN_IKEV2_MSG_TIMEOUT"); + sFailCauseMap.put(IWLAN_IKEV2_CERT_INVALID, "IWLAN_IKEV2_CERT_INVALID"); + sFailCauseMap.put(IWLAN_DNS_RESOLUTION_NAME_FAILURE, "IWLAN_DNS_RESOLUTION_NAME_FAILURE"); + sFailCauseMap.put(IWLAN_DNS_RESOLUTION_TIMEOUT, "IWLAN_DNS_RESOLUTION_TIMEOUT"); sFailCauseMap.put(OEM_DCFAILCAUSE_1, "OEM_DCFAILCAUSE_1"); sFailCauseMap.put(OEM_DCFAILCAUSE_2, "OEM_DCFAILCAUSE_2"); sFailCauseMap.put(OEM_DCFAILCAUSE_3, "OEM_DCFAILCAUSE_3"); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 3aed6019beb5..b3bdd6055c62 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -188,6 +188,7 @@ import android.net.RouteInfo; import android.net.RouteInfoParcel; import android.net.SocketKeepalive; import android.net.UidRange; +import android.net.UidRangeParcel; import android.net.Uri; import android.net.VpnManager; import android.net.metrics.IpConnectivityLog; @@ -1055,7 +1056,7 @@ public class ConnectivityServiceTest { public MockVpn(int userId) { super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService, - userId, mock(KeyStore.class)); + mMockNetd, userId, mock(KeyStore.class)); mConfig = new VpnConfig(); } @@ -1094,10 +1095,11 @@ public class ConnectivityServiceTest { mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp, mNetworkCapabilities); mMockNetworkAgent.waitForIdle(TIMEOUT_MS); - verify(mNetworkManagementService, times(1)) - .addVpnUidRanges(eq(mMockVpn.getNetId()), eq(uids.toArray(new UidRange[0]))); - verify(mNetworkManagementService, never()) - .removeVpnUidRanges(eq(mMockVpn.getNetId()), any()); + + verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetId()), + eq(toUidRangeStableParcels(uids))); + verify(mMockNetd, never()) + .networkRemoveUidRanges(eq(mMockVpn.getNetId()), any()); mAgentRegistered = true; mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities()); mNetworkAgent = mMockNetworkAgent.getNetworkAgent(); @@ -1169,6 +1171,11 @@ public class ConnectivityServiceTest { } } + private UidRangeParcel[] toUidRangeStableParcels(final @NonNull Set<UidRange> ranges) { + return ranges.stream().map( + r -> new UidRangeParcel(r.start, r.stop)).toArray(UidRangeParcel[]::new); + } + private void mockVpn(int uid) { synchronized (mService.mVpns) { int userId = UserHandle.getUserId(uid); @@ -4947,8 +4954,8 @@ public class ConnectivityServiceTest { expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME); reset(mStatsService); - // Captive portal change shouldn't update ifaces - mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL); + // Temp metered change shouldn't update ifaces + mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED); waitForIdle(); verify(mStatsService, never()) .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME), @@ -5464,6 +5471,7 @@ public class ConnectivityServiceTest { final Network wifi = mWiFiNetworkAgent.getNetwork(); final NetworkCapabilities initialCaps = new NetworkCapabilities(); + initialCaps.addTransportType(TRANSPORT_VPN); initialCaps.addCapability(NET_CAPABILITY_INTERNET); initialCaps.removeCapability(NET_CAPABILITY_NOT_VPN); @@ -5495,44 +5503,45 @@ public class ConnectivityServiceTest { withWifiAndMobileUnderlying.setLinkDownstreamBandwidthKbps(10); withWifiAndMobileUnderlying.setLinkUpstreamBandwidthKbps(20); + final NetworkCapabilities initialCapsNotMetered = new NetworkCapabilities(initialCaps); + initialCapsNotMetered.addCapability(NET_CAPABILITY_NOT_METERED); + NetworkCapabilities caps = new NetworkCapabilities(initialCaps); - final boolean notDeclaredMetered = false; - mService.applyUnderlyingCapabilities(new Network[]{}, caps, notDeclaredMetered); + mService.applyUnderlyingCapabilities(new Network[]{}, initialCapsNotMetered, caps); assertEquals(withNoUnderlying, caps); caps = new NetworkCapabilities(initialCaps); - mService.applyUnderlyingCapabilities(new Network[]{null}, caps, notDeclaredMetered); + mService.applyUnderlyingCapabilities(new Network[]{null}, initialCapsNotMetered, caps); assertEquals(withNoUnderlying, caps); caps = new NetworkCapabilities(initialCaps); - mService.applyUnderlyingCapabilities(new Network[]{mobile}, caps, notDeclaredMetered); + mService.applyUnderlyingCapabilities(new Network[]{mobile}, initialCapsNotMetered, caps); assertEquals(withMobileUnderlying, caps); - mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, notDeclaredMetered); + mService.applyUnderlyingCapabilities(new Network[]{wifi}, initialCapsNotMetered, caps); assertEquals(withWifiUnderlying, caps); - final boolean isDeclaredMetered = true; withWifiUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED); caps = new NetworkCapabilities(initialCaps); - mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, isDeclaredMetered); + mService.applyUnderlyingCapabilities(new Network[]{wifi}, initialCaps, caps); assertEquals(withWifiUnderlying, caps); caps = new NetworkCapabilities(initialCaps); - mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, caps, isDeclaredMetered); + mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, initialCaps, caps); assertEquals(withWifiAndMobileUnderlying, caps); withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED); caps = new NetworkCapabilities(initialCaps); mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi}, - caps, notDeclaredMetered); + initialCapsNotMetered, caps); assertEquals(withWifiAndMobileUnderlying, caps); caps = new NetworkCapabilities(initialCaps); mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi}, - caps, notDeclaredMetered); + initialCapsNotMetered, caps); assertEquals(withWifiAndMobileUnderlying, caps); - mService.applyUnderlyingCapabilities(null, caps, notDeclaredMetered); + mService.applyUnderlyingCapabilities(null, initialCapsNotMetered, caps); assertEquals(withWifiUnderlying, caps); } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 337507ac1d46..6e380be6c583 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -58,6 +58,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.content.res.Resources; import android.net.ConnectivityManager; +import android.net.INetd; import android.net.Ikev2VpnProfile; import android.net.InetAddresses; import android.net.IpPrefix; @@ -70,6 +71,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo.DetailedState; import android.net.RouteInfo; import android.net.UidRange; +import android.net.UidRangeParcel; import android.net.VpnManager; import android.net.VpnService; import android.net.ipsec.ike.IkeSessionCallback; @@ -172,11 +174,13 @@ public class VpnTest { mPackages.put(PKGS[i], PKG_UIDS[i]); } } + private static final UidRange PRI_USER_RANGE = UidRange.createForUser(primaryUser.id); @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private UserManager mUserManager; @Mock private PackageManager mPackageManager; @Mock private INetworkManagementService mNetService; + @Mock private INetd mNetd; @Mock private AppOpsManager mAppOps; @Mock private NotificationManager mNotificationManager; @Mock private Vpn.SystemServices mSystemServices; @@ -256,8 +260,7 @@ public class VpnTest { null, null); assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { - UidRange.createForUser(primaryUser.id), - UidRange.createForUser(restrictedProfileA.id) + PRI_USER_RANGE, UidRange.createForUser(restrictedProfileA.id) })), ranges); } @@ -269,9 +272,7 @@ public class VpnTest { final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null); - assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { - UidRange.createForUser(primaryUser.id) - })), ranges); + assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges); } @Test @@ -282,15 +283,13 @@ public class VpnTest { final Set<UidRange> ranges = new ArraySet<>(); vpn.addUserToRanges(ranges, primaryUser.id, null, null); - assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { - UidRange.createForUser(primaryUser.id) - })), ranges); + assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges); } @Test public void testUidAllowAndDenylist() throws Exception { final Vpn vpn = createVpn(primaryUser.id); - final UidRange user = UidRange.createForUser(primaryUser.id); + final UidRange user = PRI_USER_RANGE; final String[] packages = {PKGS[0], PKGS[1], PKGS[2]}; // Allowed list @@ -339,62 +338,67 @@ public class VpnTest { @Test public void testLockdownChangingPackage() throws Exception { final Vpn vpn = createVpn(primaryUser.id); - final UidRange user = UidRange.createForUser(primaryUser.id); + final UidRange user = PRI_USER_RANGE; // Default state. - assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); + assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], + user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); // Set always-on without lockdown. assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null, mKeyStore)); - assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); + assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], + user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); // Set always-on with lockdown. assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null, mKeyStore)); - verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { - new UidRange(user.start, user.start + PKG_UIDS[1] - 1), - new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) + verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] { + new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1), + new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop) })); - assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); + + assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], + user.start + PKG_UIDS[3]); assertUnblocked(vpn, user.start + PKG_UIDS[1]); // Switch to another app. assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore)); - verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { - new UidRange(user.start, user.start + PKG_UIDS[1] - 1), - new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) + verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] { + new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1), + new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop) })); - verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { - new UidRange(user.start, user.start + PKG_UIDS[3] - 1), - new UidRange(user.start + PKG_UIDS[3] + 1, user.stop) + + verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] { + new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1), + new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop) })); - assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); + assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], + user.start + PKG_UIDS[2]); assertUnblocked(vpn, user.start + PKG_UIDS[3]); } @Test public void testLockdownAllowlist() throws Exception { final Vpn vpn = createVpn(primaryUser.id); - final UidRange user = UidRange.createForUser(primaryUser.id); + final UidRange user = PRI_USER_RANGE; // Set always-on with lockdown and allow app PKGS[2] from lockdown. assertTrue(vpn.setAlwaysOnPackage( PKGS[1], true, Collections.singletonList(PKGS[2]), mKeyStore)); - verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { - new UidRange(user.start, user.start + PKG_UIDS[1] - 1), - new UidRange(user.start + PKG_UIDS[2] + 1, user.stop) + verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] { + new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1), + new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop) })); assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]); assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); - // Change allowed app list to PKGS[3]. assertTrue(vpn.setAlwaysOnPackage( PKGS[1], true, Collections.singletonList(PKGS[3]), mKeyStore)); - verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { - new UidRange(user.start + PKG_UIDS[2] + 1, user.stop) + verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] { + new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop) })); - verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { - new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1), - new UidRange(user.start + PKG_UIDS[3] + 1, user.stop) + verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] { + new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1), + new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop) })); assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]); assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]); @@ -402,25 +406,25 @@ public class VpnTest { // Change the VPN app. assertTrue(vpn.setAlwaysOnPackage( PKGS[0], true, Collections.singletonList(PKGS[3]), mKeyStore)); - verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { - new UidRange(user.start, user.start + PKG_UIDS[1] - 1), - new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1) + verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] { + new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1), + new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1) })); - verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { - new UidRange(user.start, user.start + PKG_UIDS[0] - 1), - new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1) + verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] { + new UidRangeParcel(user.start, user.start + PKG_UIDS[0] - 1), + new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1) })); assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]); // Remove the list of allowed packages. assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null, mKeyStore)); - verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { - new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1), - new UidRange(user.start + PKG_UIDS[3] + 1, user.stop) + verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] { + new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1), + new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop) })); - verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { - new UidRange(user.start + PKG_UIDS[0] + 1, user.stop), + verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] { + new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop), })); assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); @@ -429,12 +433,12 @@ public class VpnTest { // Add the list of allowed packages. assertTrue(vpn.setAlwaysOnPackage( PKGS[0], true, Collections.singletonList(PKGS[1]), mKeyStore)); - verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { - new UidRange(user.start + PKG_UIDS[0] + 1, user.stop) + verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] { + new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop) })); - verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { - new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), - new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) + verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] { + new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), + new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop) })); assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]); @@ -447,13 +451,13 @@ public class VpnTest { // allowed package should change from PGKS[1] to PKGS[2]. assertTrue(vpn.setAlwaysOnPackage( PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"), mKeyStore)); - verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{ - new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), - new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) + verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[]{ + new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), + new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop) })); - verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[]{ - new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1), - new UidRange(user.start + PKG_UIDS[2] + 1, user.stop) + verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[]{ + new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1), + new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop) })); } @@ -467,86 +471,86 @@ public class VpnTest { restrictedProfileA.flags); tempProfile.restrictedProfileParentId = primaryUser.id; - final UidRange user = UidRange.createForUser(primaryUser.id); + final UidRange user = PRI_USER_RANGE; final UidRange profile = UidRange.createForUser(tempProfile.id); // Set lockdown. assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore)); - verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { - new UidRange(user.start, user.start + PKG_UIDS[3] - 1), - new UidRange(user.start + PKG_UIDS[3] + 1, user.stop) + verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] { + new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1), + new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop) })); - // Verify restricted user isn't affected at first. assertUnblocked(vpn, profile.start + PKG_UIDS[0]); // Add the restricted user. setMockedUsers(primaryUser, tempProfile); vpn.onUserAdded(tempProfile.id); - verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { - new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1), - new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop) + verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] { + new UidRangeParcel(profile.start, profile.start + PKG_UIDS[3] - 1), + new UidRangeParcel(profile.start + PKG_UIDS[3] + 1, profile.stop) })); // Remove the restricted user. tempProfile.partial = true; vpn.onUserRemoved(tempProfile.id); - verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { - new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1), - new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop) + verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] { + new UidRangeParcel(profile.start, profile.start + PKG_UIDS[3] - 1), + new UidRangeParcel(profile.start + PKG_UIDS[3] + 1, profile.stop) })); } @Test public void testLockdownRuleRepeatability() throws Exception { final Vpn vpn = createVpn(primaryUser.id); - + final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] { + new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)}; // Given legacy lockdown is already enabled, vpn.setLockdown(true); - verify(mNetService, times(1)).setAllowOnlyVpnForUids( - eq(true), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)})); + + verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(primaryUserRangeParcel)); // Enabling legacy lockdown twice should do nothing. vpn.setLockdown(true); - verify(mNetService, times(1)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class)); + verify(mNetd, times(1)) + .networkRejectNonSecureVpn(anyBoolean(), any(UidRangeParcel[].class)); // And disabling should remove the rules exactly once. vpn.setLockdown(false); - verify(mNetService, times(1)).setAllowOnlyVpnForUids( - eq(false), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)})); + verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(primaryUserRangeParcel)); // Removing the lockdown again should have no effect. vpn.setLockdown(false); - verify(mNetService, times(2)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class)); + verify(mNetd, times(2)).networkRejectNonSecureVpn( + anyBoolean(), any(UidRangeParcel[].class)); } @Test public void testLockdownRuleReversibility() throws Exception { final Vpn vpn = createVpn(primaryUser.id); - - final UidRange[] entireUser = { - UidRange.createForUser(primaryUser.id) + final UidRangeParcel[] entireUser = { + new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop) }; - final UidRange[] exceptPkg0 = { - new UidRange(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1), - new UidRange(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop) + final UidRangeParcel[] exceptPkg0 = { + new UidRangeParcel(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1), + new UidRangeParcel(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop) }; - final InOrder order = inOrder(mNetService); + final InOrder order = inOrder(mNetd); // Given lockdown is enabled with no package (legacy VPN), vpn.setLockdown(true); - order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser)); + order.verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(entireUser)); // When a new VPN package is set the rules should change to cover that package. vpn.prepare(null, PKGS[0], VpnManager.TYPE_VPN_SERVICE); - order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(entireUser)); - order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(exceptPkg0)); + order.verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(entireUser)); + order.verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(exceptPkg0)); // When that VPN package is unset, everything should be undone again in reverse. vpn.prepare(null, VpnConfig.LEGACY_VPN, VpnManager.TYPE_VPN_SERVICE); - order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(exceptPkg0)); - order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser)); + order.verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(exceptPkg0)); + order.verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(entireUser)); } @Test @@ -1186,7 +1190,7 @@ public class VpnTest { .thenReturn(asUserContext); final TestLooper testLooper = new TestLooper(); final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService, - userId, mKeyStore, mSystemServices, mIkev2SessionCreator); + mNetd, userId, mKeyStore, mSystemServices, mIkev2SessionCreator); verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat( provider -> provider.getName().contains("VpnNetworkProvider") )); diff --git a/wifi/api/current.txt b/wifi/api/current.txt index e11b33efcc33..4b0d38df0260 100644 --- a/wifi/api/current.txt +++ b/wifi/api/current.txt @@ -35,6 +35,7 @@ package android.net.wifi { field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.ScanResult> CREATOR; field public String SSID; field public static final int WIFI_STANDARD_11AC = 5; // 0x5 + field public static final int WIFI_STANDARD_11AD = 7; // 0x7 field public static final int WIFI_STANDARD_11AX = 6; // 0x6 field public static final int WIFI_STANDARD_11N = 4; // 0x4 field public static final int WIFI_STANDARD_LEGACY = 1; // 0x1 @@ -1156,7 +1157,11 @@ package android.net.wifi.rtt { public final class RangingRequest implements android.os.Parcelable { method public int describeContents(); + method public static int getDefaultRttBurstSize(); method public static int getMaxPeers(); + method public static int getMaxRttBurstSize(); + method public static int getMinRttBurstSize(); + method public int getRttBurstSize(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.rtt.RangingRequest> CREATOR; } @@ -1168,6 +1173,7 @@ package android.net.wifi.rtt { method public android.net.wifi.rtt.RangingRequest.Builder addWifiAwarePeer(@NonNull android.net.MacAddress); method public android.net.wifi.rtt.RangingRequest.Builder addWifiAwarePeer(@NonNull android.net.wifi.aware.PeerHandle); method public android.net.wifi.rtt.RangingRequest build(); + method @NonNull public android.net.wifi.rtt.RangingRequest.Builder setRttBurstSize(int); } public final class RangingResult implements android.os.Parcelable { diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt index 15a55485c1d4..e15d0f132b87 100644 --- a/wifi/api/system-current.txt +++ b/wifi/api/system-current.txt @@ -277,6 +277,7 @@ package android.net.wifi { method @Nullable public android.net.wifi.WifiConfiguration toWifiConfiguration(); field public static final int BAND_2GHZ = 1; // 0x1 field public static final int BAND_5GHZ = 2; // 0x2 + field public static final int BAND_60GHZ = 8; // 0x8 field public static final int BAND_6GHZ = 4; // 0x4 field @Deprecated public static final int BAND_ANY = 7; // 0x7 field public static final int RANDOMIZATION_NONE = 0; // 0x0 @@ -314,9 +315,13 @@ package android.net.wifi { field public static final int CHANNEL_WIDTH_160MHZ = 6; // 0x6 field public static final int CHANNEL_WIDTH_20MHZ = 2; // 0x2 field public static final int CHANNEL_WIDTH_20MHZ_NOHT = 1; // 0x1 + field public static final int CHANNEL_WIDTH_2160MHZ = 7; // 0x7 field public static final int CHANNEL_WIDTH_40MHZ = 3; // 0x3 + field public static final int CHANNEL_WIDTH_4320MHZ = 8; // 0x8 + field public static final int CHANNEL_WIDTH_6480MHZ = 9; // 0x9 field public static final int CHANNEL_WIDTH_80MHZ = 4; // 0x4 field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 5; // 0x5 + field public static final int CHANNEL_WIDTH_8640MHZ = 10; // 0xa field public static final int CHANNEL_WIDTH_INVALID = 0; // 0x0 field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApInfo> CREATOR; } @@ -959,6 +964,10 @@ package android.net.wifi.p2p { package android.net.wifi.rtt { + public final class RangingRequest implements android.os.Parcelable { + method @NonNull public java.util.List<android.net.wifi.rtt.ResponderConfig> getRttPeers(); + } + public static final class RangingRequest.Builder { method public android.net.wifi.rtt.RangingRequest.Builder addResponder(@NonNull android.net.wifi.rtt.ResponderConfig); } diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java index 4c23286258d8..9f8ecf14175d 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -320,6 +320,11 @@ public final class ScanResult implements Parcelable { public static final int WIFI_STANDARD_11AX = 6; /** + * Wi-Fi 802.11ad/ay + */ + public static final int WIFI_STANDARD_11AD = 7; + + /** * AP wifi standard. */ private @WifiStandard int mWifiStandard; @@ -352,6 +357,8 @@ public final class ScanResult implements Parcelable { return "11ac"; case WIFI_STANDARD_11AX: return "11ax"; + case WIFI_STANDARD_11AD: + return "11ad"; case WIFI_STANDARD_UNKNOWN: return "unknown"; } @@ -705,6 +712,13 @@ public final class ScanResult implements Parcelable { return UNSPECIFIED; } } + if (band == WifiScanner.WIFI_BAND_60_GHZ) { + if (channel >= BAND_60_GHZ_FIRST_CH_NUM && channel <= BAND_60_GHZ_LAST_CH_NUM) { + return ((channel - BAND_60_GHZ_FIRST_CH_NUM) * 2160) + BAND_60_GHZ_START_FREQ_MHZ; + } else { + return UNSPECIFIED; + } + } return UNSPECIFIED; } diff --git a/wifi/java/android/net/wifi/SecurityParams.java b/wifi/java/android/net/wifi/SecurityParams.java index 157d1c5748d0..0ab6f572fba3 100644 --- a/wifi/java/android/net/wifi/SecurityParams.java +++ b/wifi/java/android/net/wifi/SecurityParams.java @@ -16,6 +16,7 @@ package android.net.wifi; +import android.annotation.IntDef; import android.annotation.NonNull; import android.net.wifi.WifiConfiguration.AuthAlgorithm; import android.net.wifi.WifiConfiguration.GroupCipher; @@ -27,6 +28,8 @@ import android.net.wifi.WifiConfiguration.SecurityType; import android.net.wifi.WifiConfiguration.SuiteBCipher; import android.os.Parcel; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.BitSet; import java.util.Objects; @@ -37,6 +40,23 @@ import java.util.Objects; public class SecurityParams { private static final String TAG = "SecurityParams"; + /** Passpoint Release 1 */ + public static final int PASSPOINT_R1 = 1; + + /** Passpoint Release 2 */ + public static final int PASSPOINT_R2 = 2; + + /** Passpoint Release 3 */ + public static final int PASSPOINT_R3 = 3; + + @IntDef(prefix = { "PASSPOINT_" }, value = { + PASSPOINT_R1, + PASSPOINT_R2, + PASSPOINT_R3, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PasspointRelease {} + private @SecurityType int mSecurityType = WifiConfiguration.SECURITY_TYPE_PSK; /** @@ -99,6 +119,8 @@ public class SecurityParams { */ private boolean mRequirePmf = false; + private @PasspointRelease int mPasspointRelease = PASSPOINT_R2; + /** Indicate that this SAE security type only accepts H2E (Hash-to-Element) mode. */ private boolean mIsSaeH2eOnlyMode = false; @@ -562,11 +584,22 @@ public class SecurityParams { } /** - * Create EAP security params for Passpoint. + * Create Passpoint security params. */ - public static @NonNull SecurityParams createPasspointParams(boolean requirePmf) { + public static @NonNull SecurityParams createPasspointParams(@PasspointRelease int release) { SecurityParams params = new SecurityParams(); - params.mSecurityType = WifiConfiguration.SECURITY_TYPE_EAP; + switch (release) { + case PASSPOINT_R1: + case PASSPOINT_R2: + params.mSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2; + break; + case PASSPOINT_R3: + params.mSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3; + params.mRequirePmf = true; + break; + default: + throw new IllegalArgumentException("invalid passpoint release " + release); + } params.mAllowedKeyManagement.set(KeyMgmt.WPA_EAP); params.mAllowedKeyManagement.set(KeyMgmt.IEEE8021X); @@ -574,12 +607,9 @@ public class SecurityParams { params.mAllowedProtocols.set(Protocol.RSN); params.mAllowedPairwiseCiphers.set(PairwiseCipher.CCMP); - params.mAllowedPairwiseCiphers.set(PairwiseCipher.TKIP); params.mAllowedGroupCiphers.set(GroupCipher.CCMP); - params.mAllowedGroupCiphers.set(GroupCipher.TKIP); - params.mRequirePmf = requirePmf; return params; } diff --git a/wifi/java/android/net/wifi/SoftApCapability.java b/wifi/java/android/net/wifi/SoftApCapability.java index d570b7e8afa9..6f72f0b58b4b 100644 --- a/wifi/java/android/net/wifi/SoftApCapability.java +++ b/wifi/java/android/net/wifi/SoftApCapability.java @@ -116,6 +116,11 @@ public final class SoftApCapability implements Parcelable { private int[] mSupportedChannelListIn6g = EMPTY_INT_ARRAY; /** + * A list storing supported 60G channels. + */ + private int[] mSupportedChannelListIn60g = EMPTY_INT_ARRAY; + + /** * Get the maximum supported client numbers which AP resides on. */ public int getMaxSupportedClients() { @@ -147,8 +152,8 @@ public final class SoftApCapability implements Parcelable { * Set supported channel list in target band type. * * @param band One of the following band types: - * {@link SoftApConfiguation#BAND_2GHZ}, {@link SoftApConfiguation#BAND_5GHZ} or - * {@link SoftApConfiguation#BAND_6GHZ}. + * {@link SoftApConfiguation#BAND_2GHZ}, {@link SoftApConfiguation#BAND_5GHZ}, + * {@link SoftApConfiguation#BAND_6GHZ}, or {@link SoftApConfiguation#BAND_60GHZ}. * @param supportedChannelList supported channel list in target band * @return true if band and supportedChannelList are valid, otherwise false. * @@ -168,6 +173,9 @@ public final class SoftApCapability implements Parcelable { case SoftApConfiguration.BAND_6GHZ: mSupportedChannelListIn6g = supportedChannelList; break; + case SoftApConfiguration.BAND_60GHZ: + mSupportedChannelListIn60g = supportedChannelList; + break; default: throw new IllegalArgumentException("Invalid band: " + band); } @@ -181,8 +189,8 @@ public final class SoftApCapability implements Parcelable { * {@link SoftapConfiguration.Builder#setChannel(int, int)} API. * * @param band One of the following band types: - * {@link SoftApConfiguation#BAND_2GHZ}, {@link SoftApConfiguation#BAND_5GHZ} or - * {@link SoftApConfiguation#BAND_6GHZ}. + * {@link SoftApConfiguation#BAND_2GHZ}, {@link SoftApConfiguation#BAND_5GHZ}, + * {@link SoftApConfiguation#BAND_6GHZ}, {@link SoftApConfiguation#BAND_60GHZ}. * @return List of supported channels for the band. * * @throws IllegalArgumentException when band type is invalid. @@ -199,6 +207,8 @@ public final class SoftApCapability implements Parcelable { return mSupportedChannelListIn5g; case SoftApConfiguration.BAND_6GHZ: return mSupportedChannelListIn6g; + case SoftApConfiguration.BAND_60GHZ: + return mSupportedChannelListIn60g; default: throw new IllegalArgumentException("Invalid band: " + band); } @@ -214,6 +224,7 @@ public final class SoftApCapability implements Parcelable { mSupportedChannelListIn24g = source.mSupportedChannelListIn24g; mSupportedChannelListIn5g = source.mSupportedChannelListIn5g; mSupportedChannelListIn6g = source.mSupportedChannelListIn6g; + mSupportedChannelListIn60g = source.mSupportedChannelListIn60g; } } @@ -244,6 +255,7 @@ public final class SoftApCapability implements Parcelable { dest.writeIntArray(mSupportedChannelListIn24g); dest.writeIntArray(mSupportedChannelListIn5g); dest.writeIntArray(mSupportedChannelListIn6g); + dest.writeIntArray(mSupportedChannelListIn60g); } @NonNull @@ -255,6 +267,7 @@ public final class SoftApCapability implements Parcelable { capability.setSupportedChannelList(SoftApConfiguration.BAND_2GHZ, in.createIntArray()); capability.setSupportedChannelList(SoftApConfiguration.BAND_5GHZ, in.createIntArray()); capability.setSupportedChannelList(SoftApConfiguration.BAND_6GHZ, in.createIntArray()); + capability.setSupportedChannelList(SoftApConfiguration.BAND_60GHZ, in.createIntArray()); return capability; } @@ -273,6 +286,8 @@ public final class SoftApCapability implements Parcelable { .append(Arrays.toString(mSupportedChannelListIn24g)); sbuf.append("SupportedChannelListIn5g").append(Arrays.toString(mSupportedChannelListIn5g)); sbuf.append("SupportedChannelListIn6g").append(Arrays.toString(mSupportedChannelListIn6g)); + sbuf.append("SupportedChannelListIn60g") + .append(Arrays.toString(mSupportedChannelListIn60g)); return sbuf.toString(); } @@ -285,7 +300,8 @@ public final class SoftApCapability implements Parcelable { && mMaximumSupportedClientNumber == capability.mMaximumSupportedClientNumber && Arrays.equals(mSupportedChannelListIn24g, capability.mSupportedChannelListIn24g) && Arrays.equals(mSupportedChannelListIn5g, capability.mSupportedChannelListIn5g) - && Arrays.equals(mSupportedChannelListIn6g, capability.mSupportedChannelListIn6g); + && Arrays.equals(mSupportedChannelListIn6g, capability.mSupportedChannelListIn6g) + && Arrays.equals(mSupportedChannelListIn60g, capability.mSupportedChannelListIn60g); } @Override @@ -293,6 +309,7 @@ public final class SoftApCapability implements Parcelable { return Objects.hash(mSupportedFeatures, mMaximumSupportedClientNumber, Arrays.hashCode(mSupportedChannelListIn24g), Arrays.hashCode(mSupportedChannelListIn5g), - Arrays.hashCode(mSupportedChannelListIn6g)); + Arrays.hashCode(mSupportedChannelListIn6g), + Arrays.hashCode(mSupportedChannelListIn60g)); } } diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java index 1bb9ebccb01a..d36acb72ff8a 100644 --- a/wifi/java/android/net/wifi/SoftApConfiguration.java +++ b/wifi/java/android/net/wifi/SoftApConfiguration.java @@ -88,6 +88,13 @@ public final class SoftApConfiguration implements Parcelable { public static final int BAND_6GHZ = 1 << 2; /** + * 60GHz band. + * @hide + */ + @SystemApi + public static final int BAND_60GHZ = 1 << 3; + + /** * Device is allowed to choose the optimal band (2Ghz, 5Ghz, 6Ghz) based on device capability, * operating country code and current radio conditions. * @hide @@ -104,11 +111,13 @@ public final class SoftApConfiguration implements Parcelable { BAND_2GHZ, BAND_5GHZ, BAND_6GHZ, + BAND_60GHZ, }) public @interface BandType {} private static boolean isBandValid(@BandType int band) { - return ((band != 0) && ((band & ~BAND_ANY) == 0)); + int bandAny = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ | BAND_60GHZ; + return ((band != 0) && ((band & ~bandAny) == 0)); } private static final int MIN_CH_2G_BAND = 1; @@ -117,6 +126,8 @@ public final class SoftApConfiguration implements Parcelable { private static final int MAX_CH_5G_BAND = 196; private static final int MIN_CH_6G_BAND = 1; private static final int MAX_CH_6G_BAND = 253; + private static final int MIN_CH_60G_BAND = 1; + private static final int MAX_CH_60G_BAND = 6; @@ -139,6 +150,13 @@ public final class SoftApConfiguration implements Parcelable { return false; } break; + + case BAND_60GHZ: + if (channel < MIN_CH_60G_BAND || channel > MAX_CH_60G_BAND) { + return false; + } + break; + default: return false; } diff --git a/wifi/java/android/net/wifi/SoftApInfo.java b/wifi/java/android/net/wifi/SoftApInfo.java index c681ba9fd44f..e42e7868e944 100644 --- a/wifi/java/android/net/wifi/SoftApInfo.java +++ b/wifi/java/android/net/wifi/SoftApInfo.java @@ -86,6 +86,34 @@ public final class SoftApInfo implements Parcelable { */ public static final int CHANNEL_WIDTH_160MHZ = 6; + /** + * AP Channel bandwidth is 2160 MHZ. + * + * @see #getBandwidth() + */ + public static final int CHANNEL_WIDTH_2160MHZ = 7; + + /** + * AP Channel bandwidth is 4320 MHZ. + * + * @see #getBandwidth() + */ + public static final int CHANNEL_WIDTH_4320MHZ = 8; + + /** + * AP Channel bandwidth is 6480 MHZ. + * + * @see #getBandwidth() + */ + public static final int CHANNEL_WIDTH_6480MHZ = 9; + + /** + * AP Channel bandwidth is 8640 MHZ. + * + * @see #getBandwidth() + */ + public static final int CHANNEL_WIDTH_8640MHZ = 10; + /** The frequency which AP resides on. */ private int mFrequency = 0; @@ -125,7 +153,9 @@ public final class SoftApInfo implements Parcelable { * * @return One of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ}, * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ}, - * {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ} or {@link #CHANNEL_WIDTH_INVALID}. + * {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}, {@link #CHANNEL_WIDTH_2160MHZ}, + * {@link #CHANNEL_WIDTH_4320MHZ}, {@link #CHANNEL_WIDTH_6480MHZ}, + * {@link #CHANNEL_WIDTH_8640MHZ}, or {@link #CHANNEL_WIDTH_INVALID}. */ @WifiAnnotations.Bandwidth public int getBandwidth() { diff --git a/wifi/java/android/net/wifi/WifiAnnotations.java b/wifi/java/android/net/wifi/WifiAnnotations.java index acda7e06c95d..807b40b5722c 100644 --- a/wifi/java/android/net/wifi/WifiAnnotations.java +++ b/wifi/java/android/net/wifi/WifiAnnotations.java @@ -57,6 +57,10 @@ public final class WifiAnnotations { SoftApInfo.CHANNEL_WIDTH_80MHZ, SoftApInfo.CHANNEL_WIDTH_80MHZ_PLUS_MHZ, SoftApInfo.CHANNEL_WIDTH_160MHZ, + SoftApInfo.CHANNEL_WIDTH_2160MHZ, + SoftApInfo.CHANNEL_WIDTH_4320MHZ, + SoftApInfo.CHANNEL_WIDTH_6480MHZ, + SoftApInfo.CHANNEL_WIDTH_8640MHZ, }) @Retention(RetentionPolicy.SOURCE) public @interface Bandwidth {} @@ -77,6 +81,7 @@ public final class WifiAnnotations { ScanResult.WIFI_STANDARD_11N, ScanResult.WIFI_STANDARD_11AC, ScanResult.WIFI_STANDARD_11AX, + ScanResult.WIFI_STANDARD_11AD, }) @Retention(RetentionPolicy.SOURCE) public @interface WifiStandard{} diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index f8b824ca01bd..2a98977fc08e 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -502,6 +502,20 @@ public class WifiConfiguration implements Parcelable { * @hide */ public static final int SECURITY_TYPE_OSEN = 10; + /** + * Security type for a Passpoint R1/R2 network. + * Passpoint R1/R2 uses Enterprise security, where TKIP and WEP are not allowed. + * @hide + */ + public static final int SECURITY_TYPE_PASSPOINT_R1_R2 = 11; + + /** + * Security type for a Passpoint R3 network. + * Passpoint R3 uses Enterprise security, where TKIP and WEP are not allowed, + * and PMF must be set to Required. + * @hide + */ + public static final int SECURITY_TYPE_PASSPOINT_R3 = 12; /** * Security types we support. @@ -520,6 +534,8 @@ public class WifiConfiguration implements Parcelable { SECURITY_TYPE_WAPI_CERT, SECURITY_TYPE_EAP_WPA3_ENTERPRISE, SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT, + SECURITY_TYPE_PASSPOINT_R1_R2, + SECURITY_TYPE_PASSPOINT_R3, }) public @interface SecurityType {} @@ -546,7 +562,7 @@ public class WifiConfiguration implements Parcelable { * {@link #SECURITY_TYPE_WAPI_PSK}, * {@link #SECURITY_TYPE_WAPI_CERT}, * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE}, - * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT} + * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT}, */ public void setSecurityParams(@SecurityType int securityType) { // Clear existing data. @@ -580,7 +596,7 @@ public class WifiConfiguration implements Parcelable { * {@link #SECURITY_TYPE_WAPI_PSK}, * {@link #SECURITY_TYPE_WAPI_CERT}, * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE}, - * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT} + * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT}, * * @hide */ @@ -627,6 +643,12 @@ public class WifiConfiguration implements Parcelable { case SECURITY_TYPE_OSEN: params = SecurityParams.createOsenParams(); break; + case SECURITY_TYPE_PASSPOINT_R1_R2: + params = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R2); + break; + case SECURITY_TYPE_PASSPOINT_R3: + params = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R3); + break; default: throw new IllegalArgumentException("unknown security type " + securityType); } @@ -719,7 +741,7 @@ public class WifiConfiguration implements Parcelable { * {@link #SECURITY_TYPE_WAPI_PSK}, * {@link #SECURITY_TYPE_WAPI_CERT}, * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE}, - * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT} + * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT}, * * @hide */ @@ -743,7 +765,7 @@ public class WifiConfiguration implements Parcelable { * {@link #SECURITY_TYPE_WAPI_PSK}, * {@link #SECURITY_TYPE_WAPI_CERT}, * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE}, - * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT} + * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT}, * * @return the copy of specific security params if found; otherwise null. * @hide @@ -769,7 +791,7 @@ public class WifiConfiguration implements Parcelable { * {@link #SECURITY_TYPE_WAPI_PSK}, * {@link #SECURITY_TYPE_WAPI_CERT}, * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE}, - * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT} + * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT}, * * @return true if there is a security params matches the type. * @hide diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.java b/wifi/java/android/net/wifi/rtt/RangingRequest.java index 318efa61a110..04dfcf2f9cad 100644 --- a/wifi/java/android/net/wifi/rtt/RangingRequest.java +++ b/wifi/java/android/net/wifi/rtt/RangingRequest.java @@ -30,8 +30,11 @@ import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; +import com.android.modules.utils.build.SdkLevel; + import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.StringJoiner; /** @@ -46,6 +49,9 @@ import java.util.StringJoiner; */ public final class RangingRequest implements Parcelable { private static final int MAX_PEERS = 10; + private static final int DEFAULT_RTT_BURST_SIZE = 8; + private static final int MIN_RTT_BURST_SIZE = 2; + private static final int MAX_RTT_BURST_SIZE = 17; /** * Returns the maximum number of peers to range which can be specified in a single {@code @@ -59,12 +65,80 @@ public final class RangingRequest implements Parcelable { return MAX_PEERS; } + /** + * Returns the default RTT burst size used to determine the average range. + * + * @return the RTT burst size used by default + */ + public static int getDefaultRttBurstSize() { + if (!SdkLevel.isAtLeastS()) { + throw new UnsupportedOperationException(); + } + return DEFAULT_RTT_BURST_SIZE; + } + + /** + * Returns the minimum RTT burst size that can be used to determine a average range. + * + * @return the minimum RTT burst size that can be used + */ + public static int getMinRttBurstSize() { + if (!SdkLevel.isAtLeastS()) { + throw new UnsupportedOperationException(); + } + return MIN_RTT_BURST_SIZE; + } + + /** + * Returns the minimum RTT burst size that can be used to determine a average range. + * + * @return the maximum RTT burst size that can be used + */ + public static int getMaxRttBurstSize() { + if (!SdkLevel.isAtLeastS()) { + throw new UnsupportedOperationException(); + } + return MAX_RTT_BURST_SIZE; + } + /** @hide */ public final List<ResponderConfig> mRttPeers; /** @hide */ - private RangingRequest(List<ResponderConfig> rttPeers) { + public final int mRttBurstSize; + + /** @hide */ + private RangingRequest(List<ResponderConfig> rttPeers, int rttBurstSize) { mRttPeers = rttPeers; + mRttBurstSize = rttBurstSize; + } + + /** + * Returns the list of RTT capable peers. + * + * @return the list of RTT capable peers in a common system representation + * + * @hide + */ + @SystemApi + @NonNull + public List<ResponderConfig> getRttPeers() { + if (!SdkLevel.isAtLeastS()) { + throw new UnsupportedOperationException(); + } + return mRttPeers; + } + + /** + * Returns the RTT burst size used to determine the average range. + * + * @return the RTT burst size used + */ + public int getRttBurstSize() { + if (!SdkLevel.isAtLeastS()) { + throw new UnsupportedOperationException(); + } + return mRttBurstSize; } @Override @@ -75,6 +149,7 @@ public final class RangingRequest implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeList(mRttPeers); + dest.writeInt(mRttBurstSize); } public static final @android.annotation.NonNull Creator<RangingRequest> CREATOR = new Creator<RangingRequest>() { @@ -85,7 +160,7 @@ public final class RangingRequest implements Parcelable { @Override public RangingRequest createFromParcel(Parcel in) { - return new RangingRequest(in.readArrayList(null)); + return new RangingRequest(in.readArrayList(null), in.readInt()); } }; @@ -105,12 +180,20 @@ public final class RangingRequest implements Parcelable { throw new IllegalArgumentException( "Ranging to too many peers requested. Use getMaxPeers() API to get limit."); } - for (ResponderConfig peer: mRttPeers) { if (!peer.isValid(awareSupported)) { throw new IllegalArgumentException("Invalid Responder specification"); } } + if (SdkLevel.isAtLeastS()) { + if (mRttBurstSize < getMinRttBurstSize() || mRttBurstSize > getMaxRttBurstSize()) { + throw new IllegalArgumentException("RTT burst size is out of range"); + } + } else { + if (mRttBurstSize != DEFAULT_RTT_BURST_SIZE) { + throw new IllegalArgumentException("RTT burst size is not the default value"); + } + } } /** @@ -118,6 +201,32 @@ public final class RangingRequest implements Parcelable { */ public static final class Builder { private List<ResponderConfig> mRttPeers = new ArrayList<>(); + private int mRttBurstSize = DEFAULT_RTT_BURST_SIZE; + + /** + * Set the RTT Burst size for the ranging request. + * <p> + * If not set, the default RTT burst size given by + * {@link #getDefaultRttBurstSize()} is used to determine the default value. + * If set, the value must be in the range {@link #getMinRttBurstSize()} and + * {@link #getMaxRttBurstSize()} inclusively, or a + * {@link java.lang.IllegalArgumentException} will be thrown. + * + * @param rttBurstSize The number of FTM packets used to estimate a range. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + @NonNull + public Builder setRttBurstSize(int rttBurstSize) { + if (!SdkLevel.isAtLeastS()) { + throw new UnsupportedOperationException(); + } + if (rttBurstSize < MIN_RTT_BURST_SIZE || rttBurstSize > MAX_RTT_BURST_SIZE) { + throw new IllegalArgumentException("RTT burst size out of range."); + } + mRttBurstSize = rttBurstSize; + return this; + } /** * Add the device specified by the {@link ScanResult} to the list of devices with @@ -241,7 +350,7 @@ public final class RangingRequest implements Parcelable { * builder. */ public RangingRequest build() { - return new RangingRequest(mRttPeers); + return new RangingRequest(mRttPeers, mRttBurstSize); } } @@ -257,11 +366,13 @@ public final class RangingRequest implements Parcelable { RangingRequest lhs = (RangingRequest) o; - return mRttPeers.size() == lhs.mRttPeers.size() && mRttPeers.containsAll(lhs.mRttPeers); + return mRttPeers.size() == lhs.mRttPeers.size() + && mRttPeers.containsAll(lhs.mRttPeers) + && mRttBurstSize == lhs.mRttBurstSize; } @Override public int hashCode() { - return mRttPeers.hashCode(); + return Objects.hash(mRttPeers, mRttBurstSize); } } diff --git a/wifi/tests/src/android/net/wifi/SecurityParamsTest.java b/wifi/tests/src/android/net/wifi/SecurityParamsTest.java index e581b77c14ad..2f6b7245795f 100644 --- a/wifi/tests/src/android/net/wifi/SecurityParamsTest.java +++ b/wifi/tests/src/android/net/wifi/SecurityParamsTest.java @@ -85,11 +85,28 @@ public class SecurityParamsTest { expectedAllowedGroupCiphers, expectedRequirePmf); } - /** Verify EAP Passpoint params creator. */ + /** Verify Passpoint R1 params creator. */ @Test - public void testEapPasspointCreator() throws Exception { - SecurityParams p = SecurityParams.createPasspointParams(false); - int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_EAP; + public void testEapPasspointR1Creator() throws Exception { + SecurityParams p = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R1); + int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2; + int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X}; + int[] expectedAllowedProtocols = new int[] {}; + int[] expectedAllowedAuthAlgorithms = new int[] {}; + int[] expectedAllowedPairwiseCiphers = new int[] {}; + int[] expectedAllowedGroupCiphers = new int[] {}; + boolean expectedRequirePmf = false; + verifySecurityParams(p, expectedSecurityType, + expectedAllowedKeyManagement, expectedAllowedProtocols, + expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers, + expectedAllowedGroupCiphers, expectedRequirePmf); + } + + /** Verify Passpoint R2 params creator. */ + @Test + public void testEapPasspointR2Creator() throws Exception { + SecurityParams p = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R2); + int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2; int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X}; int[] expectedAllowedProtocols = new int[] {}; int[] expectedAllowedAuthAlgorithms = new int[] {}; @@ -100,9 +117,19 @@ public class SecurityParamsTest { expectedAllowedKeyManagement, expectedAllowedProtocols, expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers, expectedAllowedGroupCiphers, expectedRequirePmf); + } - p = SecurityParams.createPasspointParams(true); - expectedRequirePmf = true; + /** Verify Passpoint R3 params creator. */ + @Test + public void testEapPasspointR3Creator() throws Exception { + SecurityParams p = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R3); + int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3; + int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X}; + int[] expectedAllowedProtocols = new int[] {}; + int[] expectedAllowedAuthAlgorithms = new int[] {}; + int[] expectedAllowedPairwiseCiphers = new int[] {}; + int[] expectedAllowedGroupCiphers = new int[] {}; + boolean expectedRequirePmf = true; verifySecurityParams(p, expectedSecurityType, expectedAllowedKeyManagement, expectedAllowedProtocols, expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers, @@ -408,7 +435,9 @@ public class SecurityParamsTest { SecurityParams[] nonOpenSecurityParams = new SecurityParams[] { SecurityParams.createWpaWpa2EnterpriseParams(), - SecurityParams.createPasspointParams(false), + SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R1), + SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R2), + SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R3), SecurityParams.createOsenParams(), SecurityParams.createWapiCertParams(), SecurityParams.createWapiPskParams(), @@ -428,7 +457,9 @@ public class SecurityParamsTest { public void testIsEnterpriseNetwork() { SecurityParams[] enterpriseSecurityParams = new SecurityParams[] { SecurityParams.createWpaWpa2EnterpriseParams(), - SecurityParams.createPasspointParams(false), + SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R1), + SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R2), + SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R3), SecurityParams.createWapiCertParams(), SecurityParams.createWpa3Enterprise192BitParams(), SecurityParams.createWpa3EnterpriseParams(), diff --git a/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java b/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java index 702212b324f6..9e3b02266de1 100644 --- a/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java +++ b/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java @@ -42,10 +42,12 @@ public class SoftApCapabilityTest { | SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD; int[] testSupported2Glist = {1, 2, 3, 4}; int[] testSupported5Glist = {36, 149}; + int[] testSupported60Glist = {1, 2}; SoftApCapability capability = new SoftApCapability(testSoftApFeature); capability.setMaxSupportedClients(10); capability.setSupportedChannelList(SoftApConfiguration.BAND_2GHZ, testSupported2Glist); capability.setSupportedChannelList(SoftApConfiguration.BAND_5GHZ, testSupported5Glist); + capability.setSupportedChannelList(SoftApConfiguration.BAND_60GHZ, testSupported60Glist); SoftApCapability copiedCapability = new SoftApCapability(capability); @@ -64,9 +66,11 @@ public class SoftApCapabilityTest { capability.setMaxSupportedClients(10); int[] testSupported2Glist = {1, 2, 3, 4}; int[] testSupported5Glist = {36, 149}; + int[] testSupported60Glist = {1, 2}; capability.setSupportedChannelList(SoftApConfiguration.BAND_2GHZ, testSupported2Glist); capability.setSupportedChannelList(SoftApConfiguration.BAND_5GHZ, testSupported5Glist); + capability.setSupportedChannelList(SoftApConfiguration.BAND_60GHZ, testSupported60Glist); Parcel parcelW = Parcel.obtain(); capability.writeToParcel(parcelW, 0); diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java index bcfdf7d80061..a609a120b61f 100644 --- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java @@ -519,4 +519,14 @@ public class SoftApConfigurationTest { } assertTrue(isIllegalArgumentExceptionHappened); } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidConfigWhenSet60GhzChannels() throws Exception { + SparseIntArray invalid_channels = new SparseIntArray(); + invalid_channels.put(SoftApConfiguration.BAND_60GHZ, 99); + SoftApConfiguration config = new SoftApConfiguration.Builder() + .setSsid("ssid") + .setChannels(invalid_channels) + .build(); + } } diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java index e6eae416ba78..c8006fead55b 100644 --- a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java +++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java @@ -16,6 +16,8 @@ package android.net.wifi.rtt; +import static junit.framework.Assert.fail; + import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -143,6 +145,7 @@ public class WifiRttManagerTest { PeerHandle peerHandle1 = new PeerHandle(12); RangingRequest.Builder builder = new RangingRequest.Builder(); + builder.setRttBurstSize(4); builder.addAccessPoint(scanResult1); builder.addAccessPoints(scanResults2and3); builder.addWifiAwarePeer(mac1); @@ -163,6 +166,60 @@ public class WifiRttManagerTest { } /** + * Validate the rtt burst size is set correctly when in range. + */ + @Test + public void testRangingRequestSetBurstSize() { + ScanResult scanResult = new ScanResult(); + scanResult.BSSID = "AA:BB:CC:DD:EE:FF"; + + // create request + RangingRequest.Builder builder = new RangingRequest.Builder(); + builder.setRttBurstSize(4); + builder.addAccessPoint(scanResult); + RangingRequest request = builder.build(); + + // confirm rtt burst size is set correctly to default value + assertEquals(request.getRttBurstSize(), 4); + } + + /** + * Validate the rtt burst size cannot be smaller than the minimum. + */ + @Test + public void testRangingRequestMinBurstSizeIsEnforced() { + ScanResult scanResult = new ScanResult(); + scanResult.BSSID = "AA:BB:CC:DD:EE:FF"; + + // create request + try { + RangingRequest.Builder builder = new RangingRequest.Builder(); + builder.setRttBurstSize(RangingRequest.getMinRttBurstSize() - 1); + fail("RTT burst size was smaller than min value."); + } catch (IllegalArgumentException e) { + // expected + } + } + + /** + * Validate the rtt burst size cannot exceed the maximum. + */ + @Test + public void testRangingRequestMaxBurstSizeIsEnforced() { + ScanResult scanResult = new ScanResult(); + scanResult.BSSID = "AA:BB:CC:DD:EE:FF"; + + // create request + try { + RangingRequest.Builder builder = new RangingRequest.Builder(); + builder.setRttBurstSize(RangingRequest.getMaxRttBurstSize() + 1); + fail("RTT Burst size exceeded max value."); + } catch (IllegalArgumentException e) { + // expected + } + } + + /** * Validate that can request as many range operation as the upper limit on number of requests. */ @Test @@ -175,7 +232,7 @@ public class WifiRttManagerTest { } MacAddress mac1 = MacAddress.fromString("00:01:02:03:04:05"); - // create request + // create request using max RTT Peers RangingRequest.Builder builder = new RangingRequest.Builder(); builder.addAccessPoint(scanResult); builder.addAccessPoints(scanResultList); @@ -185,6 +242,18 @@ public class WifiRttManagerTest { // verify request request.enforceValidity(true); + // confirm rtt burst size is set correctly to default value + assertEquals(request.getRttBurstSize(), RangingRequest.getDefaultRttBurstSize()); + // confirm the number of peers in the request is the max number of peers + List<ResponderConfig> rttPeers = request.getRttPeers(); + int numRttPeers = rttPeers.size(); + assertEquals(RangingRequest.getMaxPeers(), numRttPeers); + // confirm each peer has the correct mac address + for (int i = 0; i < numRttPeers - 1; ++i) { + assertEquals("AA:BB:CC:DD:EE:FF", rttPeers.get(i).macAddress.toString().toUpperCase()); + } + assertEquals("00:01:02:03:04:05", + rttPeers.get(numRttPeers - 1).macAddress.toString().toUpperCase()); } /** |