summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/Notification.java15
-rw-r--r--core/java/android/content/Intent.java18
-rw-r--r--core/java/android/content/pm/ContainerEncryptionParams.java28
-rw-r--r--core/java/android/content/pm/LimitedLengthInputStream.java26
-rw-r--r--core/java/android/net/Uri.java6
-rw-r--r--core/java/android/nfc/NdefRecord.java12
-rw-r--r--core/java/android/view/View.java34
-rw-r--r--core/java/android/view/ViewGroup.java7
-rw-r--r--core/java/android/view/ViewRootImpl.java12
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java24
-rw-r--r--core/java/android/widget/AbsListView.java27
-rw-r--r--core/java/android/widget/HorizontalScrollView.java35
-rw-r--r--core/java/android/widget/NumberPicker.java204
-rw-r--r--core/java/android/widget/ScrollView.java35
14 files changed, 355 insertions, 128 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index edeeee2..ed9babf 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -390,21 +390,25 @@ public class Notification implements Parcelable
public int priority;
/**
+ * @hide
* Notification type: incoming call (voice or video) or similar synchronous communication request.
*/
public static final String KIND_CALL = "android.call";
/**
+ * @hide
* Notification type: incoming direct message (SMS, instant message, etc.).
*/
public static final String KIND_MESSAGE = "android.message";
/**
+ * @hide
* Notification type: asynchronous bulk message (email).
*/
public static final String KIND_EMAIL = "android.email";
/**
+ * @hide
* Notification type: calendar event.
*/
public static final String KIND_EVENT = "android.event";
@@ -415,6 +419,7 @@ public class Notification implements Parcelable
public static final String KIND_PROMO = "android.promo";
/**
+ * @hide
* If this notification matches of one or more special types (see the <code>KIND_*</code>
* constants), add them here, best match first.
*/
@@ -977,8 +982,14 @@ public class Notification implements Parcelable
}
/**
- * Show the {@link Notification#when} field as a countdown (or count-up) timer instead of a timestamp.
+ * Show the {@link Notification#when} field as a stopwatch.
+ *
+ * Instead of presenting <code>when</code> as a timestamp, the notification will show an
+ * automatically updating display of the minutes and seconds since <code>when</code>.
+ *
+ * Useful when showing an elapsed time (like an ongoing phone call).
*
+ * @see android.widget.Chronometer
* @see Notification#when
*/
public Builder setUsesChronometer(boolean b) {
@@ -1303,6 +1314,8 @@ public class Notification implements Parcelable
}
/**
+ * @hide
+ *
* Add a kind (category) to this notification. Optional.
*
* @see Notification#kind
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 4ed6f25..c791e47 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4573,7 +4573,7 @@ public class Intent implements Parcelable, Cloneable {
* <p><em>Note: scheme matching in the Android framework is
* case-sensitive, unlike the formal RFC. As a result,
* you should always write your Uri with a lower case scheme,
- * or use {@link Uri#normalize} or
+ * or use {@link Uri#normalizeScheme} or
* {@link #setDataAndNormalize}
* to ensure that the scheme is converted to lower case.</em>
*
@@ -4599,7 +4599,7 @@ public class Intent implements Parcelable, Cloneable {
* previously set (for example, by {@link #setType}).
*
* <p>The data Uri is normalized using
- * {@link android.net.Uri#normalize} before it is set,
+ * {@link android.net.Uri#normalizeScheme} before it is set,
* so really this is just a convenience method for
* <pre>
* setData(data.normalize())
@@ -4612,10 +4612,10 @@ public class Intent implements Parcelable, Cloneable {
*
* @see #getData
* @see #setType
- * @see android.net.Uri#normalize
+ * @see android.net.Uri#normalizeScheme
*/
public Intent setDataAndNormalize(Uri data) {
- return setData(data.normalize());
+ return setData(data.normalizeScheme());
}
/**
@@ -4687,7 +4687,7 @@ public class Intent implements Parcelable, Cloneable {
* <p><em>Note: MIME type and Uri scheme matching in the
* Android framework is case-sensitive, unlike the formal RFC definitions.
* As a result, you should always write these elements with lower case letters,
- * or use {@link #normalizeMimeType} or {@link android.net.Uri#normalize} or
+ * or use {@link #normalizeMimeType} or {@link android.net.Uri#normalizeScheme} or
* {@link #setDataAndTypeAndNormalize}
* to ensure that they are converted to lower case.</em>
*
@@ -4700,7 +4700,7 @@ public class Intent implements Parcelable, Cloneable {
* @see #setType
* @see #setData
* @see #normalizeMimeType
- * @see android.net.Uri#normalize
+ * @see android.net.Uri#normalizeScheme
* @see #setDataAndTypeAndNormalize
*/
public Intent setDataAndType(Uri data, String type) {
@@ -4716,7 +4716,7 @@ public class Intent implements Parcelable, Cloneable {
* data with your own type given here.
*
* <p>The data Uri and the MIME type are normalize using
- * {@link android.net.Uri#normalize} and {@link #normalizeMimeType}
+ * {@link android.net.Uri#normalizeScheme} and {@link #normalizeMimeType}
* before they are set, so really this is just a convenience method for
* <pre>
* setDataAndType(data.normalize(), Intent.normalizeMimeType(type))
@@ -4732,10 +4732,10 @@ public class Intent implements Parcelable, Cloneable {
* @see #setData
* @see #setDataAndType
* @see #normalizeMimeType
- * @see android.net.Uri#normalize
+ * @see android.net.Uri#normalizeScheme
*/
public Intent setDataAndTypeAndNormalize(Uri data, String type) {
- return setDataAndType(data.normalize(), normalizeMimeType(type));
+ return setDataAndType(data.normalizeScheme(), normalizeMimeType(type));
}
/**
diff --git a/core/java/android/content/pm/ContainerEncryptionParams.java b/core/java/android/content/pm/ContainerEncryptionParams.java
index 5b1440d..88112a7 100644
--- a/core/java/android/content/pm/ContainerEncryptionParams.java
+++ b/core/java/android/content/pm/ContainerEncryptionParams.java
@@ -70,16 +70,16 @@ public class ContainerEncryptionParams implements Parcelable {
private final byte[] mMacTag;
/** Offset into file where authenticated (e.g., MAC protected) data begins. */
- private final int mAuthenticatedDataStart;
+ private final long mAuthenticatedDataStart;
/** Offset into file where encrypted data begins. */
- private final int mEncryptedDataStart;
+ private final long mEncryptedDataStart;
/**
* Offset into file for the end of encrypted data (and, by extension,
* authenticated data) in file.
*/
- private final int mDataEnd;
+ private final long mDataEnd;
public ContainerEncryptionParams(String encryptionAlgorithm,
AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey)
@@ -99,6 +99,8 @@ public class ContainerEncryptionParams implements Parcelable {
* @param macAlgorithm MAC algorithm to use; format matches JCE
* @param macSpec algorithm parameters specification, may be {@code null}
* @param macKey key used for authentication (i.e., for the MAC tag)
+ * @param macTag message authentication code (MAC) tag for the authenticated
+ * data
* @param authenticatedDataStart offset of start of authenticated data in
* stream
* @param encryptedDataStart offset of start of encrypted data in stream
@@ -109,7 +111,7 @@ public class ContainerEncryptionParams implements Parcelable {
public ContainerEncryptionParams(String encryptionAlgorithm,
AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey, String macAlgorithm,
AlgorithmParameterSpec macSpec, SecretKey macKey, byte[] macTag,
- int authenticatedDataStart, int encryptedDataStart, int dataEnd)
+ long authenticatedDataStart, long encryptedDataStart, long dataEnd)
throws InvalidAlgorithmParameterException {
if (TextUtils.isEmpty(encryptionAlgorithm)) {
throw new NullPointerException("algorithm == null");
@@ -172,15 +174,15 @@ public class ContainerEncryptionParams implements Parcelable {
return mMacTag;
}
- public int getAuthenticatedDataStart() {
+ public long getAuthenticatedDataStart() {
return mAuthenticatedDataStart;
}
- public int getEncryptedDataStart() {
+ public long getEncryptedDataStart() {
return mEncryptedDataStart;
}
- public int getDataEnd() {
+ public long getDataEnd() {
return mDataEnd;
}
@@ -315,9 +317,9 @@ public class ContainerEncryptionParams implements Parcelable {
dest.writeByteArray(mMacTag);
- dest.writeInt(mAuthenticatedDataStart);
- dest.writeInt(mEncryptedDataStart);
- dest.writeInt(mDataEnd);
+ dest.writeLong(mAuthenticatedDataStart);
+ dest.writeLong(mEncryptedDataStart);
+ dest.writeLong(mDataEnd);
}
private ContainerEncryptionParams(Parcel source) throws InvalidAlgorithmParameterException {
@@ -333,9 +335,9 @@ public class ContainerEncryptionParams implements Parcelable {
mMacTag = source.createByteArray();
- mAuthenticatedDataStart = source.readInt();
- mEncryptedDataStart = source.readInt();
- mDataEnd = source.readInt();
+ mAuthenticatedDataStart = source.readLong();
+ mEncryptedDataStart = source.readLong();
+ mDataEnd = source.readLong();
switch (encParamType) {
case ENC_PARAMS_IV_PARAMETERS:
diff --git a/core/java/android/content/pm/LimitedLengthInputStream.java b/core/java/android/content/pm/LimitedLengthInputStream.java
index 25a490f..e787277 100644
--- a/core/java/android/content/pm/LimitedLengthInputStream.java
+++ b/core/java/android/content/pm/LimitedLengthInputStream.java
@@ -3,6 +3,7 @@ package android.content.pm;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.Arrays;
/**
* A class that limits the amount of data that is read from an InputStream. When
@@ -15,20 +16,20 @@ public class LimitedLengthInputStream extends FilterInputStream {
/**
* The end of the stream where we don't want to allow more data to be read.
*/
- private final int mEnd;
+ private final long mEnd;
/**
* Current offset in the stream.
*/
- private int mOffset;
+ private long mOffset;
/**
* @param in underlying stream to wrap
* @param offset offset into stream where data starts
* @param length length of data at offset
- * @throws IOException if an error occured with the underlying stream
+ * @throws IOException if an error occurred with the underlying stream
*/
- public LimitedLengthInputStream(InputStream in, int offset, int length) throws IOException {
+ public LimitedLengthInputStream(InputStream in, long offset, long length) throws IOException {
super(in);
if (in == null) {
@@ -36,11 +37,15 @@ public class LimitedLengthInputStream extends FilterInputStream {
}
if (offset < 0) {
- throw new IOException("offset == " + offset);
+ throw new IOException("offset < 0");
}
if (length < 0) {
- throw new IOException("length must be non-negative; is " + length);
+ throw new IOException("length < 0");
+ }
+
+ if (length > Long.MAX_VALUE - offset) {
+ throw new IOException("offset + length > Long.MAX_VALUE");
}
mEnd = offset + length;
@@ -65,8 +70,15 @@ public class LimitedLengthInputStream extends FilterInputStream {
return -1;
}
+ final int arrayLength = buffer.length;
+ Arrays.checkOffsetAndCount(arrayLength, offset, byteCount);
+
+ if (mOffset > Long.MAX_VALUE - byteCount) {
+ throw new IOException("offset out of bounds: " + mOffset + " + " + byteCount);
+ }
+
if (mOffset + byteCount > mEnd) {
- byteCount = mEnd - mOffset;
+ byteCount = (int) (mEnd - mOffset);
}
final int numRead = super.read(buffer, offset, byteCount);
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index defe7aa..3b990e3 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -1718,9 +1718,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
/**
- * Return a normalized representation of this Uri.
- *
- * <p>A normalized Uri has a lowercase scheme component.
+ * Return an equivalent URI with a lowercase scheme component.
* This aligns the Uri with Android best practices for
* intent filtering.
*
@@ -1740,7 +1738,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
* @see {@link android.content.Intent#setData}
* @see {@link #setNormalizedData}
*/
- public Uri normalize() {
+ public Uri normalizeScheme() {
String scheme = getScheme();
if (scheme == null) return this; // give up
String lowerScheme = scheme.toLowerCase(Locale.US);
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 0e9e8f4..8872335 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -321,7 +321,7 @@ public final class NdefRecord implements Parcelable {
* and {@link #RTD_URI}. This is the most efficient encoding
* of a URI into NDEF.<p>
* The uri parameter will be normalized with
- * {@link Uri#normalize} to set the scheme to lower case to
+ * {@link Uri#normalizeScheme} to set the scheme to lower case to
* follow Android best practices for intent filtering.
* However the unchecked exception
* {@link IllegalArgumentException} may be thrown if the uri
@@ -338,7 +338,7 @@ public final class NdefRecord implements Parcelable {
public static NdefRecord createUri(Uri uri) {
if (uri == null) throw new NullPointerException("uri is null");
- uri = uri.normalize();
+ uri = uri.normalizeScheme();
String uriString = uri.toString();
if (uriString.length() == 0) throw new IllegalArgumentException("uri is empty");
@@ -364,7 +364,7 @@ public final class NdefRecord implements Parcelable {
* and {@link #RTD_URI}. This is the most efficient encoding
* of a URI into NDEF.<p>
* The uriString parameter will be normalized with
- * {@link Uri#normalize} to set the scheme to lower case to
+ * {@link Uri#normalizeScheme} to set the scheme to lower case to
* follow Android best practices for intent filtering.
* However the unchecked exception
* {@link IllegalArgumentException} may be thrown if the uriString
@@ -665,7 +665,7 @@ public final class NdefRecord implements Parcelable {
* actually valid: it always attempts to create and return a URI if
* this record appears to be a URI record by the above rules.<p>
* The returned URI will be normalized to have a lower case scheme
- * using {@link Uri#normalize}.<p>
+ * using {@link Uri#normalizeScheme}.<p>
*
* @return URI, or null if this is not a URI record
*/
@@ -688,13 +688,13 @@ public final class NdefRecord implements Parcelable {
}
} catch (FormatException e) { }
} else if (Arrays.equals(mType, RTD_URI)) {
- return parseWktUri().normalize();
+ return parseWktUri().normalizeScheme();
}
break;
case TNF_ABSOLUTE_URI:
Uri uri = Uri.parse(new String(mType, Charsets.UTF_8));
- return uri.normalize();
+ return uri.normalizeScheme();
case TNF_EXTERNAL_TYPE:
if (inSmartPoster) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index aad6756..99079a9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5209,6 +5209,13 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* call to continue to your children, you must be sure to call the super
* implementation.
*
+ * <p>Here is a sample layout that makes use of fitting system windows
+ * to have controls for a video view placed inside of the window decorations
+ * that it hides and shows. This can be used with code like the second
+ * sample (video player) shown in {@link #setSystemUiVisibility(int)}.
+ *
+ * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete}
+ *
* @param insets Current content insets of the window. Prior to
* {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify
* the insets or else you and Android will be unhappy.
@@ -5251,7 +5258,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
/**
- * Check for the FITS_SYSTEM_WINDOWS flag. If this method returns true, this view
+ * Check for state of {@link #setFitsSystemWindows(boolean). If this method
+ * returns true, this view
* will account for system screen decorations such as the status bar and inset its
* content. This allows the view to be positioned in absolute screen coordinates
* and remain visible to the user.
@@ -5260,7 +5268,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @attr ref android.R.styleable#View_fitsSystemWindows
*/
- public boolean fitsSystemWindows() {
+ public boolean getFitsSystemWindows() {
return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS;
}
@@ -15376,7 +15384,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* playing the application would like to go into a complete full-screen mode,
* to use as much of the display as possible for the video. When in this state
* the user can not interact with the application; the system intercepts
- * touching on the screen to pop the UI out of full screen mode.
+ * touching on the screen to pop the UI out of full screen mode. See
+ * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code.
*
* {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java
* content}
@@ -15458,11 +15467,13 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
}
- void updateLocalSystemUiVisibility(int localValue, int localChanges) {
+ boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges);
if (val != mSystemUiVisibility) {
setSystemUiVisibility(val);
+ return true;
}
+ return false;
}
/** @hide */
@@ -16861,7 +16872,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
/**
* Interface definition for a callback to be invoked when the status bar changes
* visibility. This reports <strong>global</strong> changes to the system UI
- * state, not just what the application is requesting.
+ * state, not what the application is requesting.
*
* @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener)
*/
@@ -16870,10 +16881,10 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* Called when the status bar changes visibility because of a call to
* {@link View#setSystemUiVisibility(int)}.
*
- * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE} or
- * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. This tells you the
- * <strong>global</strong> state of the UI visibility flags, not what your
- * app is currently applying.
+ * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE},
+ * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}.
+ * This tells you the <strong>global</strong> state of these UI visibility
+ * flags, not what your app is currently applying.
*/
public void onSystemUiVisibilityChange(int visibility);
}
@@ -17159,6 +17170,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
int mDisabledSystemUiVisibility;
/**
+ * Last global system UI visibility reported by the window manager.
+ */
+ int mGlobalSystemUiVisibility;
+
+ /**
* True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener
* attached.
*/
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index acfca26..b3c8895 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1317,15 +1317,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
@Override
- void updateLocalSystemUiVisibility(int localValue, int localChanges) {
- super.updateLocalSystemUiVisibility(localValue, localChanges);
+ boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
+ boolean changed = super.updateLocalSystemUiVisibility(localValue, localChanges);
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i=0; i <count; i++) {
final View child = children[i];
- child.updateLocalSystemUiVisibility(localValue, localChanges);
+ changed |= child.updateLocalSystemUiVisibility(localValue, localChanges);
}
+ return changed;
}
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b43db14..1fcb2c3 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3795,13 +3795,15 @@ public final class ViewRootImpl implements ViewParent,
}
if (mView == null) return;
if (args.localChanges != 0) {
- if (mAttachInfo != null) {
- mAttachInfo.mRecomputeGlobalAttributes = true;
- }
mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
- scheduleTraversals();
}
- mView.dispatchSystemUiVisibilityChanged(args.globalVisibility);
+ if (mAttachInfo != null) {
+ int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
+ if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
+ mAttachInfo.mGlobalSystemUiVisibility = visibility;
+ mView.dispatchSystemUiVisibilityChanged(visibility);
+ }
+ }
}
public void handleDispatchDoneAnimating() {
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 6b14ba5..0517d4b 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -205,6 +205,16 @@ public class AccessibilityNodeInfo implements Parcelable {
public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800;
/**
+ * Action to scroll the node content forward.
+ */
+ public static final int ACTION_SCROLL_FORWARD = 0x00001000;
+
+ /**
+ * Action to scroll the node content backward.
+ */
+ public static final int ACTION_SCROLL_BACKWARD = 0x00002000;
+
+ /**
* Argument for which movement granularity to be used when traversing the node text.
* <p>
* <strong>Type:</strong> int<br>
@@ -569,6 +579,16 @@ public class AccessibilityNodeInfo implements Parcelable {
* @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
* @see AccessibilityNodeInfo#ACTION_SELECT
* @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
+ * @see AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS
+ * @see AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS
+ * @see AccessibilityNodeInfo#ACTION_CLICK
+ * @see AccessibilityNodeInfo#ACTION_LONG_CLICK
+ * @see AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+ * @see AccessibilityNodeInfo#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+ * @see AccessibilityNodeInfo#ACTION_NEXT_HTML_ELEMENT
+ * @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT
+ * @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD
+ * @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD
*/
public int getActions() {
return mActions;
@@ -1578,6 +1598,10 @@ public class AccessibilityNodeInfo implements Parcelable {
return "ACTION_NEXT_HTML_ELEMENT";
case ACTION_PREVIOUS_HTML_ELEMENT:
return "ACTION_PREVIOUS_HTML_ELEMENT";
+ case ACTION_SCROLL_FORWARD:
+ return "ACTION_SCROLL_FORWARD";
+ case ACTION_SCROLL_BACKWARD:
+ return "ACTION_SCROLL_BACKWARD";
default:
throw new IllegalArgumentException("Unknown action: " + action);
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 3aafba5..c4e1bf5 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1355,6 +1355,33 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(AbsListView.class.getName());
+ if (getFirstVisiblePosition() > 0) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ }
+ if (getLastVisiblePosition() < getCount() - 1) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ }
+ }
+
+ @Override
+ public boolean performAccessibilityAction(int action, Bundle arguments) {
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+ if (getLastVisiblePosition() < getCount() - 1) {
+ final int viewportHeight = getHeight() - mListPadding.top - mListPadding.bottom;
+ smoothScrollBy(viewportHeight, PositionScroller.SCROLL_DURATION);
+ return true;
+ }
+ } return false;
+ case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+ if (mFirstPosition > 0) {
+ final int viewportHeight = getHeight() - mListPadding.top - mListPadding.bottom;
+ smoothScrollBy(-viewportHeight, PositionScroller.SCROLL_DURATION);
+ return true;
+ }
+ } return false;
+ }
+ return super.performAccessibilityAction(action, arguments);
}
/**
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 1986450..ffabd1d 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
+import android.os.Bundle;
import android.util.AttributeSet;
import android.view.FocusFinder;
import android.view.InputDevice;
@@ -737,10 +738,42 @@ public class HorizontalScrollView extends FrameLayout {
}
@Override
+ public boolean performAccessibilityAction(int action, Bundle arguments) {
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+ final int viewportWidth = getWidth() - mPaddingLeft - mPaddingRight;
+ final int targetScrollX = Math.min(mScrollX + viewportWidth, getScrollRange());
+ if (targetScrollX != mScrollX) {
+ smoothScrollTo(targetScrollX, 0);
+ return true;
+ }
+ } return false;
+ case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+ final int viewportWidth = getWidth() - mPaddingLeft - mPaddingRight;
+ final int targetScrollX = Math.max(0, mScrollX - viewportWidth);
+ if (targetScrollX != mScrollX) {
+ smoothScrollTo(targetScrollX, 0);
+ return true;
+ }
+ } return false;
+ }
+ return super.performAccessibilityAction(action, arguments);
+ }
+
+ @Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(HorizontalScrollView.class.getName());
- info.setScrollable(getScrollRange() > 0);
+ final int scrollRange = getScrollRange();
+ if (scrollRange > 0) {
+ info.setScrollable(true);
+ if (mScrollX > 0) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ }
+ if (mScrollX < scrollRange) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ }
+ }
}
@Override
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 11d1ed0..6ff924b 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -133,16 +133,6 @@ public class NumberPicker extends LinearLayout {
private static final int UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE = 48;
/**
- * The default unscaled minimal distance for a swipe to be considered a fling.
- */
- private static final int UNSCALED_DEFAULT_MIN_FLING_DISTANCE = 150;
-
- /**
- * Coefficient for adjusting touch scroll distance.
- */
- private static final float TOUCH_SCROLL_DECELERATION_COEFFICIENT = 2.0f;
-
- /**
* The resource id for the default layout.
*/
private static final int DEFAULT_LAYOUT_RESOURCE_ID = R.layout.number_picker;
@@ -233,11 +223,6 @@ public class NumberPicker extends LinearLayout {
private final int mTextSize;
/**
- * The minimal distance for a swipe to be considered a fling.
- */
- private final int mMinFlingDistance;
-
- /**
* The height of the gap between text elements if the selector wheel.
*/
private int mSelectorTextGapHeight;
@@ -298,6 +283,11 @@ public class NumberPicker extends LinearLayout {
private final Paint mSelectorWheelPaint;
/**
+ * The {@link Drawable} for pressed virtual (increment/decrement) buttons.
+ */
+ private final Drawable mVirtualButtonPressedDrawable;
+
+ /**
* The height of a selector element (text + gap).
*/
private int mSelectorElementHeight;
@@ -435,11 +425,26 @@ public class NumberPicker extends LinearLayout {
private int mLastHoveredChildVirtualViewId;
/**
+ * Whether the increment virtual button is pressed.
+ */
+ private boolean mIncrementVirtualButtonPressed;
+
+ /**
+ * Whether the decrement virtual button is pressed.
+ */
+ private boolean mDecrementVirtualButtonPressed;
+
+ /**
* Provider to report to clients the semantic structure of this widget.
*/
private AccessibilityNodeProviderImpl mAccessibilityNodeProvider;
/**
+ * Helper class for managing pressed state of the virtual buttons.
+ */
+ private final PressedStateHelper mPressedStateHelper;
+
+ /**
* Interface to listen for changes of the current value.
*/
public interface OnValueChangeListener {
@@ -553,12 +558,6 @@ public class NumberPicker extends LinearLayout {
mSelectionDividersDistance = attributesArray.getDimensionPixelSize(
R.styleable.NumberPicker_selectionDividersDistance, defSelectionDividerDistance);
- final int defMinFlingDistance = (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_MIN_FLING_DISTANCE,
- getResources().getDisplayMetrics());
- mMinFlingDistance = attributesArray.getDimensionPixelSize(
- R.styleable.NumberPicker_minFlingDistance, defMinFlingDistance);
-
mMinHeight = attributesArray.getDimensionPixelSize(
R.styleable.NumberPicker_internalMinHeight, SIZE_UNSPECIFIED);
@@ -581,8 +580,13 @@ public class NumberPicker extends LinearLayout {
mComputeMaxWidth = (mMaxWidth == SIZE_UNSPECIFIED);
+ mVirtualButtonPressedDrawable = attributesArray.getDrawable(
+ R.styleable.NumberPicker_virtualButtonPressedDrawable);
+
attributesArray.recycle();
+ mPressedStateHelper = new PressedStateHelper();
+
// By default Linearlayout that we extend is not drawn. This is
// its draw() method is not called but dispatchDraw() is called
// directly (see ViewGroup.drawChild()). However, this class uses
@@ -776,7 +780,19 @@ public class NumberPicker extends LinearLayout {
mLastDownEventTime = event.getEventTime();
mIngonreMoveEvents = false;
mShowSoftInputOnTap = false;
- // Make sure we wupport flinging inside scrollables.
+ // Handle pressed state before any state change.
+ if (mLastDownEventY < mTopSelectionDividerTop) {
+ if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) {
+ mPressedStateHelper.buttonPressDelayed(
+ PressedStateHelper.BUTTON_DECREMENT);
+ }
+ } else if (mLastDownEventY > mBottomSelectionDividerBottom) {
+ if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) {
+ mPressedStateHelper.buttonPressDelayed(
+ PressedStateHelper.BUTTON_INCREMENT);
+ }
+ }
+ // Make sure we support flinging inside scrollables.
getParent().requestDisallowInterceptTouchEvent(true);
if (!mFlingScroller.isFinished()) {
mFlingScroller.forceFinished(true);
@@ -826,8 +842,7 @@ public class NumberPicker extends LinearLayout {
onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
}
} else {
- int deltaMoveY = (int) ((currentMoveY - mLastDownOrMoveEventY)
- / TOUCH_SCROLL_DECELERATION_COEFFICIENT);
+ int deltaMoveY = (int) ((currentMoveY - mLastDownOrMoveEventY));
scrollBy(0, deltaMoveY);
invalidate();
}
@@ -836,23 +851,12 @@ public class NumberPicker extends LinearLayout {
case MotionEvent.ACTION_UP: {
removeBeginSoftInputCommand();
removeChangeCurrentByOneFromLongPress();
+ mPressedStateHelper.cancel();
VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
int initialVelocity = (int) velocityTracker.getYVelocity();
if (Math.abs(initialVelocity) > mMinimumFlingVelocity) {
- int deltaMove = (int) (event.getY() - mLastDownEventY);
- int absDeltaMoveY = Math.abs(deltaMove);
- if (absDeltaMoveY > mMinFlingDistance) {
- fling(initialVelocity);
- } else {
- final int normalizedDeltaMove =
- (int) (absDeltaMoveY / TOUCH_SCROLL_DECELERATION_COEFFICIENT);
- if (normalizedDeltaMove < mSelectorElementHeight) {
- snapToNextValue(deltaMove < 0);
- } else {
- snapToClosestValue();
- }
- }
+ fling(initialVelocity);
onScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
} else {
int eventY = (int) event.getY();
@@ -867,8 +871,12 @@ public class NumberPicker extends LinearLayout {
- SELECTOR_MIDDLE_ITEM_INDEX;
if (selectorIndexOffset > 0) {
changeValueByOne(true);
+ mPressedStateHelper.buttonTapped(
+ PressedStateHelper.BUTTON_INCREMENT);
} else if (selectorIndexOffset < 0) {
changeValueByOne(false);
+ mPressedStateHelper.buttonTapped(
+ PressedStateHelper.BUTTON_DECREMENT);
}
}
} else {
@@ -1356,6 +1364,22 @@ public class NumberPicker extends LinearLayout {
float x = (mRight - mLeft) / 2;
float y = mCurrentScrollOffset;
+ // draw the virtual buttons pressed state if needed
+ if (mVirtualButtonPressedDrawable != null
+ && mScrollState == OnScrollListener.SCROLL_STATE_IDLE) {
+ if (mDecrementVirtualButtonPressed) {
+ mVirtualButtonPressedDrawable.setState(PRESSED_STATE_SET);
+ mVirtualButtonPressedDrawable.setBounds(0, 0, mRight, mTopSelectionDividerTop);
+ mVirtualButtonPressedDrawable.draw(canvas);
+ }
+ if (mIncrementVirtualButtonPressed) {
+ mVirtualButtonPressedDrawable.setState(PRESSED_STATE_SET);
+ mVirtualButtonPressedDrawable.setBounds(0, mBottomSelectionDividerBottom, mRight,
+ mBottom);
+ mVirtualButtonPressedDrawable.draw(canvas);
+ }
+ }
+
// draw the selector wheel
int[] selectorIndices = mSelectorIndices;
for (int i = 0; i < selectorIndices.length; i++) {
@@ -1465,15 +1489,15 @@ public class NumberPicker extends LinearLayout {
*/
private void initializeSelectorWheelIndices() {
mSelectorIndexToStringCache.clear();
- int[] selectorIdices = mSelectorIndices;
+ int[] selectorIndices = mSelectorIndices;
int current = getValue();
for (int i = 0; i < mSelectorIndices.length; i++) {
int selectorIndex = current + (i - SELECTOR_MIDDLE_ITEM_INDEX);
if (mWrapSelectorWheel) {
selectorIndex = getWrappedSelectorIndex(selectorIndex);
}
- mSelectorIndices[i] = selectorIndex;
- ensureCachedScrollSelectorValue(mSelectorIndices[i]);
+ selectorIndices[i] = selectorIndex;
+ ensureCachedScrollSelectorValue(selectorIndices[i]);
}
}
@@ -1775,6 +1799,7 @@ public class NumberPicker extends LinearLayout {
if (mBeginSoftInputOnLongPressCommand != null) {
removeCallbacks(mBeginSoftInputOnLongPressCommand);
}
+ mPressedStateHelper.cancel();
}
/**
@@ -1910,39 +1935,80 @@ public class NumberPicker extends LinearLayout {
return false;
}
- private void snapToNextValue(boolean increment) {
- int deltaY = mCurrentScrollOffset - mInitialScrollOffset;
- int amountToScroll = 0;
- if (deltaY != 0) {
- mPreviousScrollerY = 0;
- if (deltaY > 0) {
- if (increment) {
- amountToScroll = - deltaY;
- } else {
- amountToScroll = mSelectorElementHeight - deltaY;
- }
- } else {
- if (increment) {
- amountToScroll = - mSelectorElementHeight - deltaY;
- } else {
- amountToScroll = - deltaY;
- }
+ class PressedStateHelper implements Runnable {
+ public static final int BUTTON_INCREMENT = 1;
+ public static final int BUTTON_DECREMENT = 2;
+
+ private final int MODE_PRESS = 1;
+ private final int MODE_TAPPED = 2;
+
+ private int mManagedButton;
+ private int mMode;
+
+ public void cancel() {
+ mMode = 0;
+ mManagedButton = 0;
+ NumberPicker.this.removeCallbacks(this);
+ if (mIncrementVirtualButtonPressed) {
+ mIncrementVirtualButtonPressed = false;
+ invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom);
+ }
+ mDecrementVirtualButtonPressed = false;
+ if (mDecrementVirtualButtonPressed) {
+ invalidate(0, 0, mRight, mTopSelectionDividerTop);
}
- mFlingScroller.startScroll(0, 0, 0, amountToScroll, SNAP_SCROLL_DURATION);
- invalidate();
}
- }
- private void snapToClosestValue() {
- // adjust to the closest value
- int deltaY = mInitialScrollOffset - mCurrentScrollOffset;
- if (deltaY != 0) {
- mPreviousScrollerY = 0;
- if (Math.abs(deltaY) > mSelectorElementHeight / 2) {
- deltaY += (deltaY > 0) ? -mSelectorElementHeight : mSelectorElementHeight;
+ public void buttonPressDelayed(int button) {
+ cancel();
+ mMode = MODE_PRESS;
+ mManagedButton = button;
+ NumberPicker.this.postDelayed(this, ViewConfiguration.getTapTimeout());
+ }
+
+ public void buttonTapped(int button) {
+ cancel();
+ mMode = MODE_TAPPED;
+ mManagedButton = button;
+ NumberPicker.this.post(this);
+ }
+
+ @Override
+ public void run() {
+ switch (mMode) {
+ case MODE_PRESS: {
+ switch (mManagedButton) {
+ case BUTTON_INCREMENT: {
+ mIncrementVirtualButtonPressed = true;
+ invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom);
+ } break;
+ case BUTTON_DECREMENT: {
+ mDecrementVirtualButtonPressed = true;
+ invalidate(0, 0, mRight, mTopSelectionDividerTop);
+ }
+ }
+ } break;
+ case MODE_TAPPED: {
+ switch (mManagedButton) {
+ case BUTTON_INCREMENT: {
+ if (!mIncrementVirtualButtonPressed) {
+ NumberPicker.this.postDelayed(this,
+ ViewConfiguration.getPressedStateDuration());
+ }
+ mIncrementVirtualButtonPressed ^= true;
+ invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom);
+ } break;
+ case BUTTON_DECREMENT: {
+ if (!mDecrementVirtualButtonPressed) {
+ NumberPicker.this.postDelayed(this,
+ ViewConfiguration.getPressedStateDuration());
+ }
+ mDecrementVirtualButtonPressed ^= true;
+ invalidate(0, 0, mRight, mTopSelectionDividerTop);
+ }
+ }
+ } break;
}
- mFlingScroller.startScroll(0, 0, 0, deltaY, SNAP_SCROLL_DURATION);
- invalidate();
}
}
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index f912c66..b398ce4 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.StrictMode;
import android.util.AttributeSet;
import android.view.FocusFinder;
@@ -740,10 +741,42 @@ public class ScrollView extends FrameLayout {
}
@Override
+ public boolean performAccessibilityAction(int action, Bundle arguments) {
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+ final int viewportHeight = getHeight() - mPaddingBottom - mPaddingTop;
+ final int targetScrollY = Math.min(mScrollY + viewportHeight, getScrollRange());
+ if (targetScrollY != mScrollY) {
+ smoothScrollTo(0, targetScrollY);
+ return true;
+ }
+ } return false;
+ case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+ final int viewportHeight = getHeight() - mPaddingBottom - mPaddingTop;
+ final int targetScrollY = Math.max(mScrollY - viewportHeight, 0);
+ if (targetScrollY != mScrollY) {
+ smoothScrollTo(0, targetScrollY);
+ return true;
+ }
+ } return false;
+ }
+ return super.performAccessibilityAction(action, arguments);
+ }
+
+ @Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(ScrollView.class.getName());
- info.setScrollable(getScrollRange() > 0);
+ final int scrollRange = getScrollRange();
+ if (scrollRange > 0) {
+ info.setScrollable(true);
+ if (mScrollY > 0) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ }
+ if (mScrollY < scrollRange) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ }
+ }
}
@Override