Update a11y recommended timeout api.
Update api name to getRecommendedTimeoutMillis.
Api returns timeout for interactive or non-interactive controls.
Also provide the options for a11y service to specify two kinds of
timeout.
Bug: 111210981
Test: atest SettingsBackupTest
Test: atest AccessibilityManagerTest
Test: atest AccessibilityServiceInfoTest
Change-Id: I37d35796fd72bb4d6628a6bb33b111987f321552
diff --git a/api/current.txt b/api/current.txt
index 774831d..9c851e9 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -769,6 +769,7 @@
field public static final int insetRight = 16843192; // 0x10101b8
field public static final int insetTop = 16843193; // 0x10101b9
field public static final int installLocation = 16843447; // 0x10102b7
+ field public static final int interactiveUiTimeout = 16844181; // 0x1010595
field public static final int interpolator = 16843073; // 0x1010141
field public static final int isAlwaysSyncable = 16843571; // 0x1010333
field public static final int isAsciiCapable = 16843753; // 0x10103e9
@@ -941,7 +942,6 @@
field public static final int minSdkVersion = 16843276; // 0x101020c
field public static final int minWidth = 16843071; // 0x101013f
field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
- field public static final int minimumUiTimeout = 16844175; // 0x101058f
field public static final int minimumVerticalAngle = 16843902; // 0x101047e
field public static final int mipMap = 16843725; // 0x10103cd
field public static final int mirrorForRtl = 16843726; // 0x10103ce
@@ -965,6 +965,7 @@
field public static final int nextFocusRight = 16842978; // 0x10100e2
field public static final int nextFocusUp = 16842979; // 0x10100e3
field public static final int noHistory = 16843309; // 0x101022d
+ field public static final int nonInteractiveUiTimeout = 16844175; // 0x101058f
field public static final int normalScreens = 16843397; // 0x1010285
field public static final int notificationTimeout = 16843651; // 0x1010383
field public static final int numColumns = 16843032; // 0x1010118
@@ -2886,12 +2887,14 @@
method public int getCapabilities();
method public deprecated java.lang.String getDescription();
method public java.lang.String getId();
- method public int getMinimumUiTimeoutMillis();
+ method public int getInteractiveUiTimeoutMillis();
+ method public int getNonInteractiveUiTimeoutMillis();
method public android.content.pm.ResolveInfo getResolveInfo();
method public java.lang.String getSettingsActivityName();
method public java.lang.String loadDescription(android.content.pm.PackageManager);
method public java.lang.CharSequence loadSummary(android.content.pm.PackageManager);
- method public void setMinimumUiTimeoutMillis(int);
+ method public void setInteractiveUiTimeoutMillis(int);
+ method public void setNonInteractiveUiTimeoutMillis(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
@@ -50517,7 +50520,7 @@
method public deprecated java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
- method public int getMinimumUiTimeoutMillis();
+ method public int getRecommendedTimeoutMillis(int, int);
method public void interrupt();
method public static boolean isAccessibilityButtonSupported();
method public boolean isEnabled();
@@ -50526,6 +50529,9 @@
method public boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
method public boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+ field public static final int FLAG_CONTENT_CONTROLS = 4; // 0x4
+ field public static final int FLAG_CONTENT_ICONS = 1; // 0x1
+ field public static final int FLAG_CONTENT_TEXT = 2; // 0x2
}
public static abstract interface AccessibilityManager.AccessibilityStateChangeListener {
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index d7cca15..997ed25 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -76,7 +76,8 @@
* @attr ref android.R.styleable#AccessibilityService_notificationTimeout
* @attr ref android.R.styleable#AccessibilityService_packageNames
* @attr ref android.R.styleable#AccessibilityService_settingsActivity
- * @attr ref android.R.styleable#AccessibilityService_minimumUiTimeout
+ * @attr ref android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
+ * @attr ref android.R.styleable#AccessibilityService_interactiveUiTimeout
* @see AccessibilityService
* @see android.view.accessibility.AccessibilityEvent
* @see android.view.accessibility.AccessibilityManager
@@ -434,11 +435,14 @@
public boolean crashed;
/**
- * The minimum timeout in milliseconds that UI controls need to remain on the screen.
- *
- * @see #setMinimumUiTimeoutMillis
+ * A recommended timeout in milliseconds for non-interactive controls.
*/
- private int mMinimumUiTimeout;
+ private int mNonInteractiveUiTimeout;
+
+ /**
+ * A recommended timeout in milliseconds for interactive controls.
+ */
+ private int mInteractiveUiTimeout;
/**
* The component name the accessibility service.
@@ -544,8 +548,11 @@
notificationTimeout = asAttributes.getInt(
com.android.internal.R.styleable.AccessibilityService_notificationTimeout,
0);
- mMinimumUiTimeout = asAttributes.getInt(
- com.android.internal.R.styleable.AccessibilityService_minimumUiTimeout,
+ mNonInteractiveUiTimeout = asAttributes.getInt(
+ com.android.internal.R.styleable.AccessibilityService_nonInteractiveUiTimeout,
+ 0);
+ mInteractiveUiTimeout = asAttributes.getInt(
+ com.android.internal.R.styleable.AccessibilityService_interactiveUiTimeout,
0);
flags = asAttributes.getInt(
com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
@@ -616,7 +623,8 @@
packageNames = other.packageNames;
feedbackType = other.feedbackType;
notificationTimeout = other.notificationTimeout;
- mMinimumUiTimeout = other.mMinimumUiTimeout;
+ mNonInteractiveUiTimeout = other.mNonInteractiveUiTimeout;
+ mInteractiveUiTimeout = other.mInteractiveUiTimeout;
flags = other.flags;
}
@@ -775,26 +783,57 @@
}
/**
- * Set the minimum time that controls need to remain on the screen to support the user.
+ * Set the recommended time that non-interactive controls need to remain on the screen to
+ * support the user.
* <p>
- * <strong>This value can be dynamically set at runtime by
- * {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong>
+ * <strong>This value can be dynamically set at runtime by
+ * {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong>
* </p>
*
* @param timeout The timeout in milliseconds.
+ *
+ * @see android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
*/
- public void setMinimumUiTimeoutMillis(int timeout) {
- mMinimumUiTimeout = timeout;
+ public void setNonInteractiveUiTimeoutMillis(int timeout) {
+ mNonInteractiveUiTimeout = timeout;
}
/**
- * Get the minimum ui timeout.
+ * Get the recommended timeout for non-interactive controls.
*
- * @see #setMinimumUiTimeoutMillis
* @return The timeout in milliseconds.
+ *
+ * @see #setNonInteractiveUiTimeoutMillis(int)
*/
- public int getMinimumUiTimeoutMillis() {
- return mMinimumUiTimeout;
+ public int getNonInteractiveUiTimeoutMillis() {
+ return mNonInteractiveUiTimeout;
+ }
+
+ /**
+ * Set the recommended time that interactive controls need to remain on the screen to
+ * support the user.
+ * <p>
+ * <strong>This value can be dynamically set at runtime by
+ * {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong>
+ * </p>
+ *
+ * @param timeout The timeout in milliseconds.
+ *
+ * @see android.R.styleable#AccessibilityService_interactiveUiTimeout
+ */
+ public void setInteractiveUiTimeoutMillis(int timeout) {
+ mInteractiveUiTimeout = timeout;
+ }
+
+ /**
+ * Get the recommended timeout for interactive controls.
+ *
+ * @return The timeout in milliseconds.
+ *
+ * @see #setInteractiveUiTimeoutMillis(int)
+ */
+ public int getInteractiveUiTimeoutMillis() {
+ return mInteractiveUiTimeout;
}
/** {@hide} */
@@ -815,7 +854,8 @@
parcel.writeStringArray(packageNames);
parcel.writeInt(feedbackType);
parcel.writeLong(notificationTimeout);
- parcel.writeInt(mMinimumUiTimeout);
+ parcel.writeInt(mNonInteractiveUiTimeout);
+ parcel.writeInt(mInteractiveUiTimeout);
parcel.writeInt(flags);
parcel.writeInt(crashed ? 1 : 0);
parcel.writeParcelable(mComponentName, flagz);
@@ -833,7 +873,8 @@
packageNames = parcel.readStringArray();
feedbackType = parcel.readInt();
notificationTimeout = parcel.readLong();
- mMinimumUiTimeout = parcel.readInt();
+ mNonInteractiveUiTimeout = parcel.readInt();
+ mInteractiveUiTimeout = parcel.readInt();
flags = parcel.readInt();
crashed = parcel.readInt() != 0;
mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
@@ -884,7 +925,9 @@
stringBuilder.append(", ");
stringBuilder.append("notificationTimeout: ").append(notificationTimeout);
stringBuilder.append(", ");
- stringBuilder.append("minimumUiTimeout: ").append(mMinimumUiTimeout);
+ stringBuilder.append("nonInteractiveUiTimeout: ").append(mNonInteractiveUiTimeout);
+ stringBuilder.append(", ");
+ stringBuilder.append("interactiveUiTimeout: ").append(mInteractiveUiTimeout);
stringBuilder.append(", ");
appendFlags(stringBuilder, flags);
stringBuilder.append(", ");
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 61d08a3..f1f4b0c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6567,23 +6567,22 @@
public static final String MULTI_PRESS_TIMEOUT = "multi_press_timeout";
/**
- * Whether the user specifies a minimum ui timeout to override minimum ui timeout of
- * accessibility service
+ * Setting that specifies recommended timeout in milliseconds for controls
+ * which don't need user's interactions.
*
- * Type: int (0 for false, 1 for true)
* @hide
*/
- public static final String ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED =
- "accessibility_minimum_ui_timeout_enabled";
+ public static final String ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS =
+ "accessibility_non_interactive_ui_timeout_ms";
/**
- * Setting that specifies ui minimum timeout in milliseconds.
+ * Setting that specifies recommended timeout in milliseconds for controls
+ * which need user's interactions.
*
- * @see #ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED
* @hide
*/
- public static final String ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS =
- "accessibility_minimum_ui_timeout_ms";
+ public static final String ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS =
+ "accessibility_interactive_ui_timeout_ms";
/**
* List of the enabled print services.
@@ -8318,8 +8317,8 @@
ZEN_SETTINGS_SUGGESTION_VIEWED,
CHARGING_SOUNDS_ENABLED,
CHARGING_VIBRATION_ENABLED,
- ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED,
- ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS,
+ ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
+ ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
NOTIFICATION_NEW_INTERRUPTION_MODEL,
};
@@ -8476,8 +8475,9 @@
VALIDATORS.put(ZEN_SETTINGS_SUGGESTION_VIEWED, BOOLEAN_VALIDATOR);
VALIDATORS.put(CHARGING_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(CHARGING_VIBRATION_ENABLED, BOOLEAN_VALIDATOR);
- VALIDATORS.put(ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED, BOOLEAN_VALIDATOR);
- VALIDATORS.put(ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
+ NON_NEGATIVE_INTEGER_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(USER_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
VALIDATORS.put(ASSIST_GESTURE_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
VALIDATORS.put(NOTIFICATION_NEW_INTERRUPTION_MODEL, BOOLEAN_VALIDATOR);
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index a7d0cfb..6a17b64 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -21,6 +21,7 @@
import android.Manifest;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.AccessibilityServiceInfo.FeedbackType;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -54,6 +55,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IntPair;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -117,6 +120,39 @@
public static final String ACTION_CHOOSE_ACCESSIBILITY_BUTTON =
"com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON";
+ /**
+ * Annotations for content flag of UI.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "FLAG_CONTENT_" }, value = {
+ FLAG_CONTENT_ICONS,
+ FLAG_CONTENT_TEXT,
+ FLAG_CONTENT_CONTROLS
+ })
+ public @interface ContentFlag {}
+
+ /**
+ * Use this flag to indicate the content of a UI that times out contains icons.
+ *
+ * @see #getRecommendedTimeoutMillis(int, int)
+ */
+ public static final int FLAG_CONTENT_ICONS = 1;
+
+ /**
+ * Use this flag to indicate the content of a UI that times out contains text.
+ *
+ * @see #getRecommendedTimeoutMillis(int, int)
+ */
+ public static final int FLAG_CONTENT_TEXT = 2;
+
+ /**
+ * Use this flag to indicate the content of a UI that times out contains interactive controls.
+ *
+ * @see #getRecommendedTimeoutMillis(int, int)
+ */
+ public static final int FLAG_CONTENT_CONTROLS = 4;
+
@UnsupportedAppUsage
static final Object sInstanceSync = new Object();
@@ -142,7 +178,8 @@
int mRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK;
- int mMinimumUiTimeout;
+ int mInteractiveUiTimeout;
+ int mNonInteractiveUiTimeout;
boolean mIsTouchExplorationEnabled;
@@ -304,7 +341,9 @@
}
@Override
- public void notifyServicesStateChanged() {
+ public void notifyServicesStateChanged(long updatedUiTimeout) {
+ updateUiTimeout(updatedUiTimeout);
+
final ArrayMap<AccessibilityServicesStateChangeListener, Handler> listeners;
synchronized (mLock) {
if (mServicesStateChangeListeners.isEmpty()) {
@@ -326,11 +365,6 @@
public void setRelevantEventTypes(int eventTypes) {
mRelevantEventTypes = eventTypes;
}
-
- @Override
- public void setMinimumUiTimeout(int uiTimeout) {
- mMinimumUiTimeout = uiTimeout;
- }
};
/**
@@ -840,16 +874,35 @@
}
/**
- * Get the minimum timeout for changes to the UI needed by this user. Controls should remain
+ * Get the recommended timeout for changes to the UI needed by this user. Controls should remain
* on the screen for at least this long to give users time to react. Some users may need
* extra time to review the controls, or to reach them, or to activate assistive technology
* to activate the controls automatically.
+ * <p>
+ * Use the combination of content flags to indicate contents of UI. For example, use
+ * {@code FLAG_CONTENT_ICONS | FLAG_CONTENT_TEXT} for message notification which contains
+ * icons and text, or use {@code FLAG_CONTENT_TEXT | FLAG_CONTENT_CONTROLS} for button dialog
+ * which contains text and button controls.
+ * <p/>
*
- * @return The minimum ui timeout for the current user in milliseconds.
- * {@link Integer#MAX_VALUE} if timeout is infinite.
+ * @param originalTimeout The timeout appropriate for users with no accessibility needs.
+ * @param uiContentFlags The combination of flags {@link #FLAG_CONTENT_ICONS},
+ * {@link #FLAG_CONTENT_TEXT} or {@Link #CONTENT_CONTROLS} to
+ * indicate the contents of UI.
+ * @return The recommended UI timeout for the current user in milliseconds.
*/
- public int getMinimumUiTimeoutMillis() {
- return mMinimumUiTimeout;
+ public int getRecommendedTimeoutMillis(int originalTimeout, @ContentFlag int uiContentFlags) {
+ boolean hasControls = (uiContentFlags & FLAG_CONTENT_CONTROLS) != 0;
+ boolean hasIconsOrText = (uiContentFlags & FLAG_CONTENT_ICONS) != 0
+ || (uiContentFlags & FLAG_CONTENT_TEXT) != 0;
+ int recommendedTimeout = originalTimeout;
+ if (hasControls) {
+ recommendedTimeout = Math.max(recommendedTimeout, mInteractiveUiTimeout);
+ }
+ if (hasIconsOrText) {
+ recommendedTimeout = Math.max(recommendedTimeout, mNonInteractiveUiTimeout);
+ }
+ return recommendedTimeout;
}
/**
@@ -1192,7 +1245,7 @@
final long userStateAndRelevantEvents = service.addClient(mClient, mUserId);
setStateLocked(IntPair.first(userStateAndRelevantEvents));
mRelevantEventTypes = IntPair.second(userStateAndRelevantEvents);
- mMinimumUiTimeout = service.getMinimumUiTimeout();
+ updateUiTimeout(service.getRecommendedTimeoutMillis());
mService = service;
} catch (RemoteException re) {
Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
@@ -1266,6 +1319,17 @@
}
/**
+ * Update interactive and non-interactive UI timeout.
+ *
+ * @param uiTimeout A pair of {@code int}s. First integer for interactive one, and second
+ * integer for non-interactive one.
+ */
+ private void updateUiTimeout(long uiTimeout) {
+ mInteractiveUiTimeout = IntPair.first(uiTimeout);
+ mNonInteractiveUiTimeout = IntPair.second(uiTimeout);
+ }
+
+ /**
* Determines if the accessibility button within the system navigation area is supported.
*
* @return {@code true} if the accessibility button is supported on this device,
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 61a8a1da..2767a82 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -76,5 +76,5 @@
// System process only
boolean sendFingerprintGesture(int gestureKeyCode);
- int getMinimumUiTimeout();
+ long getRecommendedTimeoutMillis();
}
diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
index d2ddca3..94b9ad1 100644
--- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
@@ -26,9 +26,7 @@
void setState(int stateFlags);
- void notifyServicesStateChanged();
+ void notifyServicesStateChanged(long updatedUiTimeout);
void setRelevantEventTypes(int eventTypes);
-
- void setMinimumUiTimeout(int uiTimeout);
}
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 3ead633..f8acc33 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -72,8 +72,10 @@
// List of the accessibility services to which the user has granted
// permission to put the device into touch exploration mode.
optional SettingProto touch_exploration_granted_accessibility_services = 31;
- optional SettingProto minimum_ui_timeout_enabled = 32 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto minimum_ui_timeout_ms = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ reserved 32; // minimum_ui_timeout_enabled
+ reserved 33; // minimum_ui_timeout_ms
+ optional SettingProto non_interactive_ui_timeout_ms = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto interactive_ui_timeout_ms = 35 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Accessibility accessibility = 2;
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a25c998..68ec342 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3587,11 +3587,22 @@
{@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
<attr name="notificationTimeout" format="integer" />
- <!-- The minimum timeout in milliseconds that UI controls need to remain on the screen.
+ <!-- A recommended timeout in milliseconds used in
+ {@link android.view.accessibility.AccessibilityManager#getRecommendedTimeoutMillis(int, int)
+ android.view.accessibility.AccessibilityManager.getRecommendedTimeoutMillis(int, int)}
+ to return a suitable value for UIs that do not include interactive controls.
This setting can be changed at runtime by calling
{@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
- <attr name="minimumUiTimeout" format="integer" />
+ <attr name="nonInteractiveUiTimeout" format="integer" />
+ <!-- A recommended timeout in milliseconds used in
+ {@link android.view.accessibility.AccessibilityManager#getRecommendedTimeoutMillis(int, int)
+ android.view.accessibility.AccessibilityManager.getRecommendedTimeoutMillis(int, int)}
+ to return a suitable value for interactive controls.
+ This setting can be changed at runtime by calling
+ {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
+ android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
+ <attr name="interactiveUiTimeout" format="integer" />
<!-- Additional flags as specified in
{@link android.accessibilityservice.AccessibilityServiceInfo}.
This setting can be changed at runtime by calling
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e1c5df3..15f29ce 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2912,12 +2912,13 @@
<public name="supportsAmbientMode" />
<!-- @hide For use by platform and tools only. Developers should not specify this value. -->
<public name="usesNonSdkApi" />
- <public name="minimumUiTimeout" />
+ <public name="nonInteractiveUiTimeout" />
<public name="isLightTheme" />
<public name="isSplitRequired" />
<public name="textLocale" />
<public name="settingsSliceUri" />
<public name="shell" />
+ <public name="interactiveUiTimeout" />
</public-group>
<public-group type="drawable" first-id="0x010800b4">
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index b46c288..ca0267c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1643,11 +1643,11 @@
Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
SecureSettingsProto.Accessibility.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
dumpSetting(s, p,
- Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED,
- SecureSettingsProto.Accessibility.MINIMUM_UI_TIMEOUT_ENABLED);
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
+ SecureSettingsProto.Accessibility.NON_INTERACTIVE_UI_TIMEOUT_MS);
dumpSetting(s, p,
- Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS,
- SecureSettingsProto.Accessibility.MINIMUM_UI_TIMEOUT_MS);
+ Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
+ SecureSettingsProto.Accessibility.INTERACTIVE_UI_TIMEOUT_MS);
p.end(accessibilityToken);
dumpSetting(s, p,
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e89b951..5c189ce 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1672,22 +1672,23 @@
client -> client.setState(clientState)));
}
- private void scheduleNotifyClientsOfServicesStateChange(UserState userState) {
+ private void scheduleNotifyClientsOfServicesStateChangeLocked(UserState userState) {
+ updateRecommendedUiTimeoutLocked(userState);
mMainHandler.sendMessage(obtainMessage(
AccessibilityManagerService::sendServicesStateChanged,
- this, userState.mUserClients));
+ this, userState.mUserClients, getRecommendedTimeoutMillisLocked(userState)));
}
private void sendServicesStateChanged(
- RemoteCallbackList<IAccessibilityManagerClient> userClients) {
- notifyClientsOfServicesStateChange(mGlobalClients);
- notifyClientsOfServicesStateChange(userClients);
+ RemoteCallbackList<IAccessibilityManagerClient> userClients, long uiTimeout) {
+ notifyClientsOfServicesStateChange(mGlobalClients, uiTimeout);
+ notifyClientsOfServicesStateChange(userClients, uiTimeout);
}
private void notifyClientsOfServicesStateChange(
- RemoteCallbackList<IAccessibilityManagerClient> clients) {
+ RemoteCallbackList<IAccessibilityManagerClient> clients, long uiTimeout) {
clients.broadcast(ignoreRemoteException(
- client -> client.notifyServicesStateChanged()));
+ client -> client.notifyServicesStateChanged(uiTimeout)));
}
private void scheduleUpdateInputFilter(UserState userState) {
@@ -1701,24 +1702,6 @@
this, userState));
}
- private void scheduleSetAllClientsMinimumUiTimeout(UserState userState) {
- mMainHandler.sendMessage(obtainMessage(
- AccessibilityManagerService::sendMinimumUiTimeoutChanged,
- this, userState.mUserClients, userState.mMinimumUiTimeout));
- }
-
- private void sendMinimumUiTimeoutChanged(
- RemoteCallbackList<IAccessibilityManagerClient> userClients, int uiTimeout) {
- notifyClientsOfServicesMinimumUiTimeoutChange(mGlobalClients, uiTimeout);
- notifyClientsOfServicesMinimumUiTimeoutChange(userClients, uiTimeout);
- }
-
- private void notifyClientsOfServicesMinimumUiTimeoutChange(
- RemoteCallbackList<IAccessibilityManagerClient> clients, int uiTimeout) {
- clients.broadcast(ignoreRemoteException(
- client -> client.setMinimumUiTimeout(uiTimeout)));
- }
-
private void updateInputFilter(UserState userState) {
if (mUiAutomationManager.suppressingAccessibilityServicesLocked()) return;
@@ -1852,7 +1835,6 @@
scheduleUpdateClientsIfNeededLocked(userState);
updateRelevantEventsLocked(userState);
updateAccessibilityButtonTargetsLocked(userState);
- updateMinimumUiTimeoutLocked(userState);
}
private void updateAccessibilityFocusBehaviorLocked(UserState userState) {
@@ -1971,7 +1953,7 @@
somethingChanged |= readAutoclickEnabledSettingLocked(userState);
somethingChanged |= readAccessibilityShortcutSettingLocked(userState);
somethingChanged |= readAccessibilityButtonSettingsLocked(userState);
- somethingChanged |= readUserMinimumUiTimeoutSettingsLocked(userState);
+ somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState);
return somethingChanged;
}
@@ -2083,7 +2065,7 @@
}
userState.mServiceToEnableWithShortcut = componentNameToEnable;
- scheduleNotifyClientsOfServicesStateChange(userState);
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
return true;
}
@@ -2118,17 +2100,20 @@
return true;
}
- private boolean readUserMinimumUiTimeoutSettingsLocked(UserState userState) {
- final boolean enabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED, 0,
- userState.mUserId) == 1;
- final int timeout = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS, 0,
+ private boolean readUserRecommendedUiTimeoutSettingsLocked(UserState userState) {
+ final int nonInteractiveUiTimeout = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, 0,
userState.mUserId);
- if (enabled != userState.mUserMinimumUiTimeoutEnabled
- || timeout != userState.mUserMinimumUiTimeout) {
- userState.mUserMinimumUiTimeoutEnabled = enabled;
- userState.mUserMinimumUiTimeout = timeout;
+ final int interactiveUiTimeout = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, 0,
+ userState.mUserId);
+ if (nonInteractiveUiTimeout != userState.mUserNonInteractiveUiTimeout
+ || interactiveUiTimeout != userState.mUserInteractiveUiTimeout) {
+ userState.mUserNonInteractiveUiTimeout = nonInteractiveUiTimeout;
+ userState.mUserInteractiveUiTimeout = interactiveUiTimeout;
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
return true;
}
return false;
@@ -2300,25 +2285,33 @@
}
}
- private void updateMinimumUiTimeoutLocked(UserState userState) {
- int newUiTimeout = 0;
- if (userState.mUserMinimumUiTimeoutEnabled) {
- newUiTimeout = userState.mUserMinimumUiTimeout;
- } else {
+ private void updateRecommendedUiTimeoutLocked(UserState userState) {
+ int newNonInteractiveUiTimeout = userState.mUserNonInteractiveUiTimeout;
+ int newInteractiveUiTimeout = userState.mUserInteractiveUiTimeout;
+ // read from a11y services if user does not specify value
+ if (newNonInteractiveUiTimeout == 0 || newInteractiveUiTimeout == 0) {
+ int serviceNonInteractiveUiTimeout = 0;
+ int serviceInteractiveUiTimeout = 0;
final List<AccessibilityServiceConnection> services = userState.mBoundServices;
- final int numServices = services.size();
- for (int i = 0; i < numServices; i++) {
- final int serviceUiTimeout = services.get(i).getServiceInfo()
- .getMinimumUiTimeoutMillis();
- if (newUiTimeout < serviceUiTimeout) {
- newUiTimeout = serviceUiTimeout;
+ for (int i = 0; i < services.size(); i++) {
+ int timeout = services.get(i).getServiceInfo().getInteractiveUiTimeoutMillis();
+ if (serviceInteractiveUiTimeout < timeout) {
+ serviceInteractiveUiTimeout = timeout;
+ }
+ timeout = services.get(i).getServiceInfo().getNonInteractiveUiTimeoutMillis();
+ if (serviceNonInteractiveUiTimeout < timeout) {
+ serviceNonInteractiveUiTimeout = timeout;
}
}
+ if (newNonInteractiveUiTimeout == 0) {
+ newNonInteractiveUiTimeout = serviceNonInteractiveUiTimeout;
+ }
+ if (newInteractiveUiTimeout == 0) {
+ newInteractiveUiTimeout = serviceInteractiveUiTimeout;
+ }
}
- if (newUiTimeout != userState.mMinimumUiTimeout) {
- userState.mMinimumUiTimeout = newUiTimeout;
- scheduleSetAllClientsMinimumUiTimeout(userState);
- }
+ userState.mNonInteractiveUiTimeout = newNonInteractiveUiTimeout;
+ userState.mInteractiveUiTimeout = newInteractiveUiTimeout;
}
@GuardedBy("mLock")
@@ -2473,19 +2466,24 @@
}
/**
- * Get the minimum timeout for changes to the UI needed by this user. Controls should remain
- * on the screen for at least this long to give users time to react.
+ * Get the recommended timeout of interactive controls and non-interactive controls.
*
- * @return The minimum timeout for the current user in milliseconds.
+ * @return A long for pair of {@code int}s. First integer for interactive one, and second
+ * integer for non-interactive one.
*/
@Override
- public int getMinimumUiTimeout() {
+ public long getRecommendedTimeoutMillis() {
synchronized(mLock) {
final UserState userState = getCurrentUserStateLocked();
- return userState.mMinimumUiTimeout;
+ return getRecommendedTimeoutMillisLocked(userState);
}
}
+ private long getRecommendedTimeoutMillisLocked(UserState userState) {
+ return IntPair.of(userState.mInteractiveUiTimeout,
+ userState.mNonInteractiveUiTimeout);
+ }
+
@Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
@@ -2503,7 +2501,8 @@
pw.append(", navBarMagnificationEnabled="
+ userState.mIsNavBarMagnificationEnabled);
pw.append(", autoclickEnabled=" + userState.mIsAutoclickEnabled);
- pw.append(", minimumUiTimeout=" + userState.mMinimumUiTimeout);
+ pw.append(", nonInteractiveUiTimeout=" + userState.mNonInteractiveUiTimeout);
+ pw.append(", interactiveUiTimeout=" + userState.mInteractiveUiTimeout);
if (mUiAutomationManager.isUiAutomationRunningLocked()) {
pw.append(", ");
mUiAutomationManager.dumpUiAutomationService(fd, pw, args);
@@ -2819,7 +2818,7 @@
AccessibilityManagerService.UserState userState = getUserStateLocked(mCurrentUserId);
onUserStateChangedLocked(userState);
if (serviceInfoChanged) {
- scheduleNotifyClientsOfServicesStateChange(userState);
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
}
}
@@ -3794,7 +3793,8 @@
public ComponentName mServiceToEnableWithShortcut;
public int mLastSentClientState = -1;
- public int mMinimumUiTimeout = 0;
+ public int mNonInteractiveUiTimeout = 0;
+ public int mInteractiveUiTimeout = 0;
private int mSoftKeyboardShowMode = 0;
@@ -3809,8 +3809,8 @@
public boolean mIsPerformGesturesEnabled;
public boolean mIsFilterKeyEventsEnabled;
public boolean mAccessibilityFocusOnlyInActiveWindow;
- public boolean mUserMinimumUiTimeoutEnabled;
- public int mUserMinimumUiTimeout;
+ public int mUserNonInteractiveUiTimeout;
+ public int mUserInteractiveUiTimeout;
private boolean mBindInstantServiceAllowed;
@@ -3850,8 +3850,9 @@
// Clear event management state.
mLastSentClientState = -1;
- // clear minimum ui timeout
- mMinimumUiTimeout = 0;
+ // clear UI timeout
+ mNonInteractiveUiTimeout = 0;
+ mInteractiveUiTimeout = 0;
// Clear state persisted in settings.
mEnabledServices.clear();
@@ -3862,8 +3863,8 @@
mServiceAssignedToAccessibilityButton = null;
mIsNavBarMagnificationAssignedToAccessibilityButton = false;
mIsAutoclickEnabled = false;
- mUserMinimumUiTimeoutEnabled = false;
- mUserMinimumUiTimeout = 0;
+ mUserNonInteractiveUiTimeout = 0;
+ mUserInteractiveUiTimeout = 0;
}
public void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
@@ -3871,7 +3872,7 @@
serviceConnection.onAdded();
mBoundServices.add(serviceConnection);
mComponentNameToServiceMap.put(serviceConnection.mComponentName, serviceConnection);
- scheduleNotifyClientsOfServicesStateChange(this);
+ scheduleNotifyClientsOfServicesStateChangeLocked(this);
}
}
@@ -3897,7 +3898,7 @@
AccessibilityServiceConnection boundClient = mBoundServices.get(i);
mComponentNameToServiceMap.put(boundClient.mComponentName, boundClient);
}
- scheduleNotifyClientsOfServicesStateChange(this);
+ scheduleNotifyClientsOfServicesStateChangeLocked(this);
}
/**
@@ -4108,11 +4109,11 @@
private final Uri mAccessibilityButtonComponentIdUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT);
- private final Uri mUserMinimumUiTimeoutEnabledUri = Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED);
+ private final Uri mUserNonInteractiveUiTimeoutUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS);
- private final Uri mUserMinimumUiTimeoutUri = Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS);
+ private final Uri mUserInteractiveUiTimeoutUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS);
public AccessibilityContentObserver(Handler handler) {
super(handler);
@@ -4149,9 +4150,9 @@
contentResolver.registerContentObserver(
mAccessibilityButtonComponentIdUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
- mUserMinimumUiTimeoutEnabledUri, false, this, UserHandle.USER_ALL);
+ mUserNonInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
- mUserMinimumUiTimeoutUri, false, this, UserHandle.USER_ALL);
+ mUserInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
}
@Override
@@ -4202,11 +4203,9 @@
if (readAccessibilityButtonSettingsLocked(userState)) {
onUserStateChangedLocked(userState);
}
- } else if (mUserMinimumUiTimeoutEnabledUri.equals(uri)
- || mUserMinimumUiTimeoutUri.equals(uri)) {
- if (readUserMinimumUiTimeoutSettingsLocked(userState)) {
- updateMinimumUiTimeoutLocked(userState);
- }
+ } else if (mUserNonInteractiveUiTimeoutUri.equals(uri)
+ || mUserInteractiveUiTimeoutUri.equals(uri)) {
+ readUserRecommendedUiTimeoutSettingsLocked(userState);
}
}
}