summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/animation/AnimatorInflater.java6
-rw-r--r--core/java/android/hardware/Camera.java19
-rw-r--r--core/java/android/preference/MultiSelectListPreference.java6
-rw-r--r--core/java/android/provider/Settings.java16
-rw-r--r--core/java/android/text/GraphicsOperations.java4
-rw-r--r--core/java/android/text/SpannableStringBuilder.java16
-rw-r--r--core/java/android/view/InputEventConsistencyVerifier.java19
-rw-r--r--core/java/android/view/View.java44
-rw-r--r--core/java/android/view/ViewConfiguration.java22
-rw-r--r--core/java/android/view/ViewGroup.java54
-rw-r--r--core/java/android/view/ViewParent.java19
-rw-r--r--core/java/android/view/ViewRoot.java8
-rw-r--r--core/java/android/view/accessibility/AccessibilityEvent.java470
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java36
-rw-r--r--core/java/android/view/accessibility/AccessibilityRecord.java415
-rw-r--r--core/java/android/view/accessibility/IAccessibilityManager.aidl2
-rw-r--r--core/java/android/widget/AbsListView.java12
-rw-r--r--core/java/android/widget/AdapterView.java28
-rw-r--r--core/java/android/widget/CheckedTextView.java9
-rw-r--r--core/java/android/widget/CompoundButton.java26
-rw-r--r--core/java/android/widget/DatePicker.java7
-rw-r--r--core/java/android/widget/ListView.java40
-rw-r--r--core/java/android/widget/ProgressBar.java10
-rw-r--r--core/java/android/widget/TabWidget.java15
-rw-r--r--core/java/android/widget/TextView.java13
-rw-r--r--core/java/android/widget/TimePicker.java5
-rw-r--r--core/java/com/android/internal/widget/ActionBarView.java6
27 files changed, 864 insertions, 463 deletions
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index bcab66e..ed4036d 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -31,11 +31,11 @@ import java.io.IOException;
import java.util.ArrayList;
/**
- * This class is used to instantiate menu XML files into Animator objects.
+ * This class is used to instantiate animator XML files into Animator objects.
* <p>
- * For performance reasons, menu inflation relies heavily on pre-processing of
+ * For performance reasons, inflation relies heavily on pre-processing of
* XML files that is done at build time. Therefore, it is not currently possible
- * to use MenuInflater with an XmlPullParser over a plain XML file at runtime;
+ * to use this inflater with an XmlPullParser over a plain XML file at runtime;
* it only works with an XmlPullParser returned from a compiled resource (R.
* <em>something</em> file.)
*/
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 328a55b..77c2d1b 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -2600,10 +2600,12 @@ public class Camera {
* (1000, 1000) is the lower right point. The length and width of focus
* areas cannot be 0 or negative.
*
- * The weight ranges from 1 to 1000. The sum of the weights of all focus
- * areas must be 1000. Focus areas can partially overlap and the driver
- * will add the weights in the overlap region. But apps should not set
- * two focus areas that have identical coordinates.
+ * The weight must range from 1 to 1000. The weight should be
+ * interpreted as a per-pixel weight - all pixels in the area have the
+ * specified weight. This means a small area with the same weight as a
+ * larger area will have less influence on the focusing than the larger
+ * area. Focus areas can partially overlap and the driver will add the
+ * weights in the overlap region.
*
* A special case of all-zero single focus area means driver to decide
* the focus area. For example, the driver may use more signals to
@@ -2668,10 +2670,11 @@ public class Camera {
* point. (1000, 1000) is the lower right point. The length and width of
* metering areas cannot be 0 or negative.
*
- * The weight ranges from 1 to 1000. The sum of the weights of all
- * metering areas must be 1000. Metering areas can partially overlap and
- * the driver will add the weights in the overlap region. But apps
- * should not set two metering areas that have identical coordinates.
+ * The weight must range from 1 to 1000, and represents a weight for
+ * every pixel in the area. This means that a large metering area with
+ * the same weight as a smaller area will have more effect in the
+ * metering result. Metering areas can partially overlap and the driver
+ * will add the weights in the overlap region.
*
* A special case of all-zero single metering area means driver to
* decide the metering area. For example, the driver may use more
diff --git a/core/java/android/preference/MultiSelectListPreference.java b/core/java/android/preference/MultiSelectListPreference.java
index 42d555c..2e8d551 100644
--- a/core/java/android/preference/MultiSelectListPreference.java
+++ b/core/java/android/preference/MultiSelectListPreference.java
@@ -169,9 +169,9 @@ public class MultiSelectListPreference extends DialogPreference {
new DialogInterface.OnMultiChoiceClickListener() {
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
if (isChecked) {
- mPreferenceChanged |= mNewValues.add(mEntries[which].toString());
+ mPreferenceChanged |= mNewValues.add(mEntryValues[which].toString());
} else {
- mPreferenceChanged |= mNewValues.remove(mEntries[which].toString());
+ mPreferenceChanged |= mNewValues.remove(mEntryValues[which].toString());
}
}
});
@@ -180,7 +180,7 @@ public class MultiSelectListPreference extends DialogPreference {
}
private boolean[] getSelectedItems() {
- final CharSequence[] entries = mEntries;
+ final CharSequence[] entries = mEntryValues;
final int entryCount = entries.length;
final Set<String> values = mValues;
boolean[] result = new boolean[entryCount];
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2f4a4bb..570b801 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3721,6 +3721,22 @@ public final class Settings {
"setup_prepaid_data_service_url";
/**
+ * URL to attempt a GET on to see if this is a prepay device
+ * @hide
+ */
+ public static final String SETUP_PREPAID_DETECTION_TARGET_URL =
+ "setup_prepaid_detection_target_url";
+
+ /**
+ * Host to check for a redirect to after an attempt to GET
+ * SETUP_PREPAID_DETECTION_TARGET_URL. (If we redirected there,
+ * this is a prepaid device with zero balance.)
+ * @hide
+ */
+ public static final String SETUP_PREPAID_DETECTION_REDIR_HOST =
+ "setup_prepaid_detection_redir_host";
+
+ /**
* @hide
*/
public static final String[] SETTINGS_TO_BACKUP = {
diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java
index 6e2168b..831ccc5 100644
--- a/core/java/android/text/GraphicsOperations.java
+++ b/core/java/android/text/GraphicsOperations.java
@@ -61,8 +61,8 @@ extends CharSequence
* Just like {@link Paint#getTextRunAdvances}.
* @hide
*/
- float getTextRunAdvancesICU(int start, int end, int contextStart, int contextEnd,
- int flags, float[] advances, int advancesIndex, Paint paint);
+ float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
+ int flags, float[] advances, int advancesIndex, Paint paint, int reserved);
/**
* Just like {@link Paint#getTextRunCursor}.
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index ff6a4cd..6b2d8e4 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1173,8 +1173,8 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable,
* Don't call this yourself -- exists for Paint to use internally.
* {@hide}
*/
- public float getTextRunAdvancesICU(int start, int end, int contextStart, int contextEnd, int flags,
- float[] advances, int advancesPos, Paint p) {
+ public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, int flags,
+ float[] advances, int advancesPos, Paint p, int reserved) {
float ret;
@@ -1182,16 +1182,16 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable,
int len = end - start;
if (end <= mGapStart) {
- ret = p.getTextRunAdvancesICU(mText, start, len, contextStart, contextLen,
- flags, advances, advancesPos);
+ ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
+ flags, advances, advancesPos, reserved);
} else if (start >= mGapStart) {
- ret = p.getTextRunAdvancesICU(mText, start + mGapLength, len,
- contextStart + mGapLength, contextLen, flags, advances, advancesPos);
+ ret = p.getTextRunAdvances(mText, start + mGapLength, len,
+ contextStart + mGapLength, contextLen, flags, advances, advancesPos, reserved);
} else {
char[] buf = TextUtils.obtain(contextLen);
getChars(contextStart, contextEnd, buf, 0);
- ret = p.getTextRunAdvancesICU(buf, start - contextStart, len,
- 0, contextLen, flags, advances, advancesPos);
+ ret = p.getTextRunAdvances(buf, start - contextStart, len,
+ 0, contextLen, flags, advances, advancesPos, reserved);
TextUtils.recycle(buf);
}
diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java
index b5ca2c2..e14b975 100644
--- a/core/java/android/view/InputEventConsistencyVerifier.java
+++ b/core/java/android/view/InputEventConsistencyVerifier.java
@@ -30,7 +30,6 @@ import android.util.Log;
* @hide
*/
public final class InputEventConsistencyVerifier {
- private static final String TAG = "InputEventConsistencyVerifier";
private static final boolean IS_ENG_BUILD = "eng".equals(Build.TYPE);
// The number of recent events to log when a problem is detected.
@@ -44,6 +43,11 @@ public final class InputEventConsistencyVerifier {
// Consistency verifier flags.
private final int mFlags;
+ // Tag for logging which a client can set to help distinguish the output
+ // from different verifiers since several can be active at the same time.
+ // If not provided defaults to the simple class name.
+ private final String mLogTag;
+
// The most recently checked event and the nesting level at which it was checked.
// This is only set when the verifier is called from a nesting level greater than 0
// so that the verifier can detect when it has been asked to verify the same event twice.
@@ -103,8 +107,19 @@ public final class InputEventConsistencyVerifier {
* @param flags Flags to the verifier, or 0 if none.
*/
public InputEventConsistencyVerifier(Object caller, int flags) {
+ this(caller, flags, InputEventConsistencyVerifier.class.getSimpleName());
+ }
+
+ /**
+ * Creates an input consistency verifier.
+ * @param caller The object to which the verifier is attached.
+ * @param flags Flags to the verifier, or 0 if none.
+ * @param logTag Tag for logging. If null defaults to the short class name.
+ */
+ public InputEventConsistencyVerifier(Object caller, int flags, String logTag) {
this.mCaller = caller;
this.mFlags = flags;
+ this.mLogTag = (logTag != null) ? logTag : "InputEventConsistencyVerifier";
}
/**
@@ -596,7 +611,7 @@ public final class InputEventConsistencyVerifier {
}
}
- Log.d(TAG, mViolationMessage.toString());
+ Log.d(mLogTag, mViolationMessage.toString());
mViolationMessage.setLength(0);
tainted = true;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4a62892..4bc7f39 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3455,6 +3455,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
if (!isShown()) {
return;
}
+
+ // Populate these here since they are related to the View that
+ // sends the event and should not be modified while dispatching
+ // to descendants.
event.setClassName(getClass().getName());
event.setPackageName(getContext().getPackageName());
event.setEnabled(isEnabled());
@@ -3470,22 +3474,38 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
dispatchPopulateAccessibilityEvent(event);
- AccessibilityManager.getInstance(mContext).sendAccessibilityEvent(event);
+ // In the beginning we called #isShown(), so we know that getParent() is not null.
+ getParent().requestSendAccessibilityEvent(this, event);
}
/**
- * Dispatches an {@link AccessibilityEvent} to the {@link View} children
- * to be populated.
+ * Dispatches an {@link AccessibilityEvent} to the {@link View} children to be populated.
+ * This method first calls {@link #onPopulateAccessibilityEvent(AccessibilityEvent)}
+ * on this view allowing it to populate information about itself and also decide
+ * whether to intercept the population i.e. to prevent its children from populating
+ * the event.
*
* @param event The event.
*
* @return True if the event population was completed.
*/
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ onPopulateAccessibilityEvent(event);
return false;
}
/**
+ * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)}
+ * giving a chance to this View to populate the accessibility evnet with
+ * information about itself.
+ *
+ * @param event The accessibility event which to populate.
+ */
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+
+ }
+
+ /**
* Gets the {@link View} description. It briefly describes the view and is
* primarily used for accessibility support. Set this property to enable
* better accessibility support for your application. This is especially
@@ -5390,20 +5410,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* to receive the hover event.
*/
public boolean onHoverEvent(MotionEvent event) {
- final int viewFlags = mViewFlags;
-
- if (((viewFlags & CLICKABLE) != CLICKABLE &&
- (viewFlags & LONG_CLICKABLE) != LONG_CLICKABLE)) {
- // Nothing to do if the view is not clickable.
- return false;
- }
-
- if ((viewFlags & ENABLED_MASK) == DISABLED) {
- // A disabled view that is clickable still consumes the hover events, it just doesn't
- // respond to them.
- return true;
- }
-
switch (event.getAction()) {
case MotionEvent.ACTION_HOVER_ENTER:
setHovered(true);
@@ -5414,7 +5420,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
break;
}
- return true;
+ return false;
}
/**
@@ -5436,11 +5442,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
if ((mPrivateFlags & HOVERED) == 0) {
mPrivateFlags |= HOVERED;
refreshDrawableState();
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
}
} else {
if ((mPrivateFlags & HOVERED) != 0) {
mPrivateFlags &= ~HOVERED;
refreshDrawableState();
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
}
}
}
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 739758c..94eb429 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -19,7 +19,6 @@ package android.view;
import android.app.AppGlobals;
import android.content.Context;
import android.content.res.Configuration;
-import android.os.Bundle;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.SparseArray;
@@ -156,6 +155,13 @@ public class ViewConfiguration {
private static final int MAXIMUM_FLING_VELOCITY = 8000;
/**
+ * Distance between a touch up event denoting the end of a touch exploration
+ * gesture and the touch up event of a subsequent tap for the latter tap to be
+ * considered as a tap i.e. to perform a click.
+ */
+ private static final int TOUCH_EXPLORATION_TAP_SLOP = 80;
+
+ /**
* The maximum size of View's drawing cache, expressed in bytes. This size
* should be at least equal to the size of the screen in ARGB888 format.
*/
@@ -185,6 +191,7 @@ public class ViewConfiguration {
private final int mTouchSlop;
private final int mPagingTouchSlop;
private final int mDoubleTapSlop;
+ private final int mScaledTouchExplorationTapSlop;
private final int mWindowTouchSlop;
private final int mMaximumDrawingCacheSize;
private final int mOverscrollDistance;
@@ -206,6 +213,7 @@ public class ViewConfiguration {
mTouchSlop = TOUCH_SLOP;
mPagingTouchSlop = PAGING_TOUCH_SLOP;
mDoubleTapSlop = DOUBLE_TAP_SLOP;
+ mScaledTouchExplorationTapSlop = TOUCH_EXPLORATION_TAP_SLOP;
mWindowTouchSlop = WINDOW_TOUCH_SLOP;
//noinspection deprecation
mMaximumDrawingCacheSize = MAXIMUM_DRAWING_CACHE_SIZE;
@@ -242,6 +250,7 @@ public class ViewConfiguration {
mTouchSlop = (int) (sizeAndDensity * TOUCH_SLOP + 0.5f);
mPagingTouchSlop = (int) (sizeAndDensity * PAGING_TOUCH_SLOP + 0.5f);
mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
+ mScaledTouchExplorationTapSlop = (int) (density * TOUCH_EXPLORATION_TAP_SLOP + 0.5f);
mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
// Size of the screen in bytes, in ARGB_8888 format
@@ -444,6 +453,17 @@ public class ViewConfiguration {
}
/**
+ * @return Distance between a touch up event denoting the end of a touch exploration
+ * gesture and the touch up event of a subsequent tap for the latter tap to be
+ * considered as a tap i.e. to perform a click.
+ *
+ * @hide
+ */
+ public int getScaledTouchExplorationTapSlop() {
+ return mScaledTouchExplorationTapSlop;
+ }
+
+ /**
* @return Distance a touch must be outside the bounds of a window for it
* to be counted as outside the window for purposes of dismissing that
* window.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 08daa28..7b404b4 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -586,6 +586,35 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
/**
* {@inheritDoc}
*/
+ public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+ ViewParent parent = getParent();
+ if (parent == null) {
+ return false;
+ }
+ final boolean propagate = onRequestSendAccessibilityEvent(child, event);
+ if (!propagate) {
+ return false;
+ }
+ return parent.requestSendAccessibilityEvent(this, event);
+ }
+
+ /**
+ * Called when a child has requested sending an {@link AccessibilityEvent} and
+ * gives an opportunity to its parent to augment the event.
+ *
+ * @param child The child which requests sending the event.
+ * @param event The event to be sent.
+ * @return True if the event should be sent.
+ *
+ * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
+ */
+ public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
@Override
public boolean dispatchUnhandledMove(View focused, int direction) {
return mFocused != null &&
@@ -1216,9 +1245,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, mHoveredChild);
eventNoHistory.setAction(action);
-
mHoveredChild = null;
- } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
+ } else {
// Pointer is still within the child.
handled |= dispatchTransformedGenericPointerEvent(event, mHoveredChild);
}
@@ -1278,6 +1306,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
return handled;
}
+ @Override
+ public boolean onHoverEvent(MotionEvent event) {
+ // Handle the event only if leaf. This guarantees that
+ // the leafs (or any custom class that returns true from
+ // this method) will get a change to process the hover.
+ if (getChildCount() == 0) {
+ return super.onHoverEvent(event);
+ }
+ return false;
+ }
+
private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
if (event.getHistorySize() == 0) {
return event;
@@ -2091,11 +2130,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- boolean populated = false;
+ // We first get a chance to populate the event.
+ onPopulateAccessibilityEvent(event);
+ // Let our children have a shot in populating the event.
for (int i = 0, count = getChildCount(); i < count; i++) {
- populated |= getChildAt(i).dispatchPopulateAccessibilityEvent(event);
+ boolean handled = getChildAt(i).dispatchPopulateAccessibilityEvent(event);
+ if (handled) {
+ return handled;
+ }
}
- return populated;
+ return false;
}
/**
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index d7d4c3f..655df39 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -17,6 +17,7 @@
package android.view;
import android.graphics.Rect;
+import android.view.accessibility.AccessibilityEvent;
/**
* Defines the responsibilities for a class that will be a parent of a View.
@@ -222,4 +223,22 @@ public interface ViewParent {
*/
public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
boolean immediate);
+
+ /**
+ * Called by a child to request from its parent to send an {@link AccessibilityEvent}.
+ * The child has already populated a record for itself in the event and is delegating
+ * to its parent to send the event. The parent can optionally add a record for itself.
+ * <p>
+ * Note: An accessibility event is fired by an individual view which populates the
+ * event with a record for its state and requests from its parent to perform
+ * the sending. The parent can optionally add a record for itself before
+ * dispatching the request to its parent. A parent can also choose not to
+ * respect the request for sending the event. The accessibility event is sent
+ * by the topmost view in the view tree.
+ *
+ * @param child The child which requests sending the event.
+ * @param event The event to be sent.
+ * @return True if the event was sent.
+ */
+ public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event);
}
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 4104b07..f02daba 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -3530,6 +3530,14 @@ public final class ViewRoot extends Handler implements ViewParent,
public void childDrawableStateChanged(View child) {
}
+ public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+ if (mView == null) {
+ return false;
+ }
+ AccessibilityManager.getInstance(child.mContext).sendAccessibilityEvent(event);
+ return true;
+ }
+
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 9af19b8..11c9392 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -21,13 +21,26 @@ import android.os.Parcelable;
import android.text.TextUtils;
import java.util.ArrayList;
-import java.util.List;
/**
* This class represents accessibility events that are sent by the system when
* something notable happens in the user interface. For example, when a
* {@link android.widget.Button} is clicked, a {@link android.view.View} is focused, etc.
* <p>
+ * An accessibility event is fired by an individual view which populates the event with
+ * a record for its state and requests from its parent to send the event to interested
+ * parties. The parent can optionally add a record for itself before dispatching a similar
+ * request to its parent. A parent can also choose not to respect the request for sending
+ * an event. The accessibility event is sent by the topmost view in the view tree.
+ * Therefore, an {@link android.accessibilityservice.AccessibilityService} can explore
+ * all records in an accessibility event to obtain more information about the context
+ * in which the event was fired.
+ * <p>
+ * A client can add, remove, and modify records. The getters and setters for individual
+ * properties operate on the current record which can be explicitly set by the client. By
+ * default current is the first record. Thus, querying a record would require setting
+ * it as the current one and interacting with the property getters and setters.
+ * <p>
* This class represents various semantically different accessibility event
* types. Each event type has associated a set of related properties. In other
* words, each event type is characterized via a subset of the properties exposed
@@ -145,7 +158,7 @@ import java.util.List;
* @see android.view.accessibility.AccessibilityManager
* @see android.accessibilityservice.AccessibilityService
*/
-public final class AccessibilityEvent implements Parcelable {
+public final class AccessibilityEvent extends AccessibilityRecord implements Parcelable {
/**
* Invalid selection/focus position.
@@ -207,6 +220,26 @@ public final class AccessibilityEvent implements Parcelable {
public static final int TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040;
/**
+ * Represents the event of a hover enter over a {@link android.view.View}.
+ */
+ public static final int TYPE_VIEW_HOVER_ENTER = 0x00000080;
+
+ /**
+ * Represents the event of a hover exit over a {@link android.view.View}.
+ */
+ public static final int TYPE_VIEW_HOVER_EXIT = 0x00000100;
+
+ /**
+ * Represents the event of starting a touch exploration gesture.
+ */
+ public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 0x00000200;
+
+ /**
+ * Represents the event of ending a touch exploration gesture.
+ */
+ public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400;
+
+ /**
* Mask for {@link AccessibilityEvent} all types.
*
* @see #TYPE_VIEW_CLICKED
@@ -219,116 +252,53 @@ public final class AccessibilityEvent implements Parcelable {
*/
public static final int TYPES_ALL_MASK = 0xFFFFFFFF;
- private static final int MAX_POOL_SIZE = 2;
+ private static final int MAX_POOL_SIZE = 10;
private static final Object mPoolLock = new Object();
private static AccessibilityEvent sPool;
private static int sPoolSize;
- private static final int CHECKED = 0x00000001;
- private static final int ENABLED = 0x00000002;
- private static final int PASSWORD = 0x00000004;
- private static final int FULL_SCREEN = 0x00000080;
-
private AccessibilityEvent mNext;
+ private boolean mIsInPool;
private int mEventType;
- private int mBooleanProperties;
- private int mCurrentItemIndex;
- private int mItemCount;
- private int mFromIndex;
- private int mAddedCount;
- private int mRemovedCount;
-
- private long mEventTime;
-
- private CharSequence mClassName;
private CharSequence mPackageName;
- private CharSequence mContentDescription;
- private CharSequence mBeforeText;
-
- private Parcelable mParcelableData;
-
- private final List<CharSequence> mText = new ArrayList<CharSequence>();
+ private long mEventTime;
- private boolean mIsInPool;
+ private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>();
/*
* Hide constructor from clients.
*/
private AccessibilityEvent() {
- mCurrentItemIndex = INVALID_POSITION;
- }
-
- /**
- * Gets if the source is checked.
- *
- * @return True if the view is checked, false otherwise.
- */
- public boolean isChecked() {
- return getBooleanProperty(CHECKED);
- }
-
- /**
- * Sets if the source is checked.
- *
- * @param isChecked True if the view is checked, false otherwise.
- */
- public void setChecked(boolean isChecked) {
- setBooleanProperty(CHECKED, isChecked);
- }
- /**
- * Gets if the source is enabled.
- *
- * @return True if the view is enabled, false otherwise.
- */
- public boolean isEnabled() {
- return getBooleanProperty(ENABLED);
- }
-
- /**
- * Sets if the source is enabled.
- *
- * @param isEnabled True if the view is enabled, false otherwise.
- */
- public void setEnabled(boolean isEnabled) {
- setBooleanProperty(ENABLED, isEnabled);
- }
-
- /**
- * Gets if the source is a password field.
- *
- * @return True if the view is a password field, false otherwise.
- */
- public boolean isPassword() {
- return getBooleanProperty(PASSWORD);
}
/**
- * Sets if the source is a password field.
+ * Gets the number of records contained in the event.
*
- * @param isPassword True if the view is a password field, false otherwise.
+ * @return The number of records.
*/
- public void setPassword(boolean isPassword) {
- setBooleanProperty(PASSWORD, isPassword);
+ public int getRecordCount() {
+ return mRecords.size();
}
/**
- * Sets if the source is taking the entire screen.
+ * Appends an {@link AccessibilityRecord} to the end of event records.
*
- * @param isFullScreen True if the source is full screen, false otherwise.
+ * @param record The record to append.
*/
- public void setFullScreen(boolean isFullScreen) {
- setBooleanProperty(FULL_SCREEN, isFullScreen);
+ public void appendRecord(AccessibilityRecord record) {
+ mRecords.add(record);
}
/**
- * Gets if the source is taking the entire screen.
+ * Gets the records at a given index.
*
- * @return True if the source is full screen, false otherwise.
+ * @param index The index.
+ * @return The records at the specified index.
*/
- public boolean isFullScreen() {
- return getBooleanProperty(FULL_SCREEN);
+ public AccessibilityRecord getRecord(int index) {
+ return mRecords.get(index);
}
/**
@@ -350,96 +320,6 @@ public final class AccessibilityEvent implements Parcelable {
}
/**
- * Gets the number of items that can be visited.
- *
- * @return The number of items.
- */
- public int getItemCount() {
- return mItemCount;
- }
-
- /**
- * Sets the number of items that can be visited.
- *
- * @param itemCount The number of items.
- */
- public void setItemCount(int itemCount) {
- mItemCount = itemCount;
- }
-
- /**
- * Gets the index of the source in the list of items the can be visited.
- *
- * @return The current item index.
- */
- public int getCurrentItemIndex() {
- return mCurrentItemIndex;
- }
-
- /**
- * Sets the index of the source in the list of items that can be visited.
- *
- * @param currentItemIndex The current item index.
- */
- public void setCurrentItemIndex(int currentItemIndex) {
- mCurrentItemIndex = currentItemIndex;
- }
-
- /**
- * Gets the index of the first character of the changed sequence.
- *
- * @return The index of the first character.
- */
- public int getFromIndex() {
- return mFromIndex;
- }
-
- /**
- * Sets the index of the first character of the changed sequence.
- *
- * @param fromIndex The index of the first character.
- */
- public void setFromIndex(int fromIndex) {
- mFromIndex = fromIndex;
- }
-
- /**
- * Gets the number of added characters.
- *
- * @return The number of added characters.
- */
- public int getAddedCount() {
- return mAddedCount;
- }
-
- /**
- * Sets the number of added characters.
- *
- * @param addedCount The number of added characters.
- */
- public void setAddedCount(int addedCount) {
- mAddedCount = addedCount;
- }
-
- /**
- * Gets the number of removed characters.
- *
- * @return The number of removed characters.
- */
- public int getRemovedCount() {
- return mRemovedCount;
- }
-
- /**
- * Sets the number of removed characters.
- *
- * @param removedCount The number of removed characters.
- */
- public void setRemovedCount(int removedCount) {
- mRemovedCount = removedCount;
- }
-
- /**
* Gets the time in which this event was sent.
*
* @return The event time.
@@ -458,24 +338,6 @@ public final class AccessibilityEvent implements Parcelable {
}
/**
- * Gets the class name of the source.
- *
- * @return The class name.
- */
- public CharSequence getClassName() {
- return mClassName;
- }
-
- /**
- * Sets the class name of the source.
- *
- * @param className The lass name.
- */
- public void setClassName(CharSequence className) {
- mClassName = className;
- }
-
- /**
* Gets the package name of the source.
*
* @return The package name.
@@ -494,70 +356,6 @@ public final class AccessibilityEvent implements Parcelable {
}
/**
- * Gets the text of the event. The index in the list represents the priority
- * of the text. Specifically, the lower the index the higher the priority.
- *
- * @return The text.
- */
- public List<CharSequence> getText() {
- return mText;
- }
-
- /**
- * Sets the text before a change.
- *
- * @return The text before the change.
- */
- public CharSequence getBeforeText() {
- return mBeforeText;
- }
-
- /**
- * Sets the text before a change.
- *
- * @param beforeText The text before the change.
- */
- public void setBeforeText(CharSequence beforeText) {
- mBeforeText = beforeText;
- }
-
- /**
- * Gets the description of the source.
- *
- * @return The description.
- */
- public CharSequence getContentDescription() {
- return mContentDescription;
- }
-
- /**
- * Sets the description of the source.
- *
- * @param contentDescription The description.
- */
- public void setContentDescription(CharSequence contentDescription) {
- mContentDescription = contentDescription;
- }
-
- /**
- * Gets the {@link Parcelable} data.
- *
- * @return The parcelable data.
- */
- public Parcelable getParcelableData() {
- return mParcelableData;
- }
-
- /**
- * Sets the {@link Parcelable} data of the event.
- *
- * @param parcelableData The parcelable data.
- */
- public void setParcelableData(Parcelable parcelableData) {
- mParcelableData = parcelableData;
- }
-
- /**
* Returns a cached instance if such is available or a new one is
* instantiated with type property set.
*
@@ -595,11 +393,11 @@ public final class AccessibilityEvent implements Parcelable {
* <p>
* <b>Note: You must not touch the object after calling this function.</b>
*/
+ @Override
public void recycle() {
if (mIsInPool) {
return;
}
-
clear();
synchronized (mPoolLock) {
if (sPoolSize <= MAX_POOL_SIZE) {
@@ -614,44 +412,15 @@ public final class AccessibilityEvent implements Parcelable {
/**
* Clears the state of this instance.
*/
- private void clear() {
+ @Override
+ protected void clear() {
+ super.clear();
mEventType = 0;
- mBooleanProperties = 0;
- mCurrentItemIndex = INVALID_POSITION;
- mItemCount = 0;
- mFromIndex = 0;
- mAddedCount = 0;
- mRemovedCount = 0;
- mEventTime = 0;
- mClassName = null;
mPackageName = null;
- mContentDescription = null;
- mBeforeText = null;
- mParcelableData = null;
- mText.clear();
- }
-
- /**
- * Gets the value of a boolean property.
- *
- * @param property The property.
- * @return The value.
- */
- private boolean getBooleanProperty(int property) {
- return (mBooleanProperties & property) == property;
- }
-
- /**
- * Sets a boolean property.
- *
- * @param property The property.
- * @param value The value.
- */
- private void setBooleanProperty(int property, boolean value) {
- if (value) {
- mBooleanProperties |= property;
- } else {
- mBooleanProperties &= ~property;
+ mEventTime = 0;
+ while (!mRecords.isEmpty()) {
+ AccessibilityRecord record = mRecords.remove(0);
+ record.recycle();
}
}
@@ -662,38 +431,82 @@ public final class AccessibilityEvent implements Parcelable {
*/
public void initFromParcel(Parcel parcel) {
mEventType = parcel.readInt();
- mBooleanProperties = parcel.readInt();
- mCurrentItemIndex = parcel.readInt();
- mItemCount = parcel.readInt();
- mFromIndex = parcel.readInt();
- mAddedCount = parcel.readInt();
- mRemovedCount = parcel.readInt();
- mEventTime = parcel.readLong();
- mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
- mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
- mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
- mParcelableData = parcel.readParcelable(null);
- parcel.readList(mText, null);
+ mEventTime = parcel.readLong();
+ readAccessibilityRecordFromParcel(this, parcel);
+
+ // Read the records.
+ final int recordCount = parcel.readInt();
+ for (int i = 0; i < recordCount; i++) {
+ AccessibilityRecord record = AccessibilityRecord.obtain();
+ readAccessibilityRecordFromParcel(record, parcel);
+ mRecords.add(record);
+ }
}
+ /**
+ * Reads an {@link AccessibilityRecord} from a parcel.
+ *
+ * @param record The record to initialize.
+ * @param parcel The parcel to read from.
+ */
+ private void readAccessibilityRecordFromParcel(AccessibilityRecord record,
+ Parcel parcel) {
+ record.mBooleanProperties = parcel.readInt();
+ record.mCurrentItemIndex = parcel.readInt();
+ record.mItemCount = parcel.readInt();
+ record.mFromIndex = parcel.readInt();
+ record.mAddedCount = parcel.readInt();
+ record.mRemovedCount = parcel.readInt();
+ record.mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+ record.mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+ record.mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+ record.mParcelableData = parcel.readParcelable(null);
+ parcel.readList(record.mText, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mEventType);
- parcel.writeInt(mBooleanProperties);
- parcel.writeInt(mCurrentItemIndex);
- parcel.writeInt(mItemCount);
- parcel.writeInt(mFromIndex);
- parcel.writeInt(mAddedCount);
- parcel.writeInt(mRemovedCount);
- parcel.writeLong(mEventTime);
- TextUtils.writeToParcel(mClassName, parcel, 0);
TextUtils.writeToParcel(mPackageName, parcel, 0);
- TextUtils.writeToParcel(mContentDescription, parcel, 0);
- TextUtils.writeToParcel(mBeforeText, parcel, 0);
- parcel.writeParcelable(mParcelableData, flags);
- parcel.writeList(mText);
+ parcel.writeLong(mEventTime);
+ writeAccessibilityRecordToParcel(this, parcel, flags);
+
+ // Write the records.
+ final int recordCount = getRecordCount();
+ parcel.writeInt(recordCount);
+ for (int i = 0; i < recordCount; i++) {
+ AccessibilityRecord record = mRecords.get(i);
+ writeAccessibilityRecordToParcel(record, parcel, flags);
+ }
+ }
+
+ /**
+ * Writes an {@link AccessibilityRecord} to a parcel.
+ *
+ * @param record The record to write.
+ * @param parcel The parcel to which to write.
+ */
+ private void writeAccessibilityRecordToParcel(AccessibilityRecord record, Parcel parcel,
+ int flags) {
+ parcel.writeInt(record.mBooleanProperties);
+ parcel.writeInt(record.mCurrentItemIndex);
+ parcel.writeInt(record.mItemCount);
+ parcel.writeInt(record.mFromIndex);
+ parcel.writeInt(record.mAddedCount);
+ parcel.writeInt(record.mRemovedCount);
+ TextUtils.writeToParcel(record.mClassName, parcel, flags);
+ TextUtils.writeToParcel(record.mContentDescription, parcel, flags);
+ TextUtils.writeToParcel(record.mBeforeText, parcel, flags);
+ parcel.writeParcelable(record.mParcelableData, flags);
+ parcel.writeList(record.mText);
}
+ /**
+ * {@inheritDoc}
+ */
public int describeContents() {
return 0;
}
@@ -701,24 +514,21 @@ public final class AccessibilityEvent implements Parcelable {
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
- builder.append(super.toString());
builder.append("; EventType: " + mEventType);
builder.append("; EventTime: " + mEventTime);
- builder.append("; ClassName: " + mClassName);
builder.append("; PackageName: " + mPackageName);
- builder.append("; Text: " + mText);
- builder.append("; ContentDescription: " + mContentDescription);
- builder.append("; ItemCount: " + mItemCount);
- builder.append("; CurrentItemIndex: " + mCurrentItemIndex);
- builder.append("; IsEnabled: " + isEnabled());
- builder.append("; IsPassword: " + isPassword());
- builder.append("; IsChecked: " + isChecked());
- builder.append("; IsFullScreen: " + isFullScreen());
- builder.append("; BeforeText: " + mBeforeText);
- builder.append("; FromIndex: " + mFromIndex);
- builder.append("; AddedCount: " + mAddedCount);
- builder.append("; RemovedCount: " + mRemovedCount);
- builder.append("; ParcelableData: " + mParcelableData);
+ builder.append(" \n{\n");
+ builder.append(super.toString());
+ builder.append("\n");
+ for (int i = 0; i < mRecords.size(); i++) {
+ AccessibilityRecord record = mRecords.get(i);
+ builder.append(" Record ");
+ builder.append(i);
+ builder.append(":");
+ builder.append(record.toString());
+ builder.append("\n");
+ }
+ builder.append("}\n");
return builder.toString();
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 22cb0d4..dd77193 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -16,6 +16,8 @@
package android.view.accessibility;
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.Context;
import android.content.pm.ServiceInfo;
import android.os.Binder;
@@ -44,6 +46,8 @@ import java.util.List;
* @see android.content.Context#getSystemService
*/
public final class AccessibilityManager {
+ private static final boolean DEBUG = false;
+
private static final String LOG_TAG = "AccessibilityManager";
static final Object sInstanceSync = new Object();
@@ -164,7 +168,7 @@ public final class AccessibilityManager {
long identityToken = Binder.clearCallingIdentity();
doRecycle = mService.sendAccessibilityEvent(event);
Binder.restoreCallingIdentity(identityToken);
- if (false) {
+ if (DEBUG) {
Log.i(LOG_TAG, event + " sent");
}
} catch (RemoteException re) {
@@ -185,7 +189,7 @@ public final class AccessibilityManager {
}
try {
mService.interrupt();
- if (false) {
+ if (DEBUG) {
Log.i(LOG_TAG, "Requested interrupt from all services");
}
} catch (RemoteException re) {
@@ -202,7 +206,33 @@ public final class AccessibilityManager {
List<ServiceInfo> services = null;
try {
services = mService.getAccessibilityServiceList();
- if (false) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
+ }
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re);
+ }
+ return Collections.unmodifiableList(services);
+ }
+
+ /**
+ * Returns the {@link ServiceInfo}s of the enabled accessibility services
+ * for a given feedback type.
+ *
+ * @param feedbackType The type of feedback.
+ * @return An unmodifiable list with {@link ServiceInfo}s.
+ *
+ * @see AccessibilityServiceInfo#FEEDBACK_AUDIBLE
+ * @see AccessibilityServiceInfo#FEEDBACK_HAPTIC
+ * @see AccessibilityServiceInfo#FEEDBACK_SPOKEN
+ * @see AccessibilityServiceInfo#FEEDBACK_VISUAL
+ * @see AccessibilityServiceInfo#FEEDBACK_GENERIC
+ */
+ public List<ServiceInfo> getEnabledAccessibilityServiceList(int feedbackType) {
+ List<ServiceInfo> services = null;
+ try {
+ services = mService.getEnabledAccessibilityServiceList(feedbackType);
+ if (DEBUG) {
Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
}
} catch (RemoteException re) {
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
new file mode 100644
index 0000000..e095f43
--- /dev/null
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.accessibility;
+
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a record in an accessibility event. This class encapsulates
+ * the information for a {@link android.view.View}. Note that not all properties
+ * are applicable to all view types. For detailed information please refer to
+ * {@link AccessibilityEvent}.
+ *
+ * @see AccessibilityEvent
+ */
+public class AccessibilityRecord {
+
+ private static final int INVALID_POSITION = -1;
+
+ private static final int PROPERTY_CHECKED = 0x00000001;
+ private static final int PROPERTY_ENABLED = 0x00000002;
+ private static final int PROPERTY_PASSWORD = 0x00000004;
+ private static final int PROPERTY_FULL_SCREEN = 0x00000080;
+
+ private static final int MAX_POOL_SIZE = 10;
+ private static final Object mPoolLock = new Object();
+ private static AccessibilityRecord sPool;
+ private static int sPoolSize;
+
+ private AccessibilityRecord mNext;
+ private boolean mIsInPool;
+
+ protected int mBooleanProperties;
+ protected int mCurrentItemIndex;
+ protected int mItemCount;
+ protected int mFromIndex;
+ protected int mAddedCount;
+ protected int mRemovedCount;
+
+ protected CharSequence mClassName;
+ protected CharSequence mContentDescription;
+ protected CharSequence mBeforeText;
+ protected Parcelable mParcelableData;
+
+ protected final List<CharSequence> mText = new ArrayList<CharSequence>();
+
+ /*
+ * Hide constructor.
+ */
+ protected AccessibilityRecord() {
+
+ }
+
+ /**
+ * Gets if the source is checked.
+ *
+ * @return True if the view is checked, false otherwise.
+ */
+ public boolean isChecked() {
+ return getBooleanProperty(PROPERTY_CHECKED);
+ }
+
+ /**
+ * Sets if the source is checked.
+ *
+ * @param isChecked True if the view is checked, false otherwise.
+ */
+ public void setChecked(boolean isChecked) {
+ setBooleanProperty(PROPERTY_CHECKED, isChecked);
+ }
+
+ /**
+ * Gets if the source is enabled.
+ *
+ * @return True if the view is enabled, false otherwise.
+ */
+ public boolean isEnabled() {
+ return getBooleanProperty(PROPERTY_ENABLED);
+ }
+
+ /**
+ * Sets if the source is enabled.
+ *
+ * @param isEnabled True if the view is enabled, false otherwise.
+ */
+ public void setEnabled(boolean isEnabled) {
+ setBooleanProperty(PROPERTY_ENABLED, isEnabled);
+ }
+
+ /**
+ * Gets if the source is a password field.
+ *
+ * @return True if the view is a password field, false otherwise.
+ */
+ public boolean isPassword() {
+ return getBooleanProperty(PROPERTY_PASSWORD);
+ }
+
+ /**
+ * Sets if the source is a password field.
+ *
+ * @param isPassword True if the view is a password field, false otherwise.
+ */
+ public void setPassword(boolean isPassword) {
+ setBooleanProperty(PROPERTY_PASSWORD, isPassword);
+ }
+
+ /**
+ * Sets if the source is taking the entire screen.
+ *
+ * @param isFullScreen True if the source is full screen, false otherwise.
+ */
+ public void setFullScreen(boolean isFullScreen) {
+ setBooleanProperty(PROPERTY_FULL_SCREEN, isFullScreen);
+ }
+
+ /**
+ * Gets if the source is taking the entire screen.
+ *
+ * @return True if the source is full screen, false otherwise.
+ */
+ public boolean isFullScreen() {
+ return getBooleanProperty(PROPERTY_FULL_SCREEN);
+ }
+
+ /**
+ * Gets the number of items that can be visited.
+ *
+ * @return The number of items.
+ */
+ public int getItemCount() {
+ return mItemCount;
+ }
+
+ /**
+ * Sets the number of items that can be visited.
+ *
+ * @param itemCount The number of items.
+ */
+ public void setItemCount(int itemCount) {
+ mItemCount = itemCount;
+ }
+
+ /**
+ * Gets the index of the source in the list of items the can be visited.
+ *
+ * @return The current item index.
+ */
+ public int getCurrentItemIndex() {
+ return mCurrentItemIndex;
+ }
+
+ /**
+ * Sets the index of the source in the list of items that can be visited.
+ *
+ * @param currentItemIndex The current item index.
+ */
+ public void setCurrentItemIndex(int currentItemIndex) {
+ mCurrentItemIndex = currentItemIndex;
+ }
+
+ /**
+ * Gets the index of the first character of the changed sequence.
+ *
+ * @return The index of the first character.
+ */
+ public int getFromIndex() {
+ return mFromIndex;
+ }
+
+ /**
+ * Sets the index of the first character of the changed sequence.
+ *
+ * @param fromIndex The index of the first character.
+ */
+ public void setFromIndex(int fromIndex) {
+ mFromIndex = fromIndex;
+ }
+
+ /**
+ * Gets the number of added characters.
+ *
+ * @return The number of added characters.
+ */
+ public int getAddedCount() {
+ return mAddedCount;
+ }
+
+ /**
+ * Sets the number of added characters.
+ *
+ * @param addedCount The number of added characters.
+ */
+ public void setAddedCount(int addedCount) {
+ mAddedCount = addedCount;
+ }
+
+ /**
+ * Gets the number of removed characters.
+ *
+ * @return The number of removed characters.
+ */
+ public int getRemovedCount() {
+ return mRemovedCount;
+ }
+
+ /**
+ * Sets the number of removed characters.
+ *
+ * @param removedCount The number of removed characters.
+ */
+ public void setRemovedCount(int removedCount) {
+ mRemovedCount = removedCount;
+ }
+
+ /**
+ * Gets the class name of the source.
+ *
+ * @return The class name.
+ */
+ public CharSequence getClassName() {
+ return mClassName;
+ }
+
+ /**
+ * Sets the class name of the source.
+ *
+ * @param className The lass name.
+ */
+ public void setClassName(CharSequence className) {
+ mClassName = className;
+ }
+
+ /**
+ * Gets the text of the event. The index in the list represents the priority
+ * of the text. Specifically, the lower the index the higher the priority.
+ *
+ * @return The text.
+ */
+ public List<CharSequence> getText() {
+ return mText;
+ }
+
+ /**
+ * Sets the text before a change.
+ *
+ * @return The text before the change.
+ */
+ public CharSequence getBeforeText() {
+ return mBeforeText;
+ }
+
+ /**
+ * Sets the text before a change.
+ *
+ * @param beforeText The text before the change.
+ */
+ public void setBeforeText(CharSequence beforeText) {
+ mBeforeText = beforeText;
+ }
+
+ /**
+ * Gets the description of the source.
+ *
+ * @return The description.
+ */
+ public CharSequence getContentDescription() {
+ return mContentDescription;
+ }
+
+ /**
+ * Sets the description of the source.
+ *
+ * @param contentDescription The description.
+ */
+ public void setContentDescription(CharSequence contentDescription) {
+ mContentDescription = contentDescription;
+ }
+
+ /**
+ * Gets the {@link Parcelable} data.
+ *
+ * @return The parcelable data.
+ */
+ public Parcelable getParcelableData() {
+ return mParcelableData;
+ }
+
+ /**
+ * Sets the {@link Parcelable} data of the event.
+ *
+ * @param parcelableData The parcelable data.
+ */
+ public void setParcelableData(Parcelable parcelableData) {
+ mParcelableData = parcelableData;
+ }
+
+ /**
+ * Gets the value of a boolean property.
+ *
+ * @param property The property.
+ * @return The value.
+ */
+ public boolean getBooleanProperty(int property) {
+ return (mBooleanProperties & property) == property;
+ }
+
+ /**
+ * Sets a boolean property.
+ *
+ * @param property The property.
+ * @param value The value.
+ */
+ private void setBooleanProperty(int property, boolean value) {
+ if (value) {
+ mBooleanProperties |= property;
+ } else {
+ mBooleanProperties &= ~property;
+ }
+ }
+
+ /**
+ * Returns a cached instance if such is available or a new one is
+ * instantiated.
+ *
+ * @return An instance.
+ */
+ protected static AccessibilityRecord obtain() {
+ synchronized (mPoolLock) {
+ if (sPool != null) {
+ AccessibilityRecord record = sPool;
+ sPool = sPool.mNext;
+ sPoolSize--;
+ record.mNext = null;
+ record.mIsInPool = false;
+ return record;
+ }
+ return new AccessibilityRecord();
+ }
+ }
+
+ /**
+ * Return an instance back to be reused.
+ * <p>
+ * <b>Note: You must not touch the object after calling this function.</b>
+ */
+ public void recycle() {
+ if (mIsInPool) {
+ return;
+ }
+ clear();
+ synchronized (mPoolLock) {
+ if (sPoolSize <= MAX_POOL_SIZE) {
+ mNext = sPool;
+ sPool = this;
+ mIsInPool = true;
+ sPoolSize++;
+ }
+ }
+ }
+
+ /**
+ * Clears the state of this instance.
+ */
+ protected void clear() {
+ mBooleanProperties = 0;
+ mCurrentItemIndex = INVALID_POSITION;
+ mItemCount = 0;
+ mFromIndex = 0;
+ mAddedCount = 0;
+ mRemovedCount = 0;
+ mClassName = null;
+ mContentDescription = null;
+ mBeforeText = null;
+ mParcelableData = null;
+ mText.clear();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(" [ ClassName: " + mClassName);
+ builder.append("; Text: " + mText);
+ builder.append("; ContentDescription: " + mContentDescription);
+ builder.append("; ItemCount: " + mItemCount);
+ builder.append("; CurrentItemIndex: " + mCurrentItemIndex);
+ builder.append("; IsEnabled: " + getBooleanProperty(PROPERTY_ENABLED));
+ builder.append("; IsPassword: " + getBooleanProperty(PROPERTY_PASSWORD));
+ builder.append("; IsChecked: " + getBooleanProperty(PROPERTY_CHECKED));
+ builder.append("; IsFullScreen: " + getBooleanProperty(PROPERTY_FULL_SCREEN));
+ builder.append("; BeforeText: " + mBeforeText);
+ builder.append("; FromIndex: " + mFromIndex);
+ builder.append("; AddedCount: " + mAddedCount);
+ builder.append("; RemovedCount: " + mRemovedCount);
+ builder.append("; ParcelableData: " + mParcelableData);
+ builder.append(" ]");
+ return builder.toString();
+ }
+}
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 7633569..aaaae32 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -35,5 +35,7 @@ interface IAccessibilityManager {
List<ServiceInfo> getAccessibilityServiceList();
+ List<ServiceInfo> getEnabledAccessibilityServiceList(int feedbackType);
+
void interrupt();
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 6cb5c35..d63d421 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -55,6 +55,7 @@ import android.view.ViewConfiguration;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.view.accessibility.AccessibilityEvent;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@@ -2556,6 +2557,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
@Override
+ public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+ // Add a record for ourselves as well.
+ AccessibilityEvent record = AccessibilityEvent.obtain();
+ // Set the class since it is not populated in #dispatchPopulateAccessibilityEvent
+ record.setClassName(getClass().getName());
+ child.dispatchPopulateAccessibilityEvent(record);
+ event.appendRecord(record);
+ return true;
+ }
+
+ @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return false;
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index f16efbd..060f1a9 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -876,7 +876,6 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- boolean populated = false;
// This is an exceptional case which occurs when a window gets the
// focus and sends a focus event via its focused child to announce
// current focus/selection. AdapterView fires selection but not focus
@@ -885,22 +884,27 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
event.setEventType(AccessibilityEvent.TYPE_VIEW_SELECTED);
}
- // we send selection events only from AdapterView to avoid
- // generation of such event for each child
+ // We first get a chance to populate the event.
+ onPopulateAccessibilityEvent(event);
+
+ // We send selection events only from AdapterView to avoid
+ // generation of such event for each child.
View selectedView = getSelectedView();
if (selectedView != null) {
- populated = selectedView.dispatchPopulateAccessibilityEvent(event);
+ return selectedView.dispatchPopulateAccessibilityEvent(event);
}
- if (!populated) {
- if (selectedView != null) {
- event.setEnabled(selectedView.isEnabled());
- }
- event.setItemCount(getCount());
- event.setCurrentItemIndex(getSelectedItemPosition());
- }
+ return false;
+ }
- return populated;
+ @Override
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ View selectedView = getSelectedView();
+ if (selectedView != null) {
+ event.setEnabled(selectedView.isEnabled());
+ }
+ event.setItemCount(getCount());
+ event.setCurrentItemIndex(getSelectedItemPosition());
}
@Override
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index bf63607..bd595a5 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -199,11 +199,8 @@ public class CheckedTextView extends TextView implements Checkable {
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- boolean populated = super.dispatchPopulateAccessibilityEvent(event);
- if (!populated) {
- event.setChecked(mChecked);
- }
- return populated;
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+ event.setChecked(mChecked);
}
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 0df45cc..f050d41 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -208,22 +208,18 @@ public abstract class CompoundButton extends Button implements Checkable {
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- boolean populated = super.dispatchPopulateAccessibilityEvent(event);
-
- if (!populated) {
- int resourceId = 0;
- if (mChecked) {
- resourceId = R.string.accessibility_compound_button_selected;
- } else {
- resourceId = R.string.accessibility_compound_button_unselected;
- }
- String state = getResources().getString(resourceId);
- event.getText().add(state);
- event.setChecked(mChecked);
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+
+ int resourceId = 0;
+ if (mChecked) {
+ resourceId = R.string.accessibility_compound_button_selected;
+ } else {
+ resourceId = R.string.accessibility_compound_button_unselected;
}
-
- return populated;
+ String state = getResources().getString(resourceId);
+ event.getText().add(state);
+ event.setChecked(mChecked);
}
@Override
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 7210e21..30fb927 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -353,13 +353,14 @@ public class DatePicker extends FrameLayout {
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+
+ final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY
| DateUtils.FORMAT_SHOW_YEAR;
String selectedDateUtterance = DateUtils.formatDateTime(mContext,
mCurrentDate.getTimeInMillis(), flags);
event.getText().add(selectedDateUtterance);
- return true;
}
/**
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index d76a956..5618dbe 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1998,36 +1998,32 @@ public class ListView extends AbsListView {
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- boolean populated = super.dispatchPopulateAccessibilityEvent(event);
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
// If the item count is less than 15 then subtract disabled items from the count and
// position. Otherwise ignore disabled items.
- if (!populated) {
- int itemCount = 0;
- int currentItemIndex = getSelectedItemPosition();
-
- ListAdapter adapter = getAdapter();
- if (adapter != null) {
- final int count = adapter.getCount();
- if (count < 15) {
- for (int i = 0; i < count; i++) {
- if (adapter.isEnabled(i)) {
- itemCount++;
- } else if (i <= currentItemIndex) {
- currentItemIndex--;
- }
+ int itemCount = 0;
+ int currentItemIndex = getSelectedItemPosition();
+
+ ListAdapter adapter = getAdapter();
+ if (adapter != null) {
+ final int count = adapter.getCount();
+ if (count < 15) {
+ for (int i = 0; i < count; i++) {
+ if (adapter.isEnabled(i)) {
+ itemCount++;
+ } else if (i <= currentItemIndex) {
+ currentItemIndex--;
}
- } else {
- itemCount = count;
}
+ } else {
+ itemCount = count;
}
-
- event.setItemCount(itemCount);
- event.setCurrentItemIndex(currentItemIndex);
}
- return populated;
+ event.setItemCount(itemCount);
+ event.setCurrentItemIndex(currentItemIndex);
}
/**
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 8db34d9..96d41a0 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1027,12 +1027,10 @@ public class ProgressBar extends View {
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- if (!super.dispatchPopulateAccessibilityEvent(event)) {
- event.setItemCount(mMax);
- event.setCurrentItemIndex(mProgress);
- }
- return true;
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+ event.setItemCount(mMax);
+ event.setCurrentItemIndex(mProgress);
}
/**
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 6f76dd0..31ec785 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -427,12 +427,19 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- event.setItemCount(getTabCount());
- event.setCurrentItemIndex(mSelectedTab);
+ onPopulateAccessibilityEvent(event);
+ // Dispatch only to the selected tab.
if (mSelectedTab != -1) {
- getChildTabViewAt(mSelectedTab).dispatchPopulateAccessibilityEvent(event);
+ return getChildTabViewAt(mSelectedTab).dispatchPopulateAccessibilityEvent(event);
}
- return true;
+ return false;
+ }
+
+ @Override
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+ event.setItemCount(getTabCount());
+ event.setCurrentItemIndex(mSelectedTab);
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 8110d8e..4d3aa68 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2967,14 +2967,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
advancesIndex);
}
- public float getTextRunAdvancesICU(int start, int end, int contextStart,
+ public float getTextRunAdvances(int start, int end, int contextStart,
int contextEnd, int flags, float[] advances, int advancesIndex,
- Paint p) {
+ Paint p, int reserved) {
int count = end - start;
int contextCount = contextEnd - contextStart;
- return p.getTextRunAdvancesICU(mChars, start + mStart, count,
+ return p.getTextRunAdvances(mChars, start + mStart, count,
contextStart + mStart, contextCount, flags, advances,
- advancesIndex);
+ advancesIndex, reserved);
}
public int getTextRunCursor(int contextStart, int contextEnd, int flags,
@@ -7896,9 +7896,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
if (!isShown()) {
- return false;
+ return;
}
final boolean isPassword = hasPasswordTransformationMethod();
@@ -7914,7 +7914,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
} else {
event.setPassword(isPassword);
}
- return false;
}
void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText,
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 029d690..423e735 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -409,7 +409,9 @@ public class TimePicker extends FrameLayout {
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+
int flags = DateUtils.FORMAT_SHOW_TIME;
if (mIs24HourView) {
flags |= DateUtils.FORMAT_24HOUR;
@@ -421,7 +423,6 @@ public class TimePicker extends FrameLayout {
String selectedDateUtterance = DateUtils.formatDateTime(mContext,
mTempCalendar.getTimeInMillis(), flags);
event.getText().add(selectedDateUtterance);
- return true;
}
private void updateHourControl() {
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 587d678..fa8eb51 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -457,11 +457,11 @@ public class ActionBarView extends ViewGroup {
mIconView.getPaddingTop() - mIconView.getPaddingBottom();
int iconSize = res.getDimensionPixelSize(android.R.dimen.app_icon_size);
- if (iconSize * DisplayMetrics.DENSITY_LOW > availableHeight) {
+ if (iconSize * DisplayMetrics.DENSITY_LOW >= availableHeight) {
return DisplayMetrics.DENSITY_LOW;
- } else if (iconSize * DisplayMetrics.DENSITY_MEDIUM > availableHeight) {
+ } else if (iconSize * DisplayMetrics.DENSITY_MEDIUM >= availableHeight) {
return DisplayMetrics.DENSITY_MEDIUM;
- } else if (iconSize * DisplayMetrics.DENSITY_HIGH > availableHeight) {
+ } else if (iconSize * DisplayMetrics.DENSITY_HIGH >= availableHeight) {
return DisplayMetrics.DENSITY_HIGH;
}
return DisplayMetrics.DENSITY_XHIGH;