diff options
69 files changed, 983 insertions, 367 deletions
diff --git a/api/TEST_MAPPING b/api/TEST_MAPPING index 4d22d0b1f4a3..3a2e5287f01e 100644 --- a/api/TEST_MAPPING +++ b/api/TEST_MAPPING @@ -5,9 +5,11 @@ }, { "name": "CtsSystemApiSignatureTestCases" - }, + } + ], + "imports": [ { - "name": "GtsUnofficialApisUsageTestCases" + "path": "vendor/xts/gts-tests/hostsidetests/api" } ] } diff --git a/api/current.txt b/api/current.txt index 0f4231d91bfb..b7a951c39a62 100644 --- a/api/current.txt +++ b/api/current.txt @@ -34415,10 +34415,10 @@ package android.os { method @Deprecated public static String getStorageState(java.io.File); method public static boolean isExternalStorageEmulated(); method public static boolean isExternalStorageEmulated(@NonNull java.io.File); + method public static boolean isExternalStorageLegacy(); + method public static boolean isExternalStorageLegacy(@NonNull java.io.File); method public static boolean isExternalStorageRemovable(); method public static boolean isExternalStorageRemovable(@NonNull java.io.File); - method public static boolean isExternalStorageSandboxed(); - method public static boolean isExternalStorageSandboxed(@NonNull java.io.File); field public static String DIRECTORY_ALARMS; field public static String DIRECTORY_AUDIOBOOKS; field public static String DIRECTORY_DCIM; diff --git a/api/system-current.txt b/api/system-current.txt index 288cb9c9b3b2..8cd722b492cd 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5661,16 +5661,16 @@ package android.permission { ctor public PermissionControllerService(); method public final void attachBaseContext(android.content.Context); method @NonNull public final android.os.IBinder onBind(android.content.Intent); - method public abstract int onCountPermissionApps(@NonNull java.util.List<java.lang.String>, int); - method @NonNull public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(@NonNull String); - method @NonNull public abstract java.util.List<android.permission.RuntimePermissionUsageInfo> onGetPermissionUsages(boolean, long); - method public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream); - method public abstract void onGrantOrUpgradeDefaultRuntimePermissions(); + method @WorkerThread public abstract int onCountPermissionApps(@NonNull java.util.List<java.lang.String>, int); + method @WorkerThread @NonNull public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(@NonNull String); + method @WorkerThread @NonNull public abstract java.util.List<android.permission.RuntimePermissionUsageInfo> onGetPermissionUsages(boolean, long); + method @WorkerThread public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream); + method @WorkerThread public abstract void onGrantOrUpgradeDefaultRuntimePermissions(); method @BinderThread public abstract boolean onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle); method @BinderThread public abstract void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream); - method public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String); - method @NonNull public abstract java.util.Map<java.lang.String,java.util.List<java.lang.String>> onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String); - method public abstract boolean onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int); + method @WorkerThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String); + method @WorkerThread @NonNull public abstract java.util.Map<java.lang.String,java.util.List<java.lang.String>> onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String); + method @WorkerThread public abstract boolean onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int); field public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService"; } @@ -6012,17 +6012,6 @@ package android.provider { method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String); field public static final String APP_STANDBY_ENABLED = "app_standby_enabled"; field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages"; - field public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS = "captive_portal_fallback_probe_specs"; - field public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url"; - field public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url"; - field public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url"; - field public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode"; - field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2 - field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0 - field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1 - field public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS = "captive_portal_other_fallback_urls"; - field public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent"; - field public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https"; field public static final String CARRIER_APP_NAMES = "carrier_app_names"; field public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist"; field public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus"; diff --git a/api/test-current.txt b/api/test-current.txt index 63c8df047f90..3cde3f2df435 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -2265,17 +2265,6 @@ package android.provider { field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages"; field public static final String AUTOMATIC_POWER_SAVE_MODE = "automatic_power_save_mode"; field public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants"; - field public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS = "captive_portal_fallback_probe_specs"; - field public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url"; - field public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url"; - field public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url"; - field public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode"; - field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2 - field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0 - field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1 - field public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS = "captive_portal_other_fallback_urls"; - field public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent"; - field public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https"; field public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold"; field public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled"; field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions"; diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp index fa9a77aa69c6..83c034b4bc42 100644 --- a/cmds/idmap2/idmap2/Scan.cpp +++ b/cmds/idmap2/idmap2/Scan.cpp @@ -39,6 +39,8 @@ using android::idmap2::CommandLineOptions; using android::idmap2::Error; using android::idmap2::Idmap; +using android::idmap2::kPolicyOdm; +using android::idmap2::kPolicyOem; using android::idmap2::kPolicyProduct; using android::idmap2::kPolicyPublic; using android::idmap2::kPolicySystem; @@ -93,6 +95,8 @@ Result<std::unique_ptr<std::vector<std::string>>> FindApkFiles(const std::vector std::vector<std::string> PoliciesForPath(const std::string& apk_path) { static const std::vector<std::pair<std::string, std::string>> values = { + {"/odm/", kPolicyOdm}, + {"/oem/", kPolicyOem}, {"/product/", kPolicyProduct}, {"/system/", kPolicySystem}, {"/vendor/", kPolicyVendor}, diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java index 639335e53ae5..1838babf7794 100644 --- a/core/java/android/content/om/OverlayInfo.java +++ b/core/java/android/content/om/OverlayInfo.java @@ -45,8 +45,7 @@ public final class OverlayInfo implements Parcelable { STATE_DISABLED, STATE_ENABLED, STATE_ENABLED_STATIC, - // @Deprecated STATE_TARGET_UPGRADING, - STATE_TARGET_IS_BEING_REPLACED, + // @Deprecated STATE_TARGET_IS_BEING_REPLACED, STATE_OVERLAY_IS_BEING_REPLACED, }) /** @hide */ diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index dde1e6a7f5f7..e85561c7cb9f 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -1115,42 +1115,42 @@ public class Environment { } /** - * Returns whether the shared/external storage media at the given path is a - * sandboxed view that only contains files owned by the app. + * Returns whether the primary shared/external storage media is a legacy + * view that includes files not owned by the app. * <p> * This value may be different from the value requested by - * {@code allowExternalStorageSandbox} in the app's manifest, since an app - * may inherit its sandboxed state based on when it was first installed. + * {@code requestLegacyExternalStorage} in the app's manifest, since an app + * may inherit its legacy state based on when it was first installed. * <p> - * Sandboxed apps can continue to discover and read media belonging to other - * apps via {@link android.provider.MediaStore}. + * Non-legacy apps can continue to discover and read media belonging to + * other apps via {@link android.provider.MediaStore}. */ - public static boolean isExternalStorageSandboxed() { + public static boolean isExternalStorageLegacy() { final File externalDir = sCurrentUser.getExternalDirs()[0]; - return isExternalStorageSandboxed(externalDir); + return isExternalStorageLegacy(externalDir); } /** * Returns whether the shared/external storage media at the given path is a - * sandboxed view that only contains files owned by the app. + * legacy view that includes files not owned by the app. * <p> * This value may be different from the value requested by - * {@code allowExternalStorageSandbox} in the app's manifest, since an app - * may inherit its sandboxed state based on when it was first installed. + * {@code requestLegacyExternalStorage} in the app's manifest, since an app + * may inherit its legacy state based on when it was first installed. * <p> - * Sandboxed apps can continue to discover and read media belonging to other - * apps via {@link android.provider.MediaStore}. + * Non-legacy apps can continue to discover and read media belonging to + * other apps via {@link android.provider.MediaStore}. * * @throws IllegalArgumentException if the path is not a valid storage * device. */ - public static boolean isExternalStorageSandboxed(@NonNull File path) { + public static boolean isExternalStorageLegacy(@NonNull File path) { final Context context = AppGlobals.getInitialApplication(); final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); return appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, context.getApplicationInfo().uid, - context.getOpPackageName()) != AppOpsManager.MODE_ALLOWED; + context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED; } static File getDirectory(String variableName, String defaultPath) { diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java index ed44367e28c6..fd7c8739dc60 100644 --- a/core/java/android/permission/PermissionControllerService.java +++ b/core/java/android/permission/PermissionControllerService.java @@ -28,18 +28,19 @@ import static com.android.internal.util.Preconditions.checkCollectionElementsNot import static com.android.internal.util.Preconditions.checkFlagsArgument; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.internal.util.Preconditions.checkStringNotEmpty; -import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import android.Manifest; import android.annotation.BinderThread; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.WorkerThread; import android.app.Service; import android.app.admin.DevicePolicyManager.PermissionGrantState; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -96,6 +97,7 @@ public abstract class PermissionControllerService extends Service { * * @return the actually removed permissions as {@code Map<packageName, List<permission>>} */ + @WorkerThread public abstract @NonNull Map<String, List<String>> onRevokeRuntimePermissions( @NonNull Map<String, List<String>> requests, boolean doDryRun, @PermissionControllerManager.Reason int reason, @NonNull String callerPackageName); @@ -106,6 +108,7 @@ public abstract class PermissionControllerService extends Service { * @param user The user to back up * @param backup The stream to write the backup to */ + @WorkerThread public abstract void onGetRuntimePermissionsBackup(@NonNull UserHandle user, @NonNull OutputStream backup); @@ -142,6 +145,7 @@ public abstract class PermissionControllerService extends Service { * * @return descriptions of the runtime permissions of the app */ + @WorkerThread public abstract @NonNull List<RuntimePermissionPresentationInfo> onGetAppPermissions( @NonNull String packageName); @@ -151,6 +155,7 @@ public abstract class PermissionControllerService extends Service { * @param packageName The package for which to revoke * @param permissionName The permission to revoke */ + @WorkerThread public abstract void onRevokeRuntimePermission(@NonNull String packageName, @NonNull String permissionName); @@ -163,6 +168,7 @@ public abstract class PermissionControllerService extends Service { * * @return the number of apps that have one of the permissions */ + @WorkerThread public abstract int onCountPermissionApps(@NonNull List<String> permissionNames, @CountPermissionAppsFlag int flags); @@ -174,6 +180,7 @@ public abstract class PermissionControllerService extends Service { * * @return descriptions of the users of permissions */ + @WorkerThread public abstract @NonNull List<RuntimePermissionUsageInfo> onGetPermissionUsages( boolean countSystem, long numMillis); @@ -186,6 +193,7 @@ public abstract class PermissionControllerService extends Service { * @see PermissionManager#getRuntimePermissionsVersion() * @see PermissionManager#setRuntimePermissionsVersion(int) */ + @WorkerThread public abstract void onGrantOrUpgradeDefaultRuntimePermissions(); /** @@ -196,6 +204,7 @@ public abstract class PermissionControllerService extends Service { * @param permission Permission to change * @param grantState State to set the permission into */ + @WorkerThread public abstract boolean onSetRuntimePermissionGrantStateByDeviceAdmin( @NonNull String callerPackageName, @NonNull String packageName, @NonNull String permission, @PermissionGrantState int grantState); @@ -232,10 +241,9 @@ public abstract class PermissionControllerService extends Service { throw new RuntimeException(e); } - mHandler.sendMessage(obtainMessage( - PermissionControllerService::revokeRuntimePermissions, - PermissionControllerService.this, request, doDryRun, reason, - callerPackageName, callback)); + AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> + PermissionControllerService.this.revokeRuntimePermissions(request, doDryRun, + reason, callerPackageName, callback)); } @Override @@ -245,9 +253,8 @@ public abstract class PermissionControllerService extends Service { enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null); - mHandler.sendMessage(obtainMessage( - PermissionControllerService::getRuntimePermissionsBackup, - PermissionControllerService.this, user, pipe)); + AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> + PermissionControllerService.this.getRuntimePermissionsBackup(user, pipe)); } @Override @@ -287,9 +294,9 @@ public abstract class PermissionControllerService extends Service { enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null); - mHandler.sendMessage( - obtainMessage(PermissionControllerService::getAppPermissions, - PermissionControllerService.this, packageName, callback)); + AsyncTask.THREAD_POOL_EXECUTOR.execute( + () -> PermissionControllerService.this.getAppPermissions(packageName, + callback)); } @Override @@ -299,9 +306,9 @@ public abstract class PermissionControllerService extends Service { enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null); - mHandler.sendMessage( - obtainMessage(PermissionControllerService::onRevokeRuntimePermission, - PermissionControllerService.this, packageName, permissionName)); + AsyncTask.THREAD_POOL_EXECUTOR.execute( + () -> PermissionControllerService.this.onRevokeRuntimePermission( + packageName, permissionName)); } @Override @@ -313,10 +320,9 @@ public abstract class PermissionControllerService extends Service { enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null); - mHandler.sendMessage( - obtainMessage(PermissionControllerService::countPermissionApps, - PermissionControllerService.this, permissionNames, flags, - callback)); + AsyncTask.THREAD_POOL_EXECUTOR.execute( + () -> PermissionControllerService.this.countPermissionApps(permissionNames, + flags, callback)); } @Override @@ -327,10 +333,9 @@ public abstract class PermissionControllerService extends Service { enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null); - mHandler.sendMessage( - obtainMessage(PermissionControllerService::getPermissionUsages, - PermissionControllerService.this, countSystem, numMillis, - callback)); + AsyncTask.THREAD_POOL_EXECUTOR.execute( + () -> PermissionControllerService.this.getPermissionUsages(countSystem, + numMillis, callback)); } @Override @@ -356,10 +361,10 @@ public abstract class PermissionControllerService extends Service { enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, null); - mHandler.sendMessage(obtainMessage( - PermissionControllerService::setRuntimePermissionGrantStateByDeviceAdmin, - PermissionControllerService.this, callerPackageName, packageName, - permission, grantState, callback)); + AsyncTask.THREAD_POOL_EXECUTOR.execute( + () -> PermissionControllerService.this + .setRuntimePermissionGrantStateByDeviceAdmin(callerPackageName, + packageName, permission, grantState, callback)); } @Override @@ -369,9 +374,9 @@ public abstract class PermissionControllerService extends Service { enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, null); - mHandler.sendMessage(obtainMessage( - PermissionControllerService::grantOrUpgradeDefaultRuntimePermissions, - PermissionControllerService.this, callback)); + AsyncTask.THREAD_POOL_EXECUTOR.execute( + () -> PermissionControllerService.this + .grantOrUpgradeDefaultRuntimePermissions(callback)); } }; } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 58b70a7fa05b..24f42d49b243 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -11124,8 +11124,6 @@ public final class Settings { * * @hide */ - @SystemApi - @TestApi public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; /** @@ -11134,8 +11132,6 @@ public final class Settings { * * @hide */ - @SystemApi - @TestApi public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; /** @@ -11144,8 +11140,6 @@ public final class Settings { * * @hide */ - @SystemApi - @TestApi public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; /** @@ -11155,8 +11149,6 @@ public final class Settings { * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT. * @hide */ - @SystemApi - @TestApi public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode"; /** @@ -11185,8 +11177,6 @@ public final class Settings { * * @hide */ - @SystemApi - @TestApi public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url"; /** @@ -11195,8 +11185,6 @@ public final class Settings { * * @hide */ - @SystemApi - @TestApi public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url"; /** @@ -11205,8 +11193,6 @@ public final class Settings { * * @hide */ - @SystemApi - @TestApi public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url"; /** @@ -11215,8 +11201,6 @@ public final class Settings { * * @hide */ - @SystemApi - @TestApi public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS = "captive_portal_other_fallback_urls"; @@ -11226,8 +11210,6 @@ public final class Settings { * by "@@,@@". * @hide */ - @SystemApi - @TestApi public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS = "captive_portal_fallback_probe_specs"; @@ -11238,8 +11220,6 @@ public final class Settings { * * @hide */ - @SystemApi - @TestApi public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https"; /** @@ -11248,8 +11228,6 @@ public final class Settings { * * @hide */ - @SystemApi - @TestApi public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent"; /** diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 0051d01eec13..bbd44c8b85af 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -682,14 +682,6 @@ public final class AccessibilityInteractionController { // Handle this hidden action separately succeeded = handleClickableSpanActionUiThread( target, virtualDescendantId, arguments); - } else if (action == R.id.accessibilityActionOutsideTouch) { - // trigger ACTION_OUTSIDE to notify windows - final long now = SystemClock.uptimeMillis(); - MotionEvent event = MotionEvent.obtain(now, now, MotionEvent.ACTION_OUTSIDE, - 0, 0, 0); - event.setSource(InputDevice.SOURCE_TOUCHSCREEN); - mViewRootImpl.dispatchInputEvent(event); - succeeded = true; } else { AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider(); if (provider != null) { @@ -756,6 +748,33 @@ public final class AccessibilityInteractionController { } } + /** + * Notify outside touch event to the target window. + */ + public void notifyOutsideTouchClientThread() { + final Message message = mHandler.obtainMessage(); + message.what = PrivateHandler.MSG_NOTIFY_OUTSIDE_TOUCH; + + // Don't care about pid and tid because there's no interrogating client for this message. + scheduleMessage(message, 0, 0, CONSIDER_REQUEST_PREPARERS); + } + + private void notifyOutsideTouchUiThread() { + if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null + || mViewRootImpl.mStopped || mViewRootImpl.mPausedForTransition) { + return; + } + final View root = mViewRootImpl.mView; + if (root != null && isShown(root)) { + // trigger ACTION_OUTSIDE to notify windows + final long now = SystemClock.uptimeMillis(); + final MotionEvent event = MotionEvent.obtain(now, now, MotionEvent.ACTION_OUTSIDE, + 0, 0, 0); + event.setSource(InputDevice.SOURCE_TOUCHSCREEN); + mViewRootImpl.dispatchInputEvent(event); + } + } + private View findViewByAccessibilityId(int accessibilityId) { if (accessibilityId == AccessibilityNodeInfo.ROOT_ITEM_ID) { return mViewRootImpl.mView; @@ -1328,6 +1347,8 @@ public final class AccessibilityInteractionController { private static final int FIRST_NO_ACCESSIBILITY_CALLBACK_MSG = 100; private static final int MSG_CLEAR_ACCESSIBILITY_FOCUS = FIRST_NO_ACCESSIBILITY_CALLBACK_MSG + 1; + private static final int MSG_NOTIFY_OUTSIDE_TOUCH = + FIRST_NO_ACCESSIBILITY_CALLBACK_MSG + 2; public PrivateHandler(Looper looper) { super(looper); @@ -1357,6 +1378,8 @@ public final class AccessibilityInteractionController { return "MSG_APP_PREPARATION_TIMEOUT"; case MSG_CLEAR_ACCESSIBILITY_FOCUS: return "MSG_CLEAR_ACCESSIBILITY_FOCUS"; + case MSG_NOTIFY_OUTSIDE_TOUCH: + return "MSG_NOTIFY_OUTSIDE_TOUCH"; default: throw new IllegalArgumentException("Unknown message type: " + type); } @@ -1396,6 +1419,9 @@ public final class AccessibilityInteractionController { case MSG_CLEAR_ACCESSIBILITY_FOCUS: { clearAccessibilityFocusUiThread(); } break; + case MSG_NOTIFY_OUTSIDE_TOUCH: { + notifyOutsideTouchUiThread(); + } break; default: throw new IllegalArgumentException("Unknown message type: " + type); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 7ad118e760d8..865a656994b5 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2814,10 +2814,14 @@ public final class ViewRootImpl implements ViewParent, hasWindowFocus = mUpcomingWindowFocus; inTouchMode = mUpcomingInTouchMode; } - if (hasWindowFocus) { - mInsetsController.onWindowFocusGained(); - } else { - mInsetsController.onWindowFocusLost(); + if (sNewInsetsMode != NEW_INSETS_MODE_NONE) { + // TODO (b/131181940): Make sure this doesn't leak Activity with mActivityConfigCallback + // config changes. + if (hasWindowFocus) { + mInsetsController.onWindowFocusGained(); + } else { + mInsetsController.onWindowFocusLost(); + } } if (mAdded) { @@ -8819,6 +8823,15 @@ public final class ViewRootImpl implements ViewParent, .clearAccessibilityFocusClientThread(); } } + + @Override + public void notifyOutsideTouch() { + ViewRootImpl viewRootImpl = mViewRootImpl.get(); + if (viewRootImpl != null && viewRootImpl.mView != null) { + viewRootImpl.getAccessibilityInteractionController() + .notifyOutsideTouchClientThread(); + } + } } private class SendWindowContentChangedAccessibilityEvent implements Runnable { diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl index 947ff056627e..deb0d2a3fd3d 100644 --- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl +++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl @@ -57,4 +57,6 @@ oneway interface IAccessibilityInteractionConnection { int interrogatingPid, long interrogatingTid); void clearAccessibilityFocus(); + + void notifyOutsideTouch(); } diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index ca2bc7f586c9..5930f8fd14d3 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -1041,12 +1041,9 @@ public class ChooserActivity extends ResolverActivity { int cat = 0; int value = which; int directTargetAlsoRanked = -1; + int numCallerProvided = 0; HashedStringCache.HashResult directTargetHashed = null; switch (mChooserListAdapter.getPositionTargetType(which)) { - case ChooserListAdapter.TARGET_CALLER: - cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET; - value -= mChooserListAdapter.getSelectableServiceTargetCount(); - break; case ChooserListAdapter.TARGET_SERVICE: cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET; // Log the package name + target name to answer the question if most users @@ -1062,13 +1059,14 @@ public class ChooserActivity extends ResolverActivity { directTargetAlsoRanked = getRankedPosition((SelectableTargetInfo) targetInfo); if (mCallerChooserTargets != null) { - value -= mCallerChooserTargets.length; + numCallerProvided = mCallerChooserTargets.length; } break; + case ChooserListAdapter.TARGET_CALLER: case ChooserListAdapter.TARGET_STANDARD: - cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET; - value -= mChooserListAdapter.getCallerTargetCount() - + mChooserListAdapter.getSelectableServiceTargetCount(); + cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET; + value -= mChooserListAdapter.getSelectableServiceTargetCount(); + numCallerProvided = mChooserListAdapter.getCallerTargetCount(); break; case ChooserListAdapter.TARGET_STANDARD_AZ: // A-Z targets are unranked standard targets; we use -1 to mark that they @@ -1089,8 +1087,9 @@ public class ChooserActivity extends ResolverActivity { targetLogMaker.addTaggedData(MetricsEvent.FIELD_RANKED_POSITION, directTargetAlsoRanked); } + targetLogMaker.addTaggedData(MetricsEvent.FIELD_IS_CATEGORY_USED, + numCallerProvided); getMetricsLogger().write(targetLogMaker); - MetricsLogger.action(this, cat, value); } if (mIsSuccessfullySelected) { diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index d3f9196ce763..2b471fec9c8f 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -163,7 +163,7 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { } // Generic idmap parameters - const char* argv[9]; + const char* argv[10]; int argc = 0; struct stat st; @@ -203,6 +203,10 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { argv[argc++] = AssetManager::ODM_OVERLAY_DIR; } + if (stat(AssetManager::OEM_OVERLAY_DIR, &st) == 0) { + argv[argc++] = AssetManager::OEM_OVERLAY_DIR; + } + // Finally, invoke idmap (if any overlay directory exists) if (argc > 5) { execv(AssetManager::IDMAP_BIN, (char* const*)argv); @@ -241,6 +245,10 @@ static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* input_dirs.push_back(AssetManager::ODM_OVERLAY_DIR); } + if (stat(AssetManager::OEM_OVERLAY_DIR, &st) == 0) { + input_dirs.push_back(AssetManager::OEM_OVERLAY_DIR); + } + if (input_dirs.empty()) { LOG(WARNING) << "no directories for idmap2 to scan"; return env->NewObjectArray(0, g_stringClass, nullptr); diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 77ebd0290d33..fa5f931470b0 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -104,6 +104,8 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { static const char* kProductServicesOverlayDir = "/product_services/overlay"; static const char* kSystemOdmOverlayDir = "/system/odm/overlay"; static const char* kOdmOverlayDir = "/odm/overlay"; + static const char* kSystemOemOverlayDir = "/system/oem/overlay"; + static const char* kOemOverlayDir = "/oem/overlay"; static const char* kApkSuffix = ".apk"; if ((android::base::StartsWith(path, kOverlayDir) @@ -114,7 +116,9 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { || android::base::StartsWith(path, kSystemProductServicesOverlayDir) || android::base::StartsWith(path, kProductServicesOverlayDir) || android::base::StartsWith(path, kSystemOdmOverlayDir) - || android::base::StartsWith(path, kOdmOverlayDir)) + || android::base::StartsWith(path, kOdmOverlayDir) + || android::base::StartsWith(path, kSystemOemOverlayDir) + || android::base::StartsWith(path, kOemOverlayDir)) && android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) { return true; diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index ce7995a93f7f..2b0c86b49577 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -185,9 +185,6 @@ <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_HIDE_TOOLTIP}. --> <item type="id" name="accessibilityActionHideTooltip" /> - <!-- Accessibility action to notify a window there is an outside touch. --> - <item type="id" name="accessibilityActionOutsideTouch" /> - <!-- A tag used to save the view added to a transition overlay --> <item type="id" name="transition_overlay_view_tag" /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index bebba5435c40..470c9ed472dc 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -245,7 +245,6 @@ <java-symbol type="id" name="selection_end_handle" /> <java-symbol type="id" name="insertion_handle" /> <java-symbol type="id" name="accessibilityActionClickOnClickableSpan" /> - <java-symbol type="id" name="accessibilityActionOutsideTouch" /> <java-symbol type="id" name="camera" /> <java-symbol type="id" name="mic" /> <java-symbol type="id" name="overlay" /> diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 21609d30e92c..4755cb866310 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -76,6 +76,7 @@ const char* AssetManager::VENDOR_OVERLAY_DIR = "/vendor/overlay"; const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay"; const char* AssetManager::PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay"; const char* AssetManager::ODM_OVERLAY_DIR = "/odm/overlay"; +const char* AssetManager::OEM_OVERLAY_DIR = "/oem/overlay"; const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme"; const char* AssetManager::TARGET_PACKAGE_NAME = "android"; const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk"; diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h index a015eabc200c..66fba26b7289 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -63,6 +63,7 @@ public: static const char* PRODUCT_OVERLAY_DIR; static const char* PRODUCT_SERVICES_OVERLAY_DIR; static const char* ODM_OVERLAY_DIR; + static const char* OEM_OVERLAY_DIR; /* * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay * APKs in VENDOR_OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in diff --git a/libs/hwui/tests/unit/CommonPoolTests.cpp b/libs/hwui/tests/unit/CommonPoolTests.cpp index 70a5f5acbb6e..da6a2604a4b6 100644 --- a/libs/hwui/tests/unit/CommonPoolTests.cpp +++ b/libs/hwui/tests/unit/CommonPoolTests.cpp @@ -36,7 +36,9 @@ TEST(CommonPool, post) { EXPECT_TRUE(ran) << "Failed to flip atomic after 1 second"; } -TEST(CommonPool, threadCount) { +// test currently relies on timings, which +// makes it flaky. Disable for now +TEST(DISABLED_CommonPool, threadCount) { std::set<pid_t> threads; std::array<std::future<pid_t>, 64> futures; for (int i = 0; i < futures.size(); i++) { @@ -93,7 +95,9 @@ TEST(CommonPool, singleThread) { EXPECT_NE(gettid(), tid1); } -TEST(CommonPool, fullQueue) { +// Test currently relies on timings +// which makes it flaky, disable for now +TEST(DISABLED_CommonPool, fullQueue) { std::mutex lock; std::condition_variable fence; bool signaled = false; @@ -179,4 +183,4 @@ TEST(CommonPool, syncLifecycleCheck) { } CommonPool::waitForIdle(); ASSERT_EQ(0, ObjectTracker::count()); -}
\ No newline at end of file +} diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index a9150d4b7455..977e790eb42e 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -786,8 +786,13 @@ public final class AudioAttributes implements Parcelable { /** * Sets attributes as inferred from the legacy stream types. - * Use this method when building an {@link AudioAttributes} instance to initialize some of - * the attributes by information derived from a legacy stream type. + * Warning: do not use this method in combination with setting any other attributes such as + * usage, content type, flags or haptic control, as this method will overwrite (the more + * accurate) information describing the use case previously set in the <code>Builder</code>. + * In general, avoid using it and prefer setting usage and content type directly + * with {@link #setUsage(int)} and {@link #setContentType(int)}. + * <p>Use this method when building an {@link AudioAttributes} instance to initialize some + * of the attributes by information derived from a legacy stream type. * @param streamType one of {@link AudioManager#STREAM_VOICE_CALL}, * {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING}, * {@link AudioManager#STREAM_MUSIC}, {@link AudioManager#STREAM_ALARM}, @@ -799,7 +804,8 @@ public final class AudioAttributes implements Parcelable { throw new IllegalArgumentException("STREAM_ACCESSIBILITY is not a legacy stream " + "type that was used for audio playback"); } - return setInternalLegacyStreamType(streamType); + setInternalLegacyStreamType(streamType); + return this; } /** @@ -815,7 +821,14 @@ public final class AudioAttributes implements Parcelable { AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( streamType); if (attributes != null) { - return new Builder(attributes).setHapticChannelsMuted(mMuteHapticChannels); + mUsage = attributes.mUsage; + mContentType = attributes.mContentType; + mFlags = attributes.mFlags; + mMuteHapticChannels = attributes.areHapticChannelsMuted(); + mTags = attributes.mTags; + mBundle = attributes.mBundle; + mSource = attributes.mSource; + return this; } } switch(streamType) { diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 593fa0d6b1d6..ea29ebb88846 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -22,7 +22,9 @@ import android.animation.ValueAnimator; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityTaskManager; +import android.car.Car; import android.car.drivingstate.CarDrivingStateEvent; +import android.car.drivingstate.CarUxRestrictionsManager; import android.content.Context; import android.graphics.PixelFormat; import android.graphics.Rect; @@ -412,9 +414,13 @@ public class CarStatusBar extends StatusBar implements animateCollapsePanels(); } }); + Car car = Car.createCar(mContext); + CarUxRestrictionsManager carUxRestrictionsManager = (CarUxRestrictionsManager) + car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE); CarNotificationListener carNotificationListener = new CarNotificationListener(); CarUxRestrictionManagerWrapper carUxRestrictionManagerWrapper = new CarUxRestrictionManagerWrapper(); + carUxRestrictionManagerWrapper.setCarUxRestrictionsManager(carUxRestrictionsManager); NotificationDataManager notificationDataManager = new NotificationDataManager(); CarHeadsUpNotificationManager carHeadsUpNotificationManager = new CarSystemUIHeadsUpNotificationManager(mContext, clickHandlerFactory, diff --git a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java index 52e54f965cc0..69e91d1b857e 100644 --- a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java +++ b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java @@ -18,6 +18,7 @@ package android.ext.services.watchdog; import android.content.ComponentName; import android.content.Intent; +import android.provider.DeviceConfig; import android.service.watchdog.ExplicitHealthCheckService; import android.service.watchdog.PackageInfo; import android.util.Log; @@ -27,6 +28,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; /** * Routes explicit health check requests to the appropriate {@link ExplicitHealthChecker}. @@ -36,6 +38,10 @@ public final class ExplicitHealthCheckServiceImpl extends ExplicitHealthCheckSer // TODO: Add build dependency on NetworkStack stable AIDL so we can stop hard coding class name private static final String NETWORK_STACK_CONNECTOR_CLASS = "android.net.INetworkStackConnector"; + private static final String PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS = + "watchdog_request_timeout_millis"; + private static final long DEFAULT_REQUEST_TIMEOUT_MILLIS = + TimeUnit.HOURS.toMillis(1); // Modified only #onCreate, using concurrent collection to ensure thread visibility private final Map<String, ExplicitHealthChecker> mSupportedCheckers = new ConcurrentHashMap<>(); @@ -70,8 +76,17 @@ public final class ExplicitHealthCheckServiceImpl extends ExplicitHealthCheckSer @Override public List<PackageInfo> onGetSupportedPackages() { List<PackageInfo> packages = new ArrayList<>(); + long requestTimeoutMillis = DeviceConfig.getLong( + DeviceConfig.NAMESPACE_ROLLBACK, + PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS, + DEFAULT_REQUEST_TIMEOUT_MILLIS); + if (requestTimeoutMillis <= 0) { + requestTimeoutMillis = DEFAULT_REQUEST_TIMEOUT_MILLIS; + } for (ExplicitHealthChecker checker : mSupportedCheckers.values()) { - packages.add(checker.getSupportedPackage()); + PackageInfo pkg = new PackageInfo(checker.getSupportedPackageName(), + requestTimeoutMillis); + packages.add(pkg); } return packages; } @@ -87,7 +102,7 @@ public final class ExplicitHealthCheckServiceImpl extends ExplicitHealthCheckSer while (it.hasNext()) { ExplicitHealthChecker checker = it.next(); if (checker.isPending()) { - packages.add(checker.getSupportedPackage().getPackageName()); + packages.add(checker.getSupportedPackageName()); } } return packages; diff --git a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java index c51be8863d90..a982d52e59af 100644 --- a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java +++ b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java @@ -16,8 +16,6 @@ package android.ext.services.watchdog; -import android.service.watchdog.PackageInfo; - /** * A type of explicit health check that can be performed on a device, e.g network health check */ @@ -40,7 +38,7 @@ interface ExplicitHealthChecker { boolean isPending(); /** - * Returns the {@link PackageInfo} object this checker can make requests for. + * Returns the name of the package this checker can make requests for. */ - PackageInfo getSupportedPackage(); + String getSupportedPackageName(); } diff --git a/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java b/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java index 09b319e81933..5722e096dff0 100644 --- a/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java +++ b/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java @@ -21,7 +21,6 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.service.watchdog.ExplicitHealthCheckService; -import android.service.watchdog.PackageInfo; import com.android.internal.annotations.GuardedBy; @@ -35,8 +34,6 @@ final class NetworkChecker extends ConnectivityManager.NetworkCallback private final Object mLock = new Object(); private final ExplicitHealthCheckService mService; private final String mPackageName; - // TODO: Receive from DeviceConfig flag - private final long mRequestDurationMillis = 0; @GuardedBy("mLock") private boolean mIsPending; @@ -76,8 +73,8 @@ final class NetworkChecker extends ConnectivityManager.NetworkCallback } @Override - public PackageInfo getSupportedPackage() { - return new PackageInfo(mPackageName, mRequestDurationMillis); + public String getSupportedPackageName() { + return mPackageName; } // TODO(b/120598832): Also monitor NetworkCallback#onAvailable to see if we have any diff --git a/packages/NetworkStack/res/values/config.xml b/packages/NetworkStack/res/values/config.xml index 704788d7d7e2..478ed6b06596 100644 --- a/packages/NetworkStack/res/values/config.xml +++ b/packages/NetworkStack/res/values/config.xml @@ -7,6 +7,9 @@ values are meant to be the default when no other configuration is specified. --> + <!-- DNS probe timeout for network validation. Enough for 3 DNS queries 5 seconds apart. --> + <integer name="default_captive_portal_dns_probe_timeout">12500</integer> + <!-- HTTP URL for network validation, to use for detecting captive portals. --> <string name="default_captive_portal_http_url" translatable="false">http://connectivitycheck.gstatic.com/generate_204</string> @@ -27,6 +30,7 @@ <!-- Configuration hooks for the above settings. Empty by default but may be overridden by RROs. --> + <integer name="config_captive_portal_dns_probe_timeout"></integer> <!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook --> <string name="config_captive_portal_http_url" translatable="false"></string> <!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook --> diff --git a/packages/NetworkStack/res/values/overlayable.xml b/packages/NetworkStack/res/values/overlayable.xml index 7eeeefcf87f6..b9d5337ec572 100644 --- a/packages/NetworkStack/res/values/overlayable.xml +++ b/packages/NetworkStack/res/values/overlayable.xml @@ -17,9 +17,12 @@ <overlayable name="NetworkStackConfig"> <policy type="product|system|vendor"> <!-- Configuration values for NetworkMonitor --> + <item type="integer" name="config_captive_portal_dns_probe_timeout"/> <item type="string" name="config_captive_portal_http_url"/> <item type="string" name="config_captive_portal_https_url"/> <item type="array" name="config_captive_portal_fallback_urls"/> + <!-- Configuration value for DhcpResults --> + <item type="array" name="config_default_dns_servers"/> </policy> </overlayable> </resources> diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java index 97e81862f85e..2934e1cf0c82 100644 --- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java +++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java @@ -63,6 +63,49 @@ public class NetworkStackUtils { */ public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https"; + /** + * The URL used for HTTPS captive portal detection upon a new connection. + * A 204 response code from the server is used for validation. + */ + public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url"; + + /** + * The URL used for HTTP captive portal detection upon a new connection. + * A 204 response code from the server is used for validation. + */ + public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url"; + + /** + * The URL used for fallback HTTP captive portal detection when previous HTTP + * and HTTPS captive portal detection attemps did not return a conclusive answer. + */ + public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url"; + + /** + * What to do when connecting a network that presents a captive portal. + * Must be one of the CAPTIVE_PORTAL_MODE_* constants above. + * + * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT. + */ + public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode"; + + /** + * Don't attempt to detect captive portals. + */ + public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; + + /** + * When detecting a captive portal, display a notification that + * prompts the user to sign in. + */ + public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; + + /** + * When detecting a captive portal, immediately disconnect from the + * network and do not reconnect to that network in the future. + */ + public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; + static { System.loadLibrary("networkstackutilsjni"); } diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java index 093235e66214..bacec78e5699 100644 --- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java @@ -44,6 +44,12 @@ import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_MIN_EVALUATE_TI import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS; import static android.net.util.DataStallUtils.DEFAULT_DNS_LOG_SIZE; import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS; +import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_URL; +import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_HTTPS_URL; +import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_HTTP_URL; +import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_MODE; +import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_MODE_IGNORE; +import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_MODE_PROMPT; import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS; import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USER_AGENT; import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS; @@ -59,6 +65,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.net.ConnectivityManager; +import android.net.DnsResolver; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; import android.net.LinkProperties; @@ -122,6 +129,7 @@ import java.util.Random; import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; /** @@ -136,8 +144,13 @@ public class NetworkMonitor extends StateMachine { + "AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/60.0.3112.32 Safari/537.36"; + @VisibleForTesting + static final String CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT = + "captive_portal_dns_probe_timeout"; + private static final int SOCKET_TIMEOUT_MS = 10000; private static final int PROBE_TIMEOUT_MS = 3000; + enum EvaluationResult { VALIDATED(true), CAPTIVE_PORTAL(false); @@ -1168,10 +1181,10 @@ public class NetworkMonitor extends StateMachine { } private boolean getIsCaptivePortalCheckEnabled() { - String symbol = Settings.Global.CAPTIVE_PORTAL_MODE; - int defaultValue = Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT; + String symbol = CAPTIVE_PORTAL_MODE; + int defaultValue = CAPTIVE_PORTAL_MODE_PROMPT; int mode = mDependencies.getSetting(mContext, symbol, defaultValue); - return mode != Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE; + return mode != CAPTIVE_PORTAL_MODE_IGNORE; } private boolean getUseHttpsValidation() { @@ -1181,8 +1194,34 @@ public class NetworkMonitor extends StateMachine { private String getCaptivePortalServerHttpsUrl() { return getSettingFromResource(mContext, R.string.config_captive_portal_https_url, - R.string.default_captive_portal_https_url, - Settings.Global.CAPTIVE_PORTAL_HTTPS_URL); + R.string.default_captive_portal_https_url, CAPTIVE_PORTAL_HTTPS_URL); + } + + private int getDnsProbeTimeout() { + return getIntSetting(mContext, R.integer.config_captive_portal_dns_probe_timeout, + CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT, + R.integer.default_captive_portal_dns_probe_timeout); + } + + /** + * Gets an integer setting from resources or device config + * + * configResource is used if set, followed by device config if set, followed by defaultResource. + * If none of these are set then an exception is thrown. + * + * TODO: move to a common location such as a ConfigUtils class. + * TODO(b/130324939): test that the resources can be overlayed by an RRO package. + */ + @VisibleForTesting + int getIntSetting(@NonNull final Context context, @StringRes int configResource, + @NonNull String symbol, @StringRes int defaultResource) { + final Resources res = context.getResources(); + try { + return res.getInteger(configResource); + } catch (Resources.NotFoundException e) { + return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY, + symbol, res.getInteger(defaultResource)); + } } /** @@ -1194,8 +1233,7 @@ public class NetworkMonitor extends StateMachine { */ public String getCaptivePortalServerHttpUrl() { return getSettingFromResource(mContext, R.string.config_captive_portal_http_url, - R.string.default_captive_portal_http_url, - Settings.Global.CAPTIVE_PORTAL_HTTP_URL); + R.string.default_captive_portal_http_url, CAPTIVE_PORTAL_HTTP_URL); } private int getConsecutiveDnsTimeoutThreshold() { @@ -1224,8 +1262,8 @@ public class NetworkMonitor extends StateMachine { private URL[] makeCaptivePortalFallbackUrls() { try { - final String firstUrl = mDependencies.getSetting(mContext, - Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, null); + final String firstUrl = mDependencies.getSetting(mContext, CAPTIVE_PORTAL_FALLBACK_URL, + null); final URL[] settingProviderUrls; if (!TextUtils.isEmpty(firstUrl)) { @@ -1446,6 +1484,45 @@ public class NetworkMonitor extends StateMachine { return sendHttpProbe(url, probeType, null); } + /** Do a DNS lookup for the given server, or throw UnknownHostException after timeoutMs */ + @VisibleForTesting + protected InetAddress[] sendDnsProbeWithTimeout(String host, int timeoutMs) + throws UnknownHostException { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference<List<InetAddress>> resultRef = new AtomicReference<>(); + final DnsResolver.Callback<List<InetAddress>> callback = + new DnsResolver.Callback<List<InetAddress>>() { + public void onAnswer(List<InetAddress> answer, int rcode) { + if (rcode == 0) { + resultRef.set(answer); + } + latch.countDown(); + } + public void onError(@NonNull DnsResolver.DnsException e) { + validationLog("DNS error resolving " + host + ": " + e.getMessage()); + latch.countDown(); + } + }; + + final int oldTag = TrafficStats.getAndSetThreadStatsTag( + TrafficStatsConstants.TAG_SYSTEM_PROBE); + mDependencies.getDnsResolver().query(mNetwork, host, DnsResolver.FLAG_EMPTY, + r -> r.run() /* executor */, null /* cancellationSignal */, callback); + TrafficStats.setThreadStatsTag(oldTag); + + try { + latch.await(timeoutMs, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + } + + List<InetAddress> result = resultRef.get(); + if (result == null || result.size() == 0) { + throw new UnknownHostException(host); + } + + return result.toArray(new InetAddress[0]); + } + /** Do a DNS resolution of the given server. */ private void sendDnsProbe(String host) { if (TextUtils.isEmpty(host)) { @@ -1457,7 +1534,7 @@ public class NetworkMonitor extends StateMachine { int result; String connectInfo; try { - InetAddress[] addresses = mNetwork.getAllByName(host); + InetAddress[] addresses = sendDnsProbeWithTimeout(host, getDnsProbeTimeout()); StringBuffer buffer = new StringBuffer(); for (InetAddress address : addresses) { buffer.append(',').append(address.getHostAddress()); @@ -1782,6 +1859,10 @@ public class NetworkMonitor extends StateMachine { return new OneAddressPerFamilyNetwork(network); } + public DnsResolver getDnsResolver() { + return DnsResolver.getInstance(); + } + public Random getRandom() { return new Random(); } diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java index 594f2cae996d..0dc1cbf8a984 100644 --- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java +++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java @@ -33,6 +33,7 @@ import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -41,6 +42,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.never; @@ -55,6 +57,7 @@ import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.net.ConnectivityManager; +import android.net.DnsResolver; import android.net.INetworkMonitorCallbacks; import android.net.InetAddresses; import android.net.LinkProperties; @@ -69,6 +72,7 @@ import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.ConditionVariable; import android.os.Handler; +import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; @@ -79,6 +83,7 @@ import android.util.ArrayMap; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.networkstack.R; import com.android.networkstack.metrics.DataStallDetectionStats; import com.android.networkstack.metrics.DataStallStatsUtils; @@ -96,8 +101,12 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.URL; +import java.net.UnknownHostException; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Random; +import java.util.concurrent.Executor; import javax.net.ssl.SSLHandshakeException; @@ -111,6 +120,7 @@ public class NetworkMonitorTest { private @Mock IpConnectivityLog mLogger; private @Mock SharedLog mValidationLogger; private @Mock NetworkInfo mNetworkInfo; + private @Mock DnsResolver mDnsResolver; private @Mock ConnectivityManager mCm; private @Mock TelephonyManager mTelephony; private @Mock WifiManager mWifi; @@ -156,10 +166,36 @@ public class NetworkMonitorTest { private static final NetworkCapabilities NO_INTERNET_CAPABILITIES = new NetworkCapabilities() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); + private void setDnsAnswers(String[] answers) throws UnknownHostException { + if (answers == null) { + doThrow(new UnknownHostException()).when(mNetwork).getAllByName(any()); + doNothing().when(mDnsResolver).query(any(), any(), anyInt(), any(), any(), any()); + return; + } + + List<InetAddress> answerList = new ArrayList<>(); + for (String answer : answers) { + answerList.add(InetAddresses.parseNumericAddress(answer)); + } + InetAddress[] answerArray = answerList.toArray(new InetAddress[0]); + + doReturn(answerArray).when(mNetwork).getAllByName(any()); + + doAnswer((invocation) -> { + Executor executor = (Executor) invocation.getArgument(3); + DnsResolver.Callback<List<InetAddress>> callback = invocation.getArgument(5); + new Handler(Looper.getMainLooper()).post(() -> { + executor.execute(() -> callback.onAnswer(answerList, 0)); + }); + return null; + }).when(mDnsResolver).query(eq(mNetwork), any(), anyInt(), any(), any(), any()); + } + @Before public void setUp() throws IOException { MockitoAnnotations.initMocks(this); when(mDependencies.getPrivateDnsBypassNetwork(any())).thenReturn(mNetwork); + when(mDependencies.getDnsResolver()).thenReturn(mDnsResolver); when(mDependencies.getRandom()).thenReturn(mRandom); when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt())) .thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); @@ -204,9 +240,8 @@ public class NetworkMonitorTest { }).when(mNetwork).openConnection(any()); when(mHttpConnection.getRequestProperties()).thenReturn(new ArrayMap<>()); when(mHttpsConnection.getRequestProperties()).thenReturn(new ArrayMap<>()); - doReturn(new InetAddress[] { - InetAddresses.parseNumericAddress("192.168.0.0") - }).when(mNetwork).getAllByName(any()); + + setDnsAnswers(new String[]{"2001:db8::1", "192.0.2.2"}); when(mContext.registerReceiver(any(BroadcastReceiver.class), any())).then((invocation) -> { mRegisteredReceivers.add(invocation.getArgument(0)); @@ -313,6 +348,44 @@ public class NetworkMonitorTest { } @Test + public void testGetIntSetting() throws Exception { + WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor(); + + // No config resource, no device config. Expect to get default resource. + doThrow(new Resources.NotFoundException()) + .when(mResources).getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout)); + doAnswer(invocation -> { + int defaultValue = invocation.getArgument(2); + return defaultValue; + }).when(mDependencies).getDeviceConfigPropertyInt(any(), + eq(NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT), + anyInt()); + when(mResources.getInteger(eq(R.integer.default_captive_portal_dns_probe_timeout))) + .thenReturn(42); + assertEquals(42, wnm.getIntSetting(mContext, + R.integer.config_captive_portal_dns_probe_timeout, + NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT, + R.integer.default_captive_portal_dns_probe_timeout)); + + // Set device config. Expect to get device config. + when(mDependencies.getDeviceConfigPropertyInt(any(), + eq(NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT), anyInt())) + .thenReturn(1234); + assertEquals(1234, wnm.getIntSetting(mContext, + R.integer.config_captive_portal_dns_probe_timeout, + NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT, + R.integer.default_captive_portal_dns_probe_timeout)); + + // Set config resource. Expect to get config resource. + when(mResources.getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout))) + .thenReturn(5678); + assertEquals(5678, wnm.getIntSetting(mContext, + R.integer.config_captive_portal_dns_probe_timeout, + NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT, + R.integer.default_captive_portal_dns_probe_timeout)); + } + + @Test public void testIsCaptivePortal_HttpProbeIsPortal() throws IOException { setSslException(mHttpsConnection); setPortal302(mHttpConnection); @@ -642,6 +715,45 @@ public class NetworkMonitorTest { runPartialConnectivityNetworkTest(); } + private void assertIpAddressArrayEquals(String[] expected, InetAddress[] actual) { + String[] actualStrings = new String[actual.length]; + for (int i = 0; i < actual.length; i++) { + actualStrings[i] = actual[i].getHostAddress(); + } + assertArrayEquals("Array of IP addresses differs", expected, actualStrings); + } + + @Test + public void testSendDnsProbeWithTimeout() throws Exception { + WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor(); + final int shortTimeoutMs = 200; + + String[] expected = new String[]{"2001:db8::"}; + setDnsAnswers(expected); + InetAddress[] actual = wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs); + assertIpAddressArrayEquals(expected, actual); + + expected = new String[]{"2001:db8::", "192.0.2.1"}; + setDnsAnswers(expected); + actual = wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs); + assertIpAddressArrayEquals(expected, actual); + + expected = new String[0]; + setDnsAnswers(expected); + try { + wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs); + fail("No DNS results, expected UnknownHostException"); + } catch (UnknownHostException e) { + } + + setDnsAnswers(null); + try { + wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs); + fail("DNS query timed out, expected UnknownHostException"); + } catch (UnknownHostException e) { + } + } + private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) { for (int i = 0; i < count; i++) { wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount( diff --git a/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml b/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml index 675aee9cd1dd..719b70219c4a 100644 --- a/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml +++ b/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml @@ -18,24 +18,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - <path - android:pathData="M16,12h2v2h-2z" - android:fillColor="#1A73E8" - android:fillType="nonZero"/> - <path - android:pathData="M6,12h8v2h-8z" - android:fillColor="#1A73E8" - android:fillType="nonZero"/> - <path - android:pathData="M20,2C21.1046,2 22,2.8954 22,4L22,16C22,17.1046 21.1046,18 20,18L6,18L2,22L2,4C2,2.8954 2.8954,2 4,2L20,2ZM20,16L20,4L4,4L4,16L20,16Z" - android:fillColor="#1A73E8" - android:fillType="nonZero"/> - <path - android:pathData="M6,8h2v2h-2z" - android:fillColor="#1A73E8" - android:fillType="nonZero"/> - <path - android:pathData="M10,8h8v2h-8z" - android:fillColor="#1A73E8" - android:fillType="nonZero"/> + <path + android:fillColor="#FF000000" + android:pathData="M20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,18L4,18L4,6h16v12zM6,10h2v2L6,12zM6,14h8v2L6,16zM16,14h2v2h-2zM10,10h8v2h-8z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml b/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml index e818455950de..953d4fef6e58 100644 --- a/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml +++ b/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml @@ -18,20 +18,16 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - <path - android:pathData="M2.07,0.64L22,20.59L20.6,22L16.6,18L6,18L2,22L2,4C2.0006,3.8236 2.0276,3.6484 2.08,3.48L0.66,2.05L2.07,0.64ZM5.17,16L14.6,16L12.6,14L6,14L6,12L10.6,12L8,9.4L8,10L6,10L6,8L6.6,8L4,5.4L4,16L5.17,16Z" - android:fillColor="#1A73E8" - android:fillType="nonZero"/> - <path - android:pathData="M18,12l-1.74,0l1.74,1.74z" - android:fillColor="#1A73E8" - android:fillType="nonZero"/> - <path - android:pathData="M18,8l-5.74,0l2,2l3.74,0z" - android:fillColor="#1A73E8" - android:fillType="nonZero"/> - <path - android:pathData="M20,4L20,15.74L21.53,17.27C21.8296,16.9142 21.9958,16.4651 22,16L22,4C22,2.8954 21.1046,2 20,2L6.26,2L8.26,4L20,4Z" - android:fillColor="#1A73E8" - android:fillType="nonZero"/> + <path + android:fillColor="#FF000000" + android:pathData="M18,10l-5.18,0l2,2l3.18,0z"/> + <path + android:fillColor="#FF000000" + android:pathData="M18,14l-1.19,0l1.19,1.19z"/> + <path + android:fillColor="#FF000000" + android:pathData="M2,2L0.58,3.41l1.66,1.66C2.09,5.35 2,5.66 2,6v12c0,1.1 0.9,2 2,2h13.17l2.61,2.61l1.41,-1.41L2,2zM4,18V6.83L7.17,10H6v2h2v-1.17L11.17,14H6v2h7.17l2,2H4z"/> + <path + android:fillColor="#FF000000" + android:pathData="M20,4H6.82l2,2H20v11.19l1.75,1.75C21.91,18.66 22,18.34 22,18V6C22,4.9 21.1,4 20,4z"/> </vector> diff --git a/packages/SystemUI/res/values-sw900dp-land/dimen.xml b/packages/SystemUI/res/values-sw900dp-land/dimen.xml index ac7e6b815666..1e0600ed5fe0 100644 --- a/packages/SystemUI/res/values-sw900dp-land/dimen.xml +++ b/packages/SystemUI/res/values-sw900dp-land/dimen.xml @@ -19,8 +19,5 @@ <!-- Standard notification width + gravity for tablet large screen device --> <dimen name="notification_panel_width">544dp</dimen> - <!-- Maximum width of quick quick settings panel. --> - <dimen name="qs_quick_layout_width">478dp</dimen> - </resources> diff --git a/packages/SystemUI/res/values-w550dp-land/dimens.xml b/packages/SystemUI/res/values-w550dp-land/dimens.xml index 2c6645480abf..017ca6987820 100644 --- a/packages/SystemUI/res/values-w550dp-land/dimens.xml +++ b/packages/SystemUI/res/values-w550dp-land/dimens.xml @@ -19,6 +19,4 @@ <!-- Standard notification width + gravity --> <dimen name="notification_panel_width">544dp</dimen> - <!-- Maximum width of quick quick settings panel. --> - <dimen name="qs_quick_layout_width">478dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 5e84549655fb..df6bc20bbad8 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -433,8 +433,6 @@ <dimen name="qs_tile_margin_top">18dp</dimen> <dimen name="qs_tile_background_size">44dp</dimen> <dimen name="qs_quick_tile_size">48dp</dimen> - <!-- Maximum width of quick quick settings panel. Defaults to MATCH_PARENT--> - <dimen name="qs_quick_layout_width">-1px</dimen> <dimen name="qs_quick_tile_padding">12dp</dimen> <dimen name="qs_header_gear_translation">16dp</dimen> <dimen name="qs_header_tile_margin_horizontal">4dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index 1bd8e0d2ce0f..4ed28f92d5cb 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -180,6 +180,10 @@ public class AssistManager implements ConfigurationChangedReceiver { ? TIMEOUT_SERVICE : TIMEOUT_ACTIVITY); } + + if (args == null) { + args = new Bundle(); + } args.putLong(INVOCATION_TIME_MS_KEY, SystemClock.uptimeMillis()); startAssistInternal(args, assistComponent, isService); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index a4a0fe18f5cb..d9fe47a94d5f 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -717,12 +717,10 @@ public class BubbleStackView extends FrameLayout { /** Moves the bubbles out of the way if they're going to be over the keyboard. */ public void onImeVisibilityChanged(boolean visible, int height) { + mStackAnimationController.setImeHeight(height + mImeOffset); + if (!mIsExpanded) { - if (visible) { - mStackAnimationController.updateBoundsForVisibleImeAndAnimate(height + mImeOffset); - } else { - mStackAnimationController.updateBoundsForInvisibleImeAndAnimate(); - } + mStackAnimationController.animateForImeVisibility(visible); } } @@ -787,6 +785,10 @@ public class BubbleStackView extends FrameLayout { StatsLog.BUBBLE_UICHANGED__ACTION__STACK_MOVED); } + void onDragFinishAsDismiss() { + mIsDragging = false; + } + /** * Calculates how large the expanded view of the bubble can be. This takes into account the * y position when the bubbles are expanded as well as the bounds of the dismiss target. @@ -826,9 +828,12 @@ public class BubbleStackView extends FrameLayout { if (updateMessage != null && !isExpanded() && !mIsExpansionAnimating && !mIsDragging) { final PointF stackPos = mStackAnimationController.getStackPosition(); + mFlyout.setAlpha(0f); + mFlyout.setVisibility(VISIBLE); + mFlyoutText.setText(updateMessage); mFlyout.measure(WRAP_CONTENT, WRAP_CONTENT); - mFlyout.post(() -> { + post(() -> { final boolean onLeft = mStackAnimationController.isStackOnLeftSide(); final float destinationX = onLeft ? stackPos.x + mBubbleSize + mBubblePadding @@ -837,9 +842,6 @@ public class BubbleStackView extends FrameLayout { // Translate towards the stack slightly, then spring out from the stack. mFlyout.setTranslationX(destinationX + (onLeft ? -mBubblePadding : mBubblePadding)); mFlyout.setTranslationY(stackPos.y); - mFlyout.setAlpha(0f); - - mFlyout.setVisibility(VISIBLE); mFlyout.animate().alpha(1f); mFlyoutSpring.animateToFinalPosition(destinationX); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java index baeedaacdd95..a51d46c0a848 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java @@ -148,6 +148,7 @@ class BubbleTouchHandler implements View.OnTouchListener { trackMovement(event); if (mInDismissTarget && isStack) { mController.dismissStack(BubbleController.DISMISS_USER_GESTURE); + mStack.onDragFinishAsDismiss(); } else if (isFlyout) { // TODO(b/129768381): Expand if tapped, dismiss if swiped away. if (!mStack.isExpanded() && !mMovedEnough) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java index 74a6b6005450..eb6ac796612a 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java @@ -334,41 +334,38 @@ public class StackAnimationController extends mLayout.removeEndActionForProperty(DynamicAnimation.TRANSLATION_Y); } - /** - * Save the IME height so that the allowable stack bounds reflect the now-visible IME, and - * animate the stack out of the way if necessary. - */ - public void updateBoundsForVisibleImeAndAnimate(int imeHeight) { + /** Save the current IME height so that we know where the stack bounds should be. */ + public void setImeHeight(int imeHeight) { mImeHeight = imeHeight; - - final float maxBubbleY = getAllowableStackPositionRegion().bottom; - if (mStackPosition.y > maxBubbleY && mPreImeY == Float.MIN_VALUE) { - mPreImeY = mStackPosition.y; - - springFirstBubbleWithStackFollowing( - DynamicAnimation.TRANSLATION_Y, - getSpringForce(DynamicAnimation.TRANSLATION_Y, /* view */ null) - .setStiffness(SpringForce.STIFFNESS_LOW), - /* startVel */ 0f, - maxBubbleY); - } } /** - * Clear the IME height from the bounds and animate the stack back to its original position, - * assuming it wasn't moved in the meantime. + * Animates the stack either away from the newly visible IME, or back to its original position + * due to the IME going away. */ - public void updateBoundsForInvisibleImeAndAnimate() { - mImeHeight = 0; + public void animateForImeVisibility(boolean imeVisible) { + final float maxBubbleY = getAllowableStackPositionRegion().bottom; + float destinationY = Float.MIN_VALUE; - if (mPreImeY > Float.MIN_VALUE) { + if (imeVisible) { + if (mStackPosition.y > maxBubbleY && mPreImeY == Float.MIN_VALUE) { + mPreImeY = mStackPosition.y; + destinationY = maxBubbleY; + } + } else { + if (mPreImeY > Float.MIN_VALUE) { + destinationY = mPreImeY; + mPreImeY = Float.MIN_VALUE; + } + } + + if (destinationY > Float.MIN_VALUE) { springFirstBubbleWithStackFollowing( DynamicAnimation.TRANSLATION_Y, getSpringForce(DynamicAnimation.TRANSLATION_Y, /* view */ null) - .setStiffness(SpringForce.STIFFNESS_LOW), + .setStiffness(SpringForce.STIFFNESS_LOW), /* startVel */ 0f, - mPreImeY); - mPreImeY = Float.MIN_VALUE; + destinationY); } } @@ -538,6 +535,7 @@ public class StackAnimationController extends Log.d(TAG, String.format("Setting position to (%f, %f).", pos.x, pos.y)); mStackPosition.set(pos.x, pos.y); + mLayout.cancelAllAnimations(); cancelStackPositionAnimations(); // Since we're not using the chained animations, apply the offsets manually. diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java index 60dceef23f7c..84f7e89d9f2f 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java @@ -170,6 +170,11 @@ public class PipAccessibilityInteractionConnection // We should not be here. } + @Override + public void notifyOutsideTouch() { + // Do nothing. + } + public static AccessibilityNodeInfo obtainRootAccessibilityNodeInfo() { AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); info.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID, diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index fcaf98165016..89aa96db7a92 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -17,6 +17,7 @@ package com.android.systemui.qs; import static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState; +import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; import android.annotation.Nullable; import android.content.ComponentName; @@ -37,6 +38,8 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.Utils; import com.android.systemui.Dependency; +import com.android.systemui.DumpController; +import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile; @@ -51,11 +54,17 @@ import com.android.systemui.statusbar.policy.BrightnessMirrorController.Brightne import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; +import javax.inject.Inject; +import javax.inject.Named; + /** View that represents the quick settings tile panel (when expanded/pulled down). **/ -public class QSPanel extends LinearLayout implements Tunable, Callback, BrightnessMirrorListener { +public class QSPanel extends LinearLayout implements Tunable, Callback, BrightnessMirrorListener, + Dumpable { public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness"; public static final String QS_SHOW_HEADER = "qs_show_header"; @@ -74,6 +83,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne private QSDetail.Callback mCallback; private BrightnessController mBrightnessController; + private DumpController mDumpController; protected QSTileHost mHost; protected QSSecurityFooter mFooter; @@ -93,6 +103,12 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } public QSPanel(Context context, AttributeSet attrs) { + this(context, attrs, null); + } + + @Inject + public QSPanel(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, + DumpController dumpController) { super(context, attrs); mContext = context; @@ -119,6 +135,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne mBrightnessController = new BrightnessController(getContext(), findViewById(R.id.brightness_slider)); + mDumpController = dumpController; } protected void addDivider() { @@ -170,6 +187,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne if (mBrightnessMirrorController != null) { mBrightnessMirrorController.addCallback(this); } + if (mDumpController != null) mDumpController.addListener(this); } @Override @@ -184,6 +202,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne if (mBrightnessMirrorController != null) { mBrightnessMirrorController.removeCallback(this); } + if (mDumpController != null) mDumpController.removeListener(this); super.onDetachedFromWindow(); } @@ -649,6 +668,18 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } } + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println(getClass().getSimpleName() + ":"); + pw.println(" Tile records:"); + for (TileRecord record : mRecords) { + if (record.tile instanceof Dumpable) { + pw.print(" "); ((Dumpable) record.tile).dump(fd, pw, args); + pw.print(" "); pw.println(record.tileView.toString()); + } + } + } + protected static class Record { DetailAdapter detailAdapter; int x; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index dfc3e66d8d98..3c4898c7658b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -30,6 +30,8 @@ import android.text.TextUtils; import android.util.Log; import com.android.systemui.Dependency; +import com.android.systemui.DumpController; +import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.plugins.PluginListener; @@ -47,6 +49,8 @@ import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -61,7 +65,7 @@ import javax.inject.Singleton; /** Platform implementation of the quick settings tile host **/ @Singleton -public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory> { +public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, Dumpable { private static final String TAG = "QSTileHost"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -73,6 +77,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory> { private final TileServices mServices; private final TunerService mTunerService; private final PluginManager mPluginManager; + private final DumpController mDumpController; private final List<Callback> mCallbacks = new ArrayList<>(); private AutoTileManager mAutoTiles; @@ -89,17 +94,20 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory> { @Named(Dependency.BG_LOOPER_NAME) Looper bgLooper, PluginManager pluginManager, TunerService tunerService, - Provider<AutoTileManager> autoTiles) { + Provider<AutoTileManager> autoTiles, + DumpController dumpController) { mIconController = iconController; mContext = context; mTunerService = tunerService; mPluginManager = pluginManager; + mDumpController = dumpController; mServices = new TileServices(this, bgLooper); defaultFactory.setHost(this); mQsFactories.add(defaultFactory); pluginManager.addPluginListener(this, QSFactory.class, true); + mDumpController.addListener(this); mainHandler.post(() -> { // This is technically a hack to avoid circular dependency of @@ -121,6 +129,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory> { mTunerService.removeTunable(this); mServices.destroy(); mPluginManager.removePluginListener(this); + mDumpController.removeListener(this); } @Override @@ -363,4 +372,11 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory> { } return tiles; } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("QSTileHost:"); + mTiles.values().stream().filter(obj -> obj instanceof Dumpable) + .forEach(o -> ((Dumpable) o).dump(fd, pw, args)); + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 4b5513726f7e..73f6fc5ea2f4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -16,6 +16,8 @@ package com.android.systemui.qs; +import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; + import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; @@ -25,6 +27,7 @@ import android.view.View; import android.widget.LinearLayout; import com.android.systemui.Dependency; +import com.android.systemui.DumpController; import com.android.systemui.R; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.SignalState; @@ -36,6 +39,9 @@ import com.android.systemui.tuner.TunerService.Tunable; import java.util.ArrayList; import java.util.Collection; +import javax.inject.Inject; +import javax.inject.Named; + /** * Version of QSPanel that only shows N Quick Tiles in the QS Header. */ @@ -49,8 +55,10 @@ public class QuickQSPanel extends QSPanel { private int mMaxTiles; protected QSPanel mFullPanel; - public QuickQSPanel(Context context, AttributeSet attrs) { - super(context, attrs); + @Inject + public QuickQSPanel(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, + DumpController dumpController) { + super(context, attrs, dumpController); if (mFooter != null) { removeView(mFooter.getView()); } @@ -187,6 +195,10 @@ public class QuickQSPanel extends QSPanel { super(context); setClipChildren(false); setClipToPadding(false); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT); + lp.gravity = Gravity.CENTER_HORIZONTAL; + setLayoutParams(lp); } @Override @@ -200,13 +212,6 @@ public class QuickQSPanel extends QSPanel { updateResources(); } - private void updateLayoutParams() { - int width = getResources().getDimensionPixelSize(R.dimen.qs_quick_layout_width); - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(width, LayoutParams.MATCH_PARENT); - lp.gravity = Gravity.CENTER_HORIZONTAL; - setLayoutParams(lp); - } - private LayoutParams generateTileLayoutParams() { LayoutParams lp = new LayoutParams(mCellWidth, mCellHeight); return lp; @@ -238,8 +243,6 @@ public class QuickQSPanel extends QSPanel { mCellWidth = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size); mCellHeight = mCellWidth; - updateLayoutParams(); - return false; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java index 3c59f69fdee6..31526bf8f5e1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java @@ -47,6 +47,7 @@ public class QSIconViewImpl extends QSIconView { private boolean mAnimationEnabled = true; private int mState = -1; private int mTint; + private QSTile.Icon mLastIcon; public QSIconViewImpl(Context context) { super(context); @@ -75,6 +76,16 @@ public class QSIconViewImpl extends QSIconView { } @Override + public String toString() { + final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('['); + sb.append("state=" + mState); + sb.append(", tint=" + mTint); + if (mLastIcon != null) sb.append(", lastIcon=" + mLastIcon.toString()); + sb.append("]"); + return sb.toString(); + } + + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int w = getMeasuredWidth(); int top = 0; @@ -91,6 +102,7 @@ public class QSIconViewImpl extends QSIconView { if (!Objects.equals(icon, iv.getTag(R.id.qs_icon_tag)) || !Objects.equals(state.slash, iv.getTag(R.id.qs_slash_tag))) { boolean shouldAnimate = allowAnimations && shouldAnimate(iv); + mLastIcon = icon; Drawable d = icon != null ? shouldAnimate ? icon.getDrawable(mContext) : icon.getInvisibleDrawable(mContext) : null; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java index a732a253f5a3..c186e59056aa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java @@ -318,6 +318,16 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { } } + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('['); + sb.append("locInScreen=(" + mLocInScreen[0] + ", " + mLocInScreen[1] + ")"); + sb.append(", iconView=" + mIcon.toString()); + sb.append(", tileState=" + mTileState); + sb.append("]"); + return sb.toString(); + } + private class H extends Handler { private static final int STATE_CHANGED = 1; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java index e275690f70aa..1f857ff7b5ea 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java @@ -52,6 +52,7 @@ import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.Utils; import com.android.systemui.Dependency; +import com.android.systemui.Dumpable; import com.android.systemui.Prefs; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; @@ -63,6 +64,8 @@ import com.android.systemui.qs.PagedTileLayout.TilePage; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QuickStatusBarHeader; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.ArrayList; /** @@ -74,7 +77,7 @@ import java.util.ArrayList; * * @param <TState> see above */ -public abstract class QSTileImpl<TState extends State> implements QSTile, LifecycleOwner { +public abstract class QSTileImpl<TState extends State> implements QSTile, LifecycleOwner, Dumpable { protected final String TAG = "Tile." + getClass().getSimpleName(); protected static final boolean DEBUG = Log.isLoggable("Tile", Log.DEBUG); @@ -592,4 +595,10 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy return context.getDrawable(mAnimatedResId).getConstantState().newDrawable(); } } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println(this.getClass().getSimpleName() + ":"); + pw.print(" "); pw.println(getState().toString()); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index f08d7ed39ea6..7c271cef6abb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -596,8 +596,8 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onActiveStateChanged(int code, int uid, String packageName, boolean active) { - mForegroundServiceController.onAppOpChanged(code, uid, packageName, active); Dependency.get(MAIN_HANDLER).post(() -> { + mForegroundServiceController.onAppOpChanged(code, uid, packageName, active); mNotificationListController.updateNotificationsForAppOp(code, uid, packageName, active); }); } diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java index 1e486c0949a4..d521e5534ad4 100644 --- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java +++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java @@ -29,6 +29,8 @@ import com.android.keyguard.KeyguardSliceView; import com.android.systemui.SystemUIFactory; import com.android.systemui.qs.QSCarrierGroup; import com.android.systemui.qs.QSFooterImpl; +import com.android.systemui.qs.QSPanel; +import com.android.systemui.qs.QuickQSPanel; import com.android.systemui.qs.QuickStatusBarHeader; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.phone.LockIcon; @@ -154,6 +156,16 @@ public class InjectionInflationController { * Creates the keyguard LockIcon. */ LockIcon createLockIcon(); + + /** + * Creates the QSPanel. + */ + QSPanel createQSPanel(); + + /** + * Creates the QuickQSPanel. + */ + QuickQSPanel createQuickQSPanel(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 8d9c5a3740b2..43912f9eb4f7 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -27,6 +27,7 @@ import static android.media.AudioManager.STREAM_RING; import static android.media.AudioManager.STREAM_VOICE_CALL; import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE; import static android.view.View.GONE; +import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; @@ -228,9 +229,10 @@ public class VolumeDialogImpl implements VolumeDialog, mDialog.setContentView(R.layout.volume_dialog); mDialogView = mDialog.findViewById(R.id.volume_dialog); + mDialogView.setAlpha(0); mDialog.setCanceledOnTouchOutside(true); mDialog.setOnShowListener(dialog -> { - if (!isLandscape()) mDialogView.setTranslationX(mDialogView.getWidth() / 2); + if (!isLandscape()) mDialogView.setTranslationX(mDialogView.getWidth() / 2.0f); mDialogView.setAlpha(0); mDialogView.animate() .alpha(1) @@ -528,7 +530,7 @@ public class VolumeDialogImpl implements VolumeDialog, if (!mHasSeenODICaptionsTooltip && !fromDismiss && mODICaptionsTooltipViewStub != null) { mController.getCaptionsComponentState(true); } else { - if (mHasSeenODICaptionsTooltip && mODICaptionsTooltipView != null) { + if (mHasSeenODICaptionsTooltip && fromDismiss && mODICaptionsTooltipView != null) { hideCaptionsTooltip(); } } @@ -565,13 +567,14 @@ public class VolumeDialogImpl implements VolumeDialog, } private void hideCaptionsTooltip() { - if (mODICaptionsTooltipView != null) { + if (mODICaptionsTooltipView != null && mODICaptionsTooltipView.getVisibility() == VISIBLE) { mODICaptionsTooltipView.animate().cancel(); mODICaptionsTooltipView.setAlpha(1.f); mODICaptionsTooltipView.animate() .alpha(0.f) .setStartDelay(0) .setDuration(DIALOG_HIDE_ANIMATION_DURATION) + .withEndAction(() -> mODICaptionsTooltipView.setVisibility(INVISIBLE)) .start(); } } @@ -677,7 +680,7 @@ public class VolumeDialogImpl implements VolumeDialog, } private void showH(int reason) { - if (D.BUG) Log.d(TAG, "showH r=" + Events.DISMISS_REASONS[reason]); + if (D.BUG) Log.d(TAG, "showH r=" + Events.SHOW_REASONS[reason]); mHandler.removeMessages(H.SHOW); mHandler.removeMessages(H.DISMISS); rescheduleTimeoutH(); @@ -750,7 +753,7 @@ public class VolumeDialogImpl implements VolumeDialog, mDialog.dismiss(); tryToRemoveCaptionsTooltip(); }, 50)); - if (!isLandscape()) animator.translationX(mDialogView.getWidth() / 2); + if (!isLandscape()) animator.translationX(mDialogView.getWidth() / 2.0f); animator.start(); checkODICaptionsTooltip(true); mController.notifyVisible(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java index da31134d13b4..bafae6ce737a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java @@ -22,7 +22,6 @@ import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.view.View; import android.widget.TextView; import androidx.test.filters.SmallTest; @@ -53,22 +52,11 @@ public class BubbleStackViewTest extends SysuiTestCase { } @Test - public void testAnimateInFlyoutForBubble() throws InterruptedException { + public void testAnimateInFlyoutForBubble() { when(mNotifEntry.getUpdateMessage(any())).thenReturn("Test Flyout Message."); mStackView.animateInFlyoutForBubble(mBubble); - // Wait for the fade in. - Thread.sleep(200); - - // Flyout should be visible and showing our text. - assertEquals(1f, mStackView.findViewById(R.id.bubble_flyout).getAlpha(), .01f); assertEquals("Test Flyout Message.", ((TextView) mStackView.findViewById(R.id.bubble_flyout_text)).getText()); - - // Wait until it should have gone away. - Thread.sleep(BubbleStackView.FLYOUT_HIDE_AFTER + 200); - - // Flyout should be gone. - assertEquals(View.GONE, mStackView.findViewById(R.id.bubble_flyout).getVisibility()); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index 10d1572ca621..db4f5ffcdfeb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -35,6 +35,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.keyguard.CarrierText; import com.android.systemui.Dependency; +import com.android.systemui.DumpController; import com.android.systemui.R; import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiBaseFragmentTest; @@ -95,7 +96,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { QSTileHost host = new QSTileHost(mContext, mock(StatusBarIconController.class), mock(QSFactoryImpl.class), new Handler(), Looper.myLooper(), mock(PluginManager.class), mock(TunerService.class), - () -> mock(AutoTileManager.class)); + () -> mock(AutoTileManager.class), mock(DumpController.class)); qs.setHost(host); qs.setListening(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java index c6b31d03ff3b..38cdee4c090b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java @@ -14,10 +14,12 @@ package com.android.systemui.qs; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -34,9 +36,9 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.SysuiTestCase; -import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTileView; import com.android.systemui.qs.customize.QSCustomizer; +import com.android.systemui.qs.tileimpl.QSTileImpl; import org.junit.Before; import org.junit.Test; @@ -44,6 +46,9 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.Collections; @RunWith(AndroidTestingRunner.class) @@ -59,10 +64,12 @@ public class QSPanelTest extends SysuiTestCase { @Mock private QSCustomizer mCustomizer; @Mock - private QSTile dndTile; + private QSTileImpl dndTile; private ViewGroup mParentView; @Mock private QSDetail.Callback mCallback; + @Mock + private QSTileView mQSTileView; @Before public void setup() throws Exception { @@ -78,7 +85,7 @@ public class QSPanelTest extends SysuiTestCase { when(dndTile.getTileSpec()).thenReturn("dnd"); when(mHost.getTiles()).thenReturn(Collections.emptyList()); - when(mHost.createTileView(any(), anyBoolean())).thenReturn(mock(QSTileView.class)); + when(mHost.createTileView(any(), anyBoolean())).thenReturn(mQSTileView); mQsPanel.setHost(mHost, mCustomizer); mQsPanel.addTile(dndTile, true); @@ -120,4 +127,27 @@ public class QSPanelTest extends SysuiTestCase { verify(mCallback, never()).onShowingDetail(any(), anyInt(), anyInt()); } + + @Test + public void testDump() { + String mockTileViewString = "Mock Tile View"; + String mockTileString = "Mock Tile"; + doAnswer(invocation -> { + PrintWriter pw = invocation.getArgument(1); + pw.println(mockTileString); + return null; + }).when(dndTile).dump(any(FileDescriptor.class), any(PrintWriter.class), + any(String[].class)); + when(mQSTileView.toString()).thenReturn(mockTileViewString); + + StringWriter w = new StringWriter(); + PrintWriter pw = new PrintWriter(w); + mQsPanel.dump(mock(FileDescriptor.class), pw, new String[]{}); + String expected = "QSPanel:\n" + + " Tile records:\n" + + " " + mockTileString + "\n" + + " " + mockTileViewString + "\n"; + assertEquals(expected, w.getBuffer().toString()); + } + } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index a458928da9d8..f73472f86d8c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -17,23 +17,100 @@ package com.android.systemui.qs; +import static junit.framework.Assert.assertEquals; import static junit.framework.TestCase.assertFalse; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.Looper; import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.testing.TestableLooper.RunWithLooper; import androidx.test.filters.SmallTest; +import com.android.systemui.DumpController; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.qs.QSFactory; +import com.android.systemui.plugins.qs.QSTile; +import com.android.systemui.qs.tileimpl.QSFactoryImpl; +import com.android.systemui.qs.tileimpl.QSTileImpl; +import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.phone.AutoTileManager; +import com.android.systemui.statusbar.phone.StatusBarIconController; +import com.android.systemui.tuner.TunerService; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.List; +import javax.inject.Provider; + @RunWith(AndroidTestingRunner.class) @SmallTest +@RunWithLooper public class QSTileHostTest extends SysuiTestCase { + private static String MOCK_STATE_STRING = "MockState"; + + @Mock + private StatusBarIconController mIconController; + @Mock + private QSFactoryImpl mDefaultFactory; + @Mock + private PluginManager mPluginManager; + @Mock + private TunerService mTunerService; + @Mock + private Provider<AutoTileManager> mAutoTiles; + @Mock + private DumpController mDumpController; + @Mock + private QSTile.State mMockState; + private Handler mHandler; + private TestableLooper mLooper; + private QSTileHost mQSTileHost; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mLooper = TestableLooper.get(this); + mHandler = new Handler(mLooper.getLooper()); + mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler, + mLooper.getLooper(), + mPluginManager, mTunerService, mAutoTiles, mDumpController); + setUpTileFactory(); + } + + private void setUpTileFactory() { + when(mMockState.toString()).thenReturn(MOCK_STATE_STRING); + when(mDefaultFactory.createTile(anyString())).thenAnswer( + invocation -> { + String spec = invocation.getArgument(0); + switch (spec) { + case "spec1": + return new TestTile1(mQSTileHost); + case "spec2": + return new TestTile2(mQSTileHost); + default: + return null; + } + }); + + } + @Test public void testLoadTileSpecs_emptySetting() { List<String> tiles = QSTileHost.loadTileSpecs(mContext, ""); @@ -45,4 +122,91 @@ public class QSTileHostTest extends SysuiTestCase { List<String> tiles = QSTileHost.loadTileSpecs(mContext, null); assertFalse(tiles.isEmpty()); } + + @Test + public void testDump() { + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2"); + StringWriter w = new StringWriter(); + PrintWriter pw = new PrintWriter(w); + mQSTileHost.dump(mock(FileDescriptor.class), pw, new String[]{}); + String output = "QSTileHost:\n" + + TestTile1.class.getSimpleName() + ":\n" + + " " + MOCK_STATE_STRING + "\n" + + TestTile2.class.getSimpleName() + ":\n" + + " " + MOCK_STATE_STRING + "\n"; + assertEquals(output, w.getBuffer().toString()); + } + + private static class TestQSTileHost extends QSTileHost { + TestQSTileHost(Context context, StatusBarIconController iconController, + QSFactoryImpl defaultFactory, Handler mainHandler, Looper bgLooper, + PluginManager pluginManager, TunerService tunerService, + Provider<AutoTileManager> autoTiles, DumpController dumpController) { + super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager, + tunerService, autoTiles, dumpController); + } + + @Override + public void onPluginConnected(QSFactory plugin, Context pluginContext) { + } + + @Override + public void onPluginDisconnected(QSFactory plugin) { + } + } + + private class TestTile extends QSTileImpl<QSTile.State> { + + protected TestTile(QSHost host) { + super(host); + } + + @Override + public State newTileState() { + return mMockState; + } + + @Override + public State getState() { + return mMockState; + } + + @Override + protected void handleClick() {} + + @Override + protected void handleUpdateState(State state, Object arg) {} + + @Override + public int getMetricsCategory() { + return 0; + } + + @Override + public Intent getLongClickIntent() { + return null; + } + + @Override + protected void handleSetListening(boolean listening) {} + + @Override + public CharSequence getTileLabel() { + return null; + } + } + + private class TestTile1 extends TestTile { + + protected TestTile1(QSHost host) { + super(host); + } + } + + private class TestTile2 extends TestTile { + + protected TestTile2(QSHost host) { + super(host); + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java index 03278b4aadc6..183e027478df 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java @@ -29,6 +29,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; +import com.android.systemui.DumpController; import com.android.systemui.SysuiTestCase; import com.android.systemui.qs.QSTileHost; import com.android.systemui.qs.tileimpl.QSFactoryImpl; @@ -67,7 +68,8 @@ public class TileServicesTest extends SysuiTestCase { Looper.myLooper(), mock(PluginManager.class), mock(TunerService.class), - () -> mock(AutoTileManager.class)); + () -> mock(AutoTileManager.class), + mock(DumpController.class)); mTileService = new TestTileServices(host, Looper.getMainLooper()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java index 8a36cfbc4e2e..63ebe9290f64 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java @@ -14,6 +14,8 @@ package com.android.systemui.qs.tileimpl; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.mock; @@ -43,6 +45,7 @@ import org.junit.runner.RunWith; public class QSIconViewImplTest extends SysuiTestCase { private QSIconViewImpl mIconView; + private static int RES_ID = 1; @Before public void setup() { @@ -81,4 +84,24 @@ public class QSIconViewImplTest extends SysuiTestCase { mIconView.setIcon(iv, s, true); verify(iv).setImageTintList(argThat(stateList -> stateList.getColors()[0] == desiredColor)); } + + @Test + public void testStateSetCorrectly_toString() { + ImageView iv = mock(ImageView.class); + State s = new State(); + s.state = Tile.STATE_ACTIVE; + int desiredColor = mIconView.getColor(s.state); + Icon i = mock(Icon.class); + s.icon = i; + when(i.toString()).thenReturn("MOCK ICON"); + mIconView.setIcon(iv, s, false); + + assertEquals("QSIconViewImpl[state=" + Tile.STATE_ACTIVE + ", tint=" + desiredColor + + ", lastIcon=" + i.toString() + "]", mIconView.toString()); + } + + @Test + public void testIconNotSet_toString() { + assertFalse(mIconView.toString().contains("lastIcon")); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java index 3df8a8aadda2..192d8f8e8226 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java @@ -34,6 +34,8 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static java.lang.Thread.sleep; + import android.content.Intent; import android.metrics.LogMaker; import android.testing.AndroidTestingRunner; @@ -60,8 +62,6 @@ import org.mockito.ArgumentMatcher; import org.mockito.Captor; import org.mockito.MockitoAnnotations; -import static java.lang.Thread.sleep; - @RunWith(AndroidTestingRunner.class) @RunWithLooper @SmallTest diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 334262fa3570..05b937a34626 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -2722,9 +2722,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return -1; } - private void notifyOutsideTouchIfNeeded(int targetWindowId, int action, Bundle arguments, - int interactionId, IAccessibilityInteractionConnectionCallback callback, int fetchFlags, - int interrogatingPid, long interrogatingTid) { + private void notifyOutsideTouchIfNeeded(int targetWindowId, int action) { if (action != ACTION_CLICK && action != ACTION_LONG_CLICK) { return; } @@ -2741,13 +2739,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub final RemoteAccessibilityConnection connection = connectionList.get(i); if (connection != null) { try { - connection.mConnection.performAccessibilityAction( - AccessibilityNodeInfo.ROOT_ITEM_ID, - R.id.accessibilityActionOutsideTouch, arguments, interactionId, - callback, fetchFlags, interrogatingPid, interrogatingTid); + connection.getRemote().notifyOutsideTouch(); } catch (RemoteException re) { if (DEBUG) { - Slog.e(LOG_TAG, "Error calling performAccessibilityAction: " + re); + Slog.e(LOG_TAG, "Error calling notifyOutsideTouch()"); } } } @@ -2833,8 +2828,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mPowerManager.userActivity(SystemClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY, 0); - notifyOutsideTouchIfNeeded(resolvedWindowId, action, arguments, interactionId, callback, - fetchFlags, interrogatingPid, interrogatingTid); + notifyOutsideTouchIfNeeded(resolvedWindowId, action); if (activityToken != null) { LocalServices.getService(ActivityTaskManagerInternal.class) .setFocusedActivity(activityToken); @@ -3790,7 +3784,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private List<Integer> getWatchOutsideTouchWindowIdLocked(int targetWindowId) { final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId); - if (targetWindow != null && mWindowInfoById != null && mHasWatchOutsideTouchWindow) { + if (targetWindow != null && mHasWatchOutsideTouchWindow) { final List<Integer> outsideWindowsId = new ArrayList<>(); for (int i = 0; i < mWindowInfoById.size(); i++) { WindowInfo window = mWindowInfoById.valueAt(i); diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index ce1d33a06f80..6c1ffa7225f0 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3999,8 +3999,6 @@ class StorageManagerService extends IStorageManager.Stub @Override public void onExternalStoragePolicyChanged(int uid, String packageName) { - // No runtime storage permissions in isolated storage world, so nothing to do here. - if (ENABLE_ISOLATED_STORAGE) return; final int mountMode = getExternalStorageMountMode(uid, packageName); remountUidExternalStorage(uid, mountMode); } diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java index 1913635f80e2..e33392d359dd 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -34,6 +34,7 @@ import android.net.IDnsResolver; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkUtils; +import android.net.ResolverParamsParcel; import android.net.Uri; import android.net.shared.PrivateDnsConfig; import android.os.Binder; @@ -311,11 +312,9 @@ public class DnsManager { public void setDnsConfigurationForNetwork( int netId, LinkProperties lp, boolean isDefaultNetwork) { - final String[] assignedServers = NetworkUtils.makeStrings(lp.getDnsServers()); - final String[] domainStrs = getDomainStrings(lp.getDomains()); updateParametersSettings(); - final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples }; + final ResolverParamsParcel paramsParcel = new ResolverParamsParcel(); // We only use the PrivateDnsConfig data pushed to this class instance // from ConnectivityService because it works in coordination with @@ -329,34 +328,44 @@ public class DnsManager { final boolean useTls = privateDnsCfg.useTls; final boolean strictMode = privateDnsCfg.inStrictMode(); - final String tlsHostname = strictMode ? privateDnsCfg.hostname : ""; - final String[] tlsServers = + paramsParcel.netId = netId; + paramsParcel.sampleValiditySeconds = mSampleValidity; + paramsParcel.successThreshold = mSuccessThreshold; + paramsParcel.minSamples = mMinSamples; + paramsParcel.maxSamples = mMaxSamples; + paramsParcel.servers = NetworkUtils.makeStrings(lp.getDnsServers()); + paramsParcel.domains = getDomainStrings(lp.getDomains()); + paramsParcel.tlsName = strictMode ? privateDnsCfg.hostname : ""; + paramsParcel.tlsServers = strictMode ? NetworkUtils.makeStrings( Arrays.stream(privateDnsCfg.ips) .filter((ip) -> lp.isReachable(ip)) .collect(Collectors.toList())) - : useTls ? assignedServers // Opportunistic + : useTls ? paramsParcel.servers // Opportunistic : new String[0]; // Off - + paramsParcel.tlsFingerprints = new String[0]; // Prepare to track the validation status of the DNS servers in the // resolver config when private DNS is in opportunistic or strict mode. if (useTls) { if (!mPrivateDnsValidationMap.containsKey(netId)) { mPrivateDnsValidationMap.put(netId, new PrivateDnsValidationStatuses()); } - mPrivateDnsValidationMap.get(netId).updateTrackedDnses(tlsServers, tlsHostname); + mPrivateDnsValidationMap.get(netId).updateTrackedDnses(paramsParcel.tlsServers, + paramsParcel.tlsName); } else { mPrivateDnsValidationMap.remove(netId); } - Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)", - netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs), - Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers))); - final String[] tlsFingerprints = new String[0]; + Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, " + + "%d, %d, %s, %s)", paramsParcel.netId, Arrays.toString(paramsParcel.servers), + Arrays.toString(paramsParcel.domains), paramsParcel.sampleValiditySeconds, + paramsParcel.successThreshold, paramsParcel.minSamples, + paramsParcel.maxSamples, paramsParcel.baseTimeoutMsec, + paramsParcel.retryCount, paramsParcel.tlsName, + Arrays.toString(paramsParcel.tlsServers))); + try { - mDnsResolver.setResolverConfiguration( - netId, assignedServers, domainStrs, params, - tlsHostname, tlsServers, tlsFingerprints); + mDnsResolver.setResolverConfiguration(paramsParcel); } catch (RemoteException | ServiceSpecificException e) { Slog.e(TAG, "Error setting DNS configuration: " + e); return; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 3c336eac1ae6..a25f8c082d71 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -598,6 +598,8 @@ public class PackageManagerService extends IPackageManager.Stub private static final String ODM_OVERLAY_DIR = "/odm/overlay"; + private static final String OEM_OVERLAY_DIR = "/oem/overlay"; + /** Canonical intent used to identify what counts as a "web browser" app */ private static final Intent sBrowserIntent; static { @@ -2631,6 +2633,13 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_SYSTEM | SCAN_AS_ODM, 0); + scanDirTracedLI(new File(OEM_OVERLAY_DIR), + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_OEM, + 0); mParallelPackageParserCallback.findStaticOverlayPackages(); diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index 654c47780f4a..0e20905db32a 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -39,7 +39,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.database.CursorWindow; -import android.os.AsyncTask; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -201,8 +200,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C // Package is being upgraded - we're about to get ACTION_PACKAGE_ADDED return; } - AsyncTask.THREAD_POOL_EXECUTOR.execute( - () -> performInitialGrantsIfNecessaryAsync(userId)); + performInitialGrantsIfNecessaryAsync(userId); } }, UserHandle.ALL, intentFilter, null, null); } diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java index 9f7cb3d35ecb..6318486683ae 100644 --- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java +++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java @@ -129,7 +129,7 @@ class AppWindowThumbnail implements Animatable { mSurfaceAnimator.startAnimation(t, new LocalAnimationAdapter( new WindowAnimationSpec(anim, position, mAppToken.getDisplayContent().mAppTransition.canSkipFirstFrame(), - mAppToken.mWmService.mWindowCornerRadius), + mAppToken.getWindowCornerRadiusForAnimation()), mAppToken.mWmService.mSurfaceAnimationRunner), false /* hidden */); } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index a53f85daaa25..155ab41288e9 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -21,8 +21,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.ActivityInfo.COLOR_MODE_DEFAULT; -import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; -import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; @@ -2542,7 +2540,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree getDisplayContent().mAppTransition.canSkipFirstFrame(), appStackClipMode, true /* isAppAnimation */, - mWmService.mWindowCornerRadius), + getWindowCornerRadiusForAnimation()), mWmService.mSurfaceAnimationRunner); if (a.getZAdjustment() == Animation.ZORDER_TOP) { mNeedsZBoost = true; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 4105487c88ca..c29b132836a5 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -4553,7 +4553,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP anim.scaleCurrentDuration(mWmService.getWindowAnimationScaleLocked()); final AnimationAdapter adapter = new LocalAnimationAdapter( new WindowAnimationSpec(anim, mSurfacePosition, false /* canSkipFirstFrame */, - mWmService.mWindowCornerRadius), + mToken.getWindowCornerRadiusForAnimation()), mWmService.mSurfaceAnimationRunner); startAnimation(mPendingTransaction, adapter); commitPendingTransaction(); diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index f0b9c62f2843..f65f0ab62f69 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -345,4 +345,8 @@ class WindowToken extends WindowContainer<WindowState> { mOwnerCanManageAppTokens); return mOwnerCanManageAppTokens && (layer > navLayer); } + + float getWindowCornerRadiusForAnimation() { + return mDisplayContent.isDefaultDisplay ? mWmService.mWindowCornerRadius : 0; + } } diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java index 3f9a57e07876..3cdadd58486f 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java @@ -19,7 +19,6 @@ package com.android.server.om; import static android.content.om.OverlayInfo.STATE_DISABLED; import static android.content.om.OverlayInfo.STATE_ENABLED; import static android.content.om.OverlayInfo.STATE_MISSING_TARGET; -import static android.content.om.OverlayInfo.STATE_TARGET_IS_BEING_REPLACED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -172,8 +171,9 @@ public class OverlayManagerServiceImplTests { mImpl.setEnabled(OVERLAY, true, USER); assertState(STATE_ENABLED, OVERLAY, USER); + // target upgrades do not change the state of the overlay beginUpgradeTargetPackage(TARGET, USER); - assertState(STATE_TARGET_IS_BEING_REPLACED, OVERLAY, USER); + assertState(STATE_ENABLED, OVERLAY, USER); endUpgradeTargetPackage(TARGET, USER); assertState(STATE_ENABLED, OVERLAY, USER); diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java index d41a5d68912e..f9304f242ef3 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java @@ -39,6 +39,7 @@ import android.util.Log; import androidx.test.InstrumentationRegistry; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -774,6 +775,40 @@ public class RollbackTest { } } + @Test + @Ignore("b/120200473") + /** + * Test rollback when app is updated to its same version. + */ + public void testSameVersionUpdate() throws Exception { + try { + RollbackTestUtils.adoptShellPermissionIdentity( + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.DELETE_PACKAGES, + Manifest.permission.TEST_MANAGE_ROLLBACKS); + RollbackManager rm = RollbackTestUtils.getRollbackManager(); + + RollbackTestUtils.uninstall(TEST_APP_A); + RollbackTestUtils.install("RollbackTestAppAv1.apk", false); + RollbackTestUtils.install("RollbackTestAppAv2.apk", true); + RollbackTestUtils.install("RollbackTestAppACrashingV2.apk", true); + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + + RollbackInfo rollback = getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TEST_APP_A); + assertRollbackInfoEquals(TEST_APP_A, 2, 2, rollback); + + RollbackTestUtils.rollback(rollback.getRollbackId()); + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + + rollback = getUniqueRollbackInfoForPackage( + rm.getRecentlyCommittedRollbacks(), TEST_APP_A); + assertRollbackInfoEquals(TEST_APP_A, 2, 2, rollback); + } finally { + RollbackTestUtils.dropShellPermissionIdentity(); + } + } + /** * Test bad update automatic rollback. */ diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 44380cce1c77..5f08a347eefd 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -131,6 +131,7 @@ import android.net.NetworkStackClient; import android.net.NetworkState; import android.net.NetworkUtils; import android.net.ProxyInfo; +import android.net.ResolverParamsParcel; import android.net.RouteInfo; import android.net.SocketKeepalive; import android.net.UidRange; @@ -262,7 +263,8 @@ public class ConnectivityServiceTest { @Mock INetd mMockNetd; @Mock NetworkStackClient mNetworkStack; - private ArgumentCaptor<String[]> mStringArrayCaptor = ArgumentCaptor.forClass(String[].class); + private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor = + ArgumentCaptor.forClass(ResolverParamsParcel.class); // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods // do not go through ConnectivityService but talk to netd directly, so they don't automatically @@ -4819,16 +4821,13 @@ public class ConnectivityServiceTest { @Test public void testBasicDnsConfigurationPushed() throws Exception { setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); - ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class); // Clear any interactions that occur as a result of CS starting up. reset(mMockDnsResolver); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); waitForIdle(); - verify(mMockDnsResolver, never()).setResolverConfiguration( - anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), - eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); + verify(mMockDnsResolver, never()).setResolverConfiguration(any()); verifyNoMoreInteractions(mMockDnsResolver); final LinkProperties cellLp = new LinkProperties(); @@ -4846,35 +4845,33 @@ public class ConnectivityServiceTest { mCellNetworkAgent.connect(false); waitForIdle(); // CS tells netd about the empty DNS config for this network. - verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), - eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); + verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any()); reset(mMockDnsResolver); cellLp.addDnsServer(InetAddress.getByName("2001:db8::1")); mCellNetworkAgent.sendLinkProperties(cellLp); waitForIdle(); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY)); - assertEquals(1, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "2001:db8::1")); + mResolverParamsParcelCaptor.capture()); + ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(1, resolvrParams.servers.length); + assertTrue(ArrayUtils.contains(resolvrParams.servers, "2001:db8::1")); // Opportunistic mode. - assertTrue(ArrayUtils.contains(tlsServers.getValue(), "2001:db8::1")); + assertTrue(ArrayUtils.contains(resolvrParams.tlsServers, "2001:db8::1")); reset(mMockDnsResolver); cellLp.addDnsServer(InetAddress.getByName("192.0.2.1")); mCellNetworkAgent.sendLinkProperties(cellLp); waitForIdle(); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY)); - assertEquals(2, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), + mResolverParamsParcelCaptor.capture()); + resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(2, resolvrParams.servers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.servers, new String[]{"2001:db8::1", "192.0.2.1"})); // Opportunistic mode. - assertEquals(2, tlsServers.getValue().length); - assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), + assertEquals(2, resolvrParams.tlsServers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers, new String[]{"2001:db8::1", "192.0.2.1"})); reset(mMockDnsResolver); @@ -4887,18 +4884,16 @@ public class ConnectivityServiceTest { waitForIdle(); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(TLS_SPECIFIER), eq(TLS_SERVERS), eq(EMPTY_STRING_ARRAY)); - assertEquals(2, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), + mResolverParamsParcelCaptor.capture()); + resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(2, resolvrParams.servers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.servers, new String[]{"2001:db8::1", "192.0.2.1"})); reset(mMockDnsResolver); } @Test public void testPrivateDnsSettingsChange() throws Exception { - ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class); - // Clear any interactions that occur as a result of CS starting up. reset(mMockDnsResolver); @@ -4913,9 +4908,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); waitForIdle(); // CS tells netd about the empty DNS config for this network. - verify(mMockDnsResolver, never()).setResolverConfiguration( - anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), - eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); + verify(mMockDnsResolver, never()).setResolverConfiguration(any()); verifyNoMoreInteractions(mMockDnsResolver); final LinkProperties cellLp = new LinkProperties(); @@ -4936,14 +4929,14 @@ public class ConnectivityServiceTest { mCellNetworkAgent.connect(false); waitForIdle(); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY)); - assertEquals(2, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), + mResolverParamsParcelCaptor.capture()); + ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(2, resolvrParams.tlsServers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers, new String[]{"2001:db8::1", "192.0.2.1"})); // Opportunistic mode. - assertEquals(2, tlsServers.getValue().length); - assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), + assertEquals(2, resolvrParams.tlsServers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers, new String[]{"2001:db8::1", "192.0.2.1"})); reset(mMockDnsResolver); cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent); @@ -4958,23 +4951,23 @@ public class ConnectivityServiceTest { setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com"); verify(mMockDnsResolver, times(1)).setResolverConfiguration( - anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); - assertEquals(2, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), + mResolverParamsParcelCaptor.capture()); + resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(2, resolvrParams.servers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.servers, new String[]{"2001:db8::1", "192.0.2.1"})); reset(mMockDnsResolver); cellNetworkCallback.assertNoCallback(); setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY)); - assertEquals(2, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), + mResolverParamsParcelCaptor.capture()); + resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(2, resolvrParams.servers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.servers, new String[]{"2001:db8::1", "192.0.2.1"})); - assertEquals(2, tlsServers.getValue().length); - assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), + assertEquals(2, resolvrParams.tlsServers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers, new String[]{"2001:db8::1", "192.0.2.1"})); reset(mMockDnsResolver); cellNetworkCallback.assertNoCallback(); @@ -5826,9 +5819,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent.sendLinkProperties(cellLp); networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId); - verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - eq(cellNetId), eq(EMPTY_STRING_ARRAY), any(), any(), - eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); + verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any()); verifyNoMoreInteractions(mMockNetd); verifyNoMoreInteractions(mMockDnsResolver); @@ -5871,10 +5862,10 @@ public class ConnectivityServiceTest { assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0)); verify(mMockDnsResolver, times(1)).setResolverConfiguration( - eq(cellNetId), mStringArrayCaptor.capture(), any(), any(), - eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); - assertEquals(1, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "8.8.8.8")); + mResolverParamsParcelCaptor.capture()); + ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(1, resolvrParams.servers.length); + assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8")); // Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked // linkproperties are cleaned up. diff --git a/wifi/java/android/net/wifi/WifiSsid.java b/wifi/java/android/net/wifi/WifiSsid.java index fd59390a87c0..70ca0882d7da 100644 --- a/wifi/java/android/net/wifi/WifiSsid.java +++ b/wifi/java/android/net/wifi/WifiSsid.java @@ -129,6 +129,8 @@ public class WifiSsid implements Parcelable { val = Integer.parseInt(asciiEncoded.substring(i, i + 2), HEX_RADIX); } catch (NumberFormatException e) { val = -1; + } catch (StringIndexOutOfBoundsException e) { + val = -1; } if (val < 0) { val = Character.digit(asciiEncoded.charAt(i), HEX_RADIX); |