Removes gestures from ListView.
This commit is contained in:
@@ -1,279 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.gesture;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static android.gesture.GestureConstants.LOG_TAG;
|
||||
|
||||
public class LetterRecognizer {
|
||||
static final String GESTURE_FILE_NAME = "letters.gestures";
|
||||
|
||||
private final static int ADJUST_RANGE = 3;
|
||||
|
||||
private SigmoidUnit[] mHiddenLayer;
|
||||
private SigmoidUnit[] mOutputLayer;
|
||||
|
||||
private final String[] mClasses;
|
||||
|
||||
private final int mPatchSize;
|
||||
|
||||
private GestureLibrary mGestureStore;
|
||||
|
||||
private final Comparator<Prediction> mComparator = new PredictionComparator();
|
||||
|
||||
private static class SigmoidUnit {
|
||||
final float[] mWeights;
|
||||
|
||||
SigmoidUnit(float[] weights) {
|
||||
mWeights = weights;
|
||||
}
|
||||
|
||||
private float compute(float[] inputs) {
|
||||
float sum = 0;
|
||||
|
||||
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];
|
||||
|
||||
return 1.0f / (float) (1 + Math.exp(-sum));
|
||||
}
|
||||
}
|
||||
|
||||
private LetterRecognizer(int numOfInput, int numOfHidden, String[] classes) {
|
||||
mPatchSize = (int) Math.sqrt(numOfInput);
|
||||
mHiddenLayer = new SigmoidUnit[numOfHidden];
|
||||
mClasses = classes;
|
||||
mOutputLayer = new SigmoidUnit[classes.length];
|
||||
}
|
||||
|
||||
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);
|
||||
predictions = classify(query, predictions);
|
||||
adjustPrediction(gesture, predictions);
|
||||
return predictions;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
double sum = 0;
|
||||
|
||||
final String[] classes = mClasses;
|
||||
final int count = classes.length;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
double score = output[i];
|
||||
sum += score;
|
||||
predictions.add(new Prediction(classes[i], score));
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
predictions.get(i).score /= sum;
|
||||
}
|
||||
|
||||
Collections.sort(predictions, mComparator);
|
||||
|
||||
return predictions;
|
||||
}
|
||||
|
||||
private float[] compute(SigmoidUnit[] layer, float[] input) {
|
||||
final float[] output = new float[layer.length];
|
||||
final int count = layer.length;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
output[i] = layer[i].compute(input);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static LetterRecognizer createFromResource(Context context, int resourceID) {
|
||||
final Resources resources = context.getResources();
|
||||
final InputStream stream = resources.openRawResource(resourceID);
|
||||
return createFromStream(stream);
|
||||
}
|
||||
|
||||
static LetterRecognizer createFromStream(InputStream stream) {
|
||||
DataInputStream in = null;
|
||||
LetterRecognizer classifier = null;
|
||||
|
||||
try {
|
||||
in = new DataInputStream(new BufferedInputStream(stream,
|
||||
GestureConstants.IO_BUFFER_SIZE));
|
||||
|
||||
final int version = in.readShort();
|
||||
|
||||
switch (version) {
|
||||
case 1:
|
||||
classifier = readV1(in);
|
||||
break;
|
||||
default:
|
||||
Log.d(LOG_TAG, "Couldn't load handwriting data: version " + version +
|
||||
" not supported");
|
||||
break;
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
Log.d(LOG_TAG, "Failed to load handwriting data:", e);
|
||||
} finally {
|
||||
GestureUtilities.closeStream(in);
|
||||
}
|
||||
|
||||
return classifier;
|
||||
}
|
||||
|
||||
private static LetterRecognizer readV1(DataInputStream in) throws IOException {
|
||||
|
||||
final int iCount = in.readInt();
|
||||
final int hCount = in.readInt();
|
||||
final int oCount = in.readInt();
|
||||
|
||||
final String[] classes = new String[oCount];
|
||||
for (int i = 0; i < classes.length; i++) {
|
||||
classes[i] = in.readUTF();
|
||||
}
|
||||
|
||||
final LetterRecognizer classifier = new LetterRecognizer(iCount, hCount, classes);
|
||||
final SigmoidUnit[] hiddenLayer = new SigmoidUnit[hCount];
|
||||
final SigmoidUnit[] outputLayer = new SigmoidUnit[oCount];
|
||||
|
||||
for (int i = 0; i < hCount; i++) {
|
||||
final float[] weights = new float[iCount + 1];
|
||||
for (int j = 0; j <= iCount; j++) {
|
||||
weights[j] = in.readFloat();
|
||||
}
|
||||
hiddenLayer[i] = new SigmoidUnit(weights);
|
||||
}
|
||||
|
||||
for (int i = 0; i < oCount; i++) {
|
||||
final float[] weights = new float[hCount + 1];
|
||||
for (int j = 0; j <= hCount; j++) {
|
||||
weights[j] = in.readFloat();
|
||||
}
|
||||
outputLayer[i] = new SigmoidUnit(weights);
|
||||
}
|
||||
|
||||
classifier.mHiddenLayer = hiddenLayer;
|
||||
classifier.mOutputLayer = outputLayer;
|
||||
|
||||
return classifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Publish this API once we figure out where we should save the personalized
|
||||
* gestures, and how to do so across all apps
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean save() {
|
||||
if (mGestureStore != null) {
|
||||
return mGestureStore.save();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Publish this API once we figure out where we should save the personalized
|
||||
* gestures, and how to do so across all apps
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void setPersonalizationEnabled(boolean enabled) {
|
||||
if (enabled) {
|
||||
mGestureStore = GestureLibraries.fromFile(GESTURE_FILE_NAME);
|
||||
mGestureStore.setSequenceType(GestureStore.SEQUENCE_INVARIANT);
|
||||
mGestureStore.load();
|
||||
} else {
|
||||
mGestureStore = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Publish this API once we figure out where we should save the personalized
|
||||
* gestures, and how to do so across all apps
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void addExample(String letter, Gesture example) {
|
||||
if (mGestureStore != null) {
|
||||
mGestureStore.addGesture(letter, example);
|
||||
}
|
||||
}
|
||||
|
||||
private void adjustPrediction(Gesture query, ArrayList<Prediction> predictions) {
|
||||
if (mGestureStore != null) {
|
||||
final ArrayList<Prediction> results = mGestureStore.recognize(query);
|
||||
final HashMap<String, Prediction> topNList = new HashMap<String, Prediction>();
|
||||
|
||||
for (int j = 0; j < ADJUST_RANGE; j++) {
|
||||
Prediction prediction = predictions.remove(0);
|
||||
topNList.put(prediction.name, prediction);
|
||||
}
|
||||
|
||||
final int count = results.size();
|
||||
for (int j = count - 1; j >= 0 && !topNList.isEmpty(); j--) {
|
||||
final Prediction item = results.get(j);
|
||||
final Prediction original = topNList.get(item.name);
|
||||
if (original != null) {
|
||||
predictions.add(0, original);
|
||||
topNList.remove(item.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.gesture;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import static android.gesture.GestureConstants.LOG_TAG;
|
||||
import static android.gesture.LetterRecognizer.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public final class LetterRecognizers {
|
||||
public final static int RECOGNIZER_LATIN_LOWERCASE = 0;
|
||||
|
||||
private LetterRecognizers() {
|
||||
}
|
||||
|
||||
public static LetterRecognizer fromType(Context context, int type) {
|
||||
switch (type) {
|
||||
case RECOGNIZER_LATIN_LOWERCASE: {
|
||||
return createFromResource(context, com.android.internal.R.raw.latin_lowercase);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static LetterRecognizer fromResource(Context context, int resourceId) {
|
||||
return createFromResource(context, resourceId);
|
||||
}
|
||||
|
||||
public static LetterRecognizer fromFile(String path) {
|
||||
return fromFile(new File(path));
|
||||
}
|
||||
|
||||
public static LetterRecognizer fromFile(File file) {
|
||||
try {
|
||||
return createFromStream(new FileInputStream(file));
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.d(LOG_TAG, "Failed to load handwriting data from file " + file, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static LetterRecognizer fromStream(InputStream stream) {
|
||||
return createFromStream(stream);
|
||||
}
|
||||
}
|
||||
@@ -41,18 +41,12 @@ 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.Gesture;
|
||||
import android.gesture.LetterRecognizer;
|
||||
import android.gesture.Prediction;
|
||||
import android.gesture.LetterRecognizers;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
@@ -73,7 +67,6 @@ 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,
|
||||
@@ -101,31 +94,6 @@ 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
|
||||
*/
|
||||
@@ -461,18 +429,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
*/
|
||||
private FastScroller mFastScroller;
|
||||
|
||||
/**
|
||||
* 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 boolean mGlobalLayoutListenerAddedFilter;
|
||||
|
||||
private int mTouchSlop;
|
||||
@@ -583,9 +539,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
boolean smoothScrollbar = a.getBoolean(R.styleable.AbsListView_smoothScrollbar, true);
|
||||
setSmoothScrollbarEnabled(smoothScrollbar);
|
||||
|
||||
int gestures = a.getInt(R.styleable.AbsListView_gestures, GESTURES_NONE);
|
||||
setGestures(gestures);
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@@ -600,160 +553,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
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();
|
||||
mGesturesOverlay.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);
|
||||
mGesturesOverlay.addOnGesturePerformedListener(new GesturesProcessor());
|
||||
}
|
||||
}
|
||||
|
||||
private void uninstallGesturesOverlay() {
|
||||
dismissGesturesPopup();
|
||||
mGesturesPopup = null;
|
||||
if (mGesturesLayoutListener != null) {
|
||||
getViewTreeObserver().removeGlobalOnLayoutListener(mGesturesLayoutListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (mGestures != GESTURES_NONE) {
|
||||
if ((ev.getAction() != MotionEvent.ACTION_DOWN || mFastScroller == null ||
|
||||
!mFastScroller.isPointInside(ev.getX(), ev.getY())) &&
|
||||
mGesturesPopup.isShowing()) {
|
||||
mGesturesOverlay.dispatchTouchEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@@ -1037,7 +836,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
* about having leaked the window.
|
||||
*/
|
||||
dismissPopup();
|
||||
dismissGesturesPopup();
|
||||
|
||||
Parcelable superState = super.onSaveInstanceState();
|
||||
|
||||
@@ -1325,11 +1123,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
if (mFiltered && visible && mPopup != null && mPopup.isShowing()) {
|
||||
positionPopup();
|
||||
}
|
||||
|
||||
if (mGestures != GESTURES_NONE && visible && mGesturesPopup != null &&
|
||||
mGesturesPopup.isShowing()) {
|
||||
positionGesturesPopup();
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
@@ -1544,13 +1337,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
if (mFastScroller != null) {
|
||||
mFastScroller.onSizeChanged(w, h, oldw, oldh);
|
||||
}
|
||||
|
||||
if (mInstallGesturesOverlay) {
|
||||
installGesturesOverlay();
|
||||
positionGesturesPopup();
|
||||
} else if (mGesturesPopup != null && mGesturesPopup.isShowing()) {
|
||||
mGesturesPopup.update(w, h);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1737,10 +1523,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
if (mTextFilterEnabled && mPopup != null && !mGlobalLayoutListenerAddedFilter) {
|
||||
treeObserver.addOnGlobalLayoutListener(this);
|
||||
}
|
||||
if (mGestures != GESTURES_NONE && mGesturesPopup != null &&
|
||||
!mGlobalLayoutListenerAddedGestures) {
|
||||
treeObserver.addOnGlobalLayoutListener(mGesturesLayoutListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1755,10 +1537,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
treeObserver.removeGlobalOnLayoutListener(this);
|
||||
mGlobalLayoutListenerAddedFilter = false;
|
||||
}
|
||||
if (mGesturesLayoutListener != null && mGesturesPopup != null) {
|
||||
mGlobalLayoutListenerAddedGestures = false;
|
||||
treeObserver.removeGlobalOnLayoutListener(mGesturesLayoutListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1773,7 +1551,6 @@ 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
|
||||
@@ -1784,9 +1561,6 @@ 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) {
|
||||
@@ -1907,8 +1681,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
final int longPressPosition, final long longPressId) {
|
||||
boolean handled = false;
|
||||
|
||||
dismissGesturesPopup();
|
||||
|
||||
if (mOnItemLongClickListener != null) {
|
||||
handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, child,
|
||||
longPressPosition, longPressId);
|
||||
@@ -3829,79 +3601,4 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class GesturesProcessor implements GestureOverlayView.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 = LetterRecognizers.fromType(getContext(),
|
||||
LetterRecognizers.RECOGNIZER_LATIN_LOWERCASE);
|
||||
if (mRecognizer == null) {
|
||||
setGestures(GESTURES_NONE);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -1381,16 +1381,6 @@
|
||||
will use only the number of items in the adapter and the number of items visible
|
||||
on screen to determine the scrollbar's properties. -->
|
||||
<attr name="smoothScrollbar" format="boolean" />
|
||||
<!-- Defines the type of gesture to enable for the widget. -->
|
||||
<attr name="gestures">
|
||||
<!-- No gesture -->
|
||||
<enum name="none" value="0" />
|
||||
<!-- Gestures jump to a specific position in the content. This requires
|
||||
fast scroll to be enabled. -->
|
||||
<enum name="jump" value="1" />
|
||||
<!-- Gestures filter the content. This requires text filtering to be enabled. -->
|
||||
<enum name="filter" value="2" />
|
||||
</attr>
|
||||
</declare-styleable>
|
||||
<declare-styleable name="AbsSpinner">
|
||||
<!-- Reference to an array resource that will populate the Spinner. For static content,
|
||||
|
||||
@@ -1106,7 +1106,6 @@
|
||||
<public type="attr" name="uncertainGestureColor" />
|
||||
<public type="attr" name="fadeOffset" />
|
||||
<public type="attr" name="fadeDuration" />
|
||||
<public type="attr" name="gestures" />
|
||||
<public type="attr" name="gestureStrokeType" />
|
||||
<public type="attr" name="gestureStrokeLengthThreshold" />
|
||||
<public type="attr" name="gestureStrokeSquarenessThreshold" />
|
||||
|
||||
Reference in New Issue
Block a user