summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
authorRomain Guy <romainguy@android.com>2009-05-21 23:10:10 -0700
committerRomain Guy <romainguy@android.com>2009-05-22 01:59:59 -0700
commitd6a463a9f23b3901bf729f2f27a6bb8f78b95248 (patch)
tree1371cafd6a1c0fe8d3cd4580e7878a9adb86b183 /core/java
parentcfcc0df2658d0ce7dc753511bb44ab8ae7a636f7 (diff)
downloadframeworks_base-d6a463a9f23b3901bf729f2f27a6bb8f78b95248.zip
frameworks_base-d6a463a9f23b3901bf729f2f27a6bb8f78b95248.tar.gz
frameworks_base-d6a463a9f23b3901bf729f2f27a6bb8f78b95248.tar.bz2
Add a new API to ListView: setGestures(int). This allows developers to enable gestures to jump inside the list or filter it. This change also introduces a new XML attribute to control this API. It also adds the ability to theme the GestureOverlayView from the gestures library. Finally, this adds a new VERSION header to the binary format used to store the letters for the recognizer.
Diffstat (limited to 'core/java')
-rwxr-xr-xcore/java/android/gesture/GestureOverlayView.java245
-rw-r--r--core/java/android/gesture/GestureStroke.java8
-rw-r--r--core/java/android/gesture/LetterRecognizer.java69
-rw-r--r--core/java/android/gesture/TouchThroughGestureListener.java11
-rw-r--r--core/java/android/view/View.java31
-rw-r--r--core/java/android/view/ViewGroup.java9
-rw-r--r--core/java/android/widget/AbsListView.java389
-rw-r--r--core/java/android/widget/FastScroller.java19
-rw-r--r--core/java/android/widget/PopupWindow.java14
-rw-r--r--core/java/android/widget/TextView.java11
10 files changed, 644 insertions, 162 deletions
diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java
index bffd12e..64ddbbd 100755
--- a/core/java/android/gesture/GestureOverlayView.java
+++ b/core/java/android/gesture/GestureOverlayView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2009 The Android Open Source Project
+ * Copyright (C) 2009 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.
@@ -17,62 +17,54 @@
package android.gesture;
import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
-import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
-import android.graphics.Color;
-import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import com.android.internal.R;
import java.util.ArrayList;
/**
* A (transparent) overlay for gesture input that can be placed on top of other
- * widgets. The view can also be opaque.
+ * widgets.
+ *
+ * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeWidth
+ * @attr ref android.R.styleable#GestureOverlayView_gestureColor
+ * @attr ref android.R.styleable#GestureOverlayView_uncertainGestureColor
+ * @attr ref android.R.styleable#GestureOverlayView_fadeDuration
+ * @attr ref android.R.styleable#GestureOverlayView_fadeOffset
*/
-
public class GestureOverlayView extends View {
- static final float TOUCH_TOLERANCE = 3;
-
- // TODO: Move all these values into XML attributes
private static final int TRANSPARENT_BACKGROUND = 0x00000000;
-
- // TODO: SHOULD BE A TOTAL DURATION
- private static final float FADING_ALPHA_CHANGE = 0.15f;
- private static final long FADING_OFFSET = 300;
- private static final long FADING_REFRESHING_RATE = 16;
-
- private static final int GESTURE_STROKE_WIDTH = 12;
private static final boolean GESTURE_RENDERING_ANTIALIAS = true;
-
private static final boolean DITHER_FLAG = true;
- public static final int DEFAULT_GESTURE_COLOR = 0xFFFFFF00;
- public static final int DEFAULT_UNCERTAIN_GESTURE_COLOR = Color.argb(60, 255, 255, 0);
-
- private static final int REFRESH_RANGE = 10;
-
- private static final BlurMaskFilter BLUR_MASK_FILTER =
- new BlurMaskFilter(1, BlurMaskFilter.Blur.NORMAL);
-
private Paint mGesturePaint;
private final Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
- private Bitmap mBitmap; // with transparent background
+ private Bitmap mBitmap;
private Canvas mBitmapCanvas;
- private int mCertainGestureColor = DEFAULT_GESTURE_COLOR;
- private int mUncertainGestureColor = DEFAULT_UNCERTAIN_GESTURE_COLOR;
+ private long mFadeDuration = 300;
+ private long mFadeOffset = 300;
+ private long mFadingStart;
- // for rendering immediate ink feedback
- private Rect mInvalidRect = new Rect();
+ private float mGestureStroke = 12.0f;
+ private int mCertainGestureColor = 0xFFFFFF00;
+ private int mUncertainGestureColor = 0x3CFFFF00;
+ private int mInvalidateExtraBorder = 10;
- private Path mPath;
+ // for rendering immediate ink feedback
+ private final Rect mInvalidRect = new Rect();
+ private final Path mPath = new Path();
private float mX;
private float mY;
@@ -84,26 +76,32 @@ public class GestureOverlayView extends View {
private Gesture mCurrentGesture = null;
// TODO: Make this a list of WeakReferences
- private final ArrayList<OnGestureListener> mOnGestureListeners = new ArrayList<OnGestureListener>();
- private ArrayList<GesturePoint> mPointBuffer = null;
+ private final ArrayList<OnGestureListener> mOnGestureListeners =
+ new ArrayList<OnGestureListener>();
+ private final ArrayList<GesturePoint> mPointBuffer = new ArrayList<GesturePoint>(100);
// fading out effect
private boolean mIsFadingOut = false;
private float mFadingAlpha = 1;
-
- private Handler mHandler = new Handler();
+ private final AccelerateDecelerateInterpolator mInterpolator =
+ new AccelerateDecelerateInterpolator();
private final Runnable mFadingOut = new Runnable() {
public void run() {
if (mIsFadingOut) {
- mFadingAlpha -= FADING_ALPHA_CHANGE;
- if (mFadingAlpha <= 0) {
+ final long now = AnimationUtils.currentAnimationTimeMillis();
+ final long duration = now - mFadingStart;
+
+ if (duration > mFadeDuration) {
mIsFadingOut = false;
- mPath = null;
+ mPath.rewind();
mCurrentGesture = null;
mBitmap.eraseColor(TRANSPARENT_BACKGROUND);
} else {
- mHandler.postDelayed(this, FADING_REFRESHING_RATE);
+ float interpolatedTime = Math.max(0.0f,
+ Math.min(1.0f, duration / (float) mFadeDuration));
+ mFadingAlpha = 1.0f - mInterpolator.getInterpolation(interpolatedTime);
+ postDelayed(this, 16);
}
invalidate();
}
@@ -116,7 +114,27 @@ public class GestureOverlayView extends View {
}
public GestureOverlayView(Context context, AttributeSet attrs) {
- super(context, attrs);
+ this(context, attrs, com.android.internal.R.attr.gestureOverlayViewStyle);
+ }
+
+ public GestureOverlayView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.GestureOverlayView, defStyle, 0);
+
+ mGestureStroke = a.getFloat(R.styleable.GestureOverlayView_gestureStrokeWidth,
+ mGestureStroke);
+ mInvalidateExtraBorder = Math.max(1, ((int) mGestureStroke) - 1);
+ mCertainGestureColor = a.getColor(R.styleable.GestureOverlayView_gestureColor,
+ mCertainGestureColor);
+ mUncertainGestureColor = a.getColor(R.styleable.GestureOverlayView_uncertainGestureColor,
+ mUncertainGestureColor);
+ mFadeDuration = a.getInt(R.styleable.GestureOverlayView_fadeDuration, (int) mFadeDuration);
+ mFadeOffset = a.getInt(R.styleable.GestureOverlayView_fadeOffset, (int) mFadeOffset);
+
+ a.recycle();
+
init();
}
@@ -139,6 +157,7 @@ public class GestureOverlayView extends View {
mBitmap.eraseColor(TRANSPARENT_BACKGROUND);
mCurrentGesture.draw(mBitmapCanvas, mGesturePaint);
}
+ invalidate();
}
public void setGestureColor(int color) {
@@ -157,6 +176,16 @@ public class GestureOverlayView extends View {
return mCertainGestureColor;
}
+ public float getGestureStroke() {
+ return mGestureStroke;
+ }
+
+ public void setGestureStroke(float gestureStroke) {
+ mGestureStroke = gestureStroke;
+ mInvalidateExtraBorder = Math.max(1, ((int) mGestureStroke) - 1);
+ mGesturePaint.setStrokeWidth(mGestureStroke);
+ }
+
/**
* Set the gesture to be shown in the view
*
@@ -182,14 +211,12 @@ public class GestureOverlayView extends View {
final Paint gesturePaint = mGesturePaint;
gesturePaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS);
- gesturePaint.setColor(DEFAULT_GESTURE_COLOR);
+ gesturePaint.setColor(mCertainGestureColor);
gesturePaint.setStyle(Paint.Style.STROKE);
gesturePaint.setStrokeJoin(Paint.Join.ROUND);
gesturePaint.setStrokeCap(Paint.Cap.ROUND);
- gesturePaint.setStrokeWidth(GESTURE_STROKE_WIDTH);
+ gesturePaint.setStrokeWidth(mGestureStroke);
gesturePaint.setDither(DITHER_FLAG);
-
- mPath = null;
}
@Override
@@ -226,6 +253,10 @@ public class GestureOverlayView extends View {
mOnGestureListeners.remove(listener);
}
+ public void removeAllOnGestureListeners() {
+ mOnGestureListeners.clear();
+ }
+
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
@@ -240,25 +271,24 @@ public class GestureOverlayView extends View {
}
// draw the current stroke
- if (mPath != null) {
- canvas.drawPath(mPath, mGesturePaint);
- }
+ canvas.drawPath(mPath, mGesturePaint);
}
/**
* Clear up the overlay
*
* @param fadeOut whether the gesture on the overlay should fade out
- * gradually or disappear immediately
+ * gradually or disappear immediately
*/
public void clear(boolean fadeOut) {
if (fadeOut) {
- mFadingAlpha = 1;
+ mFadingAlpha = 1.0f;
mIsFadingOut = true;
- mHandler.removeCallbacks(mFadingOut);
- mHandler.postDelayed(mFadingOut, FADING_OFFSET);
+ removeCallbacks(mFadingOut);
+ mFadingStart = AnimationUtils.currentAnimationTimeMillis() + mFadeOffset;
+ postDelayed(mFadingOut, mFadeOffset);
} else {
- mPath = null;
+ mPath.rewind();
mCurrentGesture = null;
if (mBitmap != null) {
mBitmap.eraseColor(TRANSPARENT_BACKGROUND);
@@ -269,7 +299,7 @@ public class GestureOverlayView extends View {
public void cancelFadingOut() {
mIsFadingOut = false;
- mHandler.removeCallbacks(mFadingOut);
+ removeCallbacks(mFadingOut);
}
@Override
@@ -278,6 +308,12 @@ public class GestureOverlayView extends View {
return true;
}
+ processEvent(event);
+
+ return true;
+ }
+
+ public void processEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Rect rect = touchStart(event);
@@ -290,12 +326,14 @@ public class GestureOverlayView extends View {
}
break;
case MotionEvent.ACTION_UP:
- touchUp(event);
+ touchUp(event, false);
+ invalidate();
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ touchUp(event, true);
invalidate();
break;
}
-
- return true;
}
private Rect touchStart(MotionEvent event) {
@@ -310,7 +348,7 @@ public class GestureOverlayView extends View {
// if there is fading out going on, stop it.
if (mIsFadingOut) {
mIsFadingOut = false;
- mHandler.removeCallbacks(mFadingOut);
+ removeCallbacks(mFadingOut);
mBitmap.eraseColor(TRANSPARENT_BACKGROUND);
mCurrentGesture = null;
}
@@ -325,14 +363,13 @@ public class GestureOverlayView extends View {
mCurrentGesture = new Gesture();
}
- mPointBuffer = new ArrayList<GesturePoint>();
mPointBuffer.add(new GesturePoint(x, y, event.getEventTime()));
- mPath = new Path();
+ mPath.rewind();
mPath.moveTo(x, y);
- mInvalidRect.set((int) x - REFRESH_RANGE, (int) y - REFRESH_RANGE,
- (int) x + REFRESH_RANGE, (int) y + REFRESH_RANGE);
+ mInvalidRect.set((int) x - mInvalidateExtraBorder, (int) y - mInvalidateExtraBorder,
+ (int) x + mInvalidateExtraBorder, (int) y + mInvalidateExtraBorder);
mCurveEndX = x;
mCurveEndY = y;
@@ -343,36 +380,47 @@ public class GestureOverlayView extends View {
private Rect touchMove(MotionEvent event) {
Rect areaToRefresh = null;
- float x = event.getX();
- float y = event.getY();
+ final float x = event.getX();
+ final float y = event.getY();
+
+ final float previousX = mX;
+ final float previousY = mY;
- float dx = Math.abs(x - mX);
- float dy = Math.abs(y - mY);
+ final float dx = Math.abs(x - previousX);
+ final float dy = Math.abs(y - previousY);
- if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
-
+ if (dx >= GestureStroke.TOUCH_TOLERANCE || dy >= GestureStroke.TOUCH_TOLERANCE) {
+ areaToRefresh = mInvalidRect;
+
// start with the curve end
- mInvalidRect.set((int) mCurveEndX - REFRESH_RANGE, (int) mCurveEndY - REFRESH_RANGE,
- (int) mCurveEndX + REFRESH_RANGE, (int) mCurveEndY + REFRESH_RANGE);
+ areaToRefresh.set(
+ (int) mCurveEndX - mInvalidateExtraBorder,
+ (int) mCurveEndY - mInvalidateExtraBorder,
+ (int) mCurveEndX + mInvalidateExtraBorder,
+ (int) mCurveEndY + mInvalidateExtraBorder);
- mCurveEndX = (x + mX) / 2;
- mCurveEndY = (y + mY) / 2;
- mPath.quadTo(mX, mY, mCurveEndX, mCurveEndY);
+ mCurveEndX = (x + previousX) / 2;
+ mCurveEndY = (y + previousY) / 2;
+
+ mPath.quadTo(previousX, previousY, mCurveEndX, mCurveEndY);
// union with the control point of the new curve
- mInvalidRect.union((int) mX - REFRESH_RANGE, (int) mY - REFRESH_RANGE,
- (int) mX + REFRESH_RANGE, (int) mY + REFRESH_RANGE);
+ areaToRefresh.union(
+ (int) previousX - mInvalidateExtraBorder,
+ (int) previousY - mInvalidateExtraBorder,
+ (int) previousX + mInvalidateExtraBorder,
+ (int) previousY + mInvalidateExtraBorder);
// union with the end point of the new curve
- mInvalidRect.union((int) mCurveEndX - REFRESH_RANGE, (int) mCurveEndY - REFRESH_RANGE,
- (int) mCurveEndX + REFRESH_RANGE, (int) mCurveEndY + REFRESH_RANGE);
+ areaToRefresh.union(
+ (int) mCurveEndX - mInvalidateExtraBorder,
+ (int) mCurveEndY - mInvalidateExtraBorder,
+ (int) mCurveEndX + mInvalidateExtraBorder,
+ (int) mCurveEndY + mInvalidateExtraBorder);
- areaToRefresh = mInvalidRect;
-
mX = x;
mY = y;
}
-
mPointBuffer.add(new GesturePoint(x, y, event.getEventTime()));
@@ -386,34 +434,43 @@ public class GestureOverlayView extends View {
return areaToRefresh;
}
- private void touchUp(MotionEvent event) {
+ private void touchUp(MotionEvent event, boolean cancel) {
// add the stroke to the current gesture
mCurrentGesture.addStroke(new GestureStroke(mPointBuffer));
// add the stroke to the double buffer
- mGesturePaint.setMaskFilter(BLUR_MASK_FILTER);
mBitmapCanvas.drawPath(mPath, mGesturePaint);
- mGesturePaint.setMaskFilter(null);
-
- // pass the event to handlers
- final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
- final int count = listeners.size();
- for (int i = 0; i < count; i++) {
- listeners.get(i).onGestureEnded(this, event);
+
+ if (!cancel) {
+ // pass the event to handlers
+ final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
+ final int count = listeners.size();
+ for (int i = 0; i < count; i++) {
+ listeners.get(i).onGestureEnded(this, event);
+ }
+ } else {
+ // pass the event to handlers
+ final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
+ final int count = listeners.size();
+ for (int i = 0; i < count; i++) {
+ listeners.get(i).onGestureCancelled(this, event);
+ }
}
-
- mPath = null;
- mPointBuffer = null;
+
+ mPath.rewind();
+ mPointBuffer.clear();
}
/**
* An interface for processing gesture events
*/
public static interface OnGestureListener {
- public void onGestureStarted(GestureOverlayView overlay, MotionEvent event);
+ void onGestureStarted(GestureOverlayView overlay, MotionEvent event);
+
+ void onGesture(GestureOverlayView overlay, MotionEvent event);
- public void onGesture(GestureOverlayView overlay, MotionEvent event);
+ void onGestureEnded(GestureOverlayView overlay, MotionEvent event);
- public void onGestureEnded(GestureOverlayView overlay, MotionEvent event);
+ void onGestureCancelled(GestureOverlayView overlay, MotionEvent event);
}
}
diff --git a/core/java/android/gesture/GestureStroke.java b/core/java/android/gesture/GestureStroke.java
index 5160a76..6d022b4 100644
--- a/core/java/android/gesture/GestureStroke.java
+++ b/core/java/android/gesture/GestureStroke.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2009 The Android Open Source Project
+ * Copyright (C) 2009 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.
@@ -31,6 +31,8 @@ import java.util.ArrayList;
* A gesture stroke started on a touch down and ended on a touch up.
*/
public class GestureStroke {
+ static final float TOUCH_TOLERANCE = 3;
+
public final RectF boundingBox;
public final float length;
@@ -156,8 +158,8 @@ public class GestureStroke {
} else {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
- if (dx >= GestureOverlayView.TOUCH_TOLERANCE ||
- dy >= GestureOverlayView.TOUCH_TOLERANCE) {
+ if (dx >= TOUCH_TOLERANCE ||
+ dy >= TOUCH_TOLERANCE) {
path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
diff --git a/core/java/android/gesture/LetterRecognizer.java b/core/java/android/gesture/LetterRecognizer.java
index 4476746..b26b3f2 100644
--- a/core/java/android/gesture/LetterRecognizer.java
+++ b/core/java/android/gesture/LetterRecognizer.java
@@ -45,32 +45,27 @@ public class LetterRecognizer {
private GestureLibrary mGestureLibrary;
+ private final Comparator<Prediction> mComparator = new PredictionComparator();
+
private static class SigmoidUnit {
final float[] mWeights;
- private boolean mComputed;
- private float mResult;
-
SigmoidUnit(float[] weights) {
mWeights = weights;
}
private float compute(float[] inputs) {
- if (!mComputed) {
- float sum = 0;
+ float sum = 0;
- final int count = inputs.length;
- final float[] weights = mWeights;
+ final int count = inputs.length;
+ final float[] weights = mWeights;
- for (int i = 0; i < count; i++) {
- sum += inputs[i] * weights[i];
- }
- sum += weights[weights.length - 1];
-
- mResult = 1.0f / (float) (1 + Math.exp(-sum));
- mComputed = true;
+ for (int i = 0; i < count; i++) {
+ sum += inputs[i] * weights[i];
}
- return mResult;
+ sum += weights[weights.length - 1];
+
+ return 1.0f / (float) (1 + Math.exp(-sum));
}
}
@@ -91,16 +86,25 @@ public class LetterRecognizer {
}
public ArrayList<Prediction> recognize(Gesture gesture) {
+ return recognize(gesture, null);
+ }
+
+ public ArrayList<Prediction> recognize(Gesture gesture, ArrayList<Prediction> predictions) {
float[] query = GestureUtilities.spatialSampling(gesture, mPatchSize);
- ArrayList<Prediction> predictions = classify(query);
+ predictions = classify(query, predictions);
adjustPrediction(gesture, predictions);
return predictions;
}
- private ArrayList<Prediction> classify(float[] vector) {
+ private ArrayList<Prediction> classify(float[] vector, ArrayList<Prediction> predictions) {
+ if (predictions == null) {
+ predictions = new ArrayList<Prediction>();
+ } else {
+ predictions.clear();
+ }
+
final float[] intermediateOutput = compute(mHiddenLayer, vector);
final float[] output = compute(mOutputLayer, intermediateOutput);
- final ArrayList<Prediction> predictions = new ArrayList<Prediction>();
double sum = 0;
@@ -117,19 +121,8 @@ public class LetterRecognizer {
predictions.get(i).score /= sum;
}
- Collections.sort(predictions, new Comparator<Prediction>() {
- public int compare(Prediction object1, Prediction object2) {
- double score1 = object1.score;
- double score2 = object2.score;
- if (score1 > score2) {
- return -1;
- } else if (score1 < score2) {
- return 1;
- } else {
- return 0;
- }
- }
- });
+ Collections.sort(predictions, mComparator);
+
return predictions;
}
@@ -270,4 +263,18 @@ public class LetterRecognizer {
}
}
}
+
+ private static class PredictionComparator implements Comparator<Prediction> {
+ public int compare(Prediction object1, Prediction object2) {
+ double score1 = object1.score;
+ double score2 = object2.score;
+ if (score1 > score2) {
+ return -1;
+ } else if (score1 < score2) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
}
diff --git a/core/java/android/gesture/TouchThroughGestureListener.java b/core/java/android/gesture/TouchThroughGestureListener.java
index 7621ddf..09a528d 100644
--- a/core/java/android/gesture/TouchThroughGestureListener.java
+++ b/core/java/android/gesture/TouchThroughGestureListener.java
@@ -55,7 +55,7 @@ public class TouchThroughGestureListener implements GestureOverlayView.OnGesture
private boolean mStealEvents = false;
public TouchThroughGestureListener(View model) {
- this(model, false);
+ this(model, true);
}
public TouchThroughGestureListener(View model, boolean stealEvents) {
@@ -125,7 +125,7 @@ public class TouchThroughGestureListener implements GestureOverlayView.OnGesture
overlay.setGestureDrawingColor(overlay.getGestureColor());
if (mStealEvents) {
event = MotionEvent.obtain(event.getDownTime(), System.currentTimeMillis(),
- MotionEvent.ACTION_UP, x, y, event.getPressure(), event.getSize(),
+ MotionEvent.ACTION_CANCEL, x, y, event.getPressure(), event.getSize(),
event.getMetaState(), event.getXPrecision(), event.getYPrecision(),
event.getDeviceId(), event.getEdgeFlags());
}
@@ -153,6 +153,13 @@ public class TouchThroughGestureListener implements GestureOverlayView.OnGesture
}
}
+ public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
+ overlay.clear(mIsGesturing);
+ if (!mIsGesturing) {
+ dispatchEventToModel(event);
+ }
+ }
+
public void addOnGestureActionListener(OnGesturePerformedListener listener) {
mPerformedListeners.add(listener);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1f72eea..bcb97ed 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -538,21 +538,48 @@ import java.util.WeakHashMap;
* take care of redrawing the appropriate views until the animation completes.
* </p>
*
+ * @attr ref android.R.styleable#View_background
+ * @attr ref android.R.styleable#View_clickable
+ * @attr ref android.R.styleable#View_contentDescription
+ * @attr ref android.R.styleable#View_drawingCacheQuality
+ * @attr ref android.R.styleable#View_duplicateParentState
+ * @attr ref android.R.styleable#View_id
+ * @attr ref android.R.styleable#View_fadingEdge
+ * @attr ref android.R.styleable#View_fadingEdgeLength
* @attr ref android.R.styleable#View_fitsSystemWindows
+ * @attr ref android.R.styleable#View_isScrollContainer
+ * @attr ref android.R.styleable#View_focusable
+ * @attr ref android.R.styleable#View_focusableInTouchMode
+ * @attr ref android.R.styleable#View_hapticFeedbackEnabled
+ * @attr ref android.R.styleable#View_keepScreenOn
+ * @attr ref android.R.styleable#View_longClickable
+ * @attr ref android.R.styleable#View_minHeight
+ * @attr ref android.R.styleable#View_minWidth
* @attr ref android.R.styleable#View_nextFocusDown
* @attr ref android.R.styleable#View_nextFocusLeft
* @attr ref android.R.styleable#View_nextFocusRight
* @attr ref android.R.styleable#View_nextFocusUp
+ * @attr ref android.R.styleable#View_onClick
+ * @attr ref android.R.styleable#View_padding
+ * @attr ref android.R.styleable#View_paddingBottom
+ * @attr ref android.R.styleable#View_paddingLeft
+ * @attr ref android.R.styleable#View_paddingRight
+ * @attr ref android.R.styleable#View_paddingTop
+ * @attr ref android.R.styleable#View_saveEnabled
* @attr ref android.R.styleable#View_scrollX
* @attr ref android.R.styleable#View_scrollY
- * @attr ref android.R.styleable#View_scrollbarTrackHorizontal
- * @attr ref android.R.styleable#View_scrollbarThumbHorizontal
* @attr ref android.R.styleable#View_scrollbarSize
+ * @attr ref android.R.styleable#View_scrollbarStyle
* @attr ref android.R.styleable#View_scrollbars
+ * @attr ref android.R.styleable#View_scrollbarTrackHorizontal
+ * @attr ref android.R.styleable#View_scrollbarThumbHorizontal
* @attr ref android.R.styleable#View_scrollbarThumbVertical
* @attr ref android.R.styleable#View_scrollbarTrackVertical
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
+ * @attr ref android.R.styleable#View_soundEffectsEnabled
+ * @attr ref android.R.styleable#View_tag
+ * @attr ref android.R.styleable#View_visibility
*
* @see android.view.ViewGroup
*/
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index bf04dcd..c6f36a0 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -53,6 +53,15 @@ import java.util.ArrayList;
* <p>
* Also see {@link LayoutParams} for layout attributes.
* </p>
+ *
+ * @attr ref android.R.styleable#ViewGroup_clipChildren
+ * @attr ref android.R.styleable#ViewGroup_clipToPadding
+ * @attr ref android.R.styleable#ViewGroup_layoutAnimation
+ * @attr ref android.R.styleable#ViewGroup_animationCache
+ * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
+ * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
+ * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
+ * @attr ref android.R.styleable#ViewGroup_descendantFocusability
*/
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
private static final boolean DBG = false;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 1ca59b2..8a538d7 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -41,12 +41,18 @@ import android.view.ViewConfiguration;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.view.KeyCharacterMap;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionWrapper;
import android.view.inputmethod.InputMethodManager;
import android.view.ContextMenu.ContextMenuInfo;
+import android.gesture.GestureOverlayView;
+import android.gesture.TouchThroughGestureListener;
+import android.gesture.Gesture;
+import android.gesture.LetterRecognizer;
+import android.gesture.Prediction;
import com.android.internal.R;
@@ -54,7 +60,9 @@ import java.util.ArrayList;
import java.util.List;
/**
- * Common code shared between ListView and GridView
+ * Base class that can be used to implement virtualized lists of items. A list does
+ * not have a spatial definition here. For instance, subclases of this class can
+ * display the content of the list in a grid, in a carousel, as stack, etc.
*
* @attr ref android.R.styleable#AbsListView_listSelector
* @attr ref android.R.styleable#AbsListView_drawSelectorOnTop
@@ -65,6 +73,7 @@ import java.util.List;
* @attr ref android.R.styleable#AbsListView_cacheColorHint
* @attr ref android.R.styleable#AbsListView_fastScrollEnabled
* @attr ref android.R.styleable#AbsListView_smoothScrollbar
+ * @attr ref android.R.styleable#AbsListView_gestures
*/
public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
@@ -93,6 +102,31 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
public static final int TRANSCRIPT_MODE_ALWAYS_SCROLL = 2;
/**
+ * Disables gestures.
+ *
+ * @see #setGestures(int)
+ * @see #GESTURES_JUMP
+ * @see #GESTURES_FILTER
+ */
+ public static final int GESTURES_NONE = 0;
+ /**
+ * When a letter gesture is recognized the list jumps to a matching position.
+ *
+ * @see #setGestures(int)
+ * @see #GESTURES_NONE
+ * @see #GESTURES_FILTER
+ */
+ public static final int GESTURES_JUMP = 1;
+ /**
+ * When a letter gesture is recognized the letter is added to the filter.
+ *
+ * @see #setGestures(int)
+ * @see #GESTURES_NONE
+ * @see #GESTURES_JUMP
+ */
+ public static final int GESTURES_FILTER = 2;
+
+ /**
* Indicates that we are not in the middle of a touch gesture
*/
static final int TOUCH_MODE_REST = -1;
@@ -427,8 +461,23 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
private FastScroller mFastScroller;
- private int mTouchSlop;
+ /**
+ * Indicates the type of gestures to use: GESTURES_NONE, GESTURES_FILTER or GESTURES_NONE
+ */
+ private int mGestures;
+
+ // Used to implement the gestures overlay
+ private GestureOverlayView mGesturesOverlay;
+ private PopupWindow mGesturesPopup;
+ private ViewTreeObserver.OnGlobalLayoutListener mGesturesLayoutListener;
+ private boolean mGlobalLayoutListenerAddedGestures;
+ private boolean mInstallGesturesOverlay;
+ private TouchThroughGestureListener mGesturesListener;
+ private boolean mPreviousGesturing;
+
+ private boolean mGlobalLayoutListenerAddedFilter;
+ private int mTouchSlop;
private float mDensityScale;
private InputConnection mDefInputConnection;
@@ -535,10 +584,197 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
boolean smoothScrollbar = a.getBoolean(R.styleable.AbsListView_smoothScrollbar, true);
setSmoothScrollbarEnabled(smoothScrollbar);
-
+
+ int defaultGestures = GESTURES_NONE;
+ if (useTextFilter) {
+ defaultGestures = GESTURES_FILTER;
+ } else if (enableFastScroll) {
+ defaultGestures = GESTURES_JUMP;
+ }
+ int gestures = a.getInt(R.styleable.AbsListView_gestures, defaultGestures);
+ setGestures(gestures);
+
a.recycle();
}
+ private void initAbsListView() {
+ // Setting focusable in touch mode will set the focusable property to true
+ setFocusableInTouchMode(true);
+ setWillNotDraw(false);
+ setAlwaysDrawnWithCacheEnabled(false);
+ setScrollingCacheEnabled(true);
+
+ mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ mDensityScale = getContext().getResources().getDisplayMetrics().density;
+ }
+
+ /**
+ * <p>Sets the type of gestures to use with this list. When gestures are enabled,
+ * that is if the <code>gestures</code> parameter is not {@link #GESTURES_NONE},
+ * the user can draw characters on top of this view. When a character is
+ * recognized and matches a known character, the list will either:</p>
+ * <ul>
+ * <li>Jump to the appropriate position ({@link #GESTURES_JUMP})</li>
+ * <li>Add the character to the current filter ({@link #GESTURES_FILTER})</li>
+ * </ul>
+ * <p>Using {@link #GESTURES_JUMP} requires {@link #isFastScrollEnabled()} to
+ * be true. Using {@link #GESTURES_FILTER} requires {@link #isTextFilterEnabled()}
+ * to be true.</p>
+ *
+ * @param gestures The type of gestures to enable for this list:
+ * {@link #GESTURES_NONE}, {@link #GESTURES_JUMP} or {@link #GESTURES_FILTER}
+ *
+ * @see #GESTURES_NONE
+ * @see #GESTURES_JUMP
+ * @see #GESTURES_FILTER
+ * @see #getGestures()
+ */
+ public void setGestures(int gestures) {
+ switch (gestures) {
+ case GESTURES_JUMP:
+ if (!mFastScrollEnabled) {
+ throw new IllegalStateException("Jump gestures can only be used with "
+ + "fast scroll enabled");
+ }
+ break;
+ case GESTURES_FILTER:
+ if (!mTextFilterEnabled) {
+ throw new IllegalStateException("Filter gestures can only be used with "
+ + "text filtering enabled");
+ }
+ break;
+ }
+
+ final int oldGestures = mGestures;
+ mGestures = gestures;
+
+ // Install overlay later
+ if (oldGestures == GESTURES_NONE && gestures != GESTURES_NONE) {
+ mInstallGesturesOverlay = true;
+ // Uninstall overlay
+ } else if (oldGestures != GESTURES_NONE && gestures == GESTURES_NONE) {
+ uninstallGesturesOverlay();
+ }
+ }
+
+ /**
+ * Indicates what gestures are enabled on this view.
+ *
+ * @return {@link #GESTURES_NONE}, {@link #GESTURES_JUMP} or {@link #GESTURES_FILTER}
+ *
+ * @see #GESTURES_NONE
+ * @see #GESTURES_JUMP
+ * @see #GESTURES_FILTER
+ * @see #setGestures(int)
+ */
+ @ViewDebug.ExportedProperty(mapping = {
+ @ViewDebug.IntToString(from = GESTURES_NONE, to = "NONE"),
+ @ViewDebug.IntToString(from = GESTURES_JUMP, to = "JUMP"),
+ @ViewDebug.IntToString(from = GESTURES_FILTER, to = "FILTER")
+ })
+ public int getGestures() {
+ return mGestures;
+ }
+
+ private void dismissGesturesPopup() {
+ if (mGesturesPopup != null) {
+ mGesturesPopup.dismiss();
+ }
+ }
+
+ private void showGesturesPopup() {
+ // Make sure we have a window before showing the popup
+ if (getWindowVisibility() == View.VISIBLE) {
+ installGesturesOverlay();
+ positionGesturesPopup();
+ }
+ }
+
+ private void positionGesturesPopup() {
+ final int[] xy = new int[2];
+ getLocationOnScreen(xy);
+ if (!mGesturesPopup.isShowing()) {
+ mGesturesPopup.showAtLocation(this, Gravity.LEFT | Gravity.TOP, xy[0], xy[1]);
+ } else {
+ mGesturesPopup.update(xy[0], xy[1], -1, -1);
+ }
+ }
+
+ private void installGesturesOverlay() {
+ mInstallGesturesOverlay = false;
+
+ if (mGesturesPopup == null) {
+ final Context c = getContext();
+ final LayoutInflater layoutInflater = (LayoutInflater)
+ c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mGesturesOverlay = (GestureOverlayView)
+ layoutInflater.inflate(R.layout.list_gestures_overlay, null);
+
+ final PopupWindow p = new PopupWindow(c);
+ p.setFocusable(false);
+ p.setTouchable(false);
+ p.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+ p.setContentView(mGesturesOverlay);
+ p.setWidth(getWidth());
+ p.setHeight(getHeight());
+ p.setBackgroundDrawable(null);
+
+ if (mGesturesLayoutListener == null) {
+ mGesturesLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
+ public void onGlobalLayout() {
+ if (isShown()) {
+ showGesturesPopup();
+ } else if (mGesturesPopup.isShowing()) {
+ dismissGesturesPopup();
+ }
+ }
+ };
+ }
+ getViewTreeObserver().addOnGlobalLayoutListener(mGesturesLayoutListener);
+ mGlobalLayoutListenerAddedGestures = true;
+
+ mGesturesPopup = p;
+
+ mGesturesOverlay.removeAllOnGestureListeners();
+ mGesturesListener = new TouchThroughGestureListener(null);
+ mGesturesListener.setGestureType(TouchThroughGestureListener.MULTIPLE_STROKE);
+ mGesturesListener.addOnGestureActionListener(new GesturesProcessor());
+ mGesturesOverlay.addOnGestureListener(mGesturesListener);
+
+ mPreviousGesturing = false;
+ }
+ }
+
+ private void uninstallGesturesOverlay() {
+ dismissGesturesPopup();
+ mGesturesPopup = null;
+ if (mGesturesLayoutListener != null) {
+ getViewTreeObserver().removeGlobalOnLayoutListener(mGesturesLayoutListener);
+ }
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (mGestures != GESTURES_NONE) {
+ mGesturesOverlay.processEvent(ev);
+
+ final boolean isGesturing = mGesturesListener.isGesturing();
+
+ if (!isGesturing) {
+ mPreviousGesturing = isGesturing;
+ return super.dispatchTouchEvent(ev);
+ } else if (!mPreviousGesturing){
+ mPreviousGesturing = isGesturing;
+ final MotionEvent event = MotionEvent.obtain(ev);
+ event.setAction(MotionEvent.ACTION_CANCEL);
+ super.dispatchTouchEvent(event);
+ return true;
+ }
+ }
+
+ return super.dispatchTouchEvent(ev);
+ }
+
/**
* Enables fast scrolling by letting the user quickly scroll through lists by
* dragging the fast scroll thumb. The adapter attached to the list may want
@@ -712,17 +948,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
- private void initAbsListView() {
- // Setting focusable in touch mode will set the focusable property to true
- setFocusableInTouchMode(true);
- setWillNotDraw(false);
- setAlwaysDrawnWithCacheEnabled(false);
- setScrollingCacheEnabled(true);
-
- mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
- mDensityScale = getContext().getResources().getDisplayMetrics().density;
- }
-
private void useDefaultSelector() {
setSelector(getResources().getDrawable(
com.android.internal.R.drawable.list_selector_background));
@@ -908,11 +1133,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
private boolean acceptFilter() {
- if (!mTextFilterEnabled || !(getAdapter() instanceof Filterable) ||
- ((Filterable) getAdapter()).getFilter() == null) {
- return false;
- }
- return true;
+ return mTextFilterEnabled && getAdapter() instanceof Filterable &&
+ ((Filterable) getAdapter()).getFilter() != null;
}
/**
@@ -1096,6 +1318,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
listPadding.bottom = mSelectionBottomPadding + mPaddingBottom;
}
+ /**
+ * Subclasses should NOT override this method but
+ * {@link #layoutChildren()} instead.
+ */
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
@@ -1111,17 +1337,27 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
protected boolean setFrame(int left, int top, int right, int bottom) {
final boolean changed = super.setFrame(left, top, right, bottom);
- // Reposition the popup when the frame has changed. This includes
- // translating the widget, not just changing its dimension. The
- // filter popup needs to follow the widget.
- if (mFiltered && changed && getWindowVisibility() == View.VISIBLE && mPopup != null &&
- mPopup.isShowing()) {
- positionPopup();
+ if (changed) {
+ // Reposition the popup when the frame has changed. This includes
+ // translating the widget, not just changing its dimension. The
+ // filter popup needs to follow the widget.
+ final boolean visible = getWindowVisibility() == View.VISIBLE;
+ if (mFiltered && visible && mPopup != null && mPopup.isShowing()) {
+ positionPopup();
+ }
+
+ if (mGestures != GESTURES_NONE && visible && mGesturesPopup != null &&
+ mGesturesPopup.isShowing()) {
+ positionGesturesPopup();
+ }
}
return changed;
}
+ /**
+ * Subclasses must override this method to layout their children.
+ */
protected void layoutChildren() {
}
@@ -1324,9 +1560,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mDataChanged = true;
rememberSyncState();
}
+
if (mFastScroller != null) {
mFastScroller.onSizeChanged(w, h, oldw, oldh);
}
+
+ if (mInstallGesturesOverlay) {
+ installGesturesOverlay();
+ positionGesturesPopup();
+ } else if (mGesturesPopup != null) {
+ mGesturesPopup.update(w, h);
+ }
}
/**
@@ -1510,6 +1754,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final ViewTreeObserver treeObserver = getViewTreeObserver();
if (treeObserver != null) {
treeObserver.addOnTouchModeChangeListener(this);
+ if (mTextFilterEnabled && mPopup != null && !mGlobalLayoutListenerAddedFilter) {
+ treeObserver.addOnGlobalLayoutListener(this);
+ }
+ if (mGestures != GESTURES_NONE && mGesturesPopup != null &&
+ !mGlobalLayoutListenerAddedGestures) {
+ treeObserver.addOnGlobalLayoutListener(mGesturesLayoutListener);
+ }
}
}
@@ -1520,6 +1771,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final ViewTreeObserver treeObserver = getViewTreeObserver();
if (treeObserver != null) {
treeObserver.removeOnTouchModeChangeListener(this);
+ if (mTextFilterEnabled && mPopup != null) {
+ treeObserver.removeGlobalOnLayoutListener(this);
+ mGlobalLayoutListenerAddedFilter = false;
+ }
+ if (mGesturesLayoutListener != null && mGesturesPopup != null) {
+ mGlobalLayoutListenerAddedGestures = false;
+ treeObserver.removeGlobalOnLayoutListener(mGesturesLayoutListener);
+ }
}
}
@@ -1534,6 +1793,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
removeCallbacks(mFlingRunnable);
// Always hide the type filter
dismissPopup();
+ dismissGesturesPopup();
if (touchMode == TOUCH_MODE_OFF) {
// Remember the last selected element
@@ -1544,6 +1804,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
// Show the type filter only if a filter is in effect
showPopup();
}
+ if (mGestures != GESTURES_NONE) {
+ showGesturesPopup();
+ }
// If we changed touch mode since the last time we had focus
if (touchMode != mLastTouchMode && mLastTouchMode != TOUCH_MODE_UNKNOWN) {
@@ -2775,7 +3038,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
/**
* Removes the filter window
*/
- void dismissPopup() {
+ private void dismissPopup() {
if (mPopup != null) {
mPopup.dismiss();
}
@@ -3017,6 +3280,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
p.setBackgroundDrawable(null);
mPopup = p;
getViewTreeObserver().addOnGlobalLayoutListener(this);
+ mGlobalLayoutListenerAddedFilter = true;
}
if (animateEntrance) {
mPopup.setAnimationStyle(com.android.internal.R.style.Animation_TypingFilter);
@@ -3583,4 +3847,77 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
}
+
+ private class GesturesProcessor implements
+ TouchThroughGestureListener.OnGesturePerformedListener {
+
+ private static final double SCORE_THRESHOLD = 0.1;
+
+ private LetterRecognizer mRecognizer;
+ private ArrayList<Prediction> mPredictions;
+ private final KeyCharacterMap mKeyMap;
+ private final char[] mHolder;
+
+ GesturesProcessor() {
+ mRecognizer = LetterRecognizer.getLetterRecognizer(getContext(),
+ LetterRecognizer.RECOGNIZER_LATIN_LOWERCASE);
+ if (mGestures == GESTURES_FILTER) {
+ mKeyMap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
+ mHolder = new char[1];
+ } else {
+ mKeyMap = null;
+ mHolder = null;
+ }
+ }
+
+ public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
+ mPredictions = mRecognizer.recognize(gesture, mPredictions);
+ if (!mPredictions.isEmpty()) {
+ final Prediction prediction = mPredictions.get(0);
+ if (prediction.score > SCORE_THRESHOLD) {
+ switch (mGestures) {
+ case GESTURES_JUMP:
+ processJump(prediction);
+ break;
+ case GESTURES_FILTER:
+ processFilter(prediction);
+ break;
+ }
+ }
+ }
+ }
+
+ private void processJump(Prediction prediction) {
+ final Object[] sections = mFastScroller.getSections();
+ if (sections != null) {
+ final String name = prediction.name;
+ final int count = sections.length;
+
+ int index = -1;
+ for (int i = 0; i < count; i++) {
+ if (name.equalsIgnoreCase((String) sections[i])) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index != -1) {
+ final SectionIndexer indexer = mFastScroller.getSectionIndexer();
+ final int position = indexer.getPositionForSection(index);
+ setSelection(position);
+ }
+ }
+ }
+
+ private void processFilter(Prediction prediction) {
+ mHolder[0] = prediction.name.charAt(0);
+ final KeyEvent[] events = mKeyMap.getEvents(mHolder);
+ if (events != null) {
+ for (KeyEvent event : events) {
+ sendToTextFilter(event.getKeyCode(), event.getRepeatCount(),
+ event);
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 3368477..b9fd5a6 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -134,7 +134,7 @@ class FastScroller {
mScrollCompleted = true;
- getSections();
+ getSectionsFromIndexer();
mOverlayPos = new RectF();
mScrollFade = new ScrollFade();
@@ -250,7 +250,18 @@ class FastScroller {
}
}
- private void getSections() {
+ SectionIndexer getSectionIndexer() {
+ return mSectionIndexer;
+ }
+
+ Object[] getSections() {
+ if (mListAdapter == null && mList != null) {
+ getSectionsFromIndexer();
+ }
+ return mSections;
+ }
+
+ private void getSectionsFromIndexer() {
Adapter adapter = mList.getAdapter();
mSectionIndexer = null;
if (adapter instanceof HeaderViewListAdapter) {
@@ -411,7 +422,7 @@ class FastScroller {
setState(STATE_DRAGGING);
if (mListAdapter == null && mList != null) {
- getSections();
+ getSectionsFromIndexer();
}
cancelFling();
@@ -448,7 +459,7 @@ class FastScroller {
}
return false;
}
-
+
public class ScrollFade implements Runnable {
long mStartTime;
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 975277b..68764a5 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1072,6 +1072,20 @@ public class PopupWindow {
mWindowManager.updateViewLayout(mPopupView, p);
}
}
+
+ /**
+ * <p>Updates the dimension of the popup window. Calling this function
+ * also updates the window with the current popup state as described
+ * for {@link #update()}.</p>
+ *
+ * @param width the new width
+ * @param height the new height
+ */
+ public void update(int width, int height) {
+ WindowManager.LayoutParams p = (WindowManager.LayoutParams)
+ mPopupView.getLayoutParams();
+ update(p.x, p.y, width, height, false);
+ }
/**
* <p>Updates the position and the dimension of the popup window. Width and
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 40a72a4..5c75af2c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -127,6 +127,8 @@ import java.util.ArrayList;
* @attr ref android.R.styleable#TextView_textColor
* @attr ref android.R.styleable#TextView_textColorHighlight
* @attr ref android.R.styleable#TextView_textColorHint
+ * @attr ref android.R.styleable#TextView_textAppearance
+ * @attr ref android.R.styleable#TextView_textColorLink
* @attr ref android.R.styleable#TextView_textSize
* @attr ref android.R.styleable#TextView_textScaleX
* @attr ref android.R.styleable#TextView_typeface
@@ -164,13 +166,22 @@ import java.util.ArrayList;
* @attr ref android.R.styleable#TextView_capitalize
* @attr ref android.R.styleable#TextView_autoText
* @attr ref android.R.styleable#TextView_editable
+ * @attr ref android.R.styleable#TextView_freezesText
+ * @attr ref android.R.styleable#TextView_ellipsize
* @attr ref android.R.styleable#TextView_drawableTop
* @attr ref android.R.styleable#TextView_drawableBottom
* @attr ref android.R.styleable#TextView_drawableRight
* @attr ref android.R.styleable#TextView_drawableLeft
+ * @attr ref android.R.styleable#TextView_drawablePadding
* @attr ref android.R.styleable#TextView_lineSpacingExtra
* @attr ref android.R.styleable#TextView_lineSpacingMultiplier
* @attr ref android.R.styleable#TextView_marqueeRepeatLimit
+ * @attr ref android.R.styleable#TextView_inputType
+ * @attr ref android.R.styleable#TextView_imeOptions
+ * @attr ref android.R.styleable#TextView_privateImeOptions
+ * @attr ref android.R.styleable#TextView_imeActionLabel
+ * @attr ref android.R.styleable#TextView_imeActionId
+ * @attr ref android.R.styleable#TextView_editorExtras
*/
@RemoteView
public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {