Merge "UsageStats: detach dedicated handler thread flag" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 5772fb4..2d10c05 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -19675,6 +19675,7 @@
public final class CaptureRequest extends android.hardware.camera2.CameraMetadata<android.hardware.camera2.CaptureRequest.Key<?>> implements android.os.Parcelable {
method public int describeContents();
+ method @FlaggedApi("com.android.internal.camera.flags.surface_leak_fix") protected void finalize();
method @Nullable public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
method @NonNull public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getKeys();
method @Nullable public Object getTag();
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 66efccd1..c0db77c 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -309,6 +309,8 @@
private Object mUserTag;
+ private boolean mReleaseSurfaces = false;
+
/**
* Construct empty request.
*
@@ -610,6 +612,9 @@
Parcelable[] parcelableArray = in.readParcelableArray(Surface.class.getClassLoader(),
Surface.class);
if (parcelableArray != null) {
+ if (Flags.surfaceLeakFix()) {
+ mReleaseSurfaces = true;
+ }
for (Parcelable p : parcelableArray) {
Surface s = (Surface) p;
mSurfaceSet.add(s);
@@ -792,6 +797,17 @@
}
}
+ @SuppressWarnings("Finalize")
+ @FlaggedApi(Flags.FLAG_SURFACE_LEAK_FIX)
+ @Override
+ protected void finalize() {
+ if (mReleaseSurfaces) {
+ for (Surface s : mSurfaceSet) {
+ s.release();
+ }
+ }
+ }
+
/**
* A builder for capture requests.
*
diff --git a/core/java/android/hardware/camera2/extension/SessionProcessor.java b/core/java/android/hardware/camera2/extension/SessionProcessor.java
index 2e428e5..0ec5c0a 100644
--- a/core/java/android/hardware/camera2/extension/SessionProcessor.java
+++ b/core/java/android/hardware/camera2/extension/SessionProcessor.java
@@ -363,11 +363,20 @@
private final class SessionProcessorImpl extends ISessionProcessorImpl.Stub {
private long mVendorId = -1;
+ OutputSurface mImageCaptureSurface;
+ OutputSurface mPreviewSurface;
+ OutputSurface mPostviewSurface;
+
@Override
public CameraSessionConfig initSession(IBinder token, String cameraId,
Map<String, CameraMetadataNative> charsMap, OutputSurface previewSurface,
OutputSurface imageCaptureSurface, OutputSurface postviewSurface)
throws RemoteException {
+ if (Flags.surfaceLeakFix()) {
+ mPreviewSurface = previewSurface;
+ mPostviewSurface = postviewSurface;
+ mImageCaptureSurface = imageCaptureSurface;
+ }
ExtensionConfiguration config = SessionProcessor.this.initSession(token, cameraId,
new CharacteristicsMap(charsMap),
new CameraOutputSurface(previewSurface),
@@ -390,6 +399,17 @@
@Override
public void deInitSession(IBinder token) throws RemoteException {
SessionProcessor.this.deInitSession(token);
+ if (Flags.surfaceLeakFix()) {
+ if ((mPreviewSurface != null) && (mPreviewSurface.surface != null)) {
+ mPreviewSurface.surface.release();
+ }
+ if ((mImageCaptureSurface != null) && (mImageCaptureSurface.surface != null)) {
+ mImageCaptureSurface.surface.release();
+ }
+ if ((mPostviewSurface != null) && (mPostviewSurface.surface != null)) {
+ mPostviewSurface.surface.release();
+ }
+ }
}
@Override
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 62473c5..4328d9f 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -28,6 +28,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
+import android.app.AppGlobals;
import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;
@@ -393,15 +394,34 @@
*
* @hide
*/
- public static boolean isStylusPointerIconEnabled(@NonNull Context context) {
+ public static boolean isStylusPointerIconEnabled(@NonNull Context context,
+ boolean forceReloadSetting) {
if (InputProperties.force_enable_stylus_pointer_icon().orElse(false)) {
+ // Sysprop override is set
return true;
}
- return context.getResources()
- .getBoolean(com.android.internal.R.bool.config_enableStylusPointerIcon)
- && Settings.Secure.getIntForUser(context.getContentResolver(),
- Settings.Secure.STYLUS_POINTER_ICON_ENABLED,
- DEFAULT_STYLUS_POINTER_ICON_ENABLED, UserHandle.USER_CURRENT_OR_SELF) != 0;
+ if (!context.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableStylusPointerIcon)) {
+ // Stylus pointer icons are disabled for the build
+ return false;
+ }
+ if (forceReloadSetting) {
+ return Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.STYLUS_POINTER_ICON_ENABLED,
+ DEFAULT_STYLUS_POINTER_ICON_ENABLED, UserHandle.USER_CURRENT_OR_SELF) != 0;
+ }
+ return AppGlobals.getIntCoreSetting(Settings.Secure.STYLUS_POINTER_ICON_ENABLED,
+ DEFAULT_STYLUS_POINTER_ICON_ENABLED) != 0;
+ }
+
+ /**
+ * Whether a pointer icon will be shown over the location of a stylus pointer.
+ *
+ * @hide
+ * @see #isStylusPointerIconEnabled(Context, boolean)
+ */
+ public static boolean isStylusPointerIconEnabled(@NonNull Context context) {
+ return isStylusPointerIconEnabled(context, false /* forceReloadSetting */);
}
/**
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index b1c24a7..90279c6 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -103,3 +103,6 @@
# ProfilingService
per-file ProfilingServiceManager.java = file:/PERFORMANCE_OWNERS
+
+# Memory
+per-file OomKillRecord.java = file:/MEMORY_OWNERS
\ No newline at end of file
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index b669814..8a17742 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -1259,6 +1259,24 @@
}
/**
+ * Reboot into recovery and wipe the data partition with ext4
+ *
+ * @throws IOException if something goes wrong.
+ *
+ * @hide
+ */
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.RECOVERY,
+ android.Manifest.permission.REBOOT
+ })
+ public void wipePartitionToExt4()
+ throws IOException {
+ // Reformat /data partition with ext4
+ String command = "--wipe_data\n--reformat_data=ext4";
+ rebootRecoveryWithCommand(command);
+ }
+
+ /**
* Reboot into the recovery system with the supplied argument.
* @param args to pass to the recovery utility.
* @throws IOException if something goes wrong.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index fbefbf3..52ff142 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3732,6 +3732,11 @@
return afm.shouldAlwaysIncludeWebviewInAssistStructure();
}
+ private boolean shouldIncludeInvisibleView(AutofillManager afm) {
+ if (afm == null) return false;
+ return afm.shouldIncludeInvisibleViewInAssistStructure();
+ }
+
/** @hide */
private void populateChildrenForAutofill(ArrayList<View> list, @AutofillFlags int flags) {
final int childrenCount = mChildrenCount;
@@ -3754,7 +3759,7 @@
|| (shouldIncludeAllChildrenViewWithAutofillTypeNotNone(afm)
&& child.getAutofillType() != AUTOFILL_TYPE_NONE)
|| shouldIncludeAllChildrenViews(afm)
- || (Flags.includeInvisibleViewGroupInAssistStructure()
+ || (shouldIncludeInvisibleView(afm)
&& child instanceof ViewGroup && child.getVisibility() != View.VISIBLE)) {
// If the child is a ViewGroup object and its visibility is not visible, include
// it as part of the assist structure. The children of these invisible ViewGroup
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index ae4a7d3..9708591 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -48,6 +48,7 @@
import android.content.res.Resources;
import android.os.Binder;
import android.os.Build;
+import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
@@ -67,6 +68,8 @@
import android.view.accessibility.AccessibilityEvent.EventType;
import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
+import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IntPair;
@@ -78,6 +81,8 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.Executor;
/**
@@ -189,11 +194,13 @@
* <p>Note: Keep in sync with {@link #SHORTCUT_TYPES}.</p>
* @hide
*/
+ // TODO(b/323686675): reuse the one defined in ShortcutConstants
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
// LINT.IfChange(shortcut_type_intdef)
ACCESSIBILITY_BUTTON,
- ACCESSIBILITY_SHORTCUT_KEY
+ ACCESSIBILITY_SHORTCUT_KEY,
+ UserShortcutType.QUICK_SETTINGS,
// LINT.ThenChange(:shortcut_type_array)
})
public @interface ShortcutType {}
@@ -207,6 +214,7 @@
// LINT.IfChange(shortcut_type_array)
ACCESSIBILITY_BUTTON,
ACCESSIBILITY_SHORTCUT_KEY,
+ UserShortcutType.QUICK_SETTINGS,
// LINT.ThenChange(:shortcut_type_intdef)
};
@@ -1631,6 +1639,74 @@
}
/**
+ * Turns on or off a shortcut type of the accessibility features. The shortcut type is one
+ * of the shortcut defined in the {@link ShortcutConstants.USER_SHORTCUT_TYPES}.
+ *
+ * @throws SecurityException if the app does not hold the
+ * {@link Manifest.permission#MANAGE_ACCESSIBILITY} permission
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
+ public void enableShortcutsForTargets(boolean enable,
+ @UserShortcutType int shortcutTypes, @NonNull Set<String> targets,
+ @UserIdInt int userId) {
+ final IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return;
+ }
+ }
+ try {
+ service.enableShortcutsForTargets(
+ enable, shortcutTypes, targets.stream().toList(), userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns accessibility feature's component and the provided tile map. This includes the
+ * TileService provided by the AccessibilityService or Accessibility Activity and the tile
+ * component provided by the framework's feature.
+ *
+ * @return a map of a feature's component name, and its provided tile's component name. The
+ * returned map's keys and values are not null. If a feature doesn't provide a tile, it won't
+ * have an entry in this map.
+ * @hide
+ * @see ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
+ @NonNull
+ public Map<ComponentName, ComponentName> getA11yFeatureToTileMap(@UserIdInt int userId) {
+ final IAccessibilityManager service;
+ Map<ComponentName, ComponentName> a11yFeatureToTileMap = new ArrayMap<>();
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return a11yFeatureToTileMap;
+ }
+ }
+ try {
+ Bundle a11yFeatureToTile = service.getA11yFeatureToTileMap(userId);
+ for (String key : a11yFeatureToTile.keySet()) {
+ ComponentName feature = ComponentName.unflattenFromString(key);
+ if (feature == null) {
+ continue;
+ }
+ ComponentName tileService = a11yFeatureToTile.getParcelable(key,
+ ComponentName.class);
+ if (tileService != null) {
+ a11yFeatureToTileMap.put(feature, tileService);
+ }
+ }
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ return a11yFeatureToTileMap;
+ }
+
+ /**
* Register the provided {@link RemoteAction} with the given actionId
* <p>
* To perform established system actions, an accessibility service uses the GLOBAL_ACTION
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 9617606..e215950 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -22,6 +22,7 @@
import android.accessibilityservice.IAccessibilityServiceClient;
import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
+import android.os.Bundle;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -143,4 +144,10 @@
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE)")
oneway void notifyQuickSettingsTilesChanged(int userId, in List<ComponentName> tileComponentNames);
+
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY)")
+ oneway void enableShortcutsForTargets(boolean enable, int shortcutTypes, in List<String> shortcutTargets, int userId);
+
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY)")
+ Bundle getA11yFeatureToTileMap(int userId);
}
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index 334c2b77..1acfc1b 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -220,6 +220,19 @@
DEVICE_CONFIG_ALWAYS_INCLUDE_WEBVIEW_IN_ASSIST_STRUCTURE =
"always_include_webview_in_assist_structure";
+ /**
+ * Whether to include invisible views in the assist structure. Including invisible views can fix
+ * some cases in which Session is destroyed earlier than it is suppose to.
+ *
+ * <p>See
+ * frameworks/base/services/autofill/bugfixes.aconfig#include_invisible_view_group_in_assist_structure
+ * for more information.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_INCLUDE_INVISIBLE_VIEW_GROUP_IN_ASSIST_STRUCTURE =
+ "include_invisible_view_group_in_assist_structure";
+
// END AUTOFILL FOR ALL APPS FLAGS //
@@ -473,6 +486,13 @@
DEVICE_CONFIG_ALWAYS_INCLUDE_WEBVIEW_IN_ASSIST_STRUCTURE, true);
}
+ /** @hide */
+ public static boolean shouldIncludeInvisibleViewInAssistStructure() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_INCLUDE_INVISIBLE_VIEW_GROUP_IN_ASSIST_STRUCTURE,
+ false);
+ }
/**
* Whether should enable multi-line filter
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 3ee8307..1484bfb 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -739,6 +739,9 @@
// Indicate whether WebView should always be included in the assist structure
private boolean mShouldAlwaysIncludeWebviewInAssistStructure;
+ // Indicate whether invisibles views should be included in the assist structure
+ private boolean mShouldIncludeInvisibleViewInAssistStructure;
+
// Controls logic around apps changing some properties of their views when activity loses
// focus due to autofill showing biometric activity, password manager, or password breach check.
private boolean mRelayoutFix;
@@ -968,6 +971,9 @@
mShouldAlwaysIncludeWebviewInAssistStructure =
AutofillFeatureFlags.shouldAlwaysIncludeWebviewInAssistStructure();
+ mShouldIncludeInvisibleViewInAssistStructure =
+ AutofillFeatureFlags.shouldIncludeInvisibleViewInAssistStructure();
+
mRelayoutFix = Flags.relayout();
mIsCredmanIntegrationEnabled = Flags.autofillCredmanIntegration();
}
@@ -1055,6 +1061,13 @@
}
/**
+ * @hide
+ */
+ public boolean shouldIncludeInvisibleViewInAssistStructure() {
+ return mShouldIncludeInvisibleViewInAssistStructure;
+ }
+
+ /**
* Get the denied or allowed activitiy names under specified package from the list string and
* set it in fields accordingly
*
diff --git a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
index 7ec8838..c08968d 100644
--- a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
+++ b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
@@ -16,10 +16,23 @@
package com.android.internal.accessibility.common;
+import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_TILE_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.FONT_SIZE_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.FONT_SIZE_TILE_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.ONE_HANDED_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.ONE_HANDED_TILE_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME;
+
import android.annotation.IntDef;
+import android.content.ComponentName;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Map;
/**
* Collection of common constants for accessibility shortcut.
@@ -44,6 +57,10 @@
* choose accessibility shortcut as preferred shortcut.
* {@code TRIPLETAP} for displaying specifying magnification to be toggled via quickly
* tapping screen 3 times as preferred shortcut.
+ * {@code TWOFINGER_DOUBLETAP} for displaying specifying magnification to be toggled via
+ * quickly tapping screen 2 times with two fingers as preferred shortcut.
+ * {@code QUICK_SETTINGS} for displaying specifying the accessibility services or features which
+ * choose Quick Settings as preferred shortcut.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({
@@ -51,12 +68,18 @@
UserShortcutType.SOFTWARE,
UserShortcutType.HARDWARE,
UserShortcutType.TRIPLETAP,
+ UserShortcutType.TWOFINGER_DOUBLETAP,
+ UserShortcutType.QUICK_SETTINGS,
})
public @interface UserShortcutType {
int DEFAULT = 0;
- int SOFTWARE = 1; // 1 << 0
- int HARDWARE = 2; // 1 << 1
- int TRIPLETAP = 4; // 1 << 2
+ // LINT.IfChange(shortcut_type_intdef)
+ int SOFTWARE = 1 << 0;
+ int HARDWARE = 1 << 1;
+ int TRIPLETAP = 1 << 2;
+ int TWOFINGER_DOUBLETAP = 1 << 3;
+ int QUICK_SETTINGS = 1 << 4;
+ // LINT.ThenChange(:shortcut_type_array)
}
/**
@@ -64,9 +87,13 @@
* non-default IntDef types.
*/
public static final int[] USER_SHORTCUT_TYPES = {
+ // LINT.IfChange(shortcut_type_array)
UserShortcutType.SOFTWARE,
UserShortcutType.HARDWARE,
- UserShortcutType.TRIPLETAP
+ UserShortcutType.TRIPLETAP,
+ UserShortcutType.TWOFINGER_DOUBLETAP,
+ UserShortcutType.QUICK_SETTINGS,
+ // LINT.ThenChange(:shortcut_type_intdef)
};
@@ -109,4 +136,30 @@
int LAUNCH = 0;
int EDIT = 1;
}
+
+ /**
+ * Annotation for different FAB shortcut type's menu size
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ FloatingMenuSize.UNKNOWN,
+ FloatingMenuSize.SMALL,
+ FloatingMenuSize.LARGE,
+ })
+ public @interface FloatingMenuSize {
+ int UNKNOWN = -1;
+ int SMALL = 0;
+ int LARGE = 1;
+ }
+
+ /**
+ * A map of a11y feature to its qs tile component
+ */
+ public static final Map<ComponentName, ComponentName> A11Y_FEATURE_TO_FRAMEWORK_TILE = Map.of(
+ COLOR_INVERSION_COMPONENT_NAME, COLOR_INVERSION_TILE_COMPONENT_NAME,
+ DALTONIZER_COMPONENT_NAME, DALTONIZER_TILE_COMPONENT_NAME,
+ ONE_HANDED_COMPONENT_NAME, ONE_HANDED_TILE_COMPONENT_NAME,
+ REDUCE_BRIGHT_COLORS_COMPONENT_NAME, REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME,
+ FONT_SIZE_COMPONENT_NAME, FONT_SIZE_TILE_COMPONENT_NAME
+ );
}
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
index 4f9fc39..e8472d4 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
@@ -70,6 +70,13 @@
public @interface A11yTextChangeType {
}
+ /** Denotes the accessibility enabled status */
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface State {
+ int OFF = 0;
+ int ON = 1;
+ }
+
/** Specifies no content has been changed for accessibility. */
public static final int NONE = 0;
/** Specifies some readable sequence has been changed. */
diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
index 3fd3030..f9c4d37 100644
--- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
+++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
@@ -53,10 +53,13 @@
* Opts in component id into colon-separated {@link UserShortcutType}
* key's string from Settings.
*
- * @param context The current context.
+ * @param context The current context.
* @param shortcutType The preferred shortcut type user selected.
- * @param componentId The component id that need to be opted in Settings.
+ * @param componentId The component id that need to be opted in Settings.
+ * @deprecated Use
+ * {@link AccessibilityManager#enableShortcutsForTargets(boolean, int, Set, int)}
*/
+ @Deprecated
public static void optInValueToSettings(Context context, @UserShortcutType int shortcutType,
@NonNull String componentId) {
final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR));
@@ -83,7 +86,11 @@
* @param context The current context.
* @param shortcutType The preferred shortcut type user selected.
* @param componentId The component id that need to be opted out of Settings.
+ *
+ * @deprecated Use
+ * {@link AccessibilityManager#enableShortcutForTargets(boolean, int, Set, int)}
*/
+ @Deprecated
public static void optOutValueFromSettings(
Context context, @UserShortcutType int shortcutType, @NonNull String componentId) {
final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR));
@@ -166,6 +173,10 @@
return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
case UserShortcutType.TRIPLETAP:
return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED;
+ case UserShortcutType.TWOFINGER_DOUBLETAP:
+ return Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED;
+ case UserShortcutType.QUICK_SETTINGS:
+ return Settings.Secure.ACCESSIBILITY_QS_TARGETS;
default:
throw new IllegalArgumentException(
"Unsupported user shortcut type: " + type);
@@ -252,10 +263,13 @@
* If you just want to know the current state, you can use
* {@link AccessibilityManager#getAccessibilityShortcutTargets(int)}
*/
+ @NonNull
public static Set<String> getShortcutTargetsFromSettings(
Context context, @UserShortcutType int shortcutType, int userId) {
final String targetKey = convertToKey(shortcutType);
- if (Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED.equals(targetKey)) {
+ if (Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED.equals(targetKey)
+ || Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED
+ .equals(targetKey)) {
boolean magnificationEnabled = Settings.Secure.getIntForUser(
context.getContentResolver(), targetKey, /* def= */ 0, userId) == 1;
return magnificationEnabled ? Set.of(MAGNIFICATION_CONTROLLER_NAME)
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
index e2f2554..1013bf5 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
@@ -16,13 +16,24 @@
package android.view.accessibility;
+import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_TILE_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME;
+
+import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.TestCase.assertFalse;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -34,6 +45,8 @@
import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.RemoteException;
import android.os.UserHandle;
import androidx.annotation.NonNull;
@@ -41,6 +54,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
import com.android.internal.util.IntPair;
import com.android.server.accessibility.test.MessageCapturingHandler;
@@ -54,6 +68,8 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.Executors;
/**
@@ -263,6 +279,75 @@
verify(mMockService).unregisterProxyForDisplay(proxy.getDisplayId());
}
+ @Test
+ public void getA11yFeatureToTileMap_catchRemoteExceptionAndRethrow() throws Exception {
+ AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
+ doThrow(new RemoteException(new SecurityException()))
+ .when(mMockService)
+ .getA11yFeatureToTileMap(anyInt());
+
+ Throwable rethrownException = assertThrows(RuntimeException.class,
+ () -> manager.getA11yFeatureToTileMap(UserHandle.USER_CURRENT));
+ assertThat(rethrownException.getCause().getCause()).isInstanceOf(SecurityException.class);
+ }
+
+ @Test
+ public void getA11yFeatureToTileMap_verifyServiceMethodCalled() throws Exception {
+ AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(
+ COLOR_INVERSION_COMPONENT_NAME.flattenToString(),
+ COLOR_INVERSION_TILE_COMPONENT_NAME);
+ bundle.putParcelable(
+ DALTONIZER_COMPONENT_NAME.flattenToString(),
+ DALTONIZER_TILE_COMPONENT_NAME);
+ when(mMockService.getA11yFeatureToTileMap(UserHandle.USER_CURRENT)).thenReturn(bundle);
+
+ assertThat(manager.getA11yFeatureToTileMap(UserHandle.USER_CURRENT))
+ .containsExactlyEntriesIn(Map.of(
+ COLOR_INVERSION_COMPONENT_NAME, COLOR_INVERSION_TILE_COMPONENT_NAME,
+ DALTONIZER_COMPONENT_NAME, DALTONIZER_TILE_COMPONENT_NAME
+ ));
+ verify(mMockService).getA11yFeatureToTileMap(UserHandle.USER_CURRENT);
+ }
+
+ @Test
+ public void enableShortcutsForTargets_catchRemoteExceptionAndRethrow() throws Exception {
+ AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
+ doThrow(new RemoteException(new SecurityException()))
+ .when(mMockService)
+ .enableShortcutsForTargets(anyBoolean(), anyInt(), anyList(), anyInt());
+
+ Throwable rethrownException = assertThrows(RuntimeException.class,
+ () -> manager.enableShortcutsForTargets(
+ /* enable= */ false,
+ UserShortcutType.HARDWARE,
+ Set.of(DALTONIZER_COMPONENT_NAME.flattenToString()),
+ UserHandle.USER_CURRENT
+ ));
+ assertThat(rethrownException.getCause().getCause()).isInstanceOf(SecurityException.class);
+ }
+
+ @Test
+ public void enableShortcutsForTargets_verifyServiceMethodCalled() throws Exception {
+ AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
+ int shortcutTypes = UserShortcutType.HARDWARE | UserShortcutType.TRIPLETAP;
+
+ manager.enableShortcutsForTargets(
+ /* enable= */ false,
+ shortcutTypes,
+ Set.of(DALTONIZER_COMPONENT_NAME.flattenToString()),
+ UserHandle.USER_CURRENT
+ );
+
+ verify(mMockService).enableShortcutsForTargets(
+ /* enable= */ false,
+ shortcutTypes,
+ List.of(DALTONIZER_COMPONENT_NAME.flattenToString()),
+ UserHandle.USER_CURRENT
+ );
+ }
+
private class MyAccessibilityProxy extends AccessibilityDisplayProxy {
MyAccessibilityProxy(int displayId,
@NonNull List<AccessibilityServiceInfo> serviceInfos) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 39803e2..c9669a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -318,11 +318,12 @@
relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId);
- if (captionLayoutId == R.layout.desktop_mode_app_controls_window_decor
- && TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
- // App is requesting to customize the caption bar. Allow input to fall through to the
- // windows below so that the app can respond to input events on their custom content.
- relayoutParams.mAllowCaptionInputFallthrough = true;
+ if (captionLayoutId == R.layout.desktop_mode_app_controls_window_decor) {
+ // If the app is requesting to customize the caption bar, allow input to fall through
+ // to the windows below so that the app can respond to input events on their custom
+ // content.
+ relayoutParams.mAllowCaptionInputFallthrough =
+ TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo);
// Report occluding elements as bounding rects to the insets system so that apps can
// draw in the empty space in the center:
// First, the "app chip" section of the caption bar (+ some extra margins).
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index ba3f6dd..f9b5882 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -173,7 +173,7 @@
}
@Test
- public void updateRelayoutParams_freeformAndTransparent_allowsInputFallthrough() {
+ public void updateRelayoutParams_freeformAndTransparentAppearance_allowsInputFallthrough() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
taskInfo.taskDescription.setSystemBarsAppearance(
@@ -191,7 +191,7 @@
}
@Test
- public void updateRelayoutParams_freeformButOpaque_disallowsInputFallthrough() {
+ public void updateRelayoutParams_freeformButOpaqueAppearance_disallowsInputFallthrough() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
taskInfo.taskDescription.setSystemBarsAppearance(0);
diff --git a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one_dark.xml b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_middle.xml
similarity index 60%
rename from packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one_dark.xml
rename to packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_middle.xml
index 39f49ca..781373d 100644
--- a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one_dark.xml
+++ b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_middle.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2023 The Android Open Source Project
+ ~ Copyright (C) 2024 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,16 +15,10 @@
~ limitations under the License.
-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi"
- android:color="@android:color/transparent">
- <item
- android:bottom="1dp"
- android:shape="rectangle"
- android:top="1dp">
- <shape>
- <corners android:radius="28dp" />
- <solid android:color="@android:color/system_surface_container_high_dark" />
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi">
+ <shape android:shape="rectangle">
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainer" />
</shape>
- </item>
-</ripple>
\ No newline at end of file
+</inset>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml
index f13402c..f28c354 100644
--- a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml
+++ b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml
@@ -15,16 +15,12 @@
~ limitations under the License.
-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi"
- android:color="@android:color/transparent">
- <item
- android:bottom="1dp"
- android:shape="rectangle"
- android:top="1dp">
- <shape>
- <corners android:radius="4dp" />
- <solid android:color="@color/dropdown_container" />
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi">
+ <shape android:shape="rectangle">
+ <corners android:topLeftRadius="4dp" android:topRightRadius="4dp"
+ android:bottomLeftRadius="0dp" android:bottomRightRadius="0dp"/>
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainer" />
</shape>
- </item>
-</ripple>
\ No newline at end of file
+</inset>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/more_options_list_item.xml b/packages/CredentialManager/res/drawable/more_options_list_item.xml
index d7b509e..3f9d815 100644
--- a/packages/CredentialManager/res/drawable/more_options_list_item.xml
+++ b/packages/CredentialManager/res/drawable/more_options_list_item.xml
@@ -15,17 +15,16 @@
~ limitations under the License.
-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi"
- android:color="@android:color/transparent">
- <item
- android:bottom="1dp"
- android:shape="rectangle"
- android:top="1dp">
- <shape>
- <corners android:bottomLeftRadius="4dp"
- android:bottomRightRadius="4dp"/>
- <solid android:color="@color/sign_in_options_container" />
- </shape>
- </item>
-</ripple>
\ No newline at end of file
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi"
+ android:insetLeft="-2dp"
+ android:insetRight="-2dp"
+ android:insetBottom="-2dp">
+ <shape>
+ <corners android:topLeftRadius="0dp" android:topRightRadius="0dp"
+ android:bottomLeftRadius="4dp" android:bottomRightRadius="4dp"/>
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainer"/>
+ <stroke android:color="?androidprv:attr/materialColorOutlineVariant" android:width="1dp"/>
+ </shape>
+</inset>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/layout/credman_dropdown_bottom_sheet.xml b/packages/CredentialManager/res/layout/credman_dropdown_bottom_sheet.xml
index 910ff96..7f09dd5 100644
--- a/packages/CredentialManager/res/layout/credman_dropdown_bottom_sheet.xml
+++ b/packages/CredentialManager/res/layout/credman_dropdown_bottom_sheet.xml
@@ -14,30 +14,52 @@
~ limitations under the License.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@android:id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="@dimen/dropdown_touch_target_min_height"
android:orientation="horizontal"
- android:layout_marginEnd="@dimen/dropdown_layout_horizontal_margin"
android:elevation="3dp">
- <ImageView
- android:id="@android:id/icon1"
+ <LinearLayout
+ android:id="@+id/credential_card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_alignParentStart="true"
- android:contentDescription="@string/more_options_content_description"
- android:background="@null"/>
- <TextView
- android:id="@android:id/text1"
- android:layout_width="wrap_content"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@android:id/icon1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:paddingLeft="@dimen/autofill_view_left_padding"
+ android:src="@drawable/more_horiz_24px"
+ android:tint="?androidprv:attr/materialColorOnSurface"
+ android:layout_alignParentStart="true"
+ android:contentDescription="@string/more_options_content_description"
+ android:background="@null"/>
+
+ <LinearLayout
+ android:id="@+id/text_container"
+ android:layout_width="@dimen/autofill_dropdown_textview_max_width"
android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_toEndOf="@android:id/icon1"
- android:minWidth="@dimen/autofill_dropdown_textview_min_width"
- android:maxWidth="@dimen/autofill_dropdown_textview_max_width"
- style="@style/autofill.TextTitle"/>
+ android:paddingLeft="@dimen/autofill_view_left_padding"
+ android:paddingRight="@dimen/autofill_view_right_padding"
+ android:paddingTop="@dimen/more_options_item_vertical_padding"
+ android:paddingBottom="@dimen/more_options_item_vertical_padding"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@android:id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
+ android:layout_toEndOf="@android:id/icon1"
+ style="@style/autofill.TextTitle"/>
+ </LinearLayout>
+
+ </LinearLayout>
</RelativeLayout>
diff --git a/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml b/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml
index 4bf0e99..08948d7 100644
--- a/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml
+++ b/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml
@@ -14,37 +14,60 @@
~ limitations under the License.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@android:id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="@dimen/dropdown_touch_target_min_height"
- android:layout_marginEnd="@dimen/dropdown_layout_horizontal_margin"
android:elevation="3dp">
- <ImageView
- android:id="@android:id/icon1"
+ <LinearLayout
+ android:id="@+id/credential_card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_alignParentStart="true"
- android:background="@null"/>
- <TextView
- android:id="@android:id/text1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_toEndOf="@android:id/icon1"
- android:minWidth="@dimen/autofill_dropdown_textview_min_width"
- android:maxWidth="@dimen/autofill_dropdown_textview_max_width"
- style="@style/autofill.TextTitle"/>
- <TextView
- android:id="@android:id/text2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@android:id/text1"
- android:layout_toEndOf="@android:id/icon1"
- android:minWidth="@dimen/autofill_dropdown_textview_min_width"
- android:maxWidth="@dimen/autofill_dropdown_textview_max_width"
- style="@style/autofill.TextSubtitle"/>
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@android:id/icon1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_alignParentStart="true"
+ android:paddingLeft="@dimen/autofill_view_left_padding"
+ app:tint="?androidprv:attr/materialColorOnSurface"
+ android:background="@null"/>
+
+ <LinearLayout
+ android:id="@+id/text_container"
+ android:layout_width="@dimen/autofill_dropdown_textview_max_width"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/autofill_view_left_padding"
+ android:paddingRight="@dimen/autofill_view_right_padding"
+ android:paddingTop="@dimen/autofill_view_top_padding"
+ android:paddingBottom="@dimen/autofill_view_bottom_padding"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@android:id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_toEndOf="@android:id/icon1"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
+ style="@style/autofill.TextTitle"/>
+
+ <TextView
+ android:id="@android:id/text2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/text1"
+ android:layout_toEndOf="@android:id/icon1"
+ android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"
+ style="@style/autofill.TextSubtitle"/>
+
+ </LinearLayout>
+
+ </LinearLayout>
</RelativeLayout>
diff --git a/packages/CredentialManager/res/values/colors.xml b/packages/CredentialManager/res/values/colors.xml
index b4d2eeb..9d31b35 100644
--- a/packages/CredentialManager/res/values/colors.xml
+++ b/packages/CredentialManager/res/values/colors.xml
@@ -15,14 +15,12 @@
-->
<!-- Color palette -->
-<resources>
- <!-- These colors are used for Remote Views. -->
- <color name="text_primary">#1A1B20</color>
- <color name="text_secondary">#44474F</color>
- <color name="dropdown_container">#F3F3FA</color>
- <color name="sign_in_options_container">#DADADA</color>
- <color name="sign_in_options_icon_color">#1B1B1B</color>
+<resources
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
- <!-- These colors are used for Inline Suggestions. -->
- <color name="inline_background">#FFFFFF</color>
+ <!-- These colors are used for Remote Views. -->
+ <color name="onSurface">?androidprv:attr/materialColorOnSurface</color>
+ <color name="onSurfaceVariant">?androidprv:attr/materialColorOnSurfaceVariant</color>
+ <color name="surfaceDim">?androidprv:attr/materialColorSurfaceDim</color>
+ <color name="surfaceContainer">?androidprv:attr/materialColorSurfaceContainer</color>
</resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/values/dimens.xml b/packages/CredentialManager/res/values/dimens.xml
index 82dee5c..314437e 100644
--- a/packages/CredentialManager/res/values/dimens.xml
+++ b/packages/CredentialManager/res/values/dimens.xml
@@ -18,16 +18,18 @@
<resources>
<dimen name="autofill_view_top_padding">12dp</dimen>
- <dimen name="autofill_view_right_padding">12dp</dimen>
+ <dimen name="autofill_view_right_padding">16dp</dimen>
<dimen name="autofill_view_bottom_padding">12dp</dimen>
<dimen name="autofill_view_left_padding">16dp</dimen>
- <dimen name="autofill_view_icon_to_text_padding">10dp</dimen>
+ <dimen name="autofill_view_icon_to_text_padding">16dp</dimen>
+ <dimen name="autofill_view_end_items_padding">8dp</dimen>
+ <dimen name="more_options_item_vertical_padding">14dp</dimen>
<dimen name="autofill_icon_size">24dp</dimen>
<dimen name="autofill_dropdown_textview_min_width">112dp</dimen>
<dimen name="autofill_dropdown_textview_max_width">230dp</dimen>
<dimen name="dropdown_layout_horizontal_margin">24dp</dimen>
<integer name="autofill_max_visible_datasets">4</integer>
- <dimen name="dropdown_touch_target_min_height">48dp</dimen>
+ <dimen name="dropdown_touch_target_min_height">49dp</dimen>
<dimen name="horizontal_chip_padding">8dp</dimen>
<dimen name="vertical_chip_padding">6dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 271cccb..4f2fa79 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -295,8 +295,9 @@
}
var dropdownPresentation: RemoteViews? = null
if (i < maxDatasetDisplayLimit) {
- dropdownPresentation = RemoteViewsFactory
- .createDropdownPresentation(this, icon, primaryEntry)
+ dropdownPresentation = RemoteViewsFactory.createDropdownPresentation(
+ this, icon, primaryEntry, /*isFirstEntry= */ i == 0,
+ /*isLastEntry= */ (totalEntryCount - i == 1))
}
val dataSetBuilder = Dataset.Builder()
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
index 7966a86..a46e358 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
@@ -31,12 +31,13 @@
private const val setMaxHeightMethodName = "setMaxHeight"
private const val setBackgroundResourceMethodName = "setBackgroundResource"
private const val bulletPoint = "\u2022"
- private const val passwordCharacterLength = 15
fun createDropdownPresentation(
context: Context,
icon: Icon,
- credentialEntryInfo: CredentialEntryInfo
+ credentialEntryInfo: CredentialEntryInfo,
+ isFirstEntry: Boolean,
+ isLastEntry: Boolean,
): RemoteViews {
var layoutId: Int = com.android.credentialmanager.R.layout
.credman_dropdown_presentation_layout
@@ -44,7 +45,6 @@
if (credentialEntryInfo.credentialType == CredentialType.UNKNOWN) {
return remoteViews
}
- setRemoteViewsPaddings(remoteViews, context, /* primaryTextBottomPadding=*/0)
val displayName = credentialEntryInfo.displayName ?: credentialEntryInfo.userName
remoteViews.setTextViewText(android.R.id.text1, displayName)
val secondaryText =
@@ -56,12 +56,6 @@
else (credentialEntryInfo.credentialTypeDisplayName + " " + bulletPoint + " "
+ credentialEntryInfo.providerDisplayName)
remoteViews.setTextViewText(android.R.id.text2, secondaryText)
- val textColorPrimary = ContextCompat.getColor(context,
- com.android.credentialmanager.R.color.text_primary)
- remoteViews.setTextColor(android.R.id.text1, textColorPrimary)
- val textColorSecondary = ContextCompat.getColor(context, com.android
- .credentialmanager.R.color.text_secondary)
- remoteViews.setTextColor(android.R.id.text2, textColorSecondary)
remoteViews.setImageViewIcon(android.R.id.icon1, icon);
remoteViews.setBoolean(
android.R.id.icon1, setAdjustViewBoundsMethodName, true);
@@ -73,9 +67,23 @@
remoteViews.setContentDescription(android.R.id.icon1, credentialEntryInfo
.providerDisplayName);
val drawableId =
- com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one
+ if (isFirstEntry)
+ com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one else
+ com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_middle
remoteViews.setInt(
android.R.id.content, setBackgroundResourceMethodName, drawableId);
+ if (isFirstEntry) remoteViews.setViewPadding(
+ com.android.credentialmanager.R.id.credential_card,
+ /* left=*/0,
+ /* top=*/8,
+ /* right=*/0,
+ /* bottom=*/0)
+ if (isLastEntry) remoteViews.setViewPadding(
+ com.android.credentialmanager.R.id.credential_card,
+ /*left=*/0,
+ /* top=*/0,
+ /* right=*/0,
+ /* bottom=*/8)
return remoteViews
}
@@ -83,19 +91,9 @@
var layoutId: Int = com.android.credentialmanager.R.layout
.credman_dropdown_bottom_sheet
val remoteViews = RemoteViews(context.packageName, layoutId)
- setRemoteViewsPaddings(remoteViews, context)
remoteViews.setTextViewText(android.R.id.text1, ContextCompat.getString(context,
com.android.credentialmanager
.R.string.dropdown_presentation_more_sign_in_options_text))
-
- val textColorPrimary = ContextCompat.getColor(context,
- com.android.credentialmanager.R.color.text_primary)
- remoteViews.setTextColor(android.R.id.text1, textColorPrimary)
- val icon = Icon.createWithResource(context, com
- .android.credentialmanager.R.drawable.more_horiz_24px)
- icon.setTint(ContextCompat.getColor(context,
- com.android.credentialmanager.R.color.sign_in_options_icon_color))
- remoteViews.setImageViewIcon(android.R.id.icon1, icon)
remoteViews.setBoolean(
android.R.id.icon1, setAdjustViewBoundsMethodName, true);
remoteViews.setInt(
@@ -109,50 +107,5 @@
android.R.id.content, setBackgroundResourceMethodName, drawableId);
return remoteViews
}
-
- private fun setRemoteViewsPaddings(
- remoteViews: RemoteViews, context: Context) {
- val bottomPadding = context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_view_bottom_padding)
- setRemoteViewsPaddings(remoteViews, context, bottomPadding)
- }
-
- private fun setRemoteViewsPaddings(
- remoteViews: RemoteViews, context: Context, primaryTextBottomPadding: Int) {
- val leftPadding = context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_view_left_padding)
- val iconToTextPadding = context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_view_icon_to_text_padding)
- val rightPadding = context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_view_right_padding)
- val topPadding = context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_view_top_padding)
- val bottomPadding = context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_view_bottom_padding)
- remoteViews.setViewPadding(
- android.R.id.icon1,
- leftPadding,
- /* top=*/0,
- /* right=*/0,
- /* bottom=*/0)
- remoteViews.setViewPadding(
- android.R.id.text1,
- iconToTextPadding,
- /* top=*/topPadding,
- /* right=*/rightPadding,
- primaryTextBottomPadding)
- remoteViews.setViewPadding(
- android.R.id.text2,
- iconToTextPadding,
- /* top=*/0,
- /* right=*/rightPadding,
- /* bottom=*/bottomPadding)
- }
-
- private fun isDarkMode(context: Context): Boolean {
- val currentNightMode = context.resources.configuration.uiMode and
- Configuration.UI_MODE_NIGHT_MASK
- return currentNightMode == Configuration.UI_MODE_NIGHT_YES
- }
}
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index a490b6f..30d5d4b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -268,6 +268,7 @@
Settings.Secure.EVEN_DIMMER_MIN_NITS,
Settings.Secure.STYLUS_POINTER_ICON_ENABLED,
Settings.Secure.CAMERA_EXTENSIONS_FALLBACK,
- Settings.Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED
+ Settings.Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED,
+ Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 4cdf98cb..893932f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -423,5 +423,6 @@
VALIDATORS.put(Secure.AUTOFILL_SERVICE, AUTOFILL_SERVICE_VALIDATOR);
VALIDATORS.put(Secure.STYLUS_POINTER_ICON_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.CAMERA_EXTENSIONS_FALLBACK, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.IMMERSIVE_MODE_CONFIRMATIONS, ANY_STRING_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 09d076e..46c89900 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -702,7 +702,6 @@
Settings.Secure.ENABLED_PRINT_SERVICES,
Settings.Secure.GLOBAL_ACTIONS_PANEL_AVAILABLE,
Settings.Secure.GLOBAL_ACTIONS_PANEL_DEBUG_ENABLED,
- Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR,
Settings.Secure.INPUT_METHOD_SELECTOR_VISIBILITY,
Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY,
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 40e39e9..617df74 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -155,6 +155,7 @@
"jsr330",
"lottie",
"LowLightDreamLib",
+ "TraceurCommon",
"motion_tool_lib",
"notification_flags_lib",
"PlatformComposeCore",
@@ -301,6 +302,7 @@
"androidx.compose.material_material-icons-extended",
"androidx.activity_activity-compose",
"androidx.compose.animation_animation-graphics",
+ "TraceurCommon",
],
skip_jarjar_repackage: true,
}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index d05d40d..da06830 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -610,3 +610,10 @@
description: "Refactors media code to follow the recommended architecture"
bug: "326408371"
}
+
+flag {
+ name: "qs_tile_focus_state"
+ namespace: "systemui"
+ description: "enables new focus outline for qs tiles when focused on with physical keyboard"
+ bug: "312899524"
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt
index 97c407c..970ce1f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt
@@ -47,6 +47,17 @@
private val displayRepository by lazy { kosmos.displayRepository }
@Test
+ fun propertiesInitialized() =
+ testScope.runTest {
+ val propertiesInitialized by collectLastValue(underTest.propertiesInitialized)
+ assertThat(propertiesInitialized).isFalse()
+
+ repository.supportsUdfps()
+ runCurrent()
+ assertThat(propertiesInitialized).isTrue()
+ }
+
+ @Test
fun sensorLocation_resolution1f() =
testScope.runTest {
val currSensorLocation by collectLastValue(underTest.sensorLocation)
diff --git a/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml b/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml
new file mode 100644
index 0000000..cf7a730
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+ <!-- Since this layer list has just one layer, we can remove it and replace with the inner
+ layer drawable. However this should only be done when the flag
+ com.android.systemui.qs_tile_focus_state has completed all its stages and this drawable
+ fully replaces the previous one to ensure consistency with code sections searching for
+ specific ids in drawable hierarchy -->
+ <item
+ android:id="@id/background">
+ <layer-list>
+ <item
+ android:id="@+id/qs_tile_background_base"
+ android:drawable="@drawable/qs_tile_background_shape" />
+ <item android:id="@+id/qs_tile_background_overlay">
+ <selector>
+ <item
+ android:state_hovered="true"
+ android:drawable="@drawable/qs_tile_background_shape" />
+ </selector>
+ </item>
+ <!-- In the layer below we have negative insets because we need the focus outline
+ to draw outside the bounds, around the main background. We use 5dp because
+ the outline stroke is 3dp and the required padding is 2dp.-->
+ <item
+ android:top="-5dp"
+ android:right="-5dp"
+ android:left="-5dp"
+ android:bottom="-5dp">
+ <selector>
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/qs_tile_focused_background"/>
+ </selector>
+ </item>
+ </layer-list>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_tile_focused_background.xml b/packages/SystemUI/res/drawable/qs_tile_focused_background.xml
new file mode 100644
index 0000000..fd456df
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_tile_focused_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <corners android:radius="30dp"/>
+ <stroke android:width="3dp" android:color="?androidprv:attr/materialColorSecondaryFixed"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/xml/fileprovider.xml b/packages/SystemUI/res/xml/fileprovider.xml
index b67378e..71cc05d 100644
--- a/packages/SystemUI/res/xml/fileprovider.xml
+++ b/packages/SystemUI/res/xml/fileprovider.xml
@@ -19,4 +19,5 @@
<cache-path name="leak" path="leak/"/>
<external-path name="screenrecord" path="."/>
<cache-path name="multi_user" path="multi_user/" />
-</paths>
\ No newline at end of file
+ <root-path name="traces" path="/data/local/traces"/>
+</paths>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt
index e88aaf01..aab0b1e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt
@@ -22,7 +22,6 @@
import android.content.ContentProvider
import android.content.Context
import android.content.Intent
-import android.util.Log
import androidx.core.app.AppComponentFactory
import com.android.systemui.dagger.ContextComponentHelper
import com.android.systemui.dagger.SysUIComponent
@@ -91,7 +90,8 @@
return app
}
- @UsesReflection(KeepTarget(instanceOfClassConstant = SysUIComponent::class, methodName = "inject"))
+ @UsesReflection(
+ KeepTarget(instanceOfClassConstant = SysUIComponent::class, methodName = "inject"))
override fun instantiateProviderCompat(cl: ClassLoader, className: String): ContentProvider {
val contentProvider = super.instantiateProviderCompat(cl, className)
if (contentProvider is ContextInitializer) {
@@ -103,11 +103,12 @@
.getMethod("inject", contentProvider.javaClass)
injectMethod.invoke(rootComponent, contentProvider)
} catch (e: NoSuchMethodException) {
- Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e)
+ throw RuntimeException("No injector for class: " + contentProvider.javaClass, e)
} catch (e: IllegalAccessException) {
- Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e)
+ throw RuntimeException("Injector inaccessible for class: " +
+ contentProvider.javaClass, e)
} catch (e: InvocationTargetException) {
- Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e)
+ throw RuntimeException("Error while injecting: " + contentProvider.javaClass, e)
}
initializer
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index 6d4baf4..cd3b8a6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -17,6 +17,7 @@
package com.android.systemui.accessibility.floatingmenu;
import static android.view.WindowInsets.Type.ime;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static androidx.core.view.WindowInsetsCompat.Type;
@@ -48,6 +49,7 @@
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.ArraySet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
@@ -64,6 +66,7 @@
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto;
@@ -162,35 +165,45 @@
final Runnable mDismissMenuAction = new Runnable() {
@Override
public void run() {
- mSecureSettings.putStringForUser(
- Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* value= */ "",
- UserHandle.USER_CURRENT);
+ if (android.view.accessibility.Flags.a11yQsShortcut()) {
+ mAccessibilityManager.enableShortcutsForTargets(
+ /* enable= */ false,
+ ShortcutConstants.UserShortcutType.SOFTWARE,
+ new ArraySet<>(mAccessibilityManager.getAccessibilityShortcutTargets(
+ ACCESSIBILITY_BUTTON)),
+ mSecureSettings.getRealUserHandle(UserHandle.USER_CURRENT)
+ );
+ } else {
+ mSecureSettings.putStringForUser(
+ Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, /* value= */ "",
+ UserHandle.USER_CURRENT);
- final List<ComponentName> hardwareKeyShortcutComponents =
- mAccessibilityManager.getAccessibilityShortcutTargets(
- ACCESSIBILITY_SHORTCUT_KEY)
- .stream()
- .map(ComponentName::unflattenFromString)
- .toList();
+ final List<ComponentName> hardwareKeyShortcutComponents =
+ mAccessibilityManager.getAccessibilityShortcutTargets(
+ ACCESSIBILITY_SHORTCUT_KEY)
+ .stream()
+ .map(ComponentName::unflattenFromString)
+ .toList();
- // Should disable the corresponding service when the fragment type is
- // INVISIBLE_TOGGLE, which will enable service when the shortcut is on.
- final List<AccessibilityServiceInfo> serviceInfoList =
- mAccessibilityManager.getEnabledAccessibilityServiceList(
- AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
- serviceInfoList.forEach(info -> {
- if (getAccessibilityServiceFragmentType(info) != INVISIBLE_TOGGLE) {
- return;
- }
+ // Should disable the corresponding service when the fragment type is
+ // INVISIBLE_TOGGLE, which will enable service when the shortcut is on.
+ final List<AccessibilityServiceInfo> serviceInfoList =
+ mAccessibilityManager.getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+ serviceInfoList.forEach(info -> {
+ if (getAccessibilityServiceFragmentType(info) != INVISIBLE_TOGGLE) {
+ return;
+ }
- final ComponentName serviceComponentName = info.getComponentName();
- if (hardwareKeyShortcutComponents.contains(serviceComponentName)) {
- return;
- }
+ final ComponentName serviceComponentName = info.getComponentName();
+ if (hardwareKeyShortcutComponents.contains(serviceComponentName)) {
+ return;
+ }
- setAccessibilityServiceState(getContext(), serviceComponentName, /* enabled= */
- false);
- });
+ setAccessibilityServiceState(getContext(), serviceComponentName, /* enabled= */
+ false);
+ });
+ }
mFloatingMenu.hide();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
index 0c0ed77..40d38dd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
@@ -51,6 +51,8 @@
* There is never more than one instance of the FingerprintProperty at any given time.
*/
interface FingerprintPropertyRepository {
+ /** Whether the fingerprint properties have been initialized yet. */
+ val propertiesInitialized: StateFlow<Boolean>
/** The id of fingerprint sensor. */
val sensorId: Flow<Int>
@@ -59,7 +61,7 @@
val strength: Flow<SensorStrength>
/** The types of fingerprint sensor (rear, ultrasonic, optical, etc.). */
- val sensorType: Flow<FingerprintSensorType>
+ val sensorType: StateFlow<FingerprintSensorType>
/** The sensor location relative to each physical display. */
val sensorLocations: Flow<Map<String, SensorLocationInternal>>
@@ -105,15 +107,30 @@
.stateIn(
applicationScope,
started = SharingStarted.Eagerly,
- initialValue = DEFAULT_PROPS,
+ initialValue = UNINITIALIZED_PROPS,
+ )
+
+ override val propertiesInitialized: StateFlow<Boolean> =
+ props
+ .map { it != UNINITIALIZED_PROPS }
+ .stateIn(
+ applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = props.value != UNINITIALIZED_PROPS,
)
override val sensorId: Flow<Int> = props.map { it.sensorId }
override val strength: Flow<SensorStrength> = props.map { it.sensorStrength.toSensorStrength() }
- override val sensorType: Flow<FingerprintSensorType> =
- props.map { it.sensorType.toSensorType() }
+ override val sensorType: StateFlow<FingerprintSensorType> =
+ props
+ .map { it.sensorType.toSensorType() }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = props.value.sensorType.toSensorType(),
+ )
override val sensorLocations: Flow<Map<String, SensorLocationInternal>> =
props.map {
@@ -124,6 +141,17 @@
companion object {
private const val TAG = "FingerprintPropertyRepositoryImpl"
+ private val UNINITIALIZED_PROPS =
+ FingerprintSensorPropertiesInternal(
+ -2 /* sensorId */,
+ SensorProperties.STRENGTH_CONVENIENCE,
+ 0 /* maxEnrollmentsPerUser */,
+ listOf<ComponentInfoInternal>(),
+ FingerprintSensorProperties.TYPE_UNKNOWN,
+ false /* halControlsIllumination */,
+ true /* resetLockoutRequiresHardwareAuthToken */,
+ listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT)
+ )
private val DEFAULT_PROPS =
FingerprintSensorPropertiesInternal(
-1 /* sensorId */,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
index ff9cdbd..5ae2ff0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
@@ -24,22 +24,35 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
@SysUISingleton
class FingerprintPropertyInteractor
@Inject
constructor(
+ @Application private val applicationScope: CoroutineScope,
@Application private val context: Context,
repository: FingerprintPropertyRepository,
configurationInteractor: ConfigurationInteractor,
displayStateInteractor: DisplayStateInteractor,
) {
- val isUdfps: Flow<Boolean> = repository.sensorType.map { it.isUdfps() }
+ val propertiesInitialized: StateFlow<Boolean> = repository.propertiesInitialized
+ val isUdfps: StateFlow<Boolean> =
+ repository.sensorType
+ .map { it.isUdfps() }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = repository.sensorType.value.isUdfps(),
+ )
/**
* Devices with multiple physical displays use unique display ids to determine which sensor is
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
index 72b9da6..80b52ed 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt
@@ -16,17 +16,17 @@
package com.android.systemui.deviceentry.domain.interactor
-import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.map
/** Encapsulates business logic for device entry under-display fingerprint state changes. */
@ExperimentalCoroutinesApi
@@ -34,14 +34,13 @@
class DeviceEntryUdfpsInteractor
@Inject
constructor(
+ fingerprintPropertyInteractor: FingerprintPropertyInteractor,
// TODO (b/309655554): create & use interactors for these repositories
- fingerprintPropertyRepository: FingerprintPropertyRepository,
fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
biometricSettingsRepository: BiometricSettingsRepository,
) {
/** Whether the device supports an under display fingerprint sensor. */
- val isUdfpsSupported: Flow<Boolean> =
- fingerprintPropertyRepository.sensorType.map { it.isUdfps() }
+ val isUdfpsSupported: StateFlow<Boolean> = fingerprintPropertyInteractor.isUdfps
/** Whether the under-display fingerprint sensor is enrolled and enabled for device entry. */
val isUdfpsEnrolledAndEnabled: Flow<Boolean> =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
index 0659c7c..a49b3ae 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
@@ -19,7 +19,6 @@
import android.os.Handler
import android.util.Log
-import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
@@ -30,7 +29,6 @@
import java.io.PrintWriter
import java.util.TreeMap
import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -49,7 +47,6 @@
class KeyguardBlueprintRepository
@Inject
constructor(
- configurationRepository: ConfigurationRepository,
blueprints: Set<@JvmSuppressWildcards KeyguardBlueprint>,
@Main val handler: Handler,
val assert: ThreadAssert,
@@ -60,7 +57,6 @@
TreeMap<String, KeyguardBlueprint>().apply { putAll(blueprints.associateBy { it.id }) }
val blueprint: MutableStateFlow<KeyguardBlueprint> = MutableStateFlow(blueprintIdMap[DEFAULT]!!)
val refreshTransition = MutableSharedFlow<Config>(extraBufferCapacity = 1)
- val configurationChange: Flow<Unit> = configurationRepository.onAnyConfigurationChange
private var targetTransitionConfig: Config? = null
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
index bc3f0cc..c877192 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
@@ -20,6 +20,8 @@
package com.android.systemui.keyguard.domain.interactor
import android.content.Context
+import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
+import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository
@@ -34,7 +36,9 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
@@ -47,6 +51,8 @@
private val context: Context,
private val splitShadeStateController: SplitShadeStateController,
private val clockInteractor: KeyguardClockInteractor,
+ configurationInteractor: ConfigurationInteractor,
+ fingerprintPropertyInteractor: FingerprintPropertyInteractor,
) {
/** The current blueprint for the lockscreen. */
@@ -58,11 +64,14 @@
*/
val refreshTransition = keyguardBlueprintRepository.refreshTransition
+ private val configOrPropertyChange =
+ merge(
+ configurationInteractor.onAnyConfigurationChange,
+ fingerprintPropertyInteractor.propertiesInitialized.filter { it }.map {}, // map to Unit
+ )
init {
applicationScope.launch {
- keyguardBlueprintRepository.configurationChange
- .onStart { emit(Unit) }
- .collect { updateBlueprint() }
+ configOrPropertyChange.onStart { emit(Unit) }.collect { updateBlueprint() }
}
applicationScope.launch { clockInteractor.currentClock.collect { updateBlueprint() } }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index 3fc9b42..1085f94 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -26,7 +26,6 @@
import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
-import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.LockIconView
import com.android.keyguard.LockIconViewController
import com.android.systemui.Flags.keyguardBottomAreaRefactor
@@ -56,7 +55,6 @@
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
- private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val authController: AuthController,
private val windowManager: WindowManager,
private val context: Context,
@@ -111,7 +109,12 @@
}
override fun applyConstraints(constraintSet: ConstraintSet) {
- val isUdfpsSupported = keyguardUpdateMonitor.isUdfpsSupported
+ val isUdfpsSupported =
+ if (DeviceEntryUdfpsRefactor.isEnabled) {
+ deviceEntryIconViewModel.get().isUdfpsSupported.value
+ } else {
+ authController.isUdfpsSupported
+ }
val scaleFactor: Float = authController.scaleFactor
val mBottomPaddingPx =
context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index 662a77e..4c0a949 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -20,6 +20,8 @@
import android.content.Context
import com.android.settingslib.Utils
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -30,12 +32,14 @@
import kotlinx.coroutines.flow.onStart
/** Models the UI state for the device entry icon background view. */
+@Suppress("WHEN_ENUM_CAN_BE_NULL_IN_JAVA")
@ExperimentalCoroutinesApi
class DeviceEntryBackgroundViewModel
@Inject
constructor(
val context: Context,
val deviceEntryIconViewModel: DeviceEntryIconViewModel,
+ keyguardTransitionInteractor: KeyguardTransitionInteractor,
configurationInteractor: ConfigurationInteractor,
lockscreenToAodTransitionViewModel: LockscreenToAodTransitionViewModel,
aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
@@ -94,6 +98,23 @@
alternateBouncerToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
)
.merge()
+ .onStart {
+ when (
+ keyguardTransitionInteractor.currentKeyguardState.replayCache.last()
+ ) {
+ KeyguardState.GLANCEABLE_HUB,
+ KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+ KeyguardState.GONE,
+ KeyguardState.OCCLUDED,
+ KeyguardState.OFF,
+ KeyguardState.DOZING,
+ KeyguardState.DREAMING,
+ KeyguardState.PRIMARY_BOUNCER,
+ KeyguardState.AOD -> emit(0f)
+ KeyguardState.ALTERNATE_BOUNCER,
+ KeyguardState.LOCKSCREEN -> emit(1f)
+ }
+ }
} else {
flowOf(0f)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index bd19c80..1a01897 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -36,6 +36,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
@@ -62,6 +63,7 @@
private val deviceEntryInteractor: DeviceEntryInteractor,
private val deviceEntrySourceInteractor: DeviceEntrySourceInteractor,
) {
+ val isUdfpsSupported: StateFlow<Boolean> = deviceEntryUdfpsInteractor.isUdfpsSupported
private val intEvaluator = IntEvaluator()
private val floatEvaluator = FloatEvaluator()
private val showingAlternateBouncer: Flow<Boolean> =
@@ -137,7 +139,7 @@
) { alpha, alphaMultiplier ->
alpha * alphaMultiplier
}
- val useBackgroundProtection: Flow<Boolean> = deviceEntryUdfpsInteractor.isUdfpsSupported
+ val useBackgroundProtection: StateFlow<Boolean> = isUdfpsSupported
val burnInOffsets: Flow<BurnInOffsets> =
deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolled ->
if (udfpsEnrolled) {
@@ -211,7 +213,7 @@
val isLongPressEnabled: Flow<Boolean> =
combine(
iconType,
- deviceEntryUdfpsInteractor.isUdfpsSupported,
+ isUdfpsSupported,
) { deviceEntryStatus, isUdfps ->
when (deviceEntryStatus) {
DeviceEntryIconView.IconType.LOCK -> isUdfps
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index e5af8e6..58858df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -46,7 +46,6 @@
import com.android.systemui.FontSizeUtils;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.res.R;
import com.android.systemui.qs.QSEditEvent;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.TileLayout;
@@ -57,6 +56,7 @@
import com.android.systemui.qs.dagger.QSThemedContext;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSTileViewImpl;
+import com.android.systemui.res.R;
import java.util.ArrayList;
import java.util.List;
@@ -319,6 +319,9 @@
}
FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
false);
+ if (com.android.systemui.Flags.qsTileFocusState()) {
+ frame.setClipChildren(false);
+ }
View view = new CustomizeTileView(context);
frame.addView(view);
return new Holder(frame);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 9fefcbd..6cc682a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -47,6 +47,7 @@
import androidx.annotation.VisibleForTesting
import com.android.app.tracing.traceSection
import com.android.settingslib.Utils
+import com.android.systemui.Flags
import com.android.systemui.FontSizeUtils
import com.android.systemui.animation.LaunchableView
import com.android.systemui.animation.LaunchableViewDelegate
@@ -134,7 +135,7 @@
*/
protected var showRippleEffect = true
- private lateinit var ripple: RippleDrawable
+ private lateinit var qsTileBackground: LayerDrawable
private lateinit var backgroundDrawable: LayerDrawable
private lateinit var backgroundBaseDrawable: Drawable
private lateinit var backgroundOverlayDrawable: Drawable
@@ -283,15 +284,20 @@
addView(sideView)
}
- fun createTileBackground(): Drawable {
- ripple = mContext.getDrawable(R.drawable.qs_tile_background) as RippleDrawable
- backgroundDrawable = ripple.findDrawableByLayerId(R.id.background) as LayerDrawable
+ private fun createTileBackground(): Drawable {
+ qsTileBackground = if (Flags.qsTileFocusState()) {
+ mContext.getDrawable(R.drawable.qs_tile_background_flagged) as LayerDrawable
+ } else {
+ mContext.getDrawable(R.drawable.qs_tile_background) as RippleDrawable
+ }
+ backgroundDrawable =
+ qsTileBackground.findDrawableByLayerId(R.id.background) as LayerDrawable
backgroundBaseDrawable =
backgroundDrawable.findDrawableByLayerId(R.id.qs_tile_background_base)
backgroundOverlayDrawable =
backgroundDrawable.findDrawableByLayerId(R.id.qs_tile_background_overlay)
backgroundOverlayDrawable.mutate().setTintMode(PorterDuff.Mode.SRC)
- return ripple
+ return qsTileBackground
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
@@ -366,14 +372,16 @@
override fun setClickable(clickable: Boolean) {
super.setClickable(clickable)
- background = if (clickable && showRippleEffect) {
- ripple.also {
- // In case that the colorBackgroundDrawable was used as the background, make sure
- // it has the correct callback instead of null
- backgroundDrawable.callback = it
+ if (!Flags.qsTileFocusState()){
+ background = if (clickable && showRippleEffect) {
+ qsTileBackground.also {
+ // In case that the colorBackgroundDrawable was used as the background, make sure
+ // it has the correct callback instead of null
+ backgroundDrawable.callback = it
+ }
+ } else {
+ backgroundDrawable
}
- } else {
- backgroundDrawable
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
index 20f3c4d..bd66843 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
@@ -103,14 +103,27 @@
public override fun handleClick(view: View?) {
if (isRecording) {
isRecording = false
- stopScreenRecord()
+ stopIssueRecordingService()
} else {
mUiHandler.post { showPrompt(view) }
}
refreshState()
}
- private fun stopScreenRecord() =
+ private fun startIssueRecordingService(screenRecord: Boolean, winscopeTracing: Boolean) =
+ PendingIntent.getForegroundService(
+ userContextProvider.userContext,
+ RecordingService.REQUEST_CODE,
+ IssueRecordingService.getStartIntent(
+ userContextProvider.userContext,
+ screenRecord,
+ winscopeTracing
+ ),
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ .send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle())
+
+ private fun stopIssueRecordingService() =
PendingIntent.getService(
userContextProvider.userContext,
RecordingService.REQUEST_CODE,
@@ -124,6 +137,7 @@
delegateFactory
.create {
isRecording = true
+ startIssueRecordingService(it.screenRecord, it.winscopeTracing)
refreshState()
}
.createDialog()
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingConfig.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingConfig.kt
new file mode 100644
index 0000000..bb3b654
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingConfig.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recordissue
+
+data class IssueRecordingConfig(val screenRecord: Boolean, val winscopeTracing: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
index f487258..55d7f8e 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
@@ -20,7 +20,9 @@
import android.content.Context
import android.content.Intent
import android.content.res.Resources
+import android.net.Uri
import android.os.Handler
+import android.os.UserHandle
import com.android.internal.logging.UiEventLogger
import com.android.systemui.dagger.qualifiers.LongRunning
import com.android.systemui.dagger.qualifiers.Main
@@ -30,6 +32,8 @@
import com.android.systemui.screenrecord.RecordingServiceStrings
import com.android.systemui.settings.UserContextProvider
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
+import com.android.traceur.FileSender
+import com.android.traceur.TraceUtils
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -60,9 +64,89 @@
override fun provideRecordingServiceStrings(): RecordingServiceStrings = IrsStrings(resources)
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ when (intent?.action) {
+ ACTION_START -> {
+ TraceUtils.traceStart(
+ contentResolver,
+ DEFAULT_TRACE_TAGS,
+ DEFAULT_BUFFER_SIZE,
+ DEFAULT_IS_INCLUDING_WINSCOPE,
+ DEFAULT_IS_INCLUDING_APP_TRACE,
+ DEFAULT_IS_LONG_TRACE,
+ DEFAULT_ATTACH_TO_BUGREPORT,
+ DEFAULT_MAX_TRACE_SIZE,
+ DEFAULT_MAX_TRACE_DURATION_IN_MINUTES
+ )
+ if (!intent.getBooleanExtra(EXTRA_SCREEN_RECORD, false)) {
+ // If we don't want to record the screen, the ACTION_SHOW_START_NOTIF action
+ // will circumvent the RecordingService's screen recording start code.
+ return super.onStartCommand(Intent(ACTION_SHOW_START_NOTIF), flags, startId)
+ }
+ }
+ ACTION_STOP,
+ ACTION_STOP_NOTIF -> {
+ TraceUtils.traceStop(contentResolver)
+ }
+ ACTION_SHARE -> {
+ shareRecording(intent)
+
+ // Unlike all other actions, action_share has different behavior for the screen
+ // recording qs tile than it does for the record issue qs tile. Return sticky to
+ // avoid running any of the base class' code for this action.
+ return START_STICKY
+ }
+ else -> {}
+ }
+ return super.onStartCommand(intent, flags, startId)
+ }
+
+ private fun shareRecording(intent: Intent) {
+ val files = TraceUtils.traceDump(contentResolver, TRACE_FILE_NAME).get()
+ val traceUris: MutableList<Uri> = FileSender.getUriForFiles(this, files, AUTHORITY)
+
+ if (
+ intent.hasExtra(EXTRA_PATH) && intent.getStringExtra(EXTRA_PATH)?.isNotEmpty() == true
+ ) {
+ traceUris.add(Uri.parse(intent.getStringExtra(EXTRA_PATH)))
+ }
+
+ val sendIntent =
+ FileSender.buildSendIntent(this, traceUris).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ if (mNotificationId != NOTIF_BASE_ID) {
+ val currentUserId = mUserContextTracker.userContext.userId
+ mNotificationManager.cancelAsUser(null, mNotificationId, UserHandle(currentUserId))
+ }
+
+ // TODO: Debug why the notification shade isn't closing upon starting the BetterBug activity
+ mKeyguardDismissUtil.executeWhenUnlocked(
+ {
+ startActivity(sendIntent)
+ false
+ },
+ false,
+ false
+ )
+ }
+
companion object {
private const val TAG = "IssueRecordingService"
private const val CHANNEL_ID = "issue_record"
+ private const val EXTRA_SCREEN_RECORD = "extra_screenRecord"
+ private const val EXTRA_WINSCOPE_TRACING = "extra_winscopeTracing"
+
+ private val DEFAULT_TRACE_TAGS = listOf<String>()
+ private const val DEFAULT_BUFFER_SIZE = 16384
+ private const val DEFAULT_IS_INCLUDING_WINSCOPE = true
+ private const val DEFAULT_IS_LONG_TRACE = false
+ private const val DEFAULT_IS_INCLUDING_APP_TRACE = true
+ private const val DEFAULT_ATTACH_TO_BUGREPORT = true
+ private const val DEFAULT_MAX_TRACE_SIZE = 10240
+ private const val DEFAULT_MAX_TRACE_DURATION_IN_MINUTES = 30
+
+ private val TRACE_FILE_NAME = TraceUtils.getOutputFilename(TraceUtils.RecordingType.TRACE)
+ private const val AUTHORITY = "com.android.systemui.fileprovider"
/**
* Get an intent to stop the issue recording service.
@@ -71,7 +155,7 @@
* @return
*/
fun getStopIntent(context: Context): Intent =
- Intent(context, RecordingService::class.java)
+ Intent(context, IssueRecordingService::class.java)
.setAction(ACTION_STOP)
.putExtra(Intent.EXTRA_USER_HANDLE, context.userId)
@@ -80,8 +164,15 @@
*
* @param context Context from the requesting activity
*/
- fun getStartIntent(context: Context): Intent =
- Intent(context, RecordingService::class.java).setAction(ACTION_START)
+ fun getStartIntent(
+ context: Context,
+ screenRecord: Boolean,
+ winscopeTracing: Boolean
+ ): Intent =
+ Intent(context, IssueRecordingService::class.java)
+ .setAction(ACTION_START)
+ .putExtra(EXTRA_SCREEN_RECORD, screenRecord)
+ .putExtra(EXTRA_WINSCOPE_TRACING, winscopeTracing)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
index 1c07d00..ff18a11 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/RecordIssueDialogDelegate.kt
@@ -17,8 +17,6 @@
package com.android.systemui.recordissue
import android.annotation.SuppressLint
-import android.app.BroadcastOptions
-import android.app.PendingIntent
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
@@ -43,8 +41,6 @@
import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDialogDelegate
import com.android.systemui.qs.tiles.RecordIssueTile
import com.android.systemui.res.R
-import com.android.systemui.screenrecord.RecordingService
-import com.android.systemui.settings.UserContextProvider
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -52,12 +48,12 @@
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import java.util.concurrent.Executor
+import java.util.function.Consumer
class RecordIssueDialogDelegate
@AssistedInject
constructor(
private val factory: SystemUIDialog.Factory,
- private val userContextProvider: UserContextProvider,
private val userTracker: UserTracker,
private val flags: FeatureFlagsClassic,
@Background private val bgExecutor: Executor,
@@ -66,14 +62,14 @@
private val mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
private val userFileManager: UserFileManager,
private val screenCaptureDisabledDialogDelegate: ScreenCaptureDisabledDialogDelegate,
- @Assisted private val onStarted: Runnable,
+ @Assisted private val onStarted: Consumer<IssueRecordingConfig>,
) : SystemUIDialog.Delegate {
/** To inject dependencies and allow for easier testing */
@AssistedFactory
interface Factory {
/** Create a dialog object */
- fun create(onStarted: Runnable): RecordIssueDialogDelegate
+ fun create(onStarted: Consumer<IssueRecordingConfig>): RecordIssueDialogDelegate
}
@SuppressLint("UseSwitchCompatOrMaterialCode") private lateinit var screenRecordSwitch: Switch
@@ -87,10 +83,12 @@
setIcon(R.drawable.qs_record_issue_icon_off)
setNegativeButton(R.string.cancel) { _, _ -> dismiss() }
setPositiveButton(R.string.qs_record_issue_start) { _, _ ->
- onStarted.run()
- if (screenRecordSwitch.isChecked) {
- requestScreenCapture()
- }
+ onStarted.accept(
+ IssueRecordingConfig(
+ screenRecordSwitch.isChecked,
+ true /* TODO: Base this on issueType selected */
+ )
+ )
dismiss()
}
}
@@ -177,13 +175,4 @@
show()
}
}
-
- private fun requestScreenCapture() =
- PendingIntent.getForegroundService(
- userContextProvider.userContext,
- RecordingService.REQUEST_CODE,
- IssueRecordingService.getStartIntent(userContextProvider.userContext),
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
- )
- .send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle())
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index b355d2d..ac94f39 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -60,25 +60,27 @@
public static final int REQUEST_CODE = 2;
private static final int USER_ID_NOT_SPECIFIED = -1;
- private static final int NOTIF_BASE_ID = 4273;
+ protected static final int NOTIF_BASE_ID = 4273;
private static final String TAG = "RecordingService";
private static final String CHANNEL_ID = "screen_record";
private static final String GROUP_KEY = "screen_record_saved";
private static final String EXTRA_RESULT_CODE = "extra_resultCode";
- private static final String EXTRA_PATH = "extra_path";
+ protected static final String EXTRA_PATH = "extra_path";
private static final String EXTRA_AUDIO_SOURCE = "extra_useAudio";
private static final String EXTRA_SHOW_TAPS = "extra_showTaps";
private static final String EXTRA_CAPTURE_TARGET = "extra_captureTarget";
protected static final String ACTION_START = "com.android.systemui.screenrecord.START";
+ protected static final String ACTION_SHOW_START_NOTIF =
+ "com.android.systemui.screenrecord.START_NOTIF";
protected static final String ACTION_STOP = "com.android.systemui.screenrecord.STOP";
- private static final String ACTION_STOP_NOTIF =
+ protected static final String ACTION_STOP_NOTIF =
"com.android.systemui.screenrecord.STOP_FROM_NOTIF";
- private static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
+ protected static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
private final RecordingController mController;
- private final KeyguardDismissUtil mKeyguardDismissUtil;
+ protected final KeyguardDismissUtil mKeyguardDismissUtil;
private final Handler mMainHandler;
private ScreenRecordingAudioSource mAudioSource;
private boolean mShowTaps;
@@ -86,9 +88,9 @@
private ScreenMediaRecorder mRecorder;
private final Executor mLongExecutor;
private final UiEventLogger mUiEventLogger;
- private final NotificationManager mNotificationManager;
- private final UserContextProvider mUserContextTracker;
- private int mNotificationId = NOTIF_BASE_ID;
+ protected final NotificationManager mNotificationManager;
+ protected final UserContextProvider mUserContextTracker;
+ protected int mNotificationId = NOTIF_BASE_ID;
private RecordingServiceStrings mStrings;
@Inject
@@ -185,7 +187,10 @@
return Service.START_NOT_STICKY;
}
break;
-
+ case ACTION_SHOW_START_NOTIF:
+ createRecordingNotification();
+ mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_START);
+ break;
case ACTION_STOP_NOTIF:
case ACTION_STOP:
// only difference for actions is the log event
@@ -232,6 +237,7 @@
super.onCreate();
}
+ @Nullable
@VisibleForTesting
protected ScreenMediaRecorder getRecorder() {
return mRecorder;
@@ -337,8 +343,9 @@
}
@VisibleForTesting
- protected Notification createSaveNotification(ScreenMediaRecorder.SavedRecording recording) {
- Uri uri = recording.getUri();
+ protected Notification createSaveNotification(
+ @Nullable ScreenMediaRecorder.SavedRecording recording) {
+ Uri uri = recording != null ? recording.getUri() : null;
Intent viewIntent = new Intent(Intent.ACTION_VIEW)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION)
.setDataAndType(uri, "video/mp4");
@@ -349,7 +356,7 @@
PendingIntent.getService(
this,
REQUEST_CODE,
- getShareIntent(this, uri.toString()),
+ getShareIntent(this, uri != null ? uri.toString() : null),
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
.build();
@@ -371,9 +378,10 @@
.addExtras(extras);
// Add thumbnail if available
- if (recording.getThumbnail() != null) {
+ Icon thumbnail = recording != null ? recording.getThumbnail() : null;
+ if (thumbnail != null) {
Notification.BigPictureStyle pictureStyle = new Notification.BigPictureStyle()
- .bigPicture(recording.getThumbnail())
+ .bigPicture(thumbnail)
.showBigPictureWhenCollapsed(true);
builder.setStyle(pictureStyle);
}
@@ -408,27 +416,29 @@
}
Log.d(getTag(), "notifying for user " + userId);
setTapsVisible(mOriginalShowTaps);
- if (getRecorder() != null) {
- try {
+ try {
+ if (getRecorder() != null) {
getRecorder().end();
- saveRecording(userId);
- } catch (RuntimeException exception) {
+ }
+ saveRecording(userId);
+ } catch (RuntimeException exception) {
+ if (getRecorder() != null) {
// RuntimeException could happen if the recording stopped immediately after starting
// let's release the recorder and delete all temporary files in this case
getRecorder().release();
- showErrorToast(R.string.screenrecord_start_error);
- Log.e(getTag(), "stopRecording called, but there was an error when ending"
- + "recording");
- exception.printStackTrace();
- createErrorNotification();
- } catch (Throwable throwable) {
+ }
+ showErrorToast(R.string.screenrecord_start_error);
+ Log.e(getTag(), "stopRecording called, but there was an error when ending"
+ + "recording");
+ exception.printStackTrace();
+ createErrorNotification();
+ } catch (Throwable throwable) {
+ if (getRecorder() != null) {
// Something unexpected happen, SystemUI will crash but let's delete
// the temporary files anyway
getRecorder().release();
- throw new RuntimeException(throwable);
}
- } else {
- Log.e(getTag(), "stopRecording called, but recorder was null");
+ throw new RuntimeException(throwable);
}
updateState(false);
stopForeground(STOP_FOREGROUND_DETACH);
@@ -443,7 +453,8 @@
mLongExecutor.execute(() -> {
try {
Log.d(getTag(), "saving recording");
- Notification notification = createSaveNotification(getRecorder().save());
+ Notification notification = createSaveNotification(
+ getRecorder() != null ? getRecorder().save() : null);
postGroupNotification(currentUser);
mNotificationManager.notifyAsUser(null, mNotificationId, notification,
currentUser);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 81f644f..4b16126 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -594,6 +594,7 @@
}
}
val cancelHandler = Runnable {
+ statusBarStateController.setLeaveOpenOnKeyguardHide(false)
draggedDownEntry?.apply {
setUserLocked(false)
notifyHeightChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index db15144..6602a97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -2790,6 +2790,9 @@
|| mKeyguardStateController.isKeyguardGoingAway()
|| mKeyguardViewMediator.requestedShowSurfaceBehindKeyguard()
|| mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehind());
+ boolean dreaming =
+ mKeyguardStateController.isShowing() && mKeyguardUpdateMonitor.isDreaming()
+ && !unlocking;
mScrimController.setExpansionAffectsAlpha(!unlocking);
@@ -2834,13 +2837,16 @@
// this as otherwise it can remain pending and leave keyguard in a weird state.
mUnlockScrimCallback.onCancelled();
} else if (mIsIdleOnCommunal) {
- mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ if (dreaming) {
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+ } else {
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ }
} else if (mKeyguardStateController.isShowing()
&& !mKeyguardStateController.isOccluded()
&& !unlocking) {
mScrimController.transitionTo(ScrimState.KEYGUARD);
- } else if (mKeyguardStateController.isShowing() && mKeyguardUpdateMonitor.isDreaming()
- && !unlocking) {
+ } else if (dreaming) {
mScrimController.transitionTo(ScrimState.DREAMING);
} else {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 088f894..02293a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -536,6 +536,16 @@
mAnimateChange = state.getAnimateChange();
mAnimationDuration = state.getAnimationDuration();
+ if (mState == ScrimState.GLANCEABLE_HUB_OVER_DREAM) {
+ // When the device is docked while on GLANCEABLE_HUB, the dream starts underneath the
+ // hub and the ScrimState transitions to GLANCEABLE_HUB_OVER_DREAM. To prevent the
+ // scrims from flickering in during this transition, we set the panel expansion
+ // fraction, which is 1 when idle on GLANCEABLE_HUB, to 0. This only occurs when the hub
+ // is open because the hub lives in the same window as the shade, which is not visible
+ // when transitioning from KEYGUARD to DREAMING.
+ mPanelExpansionFraction = 0f;
+ }
+
applyState();
mScrimInFront.setBlendWithMainColor(state.shouldBlendWithMainColor());
@@ -738,6 +748,7 @@
boolean relevantState = (mState == ScrimState.UNLOCKED
|| mState == ScrimState.KEYGUARD
|| mState == ScrimState.DREAMING
+ || mState == ScrimState.GLANCEABLE_HUB_OVER_DREAM
|| mState == ScrimState.SHADE_LOCKED
|| mState == ScrimState.PULSING);
if (!(relevantState && mExpansionAffectsAlpha) || mAnimatingPanelExpansionOnUnlock) {
@@ -844,7 +855,8 @@
return;
}
mBouncerHiddenFraction = bouncerHiddenAmount;
- if (mState == ScrimState.DREAMING || mState == ScrimState.GLANCEABLE_HUB) {
+ if (mState == ScrimState.DREAMING || mState == ScrimState.GLANCEABLE_HUB
+ || mState == ScrimState.GLANCEABLE_HUB_OVER_DREAM) {
// The dreaming and glanceable hub states requires this for the scrim calculation, so we
// should only trigger an update in those states.
applyAndDispatchState();
@@ -926,7 +938,8 @@
return;
}
- if (mState == ScrimState.UNLOCKED || mState == ScrimState.DREAMING) {
+ if (mState == ScrimState.UNLOCKED || mState == ScrimState.DREAMING
+ || mState == ScrimState.GLANCEABLE_HUB_OVER_DREAM) {
final boolean occluding =
mOccludeAnimationPlaying || mState.mLaunchingAffordanceWithPreview;
// Darken scrim as it's pulled down while unlocked. If we're unlocked but playing the
@@ -954,8 +967,9 @@
mInFrontAlpha = 0;
}
- if (mState == ScrimState.DREAMING
+ if ((mState == ScrimState.DREAMING || mState == ScrimState.GLANCEABLE_HUB_OVER_DREAM)
&& mBouncerHiddenFraction != KeyguardBouncerConstants.EXPANSION_HIDDEN) {
+ // Bouncer is opening over dream or glanceable hub over dream.
final float interpolatedFraction =
BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(
mBouncerHiddenFraction);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index f2a649b..d4960d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -299,9 +299,9 @@
},
/**
- * Device is locked or on dream and user has swiped from the right edge to enter the glanceable
- * hub UI. From this state, the user can swipe from the left edge to go back to the lock screen
- * or dream, as well as swipe down for the notifications and up for the bouncer.
+ * Device is on the lockscreen and user has swiped from the right edge to enter the glanceable
+ * hub UI. From this state, the user can swipe from the left edge to go back to the lock screen,
+ * as well as swipe down for the notifications and up for the bouncer.
*/
GLANCEABLE_HUB {
@Override
@@ -310,6 +310,25 @@
mBehindAlpha = 0;
mNotifAlpha = 0;
mFrontAlpha = 0;
+
+ mFrontTint = Color.TRANSPARENT;
+ mBehindTint = mBackgroundColor;
+ mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT;
+ }
+ },
+
+ /**
+ * Device is dreaming and user has swiped from the right edge to enter the glanceable hub UI.
+ * From this state, the user can swipe from the left edge to go back to the dream, as well as
+ * swipe down for the notifications and up for the bouncer.
+ *
+ * This is a separate state from {@link #GLANCEABLE_HUB} because the scrims behave differently
+ * when the dream is running.
+ */
+ GLANCEABLE_HUB_OVER_DREAM {
+ @Override
+ public void prepare(ScrimState previousState) {
+ GLANCEABLE_HUB.prepare(previousState);
}
};
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index 3862b0f..de795a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -61,6 +61,7 @@
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.ArraySet;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -71,6 +72,7 @@
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.test.filters.SmallTest;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.systemui.Flags;
@@ -220,6 +222,24 @@
}
@Test
+ @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ public void triggerDismissMenuAction_callsA11yManagerEnableShortcutsForTargets() {
+ final List<String> stubShortcutTargets = new ArrayList<>();
+ stubShortcutTargets.add(TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString());
+ when(mStubAccessibilityManager.getAccessibilityShortcutTargets(
+ AccessibilityManager.ACCESSIBILITY_BUTTON)).thenReturn(stubShortcutTargets);
+
+ mMenuViewLayer.mDismissMenuAction.run();
+
+ verify(mStubAccessibilityManager).enableShortcutsForTargets(
+ /* enable= */ false,
+ ShortcutConstants.UserShortcutType.SOFTWARE,
+ new ArraySet<>(stubShortcutTargets),
+ mSecureSettings.getRealUserHandle(UserHandle.USER_CURRENT));
+ }
+
+ @Test
+ @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void triggerDismissMenuAction_matchA11yButtonTargetsResult() {
mMenuViewLayer.mDismissMenuAction.run();
verify(mSecureSettings).putStringForUser(
@@ -228,6 +248,7 @@
}
@Test
+ @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void triggerDismissMenuAction_matchEnabledA11yServicesResult() {
setupEnabledAccessibilityServiceList();
@@ -239,6 +260,7 @@
}
@Test
+ @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void triggerDismissMenuAction_hasHardwareKeyShortcut_keepEnabledStatus() {
setupEnabledAccessibilityServiceList();
final List<String> stubShortcutTargets = new ArrayList<>();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
index 54d6b53..67ca9a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
@@ -20,6 +20,7 @@
import com.android.systemui.SysUITestComponent
import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FakeFeatureFlagsClassicModule
import com.android.systemui.flags.Flags
@@ -45,6 +46,7 @@
[
SysUITestModule::class,
UserDomainLayerModule::class,
+ BiometricsDomainLayerModule::class,
]
)
interface TestComponent : SysUITestComponent<AuthDialogPanelInteractionDetector> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
index dc438d7..7808c41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
@@ -84,8 +84,8 @@
val sensorType by collectLastValue(repository.sensorType)
val sensorLocations by collectLastValue(repository.sensorLocations)
- // Assert default properties.
- assertThat(sensorId).isEqualTo(-1)
+ // Assert non-initialized properties.
+ assertThat(sensorId).isEqualTo(-2)
assertThat(strength).isEqualTo(SensorStrength.CONVENIENCE)
assertThat(sensorType).isEqualTo(FingerprintSensorType.UNKNOWN)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DefaultUdfpsTouchOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DefaultUdfpsTouchOverlayViewModelTest.kt
index fa17672..5caa146 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DefaultUdfpsTouchOverlayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DefaultUdfpsTouchOverlayViewModelTest.kt
@@ -21,6 +21,7 @@
import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
import com.android.systemui.TestMocksModule
+import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
import com.android.systemui.collectLastValue
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FakeFeatureFlagsClassicModule
@@ -65,6 +66,7 @@
[
SysUITestModule::class,
UserDomainLayerModule::class,
+ BiometricsDomainLayerModule::class,
]
)
interface TestComponent : SysUITestComponent<DefaultUdfpsTouchOverlayViewModel> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
index e8eda80..d5839b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
@@ -21,9 +21,15 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
@@ -35,6 +41,8 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
class DeviceEntryUdfpsInteractorTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
private lateinit var fingerprintAuthRepository: FakeDeviceEntryFingerprintAuthRepository
private lateinit var biometricsRepository: FakeBiometricSettingsRepository
@@ -43,77 +51,85 @@
@Before
fun setUp() {
- fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
- fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
- biometricsRepository = FakeBiometricSettingsRepository()
+ fingerprintPropertyRepository = kosmos.fakeFingerprintPropertyRepository
+ fingerprintAuthRepository = kosmos.fakeDeviceEntryFingerprintAuthRepository
+ biometricsRepository = kosmos.fakeBiometricSettingsRepository
underTest =
DeviceEntryUdfpsInteractor(
- fingerprintPropertyRepository = fingerprintPropertyRepository,
+ fingerprintPropertyInteractor = kosmos.fingerprintPropertyInteractor,
fingerprintAuthRepository = fingerprintAuthRepository,
biometricSettingsRepository = biometricsRepository,
)
}
@Test
- fun udfpsSupported_rearFp_false() = runTest {
- val isUdfpsSupported by collectLastValue(underTest.isUdfpsSupported)
- fingerprintPropertyRepository.supportsRearFps()
- assertThat(isUdfpsSupported).isFalse()
- }
+ fun udfpsSupported_rearFp_false() =
+ testScope.runTest {
+ val isUdfpsSupported by collectLastValue(underTest.isUdfpsSupported)
+ fingerprintPropertyRepository.supportsRearFps()
+ assertThat(isUdfpsSupported).isFalse()
+ }
@Test
- fun udfpsSupoprted() = runTest {
- val isUdfpsSupported by collectLastValue(underTest.isUdfpsSupported)
- fingerprintPropertyRepository.supportsUdfps()
- assertThat(isUdfpsSupported).isTrue()
- }
+ fun udfpsSupoprted() =
+ testScope.runTest {
+ val isUdfpsSupported by collectLastValue(underTest.isUdfpsSupported)
+ fingerprintPropertyRepository.supportsUdfps()
+ assertThat(isUdfpsSupported).isTrue()
+ }
@Test
- fun udfpsEnrolledAndEnabled() = runTest {
- val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
- fingerprintPropertyRepository.supportsUdfps()
- biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
- assertThat(isUdfpsEnrolledAndEnabled).isTrue()
- }
+ fun udfpsEnrolledAndEnabled() =
+ testScope.runTest {
+ val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
+ fingerprintPropertyRepository.supportsUdfps()
+ biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ assertThat(isUdfpsEnrolledAndEnabled).isTrue()
+ }
@Test
- fun udfpsEnrolledAndEnabled_rearFp_false() = runTest {
- val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
- fingerprintPropertyRepository.supportsRearFps()
- biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
- assertThat(isUdfpsEnrolledAndEnabled).isFalse()
- }
+ fun udfpsEnrolledAndEnabled_rearFp_false() =
+ testScope.runTest {
+ val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
+ fingerprintPropertyRepository.supportsRearFps()
+ biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ assertThat(isUdfpsEnrolledAndEnabled).isFalse()
+ }
@Test
- fun udfpsEnrolledAndEnabled_notEnrolledOrEnabled_false() = runTest {
- val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
- fingerprintPropertyRepository.supportsUdfps()
- biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
- assertThat(isUdfpsEnrolledAndEnabled).isFalse()
- }
+ fun udfpsEnrolledAndEnabled_notEnrolledOrEnabled_false() =
+ testScope.runTest {
+ val isUdfpsEnrolledAndEnabled by collectLastValue(underTest.isUdfpsEnrolledAndEnabled)
+ fingerprintPropertyRepository.supportsUdfps()
+ biometricsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+ assertThat(isUdfpsEnrolledAndEnabled).isFalse()
+ }
@Test
- fun isListeningForUdfps() = runTest {
- val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
- fingerprintPropertyRepository.supportsUdfps()
- fingerprintAuthRepository.setIsRunning(true)
- assertThat(isListeningForUdfps).isTrue()
- }
+ fun isListeningForUdfps() =
+ testScope.runTest {
+ val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
+ fingerprintPropertyRepository.supportsUdfps()
+ fingerprintAuthRepository.setIsRunning(true)
+ assertThat(isListeningForUdfps).isTrue()
+ }
@Test
- fun isListeningForUdfps_rearFp_false() = runTest {
- val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
- fingerprintPropertyRepository.supportsRearFps()
- fingerprintAuthRepository.setIsRunning(true)
- assertThat(isListeningForUdfps).isFalse()
- }
+ fun isListeningForUdfps_rearFp_false() =
+ testScope.runTest {
+ val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
+ fingerprintPropertyRepository.supportsRearFps()
+ fingerprintAuthRepository.setIsRunning(true)
+ assertThat(isListeningForUdfps).isFalse()
+ }
@Test
- fun isListeningForUdfps_notRunning_false() = runTest {
- val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
- fingerprintPropertyRepository.supportsUdfps()
- fingerprintAuthRepository.setIsRunning(false)
- assertThat(isListeningForUdfps).isFalse()
- }
+ fun isListeningForUdfps_notRunning_false() =
+ testScope.runTest {
+ val isListeningForUdfps by collectLastValue(underTest.isListeningForUdfps)
+ fingerprintPropertyRepository.supportsUdfps()
+ fingerprintAuthRepository.setIsRunning(false)
+ assertThat(isListeningForUdfps).isFalse()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt
index 37836a5..bcaad01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt
@@ -62,7 +62,6 @@
whenever(defaultLockscreenBlueprint.id).thenReturn(DEFAULT)
underTest =
KeyguardBlueprintRepository(
- configurationRepository,
setOf(defaultLockscreenBlueprint),
fakeExecutorHandler,
threadAssert,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
index b0d8de3..170d348 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
@@ -21,95 +21,80 @@
import androidx.test.filters.SmallTest
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
-import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository
+import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID
import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint
import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint
-import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition
-import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
-import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
+import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.clocks.ClockConfig
import com.android.systemui.plugins.clocks.ClockController
-import com.android.systemui.statusbar.policy.SplitShadeStateController
-import com.android.systemui.util.mockito.any
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.whenever
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestScope
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.reset
-import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+@ExperimentalCoroutinesApi
@SmallTest
@RunWith(AndroidJUnit4::class)
class KeyguardBlueprintInteractorTest : SysuiTestCase() {
- private val configurationFlow = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
- private lateinit var underTest: KeyguardBlueprintInteractor
- private lateinit var testScope: TestScope
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val underTest by lazy { kosmos.keyguardBlueprintInteractor }
+ private val clockRepository by lazy { kosmos.fakeKeyguardClockRepository }
+ private val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
+ private val fingerprintPropertyRepository by lazy { kosmos.fakeFingerprintPropertyRepository }
- val refreshTransition: MutableSharedFlow<IntraBlueprintTransition.Config> =
- MutableSharedFlow(extraBufferCapacity = 1)
-
- @Mock private lateinit var splitShadeStateController: SplitShadeStateController
- @Mock private lateinit var keyguardBlueprintRepository: KeyguardBlueprintRepository
- @Mock private lateinit var clockInteractor: KeyguardClockInteractor
@Mock private lateinit var clockController: ClockController
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- testScope = TestScope(StandardTestDispatcher())
- whenever(keyguardBlueprintRepository.configurationChange).thenReturn(configurationFlow)
- whenever(keyguardBlueprintRepository.refreshTransition).thenReturn(refreshTransition)
- whenever(clockInteractor.currentClock).thenReturn(MutableStateFlow(clockController))
- clockInteractor.currentClock
-
- underTest =
- KeyguardBlueprintInteractor(
- keyguardBlueprintRepository,
- testScope.backgroundScope,
- mContext,
- splitShadeStateController,
- clockInteractor,
- )
}
@Test
fun testAppliesDefaultBlueprint() {
testScope.runTest {
- whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
- .thenReturn(false)
-
- reset(keyguardBlueprintRepository)
- configurationFlow.tryEmit(Unit)
+ val blueprint by collectLastValue(underTest.blueprint)
+ overrideResource(R.bool.config_use_split_notification_shade, false)
+ configurationRepository.onConfigurationChange()
runCurrent()
- verify(keyguardBlueprintRepository)
- .applyBlueprint(DefaultKeyguardBlueprint.Companion.DEFAULT)
+ assertThat(blueprint?.id).isEqualTo(DefaultKeyguardBlueprint.Companion.DEFAULT)
}
}
@Test
fun testAppliesSplitShadeBlueprint() {
testScope.runTest {
- whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
- .thenReturn(true)
-
- reset(keyguardBlueprintRepository)
- configurationFlow.tryEmit(Unit)
+ val blueprint by collectLastValue(underTest.blueprint)
+ overrideResource(R.bool.config_use_split_notification_shade, true)
+ configurationRepository.onConfigurationChange()
runCurrent()
- verify(keyguardBlueprintRepository)
- .applyBlueprint(SplitShadeKeyguardBlueprint.Companion.ID)
+ assertThat(blueprint?.id).isEqualTo(SplitShadeKeyguardBlueprint.Companion.ID)
+ }
+ }
+
+ @Test
+ fun fingerprintPropertyInitialized_updatesBlueprint() {
+ testScope.runTest {
+ val blueprint by collectLastValue(underTest.blueprint)
+ overrideResource(R.bool.config_use_split_notification_shade, true)
+ fingerprintPropertyRepository.supportsUdfps() // initialize properties
+ runCurrent()
+ assertThat(blueprint?.id).isEqualTo(SplitShadeKeyguardBlueprint.Companion.ID)
}
}
@@ -117,6 +102,7 @@
fun composeLockscreenOff_DoesAppliesSplitShadeWeatherClockBlueprint() {
testScope.runTest {
mSetFlagsRule.disableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
+ val blueprint by collectLastValue(underTest.blueprint)
whenever(clockController.config)
.thenReturn(
ClockConfig(
@@ -125,15 +111,12 @@
description = "clock",
)
)
- whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
- .thenReturn(true)
-
- reset(keyguardBlueprintRepository)
- configurationFlow.tryEmit(Unit)
+ clockRepository.setCurrentClock(clockController)
+ overrideResource(R.bool.config_use_split_notification_shade, true)
+ configurationRepository.onConfigurationChange()
runCurrent()
- verify(keyguardBlueprintRepository, never())
- .applyBlueprint(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID)
+ assertThat(blueprint?.id).isNotEqualTo(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID)
}
}
@@ -141,6 +124,7 @@
fun testDoesAppliesSplitShadeWeatherClockBlueprint() {
testScope.runTest {
mSetFlagsRule.enableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
+ val blueprint by collectLastValue(underTest.blueprint)
whenever(clockController.config)
.thenReturn(
ClockConfig(
@@ -149,15 +133,12 @@
description = "clock",
)
)
- whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
- .thenReturn(true)
-
- reset(keyguardBlueprintRepository)
- configurationFlow.tryEmit(Unit)
+ clockRepository.setCurrentClock(clockController)
+ overrideResource(R.bool.config_use_split_notification_shade, true)
+ configurationRepository.onConfigurationChange()
runCurrent()
- verify(keyguardBlueprintRepository)
- .applyBlueprint(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID)
+ assertThat(blueprint?.id).isEqualTo(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID)
}
}
@@ -165,6 +146,7 @@
fun testAppliesWeatherClockBlueprint() {
testScope.runTest {
mSetFlagsRule.enableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
+ val blueprint by collectLastValue(underTest.blueprint)
whenever(clockController.config)
.thenReturn(
ClockConfig(
@@ -173,33 +155,12 @@
description = "clock",
)
)
- whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
- .thenReturn(false)
-
- reset(keyguardBlueprintRepository)
- configurationFlow.tryEmit(Unit)
+ clockRepository.setCurrentClock(clockController)
+ overrideResource(R.bool.config_use_split_notification_shade, false)
+ configurationRepository.onConfigurationChange()
runCurrent()
- verify(keyguardBlueprintRepository).applyBlueprint(WEATHER_CLOCK_BLUEPRINT_ID)
+ assertThat(blueprint?.id).isEqualTo(WEATHER_CLOCK_BLUEPRINT_ID)
}
}
-
- @Test
- fun testRefreshBlueprint() {
- underTest.refreshBlueprint()
- verify(keyguardBlueprintRepository).refreshBlueprint()
- }
-
- @Test
- fun testTransitionToBlueprint() {
- underTest.transitionToBlueprint("abc")
- verify(keyguardBlueprintRepository).applyBlueprint("abc")
- }
-
- @Test
- fun testRefreshBlueprintWithTransition() {
- underTest.refreshBlueprint(Type.DefaultTransition)
- verify(keyguardBlueprintRepository)
- .refreshBlueprint(Config(Type.DefaultTransition, true, true))
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
index 699284e..09c56b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
@@ -22,7 +22,6 @@
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
-import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.LockIconViewController
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.SysuiTestCase
@@ -37,8 +36,10 @@
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationPanelView
import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.TestScope
import org.junit.Before
import org.junit.Test
@@ -53,13 +54,13 @@
@RunWith(JUnit4::class)
@SmallTest
class DefaultDeviceEntrySectionTest : SysuiTestCase() {
- @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var authController: AuthController
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var windowManager: WindowManager
@Mock private lateinit var notificationPanelView: NotificationPanelView
private lateinit var featureFlags: FakeFeatureFlags
@Mock private lateinit var lockIconViewController: LockIconViewController
@Mock private lateinit var falsingManager: FalsingManager
+ @Mock private lateinit var deviceEntryIconViewModel: DeviceEntryIconViewModel
private lateinit var underTest: DefaultDeviceEntrySection
@Before
@@ -73,14 +74,13 @@
underTest =
DefaultDeviceEntrySection(
TestScope().backgroundScope,
- keyguardUpdateMonitor,
authController,
windowManager,
context,
notificationPanelView,
featureFlags,
{ lockIconViewController },
- { mock(DeviceEntryIconViewModel::class.java) },
+ { deviceEntryIconViewModel },
{ mock(DeviceEntryForegroundViewModel::class.java) },
{ mock(DeviceEntryBackgroundViewModel::class.java) },
{ falsingManager },
@@ -129,6 +129,7 @@
@Test
fun applyConstraints_udfps_refactor_on() {
mSetFlagsRule.enableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
+ whenever(deviceEntryIconViewModel.isUdfpsSupported).thenReturn(MutableStateFlow(false))
val cs = ConstraintSet()
underTest.applyConstraints(cs)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
index ada93db..2e8160b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
@@ -37,7 +37,6 @@
import com.android.systemui.model.SysUiState
import com.android.systemui.qs.tiles.RecordIssueTile
import com.android.systemui.res.R
-import com.android.systemui.settings.UserContextProvider
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -71,12 +70,11 @@
@Mock private lateinit var devicePolicyResolver: ScreenCaptureDevicePolicyResolver
@Mock private lateinit var dprLazy: dagger.Lazy<ScreenCaptureDevicePolicyResolver>
@Mock private lateinit var mediaProjectionMetricsLogger: MediaProjectionMetricsLogger
- @Mock private lateinit var userContextProvider: UserContextProvider
@Mock private lateinit var userTracker: UserTracker
@Mock private lateinit var userFileManager: UserFileManager
@Mock private lateinit var sharedPreferences: SharedPreferences
- @Mock private lateinit var screenCaptureDisabledDialogDelegate:
- ScreenCaptureDisabledDialogDelegate
+ @Mock
+ private lateinit var screenCaptureDisabledDialogDelegate: ScreenCaptureDisabledDialogDelegate
@Mock private lateinit var screenCaptureDisabledDialog: SystemUIDialog
@Mock private lateinit var sysuiState: SysUiState
@@ -96,9 +94,8 @@
MockitoAnnotations.initMocks(this)
whenever(dprLazy.get()).thenReturn(devicePolicyResolver)
whenever(sysuiState.setFlag(anyInt(), anyBoolean())).thenReturn(sysuiState)
- whenever(userContextProvider.userContext).thenReturn(mContext)
whenever(screenCaptureDisabledDialogDelegate.createDialog())
- .thenReturn(screenCaptureDisabledDialog)
+ .thenReturn(screenCaptureDisabledDialog)
whenever(
userFileManager.getSharedPreferences(
eq(RecordIssueTile.TILE_SPEC),
@@ -123,7 +120,6 @@
dialog =
RecordIssueDialogDelegate(
factory,
- userContextProvider,
userTracker,
flags,
bgExecutor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index cdff4d1..43fcdf3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -38,6 +38,7 @@
import static org.mockito.Mockito.when;
import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
import android.annotation.IdRes;
import android.content.ContentResolver;
@@ -213,7 +214,6 @@
import java.util.Optional;
import kotlinx.coroutines.CoroutineDispatcher;
-import kotlinx.coroutines.flow.StateFlowKt;
import kotlinx.coroutines.test.TestScope;
public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
@@ -409,10 +409,10 @@
new ShadeAnimationRepository(), mShadeRepository);
mPowerInteractor = keyguardInteractorDeps.getPowerInteractor();
when(mKeyguardTransitionInteractor.isInTransitionToStateWhere(any())).thenReturn(
- StateFlowKt.MutableStateFlow(false));
+ MutableStateFlow(false));
DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
mock(DeviceEntryUdfpsInteractor.class);
- when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+ when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(MutableStateFlow(false));
mShadeInteractor = new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 3808d30..c31c625 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -36,7 +36,7 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
import android.app.IActivityManager;
import android.content.pm.ActivityInfo;
@@ -205,7 +205,7 @@
DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
mock(DeviceEntryUdfpsInteractor.class);
- when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+ when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(MutableStateFlow(false));
mShadeInteractor = new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
index 4809a47..a077164 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
@@ -22,7 +22,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
import android.content.res.Resources;
@@ -234,7 +234,8 @@
DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
mock(DeviceEntryUdfpsInteractor.class);
- when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+ when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(
+ MutableStateFlow(false));
mShadeInteractor = new ShadeInteractorImpl(
mTestScope.getBackgroundScope(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 86116a0..d35c7dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -9,6 +9,7 @@
import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
import com.android.systemui.TestMocksModule
+import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.dagger.SysUISingleton
@@ -35,6 +36,8 @@
import com.android.systemui.statusbar.policy.FakeConfigurationController
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
import com.android.systemui.user.domain.UserDomainLayerModule
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import dagger.BindsInstance
import dagger.Component
@@ -55,6 +58,7 @@
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.eq
+import org.mockito.ArgumentMatchers.isNull
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.clearInvocations
@@ -310,6 +314,17 @@
}
@Test
+ fun testGoToLockedShadeCancelDoesntLeaveShadeOpenOnKeyguardHide() {
+ whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false)
+ whenever(lockScreenUserManager.isLockscreenPublicMode(any())).thenReturn(true)
+ transitionController.goToLockedShade(null)
+ val captor = argumentCaptor<Runnable>()
+ verify(centralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(isNull(), captor.capture())
+ captor.value.run()
+ verify(statusbarStateController).setLeaveOpenOnKeyguardHide(false)
+ }
+
+ @Test
fun testDragDownAmountDoesntCallOutInLockedDownShade() {
whenever(nsslController.isInLockedDownShade).thenReturn(true)
transitionController.dragDownAmount = 10f
@@ -611,6 +626,7 @@
[
SysUITestModule::class,
UserDomainLayerModule::class,
+ BiometricsDomainLayerModule::class,
]
)
interface TestComponent {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index dfbb6ea..103dcb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -54,6 +54,7 @@
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.LargeScreenHeaderHelper
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -69,7 +70,7 @@
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
@@ -85,9 +86,8 @@
import org.mockito.Mockito
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
-import com.android.systemui.scene.shared.model.Scenes
import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -155,7 +155,7 @@
{ kosmos.sceneInteractor },
)
- whenever(deviceEntryUdfpsInteractor.isUdfpsSupported).thenReturn(emptyFlow())
+ whenever(deviceEntryUdfpsInteractor.isUdfpsSupported).thenReturn(MutableStateFlow(false))
shadeInteractor =
ShadeInteractorImpl(
testScope.backgroundScope,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 84156ee1..c8c54dbd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -859,6 +859,29 @@
}
@Test
+ public void testEnteringGlanceableHub_whenDreaming_updatesScrim() {
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ when(mKeyguardStateController.isOccluded()).thenReturn(true);
+ when(mKeyguardUpdateMonitor.isDreaming()).thenReturn(true);
+
+ // Transition to the glanceable hub.
+ mCommunalRepository.setTransitionState(flowOf(new ObservableTransitionState.Idle(
+ CommunalScenes.Communal)));
+ mTestScope.getTestScheduler().runCurrent();
+
+ // ScrimState also transitions.
+ verify(mScrimController).transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+
+ // Transition away from the glanceable hub.
+ mCommunalRepository.setTransitionState(flowOf(new ObservableTransitionState.Idle(
+ CommunalScenes.Blank)));
+ mTestScope.getTestScheduler().runCurrent();
+
+ // ScrimState goes back to UNLOCKED.
+ verify(mScrimController).transitionTo(eq(ScrimState.DREAMING));
+ }
+
+ @Test
public void testShowKeyguardImplementation_setsState() {
when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 99c2dc7..cdbbc93 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -794,6 +794,73 @@
}
@Test
+ public void transitionToHubOverDream() {
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+ finishAnimationsImmediately();
+
+ // All scrims transparent on the hub.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+ }
+
+ @Test
+ public void openBouncerOnHubOverDream() {
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+
+ // Open the bouncer.
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_VISIBLE);
+ finishAnimationsImmediately();
+
+ // Only behind widget is visible.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, OPAQUE));
+
+ // Bouncer is closed.
+ mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+ finishAnimationsImmediately();
+
+ // All scrims are transparent.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+ }
+
+ @Test
+ public void openShadeOnHubOverDream() {
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+
+ // Open the shade.
+ mScrimController.transitionTo(SHADE_LOCKED);
+ mScrimController.setQsPosition(1f, 0);
+ mScrimController.setRawPanelExpansionFraction(1f);
+ finishAnimationsImmediately();
+
+ // Shade scrims are visible.
+ assertScrimAlpha(Map.of(
+ mNotificationsScrim, OPAQUE,
+ mScrimInFront, TRANSPARENT,
+ mScrimBehind, OPAQUE));
+
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
+ finishAnimationsImmediately();
+
+ // All scrims are transparent.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+ }
+
+ @Test
public void onThemeChange_bouncerBehindTint_isUpdatedToSurfaceColor() {
assertEquals(BOUNCER.getBehindTint(), 0x112233);
mSurfaceColor = 0x223344;
@@ -1432,7 +1499,8 @@
ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, BOUNCER,
ScrimState.DREAMING, ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR,
ScrimState.UNLOCKED, SHADE_LOCKED, ScrimState.AUTH_SCRIMMED,
- ScrimState.AUTH_SCRIMMED_SHADE, ScrimState.GLANCEABLE_HUB));
+ ScrimState.AUTH_SCRIMMED_SHADE, ScrimState.GLANCEABLE_HUB,
+ ScrimState.GLANCEABLE_HUB_OVER_DREAM));
for (ScrimState state : ScrimState.values()) {
if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index c0d3d27..19f31d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -50,7 +50,7 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
import android.app.ActivityManager;
import android.app.IActivityManager;
@@ -452,7 +452,7 @@
DeviceEntryUdfpsInteractor deviceEntryUdfpsInteractor =
mock(DeviceEntryUdfpsInteractor.class);
- when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(emptyFlow());
+ when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(MutableStateFlow(false));
mShadeInteractor =
new ShadeInteractorImpl(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
index 1b951d9..9765d53 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
@@ -19,12 +19,17 @@
import android.util.Size
import com.android.systemui.biometrics.shared.model.DisplayRotation
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-class FakeDisplayStateRepository : DisplayStateRepository {
+@SysUISingleton
+class FakeDisplayStateRepository @Inject constructor() : DisplayStateRepository {
private val _isInRearDisplayMode = MutableStateFlow<Boolean>(false)
override val isInRearDisplayMode: StateFlow<Boolean> = _isInRearDisplayMode.asStateFlow()
@@ -51,3 +56,8 @@
_currentDisplaySize.value = size
}
}
+
+@Module
+interface FakeDisplayStateRepositoryModule {
+ @Binds fun bindFake(fake: FakeDisplayStateRepository): DisplayStateRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
index 005cac4..bd30fb4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
@@ -28,6 +28,7 @@
@SysUISingleton
class FakeFingerprintPropertyRepository @Inject constructor() : FingerprintPropertyRepository {
+ override val propertiesInitialized: MutableStateFlow<Boolean> = MutableStateFlow(false)
private val _sensorId: MutableStateFlow<Int> = MutableStateFlow(-1)
override val sensorId = _sensorId.asStateFlow()
@@ -54,6 +55,7 @@
_strength.value = strength
_sensorType.value = sensorType
_sensorLocations.value = sensorLocations
+ propertiesInitialized.value = true
}
/** setProperties as if the device supports UDFPS_OPTICAL. */
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt
index e262066..34a9c8a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt
@@ -21,9 +21,11 @@
import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.applicationCoroutineScope
val Kosmos.fingerprintPropertyInteractor by Fixture {
FingerprintPropertyInteractor(
+ applicationScope = applicationCoroutineScope,
context = applicationContext,
repository = fingerprintPropertyRepository,
configurationInteractor = configurationInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt
index 8ff04a63..1c8190e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/FakeDeviceEntryDataLayerModule.kt
@@ -15,8 +15,10 @@
package com.android.systemui.deviceentry.data
+import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepositoryModule
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepositoryModule
import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepositoryModule
+import com.android.systemui.display.data.repository.FakeDisplayRepositoryModule
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepositoryModule
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepositoryModule
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepositoryModule
@@ -30,6 +32,8 @@
FakeDeviceEntryRepositoryModule::class,
FakeDeviceEntryFaceAuthRepositoryModule::class,
FakeDeviceEntryFingerprintAuthRepositoryModule::class,
+ FakeDisplayRepositoryModule::class,
+ FakeDisplayStateRepositoryModule::class,
FakeFingerprintPropertyRepositoryModule::class,
FakeTrustRepositoryModule::class,
]
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt
index b04161a..81123d0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt
@@ -18,7 +18,7 @@
package com.android.systemui.deviceentry.domain.interactor
-import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor
import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
import com.android.systemui.kosmos.Kosmos
@@ -27,7 +27,7 @@
val Kosmos.deviceEntryUdfpsInteractor by Fixture {
DeviceEntryUdfpsInteractor(
- fingerprintPropertyRepository = fingerprintPropertyRepository,
+ fingerprintPropertyInteractor = fingerprintPropertyInteractor,
fingerprintAuthRepository = deviceEntryFingerprintAuthRepository,
biometricSettingsRepository = biometricSettingsRepository,
)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
index d8098b7..0fc0a3c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
@@ -16,7 +16,11 @@
package com.android.systemui.display.data.repository
import android.view.Display
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.mockito.mock
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import org.mockito.Mockito.`when` as whenever
@@ -42,8 +46,9 @@
fun createPendingDisplay(id: Int = 0): DisplayRepository.PendingDisplay =
mock<DisplayRepository.PendingDisplay> { whenever(this.id).thenReturn(id) }
+@SysUISingleton
/** Fake [DisplayRepository] implementation for testing. */
-class FakeDisplayRepository : DisplayRepository {
+class FakeDisplayRepository @Inject constructor() : DisplayRepository {
private val flow = MutableSharedFlow<Set<Display>>(replay = 1)
private val pendingDisplayFlow =
MutableSharedFlow<DisplayRepository.PendingDisplay?>(replay = 1)
@@ -71,3 +76,8 @@
override val displayChangeEvent: Flow<Int> = _displayChangeEvent
suspend fun emitDisplayChangeEvent(displayId: Int) = _displayChangeEvent.emit(displayId)
}
+
+@Module
+interface FakeDisplayRepositoryModule {
+ @Binds fun bindFake(fake: FakeDisplayRepository): DisplayRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
index 592fa38..5b642ea 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
@@ -42,7 +42,7 @@
private val _currentClockId = MutableStateFlow(DEFAULT_CLOCK_ID)
override val currentClockId: Flow<ClockId> = _currentClockId
- private val _currentClock = MutableStateFlow(null)
+ private val _currentClock: MutableStateFlow<ClockController?> = MutableStateFlow(null)
override val currentClock = _currentClock
private val _previewClockPair =
@@ -60,6 +60,10 @@
override fun setClockSize(@ClockSize size: Int) {
_clockSize.value = size
}
+
+ fun setCurrentClock(clockController: ClockController) {
+ _currentClock.value = clockController
+ }
}
@Module
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
index 8452963..75489b6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
@@ -17,10 +17,12 @@
package com.android.systemui.keyguard.data.repository
import android.os.fakeExecutorHandler
-import com.android.systemui.common.ui.data.repository.configurationRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID
import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint.Companion.DEFAULT
+import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.util.ThreadAssert
import com.android.systemui.util.mockito.mock
@@ -28,8 +30,13 @@
val Kosmos.keyguardBlueprintRepository by
Kosmos.Fixture {
KeyguardBlueprintRepository(
- configurationRepository = configurationRepository,
- blueprints = setOf(defaultBlueprint),
+ blueprints =
+ setOf(
+ defaultBlueprint,
+ splitShadeBlueprint,
+ weatherClockBlueprint,
+ splitShadeWeatherClockBlueprint,
+ ),
handler = fakeExecutorHandler,
assert = mock<ThreadAssert>(),
)
@@ -42,3 +49,27 @@
override val sections: List<KeyguardSection>
get() = listOf()
}
+
+private val weatherClockBlueprint =
+ object : KeyguardBlueprint {
+ override val id: String
+ get() = WEATHER_CLOCK_BLUEPRINT_ID
+ override val sections: List<KeyguardSection>
+ get() = listOf()
+ }
+
+private val splitShadeWeatherClockBlueprint =
+ object : KeyguardBlueprint {
+ override val id: String
+ get() = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
+ override val sections: List<KeyguardSection>
+ get() = listOf()
+ }
+
+private val splitShadeBlueprint =
+ object : KeyguardBlueprint {
+ override val id: String
+ get() = SplitShadeKeyguardBlueprint.Companion.ID
+ override val sections: List<KeyguardSection>
+ get() = listOf()
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
index 8b0bba1..87d6c17 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
@@ -17,6 +17,8 @@
package com.android.systemui.keyguard.domain.interactor
import android.content.applicationContext
+import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.keyguard.data.repository.keyguardBlueprintRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -30,5 +32,7 @@
context = applicationContext,
splitShadeStateController = splitShadeStateController,
clockInteractor = keyguardClockInteractor,
+ configurationInteractor = configurationInteractor,
+ fingerprintPropertyInteractor = fingerprintPropertyInteractor,
)
}
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index e0fe88a..10e6ed4 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -1566,6 +1566,10 @@
private String mCameraId = null;
private IBinder mToken;
+ OutputSurfaceImplStub mOutputPreviewSurfaceImpl;
+ OutputSurfaceImplStub mOutputImageCaptureSurfaceImpl;
+ OutputSurfaceImplStub mOutputPostviewSurfaceImpl;
+
public SessionProcessorImplStub(SessionProcessorImpl sessionProcessor) {
mSessionProcessor = sessionProcessor;
}
@@ -1574,21 +1578,18 @@
public CameraSessionConfig initSession(IBinder token, String cameraId,
Map<String, CameraMetadataNative> charsMapNative, OutputSurface previewSurface,
OutputSurface imageCaptureSurface, OutputSurface postviewSurface) {
- OutputSurfaceImplStub outputPreviewSurfaceImpl =
- new OutputSurfaceImplStub(previewSurface);
- OutputSurfaceImplStub outputImageCaptureSurfaceImpl =
- new OutputSurfaceImplStub(imageCaptureSurface);
- OutputSurfaceImplStub outputPostviewSurfaceImpl =
- new OutputSurfaceImplStub(postviewSurface);
+ mOutputPreviewSurfaceImpl = new OutputSurfaceImplStub(previewSurface);
+ mOutputImageCaptureSurfaceImpl = new OutputSurfaceImplStub(imageCaptureSurface);
+ mOutputPostviewSurfaceImpl = new OutputSurfaceImplStub(postviewSurface);
Camera2SessionConfigImpl sessionConfig;
if (LATENCY_IMPROVEMENTS_SUPPORTED) {
OutputSurfaceConfigurationImplStub outputSurfaceConfigs =
- new OutputSurfaceConfigurationImplStub(outputPreviewSurfaceImpl,
+ new OutputSurfaceConfigurationImplStub(mOutputPreviewSurfaceImpl,
// Image Analysis Output is currently only supported in CameraX
- outputImageCaptureSurfaceImpl, null /*imageAnalysisSurfaceConfig*/,
- outputPostviewSurfaceImpl);
+ mOutputImageCaptureSurfaceImpl, null /*imageAnalysisSurfaceConfig*/,
+ mOutputPostviewSurfaceImpl);
sessionConfig = mSessionProcessor.initSession(cameraId,
getCharacteristicsMap(charsMapNative),
@@ -1596,8 +1597,8 @@
} else {
sessionConfig = mSessionProcessor.initSession(cameraId,
getCharacteristicsMap(charsMapNative),
- getApplicationContext(), outputPreviewSurfaceImpl,
- outputImageCaptureSurfaceImpl, null /*imageAnalysisSurfaceConfig*/);
+ getApplicationContext(), mOutputPreviewSurfaceImpl,
+ mOutputImageCaptureSurfaceImpl, null /*imageAnalysisSurfaceConfig*/);
}
List<Camera2OutputConfigImpl> outputConfigs = sessionConfig.getOutputConfigs();
@@ -1632,6 +1633,18 @@
public void deInitSession(IBinder token) {
CameraExtensionsProxyService.unregisterDeathRecipient(mToken, this);
mSessionProcessor.deInitSession();
+
+ if (Flags.surfaceLeakFix()) {
+ if (mOutputImageCaptureSurfaceImpl.mSurface != null) {
+ mOutputImageCaptureSurfaceImpl.mSurface.release();
+ }
+ if (mOutputPreviewSurfaceImpl.mSurface != null) {
+ mOutputPreviewSurfaceImpl.mSurface.release();
+ }
+ if (mOutputPostviewSurfaceImpl.mSurface != null) {
+ mOutputPostviewSurfaceImpl.mSurface.release();
+ }
+ }
}
@Override
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index cbb66dc..ff48c9d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -40,6 +40,7 @@
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
+import static com.android.internal.accessibility.common.ShortcutConstants.USER_SHORTCUT_TYPES;
import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils.logAccessibilityShortcutActivated;
import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -111,6 +112,7 @@
import android.safetycenter.SafetyCenterManager;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.Log;
@@ -145,9 +147,13 @@
import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkFeatureInfo;
import com.android.internal.accessibility.AccessibilityShortcutController.LaunchableFrameworkFeatureInfo;
+import com.android.internal.accessibility.common.ShortcutConstants;
+import com.android.internal.accessibility.common.ShortcutConstants.FloatingMenuSize;
+import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity;
import com.android.internal.accessibility.util.AccessibilityUtils;
+import com.android.internal.accessibility.util.ShortcutUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
@@ -168,6 +174,7 @@
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.pm.UserManagerInternal;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.utils.Slogf;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -191,6 +198,7 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
/**
* This class is instantiated by the system as a system level service and can be
@@ -2334,6 +2342,7 @@
if (!parsedAccessibilityServiceInfos.equals(userState.mInstalledServices)) {
userState.mInstalledServices.clear();
userState.mInstalledServices.addAll(parsedAccessibilityServiceInfos);
+ userState.updateTileServiceMapForAccessibilityServiceLocked();
return true;
}
return false;
@@ -2359,6 +2368,7 @@
if (!parsedAccessibilityShortcutInfos.equals(userState.mInstalledShortcuts)) {
userState.mInstalledShortcuts.clear();
userState.mInstalledShortcuts.addAll(parsedAccessibilityShortcutInfos);
+ userState.updateTileServiceMapForAccessibilityActivityLocked();
return true;
}
return false;
@@ -2621,6 +2631,12 @@
private <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId,
Set<T> set, Function<T, String> toString) {
+ persistColonDelimitedSetToSettingLocked(settingName, userId, set,
+ toString, /* defaultEmptyString= */ null);
+ }
+
+ private <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId,
+ Set<T> set, Function<T, String> toString, String defaultEmptyString) {
final StringBuilder builder = new StringBuilder();
for (T item : set) {
final String str = (item != null ? toString.apply(item) : null);
@@ -2636,7 +2652,18 @@
try {
final String settingValue = builder.toString();
Settings.Secure.putStringForUser(mContext.getContentResolver(),
- settingName, TextUtils.isEmpty(settingValue) ? null : settingValue, userId);
+ settingName,
+ TextUtils.isEmpty(settingValue) ? defaultEmptyString : settingValue, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private void persistIntToSetting(int userId, String settingName, int settingValue) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putIntForUser(
+ mContext.getContentResolver(), settingName, settingValue, userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -3005,6 +3032,7 @@
scheduleUpdateClientsIfNeededLocked(userState, forceUpdate);
updateAccessibilityShortcutKeyTargetsLocked(userState);
updateAccessibilityButtonTargetsLocked(userState);
+ updateAccessibilityQsTargetsLocked(userState);
// Update the capabilities before the mode because we will check the current mode is
// invalid or not..
updateMagnificationCapabilitiesSettingsChangeLocked(userState);
@@ -3132,6 +3160,7 @@
somethingChanged |= readMagnificationEnabledSettingsLocked(userState);
somethingChanged |= readAutoclickEnabledSettingLocked(userState);
somethingChanged |= readAccessibilityShortcutKeySettingLocked(userState);
+ somethingChanged |= readAccessibilityQsTargetsLocked(userState);
somethingChanged |= readAccessibilityButtonTargetsLocked(userState);
somethingChanged |= readAccessibilityButtonTargetComponentLocked(userState);
somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState);
@@ -3305,6 +3334,21 @@
return true;
}
+ private boolean readAccessibilityQsTargetsLocked(AccessibilityUserState userState) {
+ final Set<String> targetsFromSetting = new ArraySet<>();
+ readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_QS_TARGETS,
+ userState.mUserId, str -> str, targetsFromSetting);
+
+ final Set<String> currentTargets =
+ userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS);
+ if (targetsFromSetting.equals(currentTargets)) {
+ return false;
+ }
+ userState.updateA11yQsTargetLocked(targetsFromSetting);
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
+ return true;
+ }
+
private boolean readAccessibilityButtonTargetsLocked(AccessibilityUserState userState) {
final Set<String> targetsFromSetting = new ArraySet<>();
readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
@@ -3636,6 +3680,8 @@
final Set<String> shortcutKeyTargets =
userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY);
+ final Set<String> qsShortcutTargets =
+ userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS);
userState.mEnabledServices.forEach(componentName -> {
if (packageName != null && componentName != null
&& !packageName.equals(componentName.getPackageName())) {
@@ -3657,7 +3703,8 @@
return;
}
if (doesShortcutTargetsStringContain(buttonTargets, serviceName)
- || doesShortcutTargetsStringContain(shortcutKeyTargets, serviceName)) {
+ || doesShortcutTargetsStringContain(shortcutKeyTargets, serviceName)
+ || doesShortcutTargetsStringContain(qsShortcutTargets, serviceName)) {
return;
}
// For enabled a11y services targeting sdk version > Q and requesting a11y button should
@@ -3678,6 +3725,33 @@
}
/**
+ * Update the Settings.Secure.ACCESSIBILITY_QS_TARGETS so that it only contains valid content,
+ * and a side loaded service can't spoof the package name of the default service.
+ */
+ private void updateAccessibilityQsTargetsLocked(AccessibilityUserState userState) {
+ final Set<String> targets =
+ userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS);
+ final int lastSize = targets.size();
+ if (lastSize == 0) {
+ return;
+ }
+
+ // Removes the targets that are no longer installed on the device.
+ boolean somethingChanged = targets.removeIf(
+ name -> !userState.isShortcutTargetInstalledLocked(name));
+ if (!somethingChanged) {
+ return;
+ }
+ userState.updateA11yQsTargetLocked(targets);
+
+ // Update setting key with new value.
+ persistColonDelimitedSetToSettingLocked(
+ Settings.Secure.ACCESSIBILITY_QS_TARGETS,
+ userState.mUserId, targets, str -> str);
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
+ }
+
+ /**
* Remove the shortcut target for the unbound service which is requesting accessibility button
* and targeting sdk > Q from the accessibility button and shortcut.
*
@@ -3691,19 +3765,42 @@
.targetSdkVersion <= Build.VERSION_CODES.Q) {
return;
}
+
+ final List<Pair<Integer, String>> shortcutTypeAndShortcutSetting = List.of(
+ new Pair<>(ACCESSIBILITY_SHORTCUT_KEY,
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE),
+ new Pair<>(ACCESSIBILITY_BUTTON,
+ Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),
+ new Pair<>(UserShortcutType.QUICK_SETTINGS,
+ Settings.Secure.ACCESSIBILITY_QS_TARGETS)
+ );
+
final ComponentName serviceName = service.getComponentName();
- if (userState.removeShortcutTargetLocked(ACCESSIBILITY_SHORTCUT_KEY, serviceName)) {
- final Set<String> currentTargets = userState.getShortcutTargetsLocked(
- ACCESSIBILITY_SHORTCUT_KEY);
- persistColonDelimitedSetToSettingLocked(
- Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
- userState.mUserId, currentTargets, str -> str);
- }
- if (userState.removeShortcutTargetLocked(ACCESSIBILITY_BUTTON, serviceName)) {
- final Set<String> currentTargets = userState.getShortcutTargetsLocked(
- ACCESSIBILITY_BUTTON);
- persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
- userState.mUserId, currentTargets, str -> str);
+ for (Pair<Integer, String> shortcutTypePair : shortcutTypeAndShortcutSetting) {
+ int shortcutType = shortcutTypePair.first;
+ String shortcutSettingName = shortcutTypePair.second;
+ if (userState.removeShortcutTargetLocked(shortcutType, serviceName)) {
+ final Set<String> currentTargets = userState.getShortcutTargetsLocked(shortcutType);
+ persistColonDelimitedSetToSettingLocked(
+ shortcutSettingName,
+ userState.mUserId, currentTargets, str -> str);
+
+ if (shortcutType != UserShortcutType.QUICK_SETTINGS) {
+ continue;
+ }
+
+ ComponentName tileService =
+ userState.getA11yFeatureToTileService().getOrDefault(serviceName, null);
+
+ final StatusBarManagerInternal statusBarManagerInternal =
+ LocalServices.getService(StatusBarManagerInternal.class);
+ // In case it's not initialized yet
+ if (statusBarManagerInternal == null || tileService == null) {
+ continue;
+ }
+ mMainHandler.sendMessage(obtainMessage(StatusBarManagerInternal::removeQsTile,
+ statusBarManagerInternal, tileService));
+ }
}
}
@@ -3967,6 +4064,262 @@
}
}
+ /**
+ * Turns on or off a shortcut type of the accessibility features. The {@code shortcutTypes} is a
+ * flag that contains values defined in the
+ * {@link ShortcutConstants.USER_SHORTCUT_TYPES}.
+ *
+ * @hide
+ */
+ @Override
+ public void enableShortcutsForTargets(
+ boolean enable, @UserShortcutType int shortcutTypes,
+ @NonNull List<String> shortcutTargets, @UserIdInt int userId) {
+ mContext.enforceCallingPermission(
+ Manifest.permission.MANAGE_ACCESSIBILITY, "enableShortcutsForTargets");
+ for (int shortcutType : USER_SHORTCUT_TYPES) {
+ if ((shortcutTypes & shortcutType) == shortcutType) {
+ enableShortcutForTargets(enable, shortcutType, shortcutTargets, userId);
+ }
+ }
+ }
+
+ private void enableShortcutForTargets(
+ boolean enable, @UserShortcutType int shortcutType,
+ @NonNull List<String> shortcutTargets, @UserIdInt int userId) {
+ final String shortcutTypeSettingKey = ShortcutUtils.convertToKey(shortcutType);
+ if (shortcutType == UserShortcutType.TRIPLETAP
+ || shortcutType == UserShortcutType.TWOFINGER_DOUBLETAP) {
+ for (String target : shortcutTargets) {
+ if (MAGNIFICATION_CONTROLLER_NAME.equals(target)) {
+ persistIntToSetting(
+ userId,
+ shortcutTypeSettingKey,
+ enable ? AccessibilityUtils.State.ON : AccessibilityUtils.State.OFF);
+ } else {
+ Slog.w(LOG_TAG,
+ "Triple tap or two-fingers double-tap is not supported for " + target);
+ }
+ }
+ return;
+ }
+ Set<String> validNewTargets;
+ Set<String> currentTargets;
+
+ Map<ComponentName, ComponentName> featureToTileMap =
+ getA11yFeatureToTileMapInternal(userId);
+ synchronized (mLock) {
+ AccessibilityUserState userState = getUserStateLocked(userId);
+ currentTargets =
+ ShortcutUtils.getShortcutTargetsFromSettings(mContext, shortcutType, userId);
+
+ Set<String> newTargets = new ArraySet<>(currentTargets);
+ if (enable) {
+ newTargets.addAll(shortcutTargets);
+ } else {
+ newTargets.removeAll(shortcutTargets);
+ }
+ validNewTargets = newTargets;
+
+ // filter out targets that doesn't have qs shortcut
+ if (shortcutType == UserShortcutType.QUICK_SETTINGS) {
+ validNewTargets = newTargets.stream().filter(target -> {
+ ComponentName targetComponent = ComponentName.unflattenFromString(target);
+ return featureToTileMap.containsKey(targetComponent);
+ }).collect(Collectors.toUnmodifiableSet());
+ }
+
+ if (currentTargets.equals(validNewTargets)) {
+ return;
+ }
+ persistColonDelimitedSetToSettingLocked(
+ shortcutTypeSettingKey,
+ userId,
+ validNewTargets,
+ str -> str,
+ /* defaultEmptyString= */ ""
+ );
+
+ if (shortcutType == UserShortcutType.QUICK_SETTINGS) {
+ userState.updateA11yQsTargetLocked(validNewTargets);
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
+ onUserStateChangedLocked(userState);
+ }
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
+ mContext, new ArraySet<>(shortcutTargets), userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ // Add or Remove tile in QS Panel
+ if (shortcutType == UserShortcutType.QUICK_SETTINGS) {
+ mMainHandler.sendMessage(obtainMessage(
+ AccessibilityManagerService::updateA11yTileServicesInQuickSettingsPanel,
+ this, validNewTargets, currentTargets, userId));
+ }
+
+ if (!enable) {
+ return;
+ }
+ if (shortcutType == UserShortcutType.HARDWARE) {
+ skipVolumeShortcutDialogTimeoutRestriction(userId);
+ } else if (shortcutType == UserShortcutType.SOFTWARE) {
+ // Update the A11y FAB size to large when the Magnification shortcut is
+ // enabled and the user hasn't changed the floating button size
+ if (shortcutTargets.contains(MAGNIFICATION_CONTROLLER_NAME)
+ && Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
+ FloatingMenuSize.UNKNOWN, userId) == FloatingMenuSize.UNKNOWN) {
+ persistIntToSetting(
+ userId,
+ Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
+ FloatingMenuSize.LARGE);
+ }
+ }
+ }
+
+ /**
+ * Add or remove the TileServices of the a11y features in the Quick Settings panel based on the
+ * changes in the new targets and current targets.
+ *
+ * <p>
+ * The framework tiles implemented in the SysUi are automatically added/removed via the
+ * SystemUI's AutoAddable framework. This method only handles updating the TileServices
+ * provided by AccessibilityService or Accessibility Activity.
+ * </p>
+ *
+ * @see com.android.systemui.qs.pipeline.domain.model.AutoAddable AutoAddable QS Tiles
+ */
+ private void updateA11yTileServicesInQuickSettingsPanel(
+ Set<String> newQsTargets,
+ Set<String> currentQsTargets, @UserIdInt int userId) {
+ // Call StatusBarManager to add/remove tiles
+ final StatusBarManagerInternal statusBarManagerInternal =
+ LocalServices.getService(StatusBarManagerInternal.class);
+ // In case it's not initialized yet
+ if (statusBarManagerInternal == null) {
+ return;
+ }
+
+ Map<ComponentName, ComponentName> a11yFeatureToTileMap =
+ getA11yFeatureToTileMapInternal(userId);
+ Set<String> targetWithNoTile = new ArraySet<>();
+
+ // Add TileServices to QS Panel that are added to the new targets
+ newQsTargets.stream()
+ .filter(target -> !currentQsTargets.contains(target))
+ .forEach(
+ target -> {
+ ComponentName targetComponent =
+ ComponentName.unflattenFromString(target);
+ if (targetComponent == null
+ || !a11yFeatureToTileMap.containsKey(targetComponent)) {
+ targetWithNoTile.add(target);
+ return;
+ }
+
+ if (ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.containsKey(
+ targetComponent)) {
+ // a11y framework tile is handled by the SysUi autoaddable framework
+ return;
+ }
+ statusBarManagerInternal.addQsTileToFrontOrEnd(
+ a11yFeatureToTileMap.get(targetComponent), /* end= */ true);
+ }
+ );
+
+ // Remove TileServices from QS Panel that are no longer in the new targets.
+ currentQsTargets.stream()
+ .filter(target -> !newQsTargets.contains(target))
+ .forEach(
+ target -> {
+ ComponentName targetComponent =
+ ComponentName.unflattenFromString(target);
+ if (targetComponent == null
+ || !a11yFeatureToTileMap.containsKey(targetComponent)) {
+ targetWithNoTile.add(target);
+ return;
+ }
+
+ if (ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.containsKey(
+ targetComponent)) {
+ // a11y framework tile is handled by the SysUi autoaddable framework
+ return;
+ }
+ statusBarManagerInternal.removeQsTile(
+ a11yFeatureToTileMap.get(targetComponent));
+ }
+ );
+
+ if (!targetWithNoTile.isEmpty()) {
+ throw new IllegalArgumentException(
+ "Unable to add/remove Tiles for a11y features: " + targetWithNoTile
+ + "as the Tiles aren't provided");
+ }
+ }
+
+ @Override
+ public Bundle getA11yFeatureToTileMap(@UserIdInt int userId) {
+ mContext.enforceCallingPermission(
+ Manifest.permission.MANAGE_ACCESSIBILITY, "getA11yFeatureToTileMap");
+
+ Bundle bundle = new Bundle();
+ Map<ComponentName, ComponentName> a11yFeatureToTile =
+ getA11yFeatureToTileMapInternal(userId);
+ for (Map.Entry<ComponentName, ComponentName> entry : a11yFeatureToTile.entrySet()) {
+ bundle.putParcelable(entry.getKey().flattenToString(), entry.getValue());
+ }
+ return bundle;
+ }
+
+
+
+ /**
+ * Returns accessibility feature's component and the provided tile map. This includes the
+ * TileService provided by the AccessibilityService or Accessibility Activity and the tile
+ * component provided by the framework's feature.
+ *
+ * @return a map of a feature's component name, and its provided tile's component name. The
+ * returned map's keys and values are not null. If a feature doesn't provide a tile, it won't
+ * have an entry in this map.
+ *
+ * @see ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE
+ */
+ @NonNull
+ private Map<ComponentName, ComponentName> getA11yFeatureToTileMapInternal(
+ @UserIdInt int userId) {
+ final Map<ComponentName, ComponentName> a11yFeatureToTileService;
+ Map<ComponentName, ComponentName> a11yFeatureToTile = new ArrayMap<>();
+ final int resolvedUserId;
+
+ synchronized (mLock) {
+ resolvedUserId = mSecurityPolicy
+ .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+ AccessibilityUserState userState = getUserStateLocked(resolvedUserId);
+ a11yFeatureToTileService = userState.getA11yFeatureToTileService();
+ }
+ final boolean shouldFilterAppAccess = Binder.getCallingPid() != OWN_PROCESS_ID;
+ final int callingUid = Binder.getCallingUid();
+ final PackageManagerInternal pm = LocalServices.getService(
+ PackageManagerInternal.class);
+
+ for (Map.Entry<ComponentName, ComponentName> entry :
+ a11yFeatureToTileService.entrySet()) {
+ if (shouldFilterAppAccess
+ && pm.filterAppAccess(
+ entry.getKey().getPackageName(), callingUid, resolvedUserId)) {
+ continue;
+ }
+ a11yFeatureToTile.put(entry.getKey(), entry.getValue());
+ }
+
+ a11yFeatureToTile.putAll(ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE);
+ return a11yFeatureToTile;
+ }
+
@Override
public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) {
if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
@@ -5836,4 +6189,15 @@
}
}
}
+
+
+ /**
+ * Bypasses the timeout restriction if volume key shortcut assigned.
+ */
+ private void skipVolumeShortcutDialogTimeoutRestriction(int userId) {
+ persistIntToSetting(
+ userId,
+ Settings.Secure.SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION,
+ /* true */ 1);
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 68ee780..063eafe 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -38,10 +38,12 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.Binder;
import android.os.RemoteCallbackList;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
@@ -51,6 +53,7 @@
import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController;
+import com.android.internal.accessibility.common.ShortcutConstants;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -99,6 +102,7 @@
final ArraySet<String> mAccessibilityShortcutKeyTargets = new ArraySet<>();
final ArraySet<String> mAccessibilityButtonTargets = new ArraySet<>();
+ private final ArraySet<String> mAccessibilityQsTargets = new ArraySet<>();
private final ServiceInfoChangeListener mServiceInfoChangeListener;
@@ -146,6 +150,8 @@
private final int mFocusStrokeWidthDefaultValue;
// The default value of the focus color.
private final int mFocusColorDefaultValue;
+ private final Map<ComponentName, ComponentName> mA11yServiceToTileService = new ArrayMap<>();
+ private final Map<ComponentName, ComponentName> mA11yActivityToTileService = new ArrayMap<>();
private Context mContext;
@@ -560,6 +566,8 @@
pw.println("}");
pw.append(" button target:{").append(mTargetAssignedToAccessibilityButton);
pw.println("}");
+ pw.append(" qs shortcut targets:" + mAccessibilityQsTargets);
+ pw.println();
pw.append(" Bound services:{");
final int serviceCount = mBoundServices.size();
for (int j = 0; j < serviceCount; j++) {
@@ -762,6 +770,8 @@
return mAccessibilityShortcutKeyTargets;
} else if (shortcutType == ACCESSIBILITY_BUTTON) {
return mAccessibilityButtonTargets;
+ } else if (shortcutType == ShortcutConstants.UserShortcutType.QUICK_SETTINGS) {
+ return getA11yQsTargets();
}
return null;
}
@@ -808,7 +818,8 @@
*/
public boolean removeShortcutTargetLocked(@ShortcutType int shortcutType,
ComponentName target) {
- return getShortcutTargetsLocked(shortcutType).removeIf(name -> {
+ Set<String> targets = getShortcutTargetsLocked(shortcutType);
+ boolean result = targets.removeIf(name -> {
ComponentName componentName;
if (name == null
|| (componentName = ComponentName.unflattenFromString(name)) == null) {
@@ -816,6 +827,11 @@
}
return componentName.equals(target);
});
+ if (shortcutType == ShortcutConstants.UserShortcutType.QUICK_SETTINGS) {
+ updateA11yQsTargetLocked(targets);
+ }
+
+ return result;
}
/**
@@ -1034,4 +1050,60 @@
}
return false;
}
+
+ public void updateTileServiceMapForAccessibilityServiceLocked() {
+ mA11yServiceToTileService.clear();
+ mInstalledServices.forEach(
+ a11yServiceInfo -> {
+ String tileServiceName = a11yServiceInfo.getTileServiceName();
+ if (!TextUtils.isEmpty(tileServiceName)) {
+ ResolveInfo resolveInfo = a11yServiceInfo.getResolveInfo();
+ ComponentName a11yFeature = new ComponentName(
+ resolveInfo.serviceInfo.packageName,
+ resolveInfo.serviceInfo.name
+ );
+ ComponentName tileService = new ComponentName(
+ a11yFeature.getPackageName(),
+ tileServiceName
+ );
+ mA11yServiceToTileService.put(a11yFeature, tileService);
+ }
+ }
+ );
+ }
+
+ public void updateTileServiceMapForAccessibilityActivityLocked() {
+ mA11yActivityToTileService.clear();
+ mInstalledShortcuts.forEach(
+ a11yShortcutInfo -> {
+ String tileServiceName = a11yShortcutInfo.getTileServiceName();
+ if (!TextUtils.isEmpty(tileServiceName)) {
+ ComponentName a11yFeature = a11yShortcutInfo.getComponentName();
+ ComponentName tileService = new ComponentName(
+ a11yFeature.getPackageName(),
+ tileServiceName);
+ mA11yActivityToTileService.put(a11yFeature, tileService);
+ }
+ }
+ );
+ }
+
+ public void updateA11yQsTargetLocked(Set<String> targets) {
+ mAccessibilityQsTargets.clear();
+ mAccessibilityQsTargets.addAll(targets);
+ }
+
+ /**
+ * Returns a copy of the targets which has qs shortcut turned on
+ */
+ public ArraySet<String> getA11yQsTargets() {
+ return new ArraySet<>(mAccessibilityQsTargets);
+ }
+
+ public Map<ComponentName, ComponentName> getA11yFeatureToTileService() {
+ Map<ComponentName, ComponentName> featureToTileServiceMap = new ArrayMap<>();
+ featureToTileServiceMap.putAll(mA11yServiceToTileService);
+ featureToTileServiceMap.putAll(mA11yActivityToTileService);
+ return featureToTileServiceMap;
+ }
}
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 982076d..91b64f8 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -80,6 +80,7 @@
sSecureSettingToTypeMap.put(Settings.Secure.MULTI_PRESS_TIMEOUT, int.class);
sSecureSettingToTypeMap.put(Settings.Secure.KEY_REPEAT_TIMEOUT_MS, int.class);
sSecureSettingToTypeMap.put(Settings.Secure.KEY_REPEAT_DELAY_MS, int.class);
+ sSecureSettingToTypeMap.put(Settings.Secure.STYLUS_POINTER_ICON_ENABLED, int.class);
// add other secure settings here...
sSystemSettingToTypeMap.put(Settings.System.TIME_12_24, String.class);
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index c02d524..a1341b7 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -258,6 +258,7 @@
}
private void updateStylusPointerIconEnabled() {
- mNative.setStylusPointerIconEnabled(InputSettings.isStylusPointerIconEnabled(mContext));
+ mNative.setStylusPointerIconEnabled(
+ InputSettings.isStylusPointerIconEnabled(mContext, true /* forceReloadSetting */));
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 19f0298..996477d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1247,6 +1247,14 @@
*/
private boolean mImePackageAppeared = false;
+ /**
+ * Remembers package names passed to {@link #onPackageDataCleared(String, int)}.
+ *
+ * <p>This field must be accessed only from callback methods in {@link PackageMonitor},
+ * which should be bound to {@link #getRegisteredHandler()}.</p>
+ */
+ private ArrayList<String> mDataClearedPackages = new ArrayList<>();
+
@GuardedBy("ImfLock.class")
void clearKnownImePackageNamesLocked() {
mKnownImePackageNames.clear();
@@ -1350,36 +1358,8 @@
@Override
public void onPackageDataCleared(String packageName, int uid) {
- final int userId = getChangingUserId();
- synchronized (ImfLock.class) {
- final boolean isCurrentUser = (userId == mSettings.getUserId());
- final AdditionalSubtypeMap additionalSubtypeMap =
- AdditionalSubtypeMapRepository.get(userId);
- final InputMethodSettings settings;
- if (isCurrentUser) {
- settings = mSettings;
- } else {
- settings = queryInputMethodServicesInternal(mContext, userId,
- additionalSubtypeMap, DirectBootAwareness.AUTO);
- }
-
- // Note that one package may implement multiple IMEs.
- final ArrayList<String> changedImes = new ArrayList<>();
- for (InputMethodInfo imi : settings.getMethodList()) {
- if (imi.getPackageName().equals(packageName)) {
- changedImes.add(imi.getId());
- }
- }
- final AdditionalSubtypeMap newMap =
- additionalSubtypeMap.cloneWithRemoveOrSelf(changedImes);
- if (newMap != additionalSubtypeMap) {
- AdditionalSubtypeMapRepository.putAndSave(userId, newMap,
- settings.getMethodMap());
- }
- if (!changedImes.isEmpty()) {
- mChangedPackages.add(packageName);
- }
- }
+ mChangedPackages.add(packageName);
+ mDataClearedPackages.add(packageName);
}
@Override
@@ -1391,6 +1371,7 @@
private void clearPackageChangeState() {
// No need to lock them because we access these fields only on getRegisteredHandler().
mChangedPackages.clear();
+ mDataClearedPackages.clear();
mImePackageAppeared = false;
}
@@ -1421,7 +1402,7 @@
synchronized (ImfLock.class) {
final int userId = getChangingUserId();
final boolean isCurrentUser = (userId == mSettings.getUserId());
- AdditionalSubtypeMap additionalSubtypeMap =
+ final AdditionalSubtypeMap additionalSubtypeMap =
AdditionalSubtypeMapRepository.get(userId);
final InputMethodSettings settings;
if (isCurrentUser) {
@@ -1434,6 +1415,8 @@
InputMethodInfo curIm = null;
String curInputMethodId = settings.getSelectedInputMethod();
final List<InputMethodInfo> methodList = settings.getMethodList();
+
+ final ArrayList<String> imesToClearAdditionalSubtypes = new ArrayList<>();
final int numImes = methodList.size();
for (int i = 0; i < numImes; i++) {
InputMethodInfo imi = methodList.get(i);
@@ -1441,6 +1424,9 @@
if (imiId.equals(curInputMethodId)) {
curIm = imi;
}
+ if (mDataClearedPackages.contains(imi.getPackageName())) {
+ imesToClearAdditionalSubtypes.add(imiId);
+ }
int change = isPackageDisappearing(imi.getPackageName());
if (change == PACKAGE_TEMPORARY_CHANGE || change == PACKAGE_PERMANENT_CHANGE) {
Slog.i(TAG, "Input method uninstalled, disabling: " + imi.getComponent());
@@ -1455,14 +1441,22 @@
} else if (change == PACKAGE_UPDATING) {
Slog.i(TAG, "Input method reinstalling, clearing additional subtypes: "
+ imi.getComponent());
- additionalSubtypeMap =
- additionalSubtypeMap.cloneWithRemoveOrSelf(imi.getId());
- AdditionalSubtypeMapRepository.putAndSave(userId,
- additionalSubtypeMap, settings.getMethodMap());
+ imesToClearAdditionalSubtypes.add(imiId);
}
}
- if (!isCurrentUser || !shouldRebuildInputMethodListLocked()) {
+ // Clear additional subtypes as a batch operation.
+ final AdditionalSubtypeMap newAdditionalSubtypeMap =
+ additionalSubtypeMap.cloneWithRemoveOrSelf(imesToClearAdditionalSubtypes);
+ final boolean additionalSubtypeChanged =
+ (newAdditionalSubtypeMap != additionalSubtypeMap);
+ if (additionalSubtypeChanged) {
+ AdditionalSubtypeMapRepository.putAndSave(userId, newAdditionalSubtypeMap,
+ settings.getMethodMap());
+ }
+
+ if (!isCurrentUser
+ || !(additionalSubtypeChanged || shouldRebuildInputMethodListLocked())) {
return;
}
diff --git a/services/core/java/com/android/server/location/contexthub/OWNERS b/services/core/java/com/android/server/location/contexthub/OWNERS
index 90c2330..c62e323 100644
--- a/services/core/java/com/android/server/location/contexthub/OWNERS
+++ b/services/core/java/com/android/server/location/contexthub/OWNERS
@@ -1,3 +1,3 @@
-arthuri@google.com
bduddie@google.com
+matthewsedam@google.com
stange@google.com
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 18b495b..97ce77c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -340,6 +340,8 @@
static final String TAG = NetworkPolicyLogger.TAG;
private static final boolean LOGD = NetworkPolicyLogger.LOGD;
private static final boolean LOGV = NetworkPolicyLogger.LOGV;
+ // TODO: b/304347838 - Remove once the feature is in staging.
+ private static final boolean ALWAYS_RESTRICT_BACKGROUND_NETWORK = false;
/**
* No opportunistic quota could be calculated from user data plan or data settings.
@@ -1068,7 +1070,8 @@
}
// The flag is boot-stable.
- mBackgroundNetworkRestricted = Flags.networkBlockedForTopSleepingAndAbove();
+ mBackgroundNetworkRestricted = ALWAYS_RESTRICT_BACKGROUND_NETWORK
+ && Flags.networkBlockedForTopSleepingAndAbove();
if (mBackgroundNetworkRestricted) {
// Firewall rules and UidBlockedState will get updated in
// updateRulesForGlobalChangeAL below.
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 59d6219..e35a169 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2710,7 +2710,8 @@
} catch (java.io.IOException e) {
mReadMessages.append("Error reading: " + e.toString());
- PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Error reading stopped packages: " + e);
Slog.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages",
e);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 95cfc2a..7ea722b 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -61,7 +61,9 @@
import android.graphics.drawable.Icon;
import android.hardware.display.DisplayManagerGlobal;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
import android.os.LocaleList;
import android.os.UserHandle;
@@ -70,20 +72,28 @@
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
+import android.testing.TestableLooper;
import android.util.ArraySet;
import android.view.Display;
import android.view.DisplayAdjustments;
import android.view.DisplayInfo;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityWindowAttributes;
+import android.view.accessibility.IAccessibilityManager;
-import androidx.test.InstrumentationRegistry;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.TestUtils;
import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
+import com.android.internal.accessibility.common.ShortcutConstants.FloatingMenuSize;
+import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
+import com.android.internal.accessibility.util.AccessibilityUtils;
+import com.android.internal.accessibility.util.ShortcutUtils;
import com.android.internal.compat.IPlatformCompat;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityManagerService.AccessibilityDisplayListener;
@@ -91,31 +101,38 @@
import com.android.server.accessibility.magnification.MagnificationConnectionManager;
import com.android.server.accessibility.magnification.MagnificationController;
import com.android.server.accessibility.magnification.MagnificationProcessor;
-import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.pm.UserManagerInternal;
+import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import org.mockito.internal.util.reflection.FieldReader;
+import org.mockito.internal.util.reflection.FieldSetter;
import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
/**
* APCT tests for {@link AccessibilityManagerService}.
*/
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
public class AccessibilityManagerServiceTest {
@Rule
public final A11yTestableContext mTestableContext = new A11yTestableContext(
@@ -140,6 +157,12 @@
TEST_PENDING_INTENT);
private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY + 1;
+ private static final String TARGET_MAGNIFICATION = MAGNIFICATION_CONTROLLER_NAME;
+ private static final ComponentName TARGET_ALWAYS_ON_A11Y_SERVICE =
+ new ComponentName("FakePackage", "AlwaysOnA11yService");
+ private static final String TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS = "TileService";
+ private static final ComponentName TARGET_STANDARD_A11Y_SERVICE =
+ new ComponentName("FakePackage", "StandardA11yService");
static final ComponentName COMPONENT_NAME = new ComponentName(
"com.android.server.accessibility", "AccessibilityManagerServiceTest");
@@ -163,24 +186,33 @@
@Mock private MagnificationController mMockMagnificationController;
@Mock private FullScreenMagnificationController mMockFullScreenMagnificationController;
@Mock private ProxyManager mProxyManager;
+ @Mock private StatusBarManagerInternal mStatusBarManagerInternal;
@Captor private ArgumentCaptor<Intent> mIntentArgumentCaptor;
- private MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
+ private IAccessibilityManager mA11yManagerServiceOnDevice;
private AccessibilityServiceConnection mAccessibilityServiceConnection;
private AccessibilityInputFilter mInputFilter;
private AccessibilityManagerService mA11yms;
+ private TestableLooper mTestableLooper;
+ private Handler mHandler;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mTestableLooper = TestableLooper.get(this);
+ mHandler = new Handler(mTestableLooper.getLooper());
+
LocalServices.removeServiceForTest(WindowManagerInternal.class);
LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
LocalServices.removeServiceForTest(UserManagerInternal.class);
+ LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
LocalServices.addService(
WindowManagerInternal.class, mMockWindowManagerService);
LocalServices.addService(
ActivityTaskManagerInternal.class, mMockActivityTaskManagerInternal);
LocalServices.addService(
UserManagerInternal.class, mMockUserManagerInternal);
+ LocalServices.addService(
+ StatusBarManagerInternal.class, mStatusBarManagerInternal);
mInputFilter = Mockito.mock(FakeInputFilter.class);
when(mMockMagnificationController.getMagnificationConnectionManager()).thenReturn(
@@ -218,6 +250,19 @@
final AccessibilityUserState userState = new AccessibilityUserState(
mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
mA11yms.mUserStates.put(mA11yms.getCurrentUserIdLocked(), userState);
+ AccessibilityManager am = mTestableContext.getSystemService(AccessibilityManager.class);
+ mA11yManagerServiceOnDevice = (IAccessibilityManager) new FieldReader(am,
+ AccessibilityManager.class.getDeclaredField("mService")).read();
+ FieldSetter.setField(am, AccessibilityManager.class.getDeclaredField("mService"), mA11yms);
+ }
+
+ @After
+ public void cleanUp() throws Exception {
+ mTestableLooper.processAllMessages();
+ AccessibilityManager am = mTestableContext.getSystemService(AccessibilityManager.class);
+ FieldSetter.setField(
+ am, AccessibilityManager.class.getDeclaredField("mService"),
+ mA11yManagerServiceOnDevice);
}
private void setupAccessibilityServiceConnection(int serviceInfoFlag) {
@@ -297,7 +342,8 @@
mA11yms.getCurrentUserIdLocked());
mA11yms.notifySystemActionsChangedLocked(userState);
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ mTestableLooper.processAllMessages();
+
verify(mMockServiceClient).onSystemActionsChanged();
}
@@ -415,7 +461,7 @@
);
mA11yms.onMagnificationTransitionEndedLocked(Display.DEFAULT_DISPLAY, true);
- mHandler.sendAllMessages();
+ mTestableLooper.processAllMessages();
ArgumentCaptor<Display> displayCaptor = ArgumentCaptor.forClass(Display.class);
verify(mInputFilter, timeout(100)).refreshMagnificationMode(displayCaptor.capture());
@@ -730,7 +776,7 @@
mA11yms.performAccessibilityShortcut(
ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
- mHandler.sendAllMessages();
+ mTestableLooper.processAllMessages();
assertStartActivityWithExpectedComponentName(mTestableContext.getMockContext(),
ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
@@ -907,11 +953,14 @@
public void testIsAccessibilityServiceWarningRequired_notRequiredIfAllowlisted() {
mockManageAccessibilityGranted(mTestableContext);
final AccessibilityServiceInfo info_a = mockAccessibilityServiceInfo(
- new ComponentName("package_a", "class_a"), true);
+ new ComponentName("package_a", "class_a"),
+ /* isSystemApp= */ true, /* isAlwaysOnService= */ false);
final AccessibilityServiceInfo info_b = mockAccessibilityServiceInfo(
- new ComponentName("package_b", "class_b"), false);
+ new ComponentName("package_b", "class_b"),
+ /* isSystemApp= */ false, /* isAlwaysOnService= */ false);
final AccessibilityServiceInfo info_c = mockAccessibilityServiceInfo(
- new ComponentName("package_c", "class_c"), true);
+ new ComponentName("package_c", "class_c"),
+ /* isSystemApp= */ true, /* isAlwaysOnService= */ false);
mTestableContext.getOrCreateTestableResources().addOverride(
R.array.config_trustedAccessibilityServices,
new String[]{
@@ -926,14 +975,380 @@
assertThat(mA11yms.isAccessibilityServiceWarningRequired(info_c)).isFalse();
}
+ @Test
+ public void enableShortcutsForTargets_permissionNotGranted_throwsException() {
+ mTestableContext.getTestablePermissions().setPermission(
+ Manifest.permission.MANAGE_ACCESSIBILITY, PackageManager.PERMISSION_DENIED);
+
+ assertThrows(SecurityException.class,
+ () -> mA11yms.enableShortcutsForTargets(
+ /* enable= */true,
+ UserShortcutType.SOFTWARE,
+ List.of(TARGET_MAGNIFICATION),
+ mA11yms.getCurrentUserIdLocked()));
+ }
+
+ @Test
+ public void enableShortcutsForTargets_enableSoftwareShortcut_shortcutTurnedOn()
+ throws Exception {
+ mockManageAccessibilityGranted(mTestableContext);
+ setupShortcutTargetServices();
+ String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ true,
+ UserShortcutType.SOFTWARE,
+ List.of(target),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(ShortcutUtils.isComponentIdExistingInSettings(
+ mTestableContext, UserShortcutType.SOFTWARE, target
+ )).isTrue();
+ }
+
+ @Test
+ public void enableShortcutsForTargets_disableSoftwareShortcut_shortcutTurnedOff()
+ throws Exception {
+ String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
+ enableShortcutsForTargets_enableSoftwareShortcut_shortcutTurnedOn();
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ false,
+ UserShortcutType.SOFTWARE,
+ List.of(target),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(ShortcutUtils.isComponentIdExistingInSettings(
+ mTestableContext, UserShortcutType.SOFTWARE, target
+ )).isFalse();
+ }
+
+ @Test
+ public void enableShortcutsForTargets_enableSoftwareShortcutWithMagnification_menuSizeIncreased() {
+ mockManageAccessibilityGranted(mTestableContext);
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ true,
+ UserShortcutType.SOFTWARE,
+ List.of(MAGNIFICATION_CONTROLLER_NAME),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(
+ Settings.Secure.getInt(
+ mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
+ FloatingMenuSize.UNKNOWN))
+ .isEqualTo(FloatingMenuSize.LARGE);
+ }
+
+ @Test
+ public void enableShortcutsForTargets_enableSoftwareShortcutWithMagnification_userConfigureSmallMenuSize_menuSizeNotChanged() {
+ mockManageAccessibilityGranted(mTestableContext);
+ Settings.Secure.putInt(
+ mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
+ FloatingMenuSize.SMALL);
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ true,
+ UserShortcutType.SOFTWARE,
+ List.of(MAGNIFICATION_CONTROLLER_NAME),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(
+ Settings.Secure.getInt(
+ mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
+ FloatingMenuSize.UNKNOWN))
+ .isEqualTo(FloatingMenuSize.SMALL);
+ }
+
+ @Test
+ public void enableShortcutsForTargets_enableAlwaysOnServiceSoftwareShortcut_turnsOnAlwaysOnService()
+ throws Exception {
+ mockManageAccessibilityGranted(mTestableContext);
+ setupShortcutTargetServices();
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ true,
+ UserShortcutType.SOFTWARE,
+ List.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString()),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(
+ AccessibilityUtils.getEnabledServicesFromSettings(
+ mTestableContext,
+ mA11yms.getCurrentUserIdLocked())
+ ).contains(TARGET_ALWAYS_ON_A11Y_SERVICE);
+ }
+
+ @Test
+ public void enableShortcutsForTargets_disableAlwaysOnServiceSoftwareShortcut_turnsOffAlwaysOnService()
+ throws Exception {
+ enableShortcutsForTargets_enableAlwaysOnServiceSoftwareShortcut_turnsOnAlwaysOnService();
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ false,
+ UserShortcutType.SOFTWARE,
+ List.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString()),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(
+ AccessibilityUtils.getEnabledServicesFromSettings(
+ mTestableContext,
+ mA11yms.getCurrentUserIdLocked())
+ ).doesNotContain(TARGET_ALWAYS_ON_A11Y_SERVICE);
+ }
+
+ @Test
+ public void enableShortcutsForTargets_enableStandardServiceSoftwareShortcut_wontTurnOnService()
+ throws Exception {
+ mockManageAccessibilityGranted(mTestableContext);
+ setupShortcutTargetServices();
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ true,
+ UserShortcutType.SOFTWARE,
+ List.of(TARGET_STANDARD_A11Y_SERVICE.flattenToString()),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(
+ AccessibilityUtils.getEnabledServicesFromSettings(
+ mTestableContext,
+ mA11yms.getCurrentUserIdLocked())
+ ).doesNotContain(TARGET_STANDARD_A11Y_SERVICE);
+ }
+
+ @Test
+ public void enableShortcutsForTargets_disableStandardServiceSoftwareShortcutWithServiceOn_wontTurnOffService()
+ throws Exception {
+ enableShortcutsForTargets_enableStandardServiceSoftwareShortcut_wontTurnOnService();
+ AccessibilityUtils.setAccessibilityServiceState(
+ mTestableContext, TARGET_STANDARD_A11Y_SERVICE, /* enabled= */ true);
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ false,
+ UserShortcutType.SOFTWARE,
+ List.of(TARGET_STANDARD_A11Y_SERVICE.flattenToString()),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(
+ AccessibilityUtils.getEnabledServicesFromSettings(
+ mTestableContext,
+ mA11yms.getCurrentUserIdLocked())
+ ).contains(TARGET_STANDARD_A11Y_SERVICE);
+ }
+
+ @Test
+ public void enableShortcutsForTargets_enableTripleTapShortcut_settingUpdated() {
+ mockManageAccessibilityGranted(mTestableContext);
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ true,
+ UserShortcutType.TRIPLETAP,
+ List.of(TARGET_MAGNIFICATION),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(
+ Settings.Secure.getInt(
+ mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
+ AccessibilityUtils.State.OFF)
+ ).isEqualTo(AccessibilityUtils.State.ON);
+ }
+
+ @Test
+ public void enableShortcutsForTargets_disableTripleTapShortcut_settingUpdated() {
+ enableShortcutsForTargets_enableTripleTapShortcut_settingUpdated();
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ false,
+ UserShortcutType.TRIPLETAP,
+ List.of(TARGET_MAGNIFICATION),
+ mA11yms.getCurrentUserIdLocked());
+
+ assertThat(
+ Settings.Secure.getInt(
+ mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
+ AccessibilityUtils.State.OFF)
+ ).isEqualTo(AccessibilityUtils.State.OFF);
+ }
+
+ @Test
+ public void enableShortcutsForTargets_enableMultiFingerMultiTapsShortcut_settingUpdated() {
+ mockManageAccessibilityGranted(mTestableContext);
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ true,
+ UserShortcutType.TWOFINGER_DOUBLETAP,
+ List.of(TARGET_MAGNIFICATION),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(
+ Settings.Secure.getInt(
+ mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
+ AccessibilityUtils.State.OFF)
+ ).isEqualTo(AccessibilityUtils.State.ON);
+ }
+
+ @Test
+ public void enableShortcutsForTargets_disableMultiFingerMultiTapsShortcut_settingUpdated() {
+ enableShortcutsForTargets_enableMultiFingerMultiTapsShortcut_settingUpdated();
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ false,
+ UserShortcutType.TWOFINGER_DOUBLETAP,
+ List.of(TARGET_MAGNIFICATION),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(
+ Settings.Secure.getInt(
+ mTestableContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
+ AccessibilityUtils.State.OFF)
+ ).isEqualTo(AccessibilityUtils.State.OFF);
+ }
+
+ @Test
+ public void enableShortcutsForTargets_enableVolumeKeysShortcut_shortcutSet() {
+ mockManageAccessibilityGranted(mTestableContext);
+ setupShortcutTargetServices();
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ true,
+ UserShortcutType.HARDWARE,
+ List.of(TARGET_STANDARD_A11Y_SERVICE.flattenToString()),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(
+ ShortcutUtils.isComponentIdExistingInSettings(
+ mTestableContext, ShortcutConstants.UserShortcutType.HARDWARE,
+ TARGET_STANDARD_A11Y_SERVICE.flattenToString())
+ ).isTrue();
+ }
+
+ @Test
+ public void enableShortcutsForTargets_disableVolumeKeysShortcut_shortcutNotSet() {
+ enableShortcutsForTargets_enableVolumeKeysShortcut_shortcutSet();
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ false,
+ UserShortcutType.HARDWARE,
+ List.of(TARGET_STANDARD_A11Y_SERVICE.flattenToString()),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(
+ ShortcutUtils.isComponentIdExistingInSettings(
+ mTestableContext, ShortcutConstants.UserShortcutType.HARDWARE,
+ TARGET_STANDARD_A11Y_SERVICE.flattenToString())
+ ).isFalse();
+ }
+
+ @Test
+ public void enableShortcutsForTargets_enableQuickSettings_shortcutSet() {
+ mockManageAccessibilityGranted(mTestableContext);
+ setupShortcutTargetServices();
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ true,
+ UserShortcutType.QUICK_SETTINGS,
+ List.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString()),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(
+ ShortcutUtils.isComponentIdExistingInSettings(
+ mTestableContext, UserShortcutType.QUICK_SETTINGS,
+ TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString())
+ ).isTrue();
+ verify(mStatusBarManagerInternal)
+ .addQsTileToFrontOrEnd(
+ new ComponentName(
+ TARGET_ALWAYS_ON_A11Y_SERVICE.getPackageName(),
+ TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS),
+ /* end= */ true);
+ }
+
+ @Test
+ public void enableShortcutsForTargets_disableQuickSettings_shortcutNotSet() {
+ enableShortcutsForTargets_enableQuickSettings_shortcutSet();
+
+ mA11yms.enableShortcutsForTargets(
+ /* enable= */ false,
+ UserShortcutType.QUICK_SETTINGS,
+ List.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString()),
+ mA11yms.getCurrentUserIdLocked());
+ mTestableLooper.processAllMessages();
+
+ assertThat(
+ ShortcutUtils.isComponentIdExistingInSettings(
+ mTestableContext, UserShortcutType.QUICK_SETTINGS,
+ TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString())
+ ).isFalse();
+ verify(mStatusBarManagerInternal)
+ .removeQsTile(
+ new ComponentName(
+ TARGET_ALWAYS_ON_A11Y_SERVICE.getPackageName(),
+ TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS));
+ }
+
+ @Test
+ public void getA11yFeatureToTileMap_permissionNotGranted_throwsException() {
+ mTestableContext.getTestablePermissions().setPermission(
+ Manifest.permission.MANAGE_ACCESSIBILITY, PackageManager.PERMISSION_DENIED);
+
+ assertThrows(SecurityException.class,
+ () -> mA11yms.getA11yFeatureToTileMap(mA11yms.getCurrentUserIdLocked()));
+ }
+
+ @Test
+ public void getA11yFeatureToTileMap() {
+ mockManageAccessibilityGranted(mTestableContext);
+ setupShortcutTargetServices();
+
+ Bundle bundle = mA11yms.getA11yFeatureToTileMap(mA11yms.getCurrentUserIdLocked());
+
+ // Framework tile size + TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS
+ assertThat(bundle.size())
+ .isEqualTo(ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.size() + 1);
+ assertThat(
+ bundle.getParcelable(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString(),
+ ComponentName.class)
+ ).isEqualTo(
+ new ComponentName(
+ TARGET_ALWAYS_ON_A11Y_SERVICE.getPackageName(),
+ TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS));
+ for (Map.Entry<ComponentName, ComponentName> entry :
+ ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.entrySet()) {
+ assertThat(bundle.getParcelable(entry.getKey().flattenToString(), ComponentName.class))
+ .isEqualTo(entry.getValue());
+ }
+ }
+
private static AccessibilityServiceInfo mockAccessibilityServiceInfo(
ComponentName componentName) {
- return mockAccessibilityServiceInfo(componentName, false);
+ return mockAccessibilityServiceInfo(
+ componentName, /* isSystemApp= */ false, /* isAlwaysOnService=*/ false);
}
private static AccessibilityServiceInfo mockAccessibilityServiceInfo(
ComponentName componentName,
- boolean isSystemApp) {
+ boolean isSystemApp, boolean isAlwaysOnService) {
AccessibilityServiceInfo accessibilityServiceInfo =
Mockito.spy(new AccessibilityServiceInfo());
accessibilityServiceInfo.setComponentName(componentName);
@@ -941,7 +1356,15 @@
when(accessibilityServiceInfo.getResolveInfo()).thenReturn(mockResolveInfo);
mockResolveInfo.serviceInfo = Mockito.mock(ServiceInfo.class);
mockResolveInfo.serviceInfo.applicationInfo = Mockito.mock(ApplicationInfo.class);
+ mockResolveInfo.serviceInfo.packageName = componentName.getPackageName();
+ mockResolveInfo.serviceInfo.name = componentName.getClassName();
when(mockResolveInfo.serviceInfo.applicationInfo.isSystemApp()).thenReturn(isSystemApp);
+ if (isAlwaysOnService) {
+ accessibilityServiceInfo.flags |=
+ AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
+ mockResolveInfo.serviceInfo.applicationInfo.targetSdkVersion =
+ Build.VERSION_CODES.R;
+ }
return accessibilityServiceInfo;
}
@@ -974,6 +1397,22 @@
Intent.EXTRA_COMPONENT_NAME)).isEqualTo(componentName);
}
+ private void setupShortcutTargetServices() {
+ AccessibilityServiceInfo alwaysOnServiceInfo = mockAccessibilityServiceInfo(
+ TARGET_ALWAYS_ON_A11Y_SERVICE,
+ /* isSystemApp= */ false,
+ /* isAlwaysOnService= */ true);
+ when(alwaysOnServiceInfo.getTileServiceName())
+ .thenReturn(TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS);
+ AccessibilityServiceInfo standardServiceInfo = mockAccessibilityServiceInfo(
+ TARGET_STANDARD_A11Y_SERVICE,
+ /* isSystemApp= */ false,
+ /* isAlwaysOnService= */ false);
+ mA11yms.getCurrentUserState().mInstalledServices.addAll(
+ List.of(alwaysOnServiceInfo, standardServiceInfo));
+ mA11yms.getCurrentUserState().updateTileServiceMapForAccessibilityServiceLocked();
+ }
+
public static class FakeInputFilter extends AccessibilityInputFilter {
FakeInputFilter(Context context,
AccessibilityManagerService service) {
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 1249707..67b131f 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -206,6 +206,7 @@
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
@@ -2150,12 +2151,14 @@
assertFalse(mService.isUidNetworkingBlocked(UID_E, false));
}
+ @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testBackgroundChainEnabled() throws Exception {
verify(mNetworkManager).setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, true);
}
+ @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testBackgroundChainOnProcStateChange() throws Exception {
@@ -2185,6 +2188,7 @@
assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
}
+ @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testBackgroundChainOnAllowlistChange() throws Exception {
@@ -2223,6 +2227,7 @@
assertFalse(mService.isUidNetworkingBlocked(UID_B, false));
}
+ @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testBackgroundChainOnTempAllowlistChange() throws Exception {
@@ -2261,6 +2266,7 @@
&& uidState.procState == procState && uidState.capability == capability;
}
+ @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testUidObserverFiltersProcStateChanges() throws Exception {
@@ -2323,6 +2329,7 @@
waitForUidEventHandlerIdle();
}
+ @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testUidObserverFiltersStaleChanges() throws Exception {
@@ -2343,6 +2350,7 @@
waitForUidEventHandlerIdle();
}
+ @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testUidObserverFiltersCapabilityChanges() throws Exception {
@@ -2422,6 +2430,7 @@
assertFalse(mService.isUidNetworkingBlocked(UID_A, false));
}
+ @Ignore("Temporarily disabled until the feature is enabled")
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testObsoleteHandleUidChanged() throws Exception {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 5a52968..ae4faa8 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.voiceinteraction;
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
@@ -1072,8 +1073,10 @@
// If visEnabledKey is set to true (or absent), we try following VIS path.
String csPkgName = mContext.getResources()
.getString(R.string.config_defaultContextualSearchPackageName);
- if (!csPkgName.equals(getCurInteractor(
- Binder.getCallingUserHandle().getIdentifier()).getPackageName())) {
+ ComponentName currInteractor =
+ getCurInteractor(Binder.getCallingUserHandle().getIdentifier());
+ if (currInteractor == null
+ || !csPkgName.equals(currInteractor.getPackageName())) {
// Check if the interactor can handle Contextual Search.
// If not, return failure.
Slog.w(TAG, "Contextual Search not supported yet. Returning failure.");
@@ -2718,7 +2721,7 @@
}
launchIntent.setComponent(resolveInfo.getComponentInfo().getComponentName());
launchIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION
- | FLAG_ACTIVITY_NO_USER_ACTION);
+ | FLAG_ACTIVITY_NO_USER_ACTION | FLAG_ACTIVITY_CLEAR_TASK);
launchIntent.putExtras(args);
boolean isAssistDataAllowed = mAtmInternal.isAssistDataAllowed();
final List<ActivityAssistInfo> records = mAtmInternal.getTopVisibleActivities();
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index 78f277e..f70a17d 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -1051,6 +1051,9 @@
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 name Ljava/lang/String;
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -1074,6 +1077,12 @@
0 18 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
0 18 3 longName Ljava/lang/String;
0 18 4 shortName Ljava/lang/String;
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ <no name>
+ <no name>
Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V
RuntimeInvisibleAnnotations:
x: #x()
@@ -1224,6 +1233,9 @@
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 name Ljava/lang/String;
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
descriptor: (Ljava/lang/String;I)V
@@ -1239,6 +1251,10 @@
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
Signature: #x // ()V
private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
@@ -2031,6 +2047,9 @@
Start Length Slot Name Signature
0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
0 10 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
public java.lang.Integer get();
descriptor: ()Ljava/lang/Integer;
@@ -2147,6 +2166,9 @@
Start Length Slot Name Signature
0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
0 10 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
public java.lang.Integer get();
descriptor: ()Ljava/lang/Integer;
@@ -2304,6 +2326,9 @@
Start Length Slot Name Signature
0 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
0 15 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
}
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeInvisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index 406cb74..37de857 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -795,6 +795,9 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -815,6 +818,12 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestStub
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ <no name>
+ <no name>
public java.lang.String getLongName();
descriptor: ()Ljava/lang/String;
@@ -969,6 +978,9 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
descriptor: (Ljava/lang/String;I)V
@@ -986,6 +998,10 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
@@ -1769,6 +1785,9 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
}
InnerClasses:
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
index c673262..c9c607c 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -1225,6 +1225,9 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -1257,6 +1260,12 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestStub
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ <no name>
+ <no name>
public java.lang.String getLongName();
descriptor: ()Ljava/lang/String;
@@ -1453,6 +1462,9 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
descriptor: (Ljava/lang/String;I)V
@@ -1474,6 +1486,10 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
@@ -2578,6 +2594,9 @@
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
public java.lang.Integer get();
descriptor: ()Ljava/lang/Integer;
@@ -2745,6 +2764,9 @@
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
public java.lang.Integer get();
descriptor: ()Ljava/lang/Integer;
@@ -2977,6 +2999,9 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
}
InnerClasses:
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
index 406cb74..37de857 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -795,6 +795,9 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -815,6 +818,12 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestStub
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ <no name>
+ <no name>
public java.lang.String getLongName();
descriptor: ()Ljava/lang/String;
@@ -969,6 +978,9 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
descriptor: (Ljava/lang/String;I)V
@@ -986,6 +998,10 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
@@ -1769,6 +1785,9 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
}
InnerClasses:
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
index 4fd5701..a57907d 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
@@ -1532,6 +1532,9 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
@@ -1569,6 +1572,12 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestStub
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
+ <no name>
+ <no name>
public java.lang.String getLongName();
descriptor: ()Ljava/lang/String;
@@ -1798,6 +1807,9 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> mandated
private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple();
descriptor: (Ljava/lang/String;I)V
@@ -1824,6 +1836,10 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> synthetic
+ <no name> synthetic
private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values();
descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
@@ -3190,6 +3206,9 @@
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
public java.lang.Integer get();
descriptor: ()Ljava/lang/Integer;
@@ -3407,6 +3426,9 @@
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
public java.lang.Integer get();
descriptor: ()Ljava/lang/Integer;
@@ -3704,6 +3726,9 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ MethodParameters:
+ Name Flags
+ <no name> final mandated
}
InnerClasses:
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses