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.ViewDebug;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
import android.view.KeyCharacterMap;
|
|
||||||
import android.view.inputmethod.BaseInputConnection;
|
import android.view.inputmethod.BaseInputConnection;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.view.inputmethod.InputConnection;
|
import android.view.inputmethod.InputConnection;
|
||||||
import android.view.inputmethod.InputConnectionWrapper;
|
import android.view.inputmethod.InputConnectionWrapper;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.view.ContextMenu.ContextMenuInfo;
|
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;
|
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_cacheColorHint
|
||||||
* @attr ref android.R.styleable#AbsListView_fastScrollEnabled
|
* @attr ref android.R.styleable#AbsListView_fastScrollEnabled
|
||||||
* @attr ref android.R.styleable#AbsListView_smoothScrollbar
|
* @attr ref android.R.styleable#AbsListView_smoothScrollbar
|
||||||
* @attr ref android.R.styleable#AbsListView_gestures
|
|
||||||
*/
|
*/
|
||||||
public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
|
public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
|
||||||
ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
|
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;
|
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
|
* 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;
|
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 boolean mGlobalLayoutListenerAddedFilter;
|
||||||
|
|
||||||
private int mTouchSlop;
|
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);
|
boolean smoothScrollbar = a.getBoolean(R.styleable.AbsListView_smoothScrollbar, true);
|
||||||
setSmoothScrollbarEnabled(smoothScrollbar);
|
setSmoothScrollbarEnabled(smoothScrollbar);
|
||||||
|
|
||||||
int gestures = a.getInt(R.styleable.AbsListView_gestures, GESTURES_NONE);
|
|
||||||
setGestures(gestures);
|
|
||||||
|
|
||||||
a.recycle();
|
a.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,160 +553,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
|||||||
mDensityScale = getContext().getResources().getDisplayMetrics().density;
|
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
|
* 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
|
* 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.
|
* about having leaked the window.
|
||||||
*/
|
*/
|
||||||
dismissPopup();
|
dismissPopup();
|
||||||
dismissGesturesPopup();
|
|
||||||
|
|
||||||
Parcelable superState = super.onSaveInstanceState();
|
Parcelable superState = super.onSaveInstanceState();
|
||||||
|
|
||||||
@@ -1325,11 +1123,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
|||||||
if (mFiltered && visible && mPopup != null && mPopup.isShowing()) {
|
if (mFiltered && visible && mPopup != null && mPopup.isShowing()) {
|
||||||
positionPopup();
|
positionPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mGestures != GESTURES_NONE && visible && mGesturesPopup != null &&
|
|
||||||
mGesturesPopup.isShowing()) {
|
|
||||||
positionGesturesPopup();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
@@ -1544,13 +1337,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
|||||||
if (mFastScroller != null) {
|
if (mFastScroller != null) {
|
||||||
mFastScroller.onSizeChanged(w, h, oldw, oldh);
|
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) {
|
if (mTextFilterEnabled && mPopup != null && !mGlobalLayoutListenerAddedFilter) {
|
||||||
treeObserver.addOnGlobalLayoutListener(this);
|
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);
|
treeObserver.removeGlobalOnLayoutListener(this);
|
||||||
mGlobalLayoutListenerAddedFilter = false;
|
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);
|
removeCallbacks(mFlingRunnable);
|
||||||
// Always hide the type filter
|
// Always hide the type filter
|
||||||
dismissPopup();
|
dismissPopup();
|
||||||
dismissGesturesPopup();
|
|
||||||
|
|
||||||
if (touchMode == TOUCH_MODE_OFF) {
|
if (touchMode == TOUCH_MODE_OFF) {
|
||||||
// Remember the last selected element
|
// 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
|
// Show the type filter only if a filter is in effect
|
||||||
showPopup();
|
showPopup();
|
||||||
}
|
}
|
||||||
if (mGestures != GESTURES_NONE) {
|
|
||||||
showGesturesPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we changed touch mode since the last time we had focus
|
// If we changed touch mode since the last time we had focus
|
||||||
if (touchMode != mLastTouchMode && mLastTouchMode != TOUCH_MODE_UNKNOWN) {
|
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) {
|
final int longPressPosition, final long longPressId) {
|
||||||
boolean handled = false;
|
boolean handled = false;
|
||||||
|
|
||||||
dismissGesturesPopup();
|
|
||||||
|
|
||||||
if (mOnItemLongClickListener != null) {
|
if (mOnItemLongClickListener != null) {
|
||||||
handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, child,
|
handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, child,
|
||||||
longPressPosition, longPressId);
|
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
|
will use only the number of items in the adapter and the number of items visible
|
||||||
on screen to determine the scrollbar's properties. -->
|
on screen to determine the scrollbar's properties. -->
|
||||||
<attr name="smoothScrollbar" format="boolean" />
|
<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>
|
||||||
<declare-styleable name="AbsSpinner">
|
<declare-styleable name="AbsSpinner">
|
||||||
<!-- Reference to an array resource that will populate the Spinner. For static content,
|
<!-- 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="uncertainGestureColor" />
|
||||||
<public type="attr" name="fadeOffset" />
|
<public type="attr" name="fadeOffset" />
|
||||||
<public type="attr" name="fadeDuration" />
|
<public type="attr" name="fadeDuration" />
|
||||||
<public type="attr" name="gestures" />
|
|
||||||
<public type="attr" name="gestureStrokeType" />
|
<public type="attr" name="gestureStrokeType" />
|
||||||
<public type="attr" name="gestureStrokeLengthThreshold" />
|
<public type="attr" name="gestureStrokeLengthThreshold" />
|
||||||
<public type="attr" name="gestureStrokeSquarenessThreshold" />
|
<public type="attr" name="gestureStrokeSquarenessThreshold" />
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
LOCAL_PATH:= $(call my-dir)
|
|
||||||
include $(CLEAR_VARS)
|
|
||||||
|
|
||||||
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
|
||||||
|
|
||||||
LOCAL_PACKAGE_NAME := Sketch
|
|
||||||
|
|
||||||
include $(BUILD_PACKAGE)
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright (C) 2008-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.
|
|
||||||
-->
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="com.android.gesture.example">
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
||||||
|
|
||||||
<application android:icon="@drawable/icon" android:label="@string/app_name">
|
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name="com.android.gesture.example.GestureEntry"
|
|
||||||
android:label="@string/app_name">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
<activity android:name="com.android.gesture.example.GestureLibViewer"/>
|
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name="com.android.gesture.example.ContactListGestureOverlay"
|
|
||||||
android:label="@string/overlay_name">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
</application>
|
|
||||||
</manifest>
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.1 KiB |
@@ -1,35 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent">
|
|
||||||
|
|
||||||
<Spinner
|
|
||||||
android:id="@+id/spinner"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:drawSelectorOnTop="true"
|
|
||||||
android:prompt="@string/recognition_result"/>
|
|
||||||
|
|
||||||
<android.gesture.GestureOverlayView
|
|
||||||
android:id="@+id/drawingpad"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent">
|
|
||||||
|
|
||||||
<Spinner
|
|
||||||
android:id="@+id/spinner"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:drawSelectorOnTop="true"
|
|
||||||
android:prompt="@string/recognition_result"/>
|
|
||||||
|
|
||||||
<android.gesture.GestureOverlayView
|
|
||||||
android:id="@+id/drawingpad"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
<Button
|
|
||||||
android:id="@+id/previous"
|
|
||||||
android:text="@string/previous"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"/>
|
|
||||||
<Button
|
|
||||||
android:id="@+id/remove"
|
|
||||||
android:text="@string/remove"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"/>
|
|
||||||
<Button
|
|
||||||
android:id="@+id/next"
|
|
||||||
android:text="@string/next"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/gesturename_edit"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_marginLeft="20dip"
|
|
||||||
android:layout_marginRight="20dip"
|
|
||||||
android:scrollHorizontally="true"
|
|
||||||
android:autoText="false"
|
|
||||||
android:capitalize="none"
|
|
||||||
android:gravity="fill_horizontal"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<android.gesture.GestureOverlayView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/overlay"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent">
|
|
||||||
|
|
||||||
<ListView
|
|
||||||
android:id="@+id/list"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent" />
|
|
||||||
|
|
||||||
</android.gesture.GestureOverlayView>
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- 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.
|
|
||||||
-->
|
|
||||||
<resources>
|
|
||||||
<string name="app_name">Gesture Demo</string>
|
|
||||||
<string name="overlay_name">Overlay Demo</string>
|
|
||||||
<string name="recognition_result">Recognition Result</string>
|
|
||||||
<string name="clear">Clear</string>
|
|
||||||
<string name="newgesture">Add</string>
|
|
||||||
<string name="viewgesture">View</string>
|
|
||||||
<string name="newgesture_dialog_ok">OK</string>
|
|
||||||
<string name="newgesture_dialog_cancel">Cancel</string>
|
|
||||||
<string name="newgesture_text_entry">Gesture Name</string>
|
|
||||||
<string name="previous">Previous</string>
|
|
||||||
<string name="remove">Remove</string>
|
|
||||||
<string name="next">Next</string>
|
|
||||||
</resources>
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008-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 com.android.gesture.example;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
class ContactAdapter extends ArrayAdapter<ContactItem> {
|
|
||||||
|
|
||||||
private LayoutInflater mInflater;
|
|
||||||
|
|
||||||
public ContactAdapter(Activity activity, ArrayList<ContactItem> contacts) {
|
|
||||||
super(activity, 0, contacts);
|
|
||||||
mInflater = activity.getLayoutInflater();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ContactItem getItem(int position) {
|
|
||||||
return super.getItem(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getItemId(int position) {
|
|
||||||
return getItem(position).itemID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
|
||||||
final ContactItem info = getItem(position);
|
|
||||||
|
|
||||||
View view = convertView;
|
|
||||||
if (view == null) {
|
|
||||||
view = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false);
|
|
||||||
view.setTag(view.findViewById(android.R.id.text1));
|
|
||||||
}
|
|
||||||
|
|
||||||
final TextView textView = (TextView)view.getTag();
|
|
||||||
textView.setText(info.toString());
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int search(String query) {
|
|
||||||
if (query != null && query.length() > 0) {
|
|
||||||
int start = 0;
|
|
||||||
int end = getCount() - 1;
|
|
||||||
int index = binarySearch(query, start, end);
|
|
||||||
for (index = index - 1; index >= 0; index--) {
|
|
||||||
String str = getItem(index).toString().toLowerCase();
|
|
||||||
if (!str.startsWith(query)) {
|
|
||||||
return index + 1;
|
|
||||||
}
|
|
||||||
if (index == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int binarySearch(String prefix, int start, int end) {
|
|
||||||
if (start > end) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int mid = (start + end) / 2;
|
|
||||||
String str = getItem(mid).toString().toLowerCase();
|
|
||||||
if (prefix.compareTo(str) <= 0) {
|
|
||||||
if (str.startsWith(prefix)) {
|
|
||||||
return mid;
|
|
||||||
} else {
|
|
||||||
return binarySearch(prefix, start, mid - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return binarySearch(prefix, mid + 1, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008-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 com.android.gesture.example;
|
|
||||||
|
|
||||||
|
|
||||||
class ContactItem {
|
|
||||||
final String itemName;
|
|
||||||
|
|
||||||
final long itemID;
|
|
||||||
|
|
||||||
public ContactItem(long id, String name) {
|
|
||||||
itemID = id;
|
|
||||||
itemName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return itemName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008-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 com.android.gesture.example;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.ContentUris;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.provider.Contacts.People;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ListView;
|
|
||||||
|
|
||||||
import android.gesture.Gesture;
|
|
||||||
import android.gesture.GestureOverlayView;
|
|
||||||
import android.gesture.LetterRecognizer;
|
|
||||||
import android.gesture.Prediction;
|
|
||||||
import android.gesture.LetterRecognizers;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
public class ContactListGestureOverlay extends Activity {
|
|
||||||
private static final String LOG_TAG = "ContactListGestureOverlay";
|
|
||||||
private static final String SORT_ORDER = People.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
|
|
||||||
private static final String[] CONTACTS_PROJECTION = new String[] {
|
|
||||||
People._ID, // 0
|
|
||||||
People.DISPLAY_NAME, // 1
|
|
||||||
};
|
|
||||||
|
|
||||||
private ContactAdapter mContactAdapter;
|
|
||||||
|
|
||||||
private ListView mContactList;
|
|
||||||
private LetterRecognizer mRecognizer;
|
|
||||||
private GestureOverlayView mOverlay;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
|
||||||
setContentView(R.layout.overlaydemo);
|
|
||||||
|
|
||||||
// create a letter recognizer
|
|
||||||
mRecognizer = LetterRecognizers.fromType(this,
|
|
||||||
LetterRecognizers.RECOGNIZER_LATIN_LOWERCASE);
|
|
||||||
mOverlay = (GestureOverlayView) findViewById(R.id.overlay);
|
|
||||||
|
|
||||||
// load the contact list
|
|
||||||
mContactList = (ListView) findViewById(R.id.list);
|
|
||||||
registerForContextMenu(mContactList);
|
|
||||||
mContactList.setTextFilterEnabled(true);
|
|
||||||
mContactList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
|
||||||
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
|
|
||||||
if (!mOverlay.isGesturing()) {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW, ContentUris.withAppendedId(
|
|
||||||
People.CONTENT_URI, id));
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ContentResolver resolver = getContentResolver();
|
|
||||||
Cursor cursor = resolver.query(People.CONTENT_URI, CONTACTS_PROJECTION, null, null,
|
|
||||||
SORT_ORDER);
|
|
||||||
ArrayList<ContactItem> list = new ArrayList<ContactItem>();
|
|
||||||
while (cursor.moveToNext()) {
|
|
||||||
list.add(new ContactItem(cursor.getLong(0), cursor.getString(1)));
|
|
||||||
}
|
|
||||||
mContactAdapter = new ContactAdapter(this, list);
|
|
||||||
mContactList.setAdapter(mContactAdapter);
|
|
||||||
|
|
||||||
mOverlay.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);
|
|
||||||
mOverlay.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() {
|
|
||||||
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
|
|
||||||
ArrayList<Prediction> predictions = mRecognizer.recognize(gesture);
|
|
||||||
if (!predictions.isEmpty()) {
|
|
||||||
Log.v(LOG_TAG, "1st Prediction : " + predictions.get(0).name +
|
|
||||||
" @" + predictions.get(0).score);
|
|
||||||
Log.v(LOG_TAG, "2nd Prediction : " + predictions.get(1).name +
|
|
||||||
" @" + predictions.get(1).score);
|
|
||||||
Log.v(LOG_TAG, "3rd Prediction : " + predictions.get(2).name +
|
|
||||||
" @" + predictions.get(2).score);
|
|
||||||
int index = mContactAdapter.search(predictions.get(0).name);
|
|
||||||
if (index != -1) {
|
|
||||||
mContactList.setSelection(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008-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 com.android.gesture.example;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.Spinner;
|
|
||||||
import android.widget.AdapterView.OnItemSelectedListener;
|
|
||||||
import android.gesture.Gesture;
|
|
||||||
|
|
||||||
import android.gesture.GestureOverlayView;
|
|
||||||
import android.gesture.Prediction;
|
|
||||||
import android.gesture.GestureLibraries;
|
|
||||||
import android.gesture.GestureLibrary;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
public class GestureEntry extends Activity {
|
|
||||||
|
|
||||||
private static final String PARCEL_KEY = "gesture";
|
|
||||||
|
|
||||||
static final String GESTURE_FILE_NAME =
|
|
||||||
Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator +
|
|
||||||
"demo_library.gestures";
|
|
||||||
|
|
||||||
private static final int DIALOG_NEW_ENTRY = 1;
|
|
||||||
|
|
||||||
private static final int NEW_ID = Menu.FIRST;
|
|
||||||
|
|
||||||
private static final int VIEW_ID = Menu.FIRST + 1;
|
|
||||||
|
|
||||||
private GestureOverlayView mGesturePad;
|
|
||||||
|
|
||||||
private Spinner mRecognitionResult;
|
|
||||||
|
|
||||||
private GestureLibrary mGestureStore;
|
|
||||||
|
|
||||||
private boolean mChangedByRecognizer = false;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.demo);
|
|
||||||
|
|
||||||
// init the gesture library
|
|
||||||
mGestureStore = GestureLibraries.fromFile(GESTURE_FILE_NAME);
|
|
||||||
mGestureStore.load();
|
|
||||||
|
|
||||||
// create the spinner for showing the recognition results
|
|
||||||
// the spinner also allows a user to correct a prediction
|
|
||||||
mRecognitionResult = (Spinner) findViewById(R.id.spinner);
|
|
||||||
mRecognitionResult.setOnItemSelectedListener(new OnItemSelectedListener() {
|
|
||||||
|
|
||||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
|
||||||
// correct the recognition result by adding the new example
|
|
||||||
if (!mChangedByRecognizer) {
|
|
||||||
mGestureStore.addGesture(parent.getSelectedItem().toString(), mGesturePad
|
|
||||||
.getGesture());
|
|
||||||
} else {
|
|
||||||
mChangedByRecognizer = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onNothingSelected(AdapterView<?> parent) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// create the area for drawing a gesture
|
|
||||||
mGesturePad = (GestureOverlayView) findViewById(R.id.drawingpad);
|
|
||||||
mGesturePad.setBackgroundColor(Color.BLACK);
|
|
||||||
mGesturePad.addOnGestureListener(new GestureOverlayView.OnGestureListener() {
|
|
||||||
public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
|
|
||||||
recognize(overlay.getGesture());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onGesture(GestureOverlayView overlay, MotionEvent event) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
|
|
||||||
overlay.clear(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
|
||||||
Gesture gesture = (Gesture) savedInstanceState.getParcelable(PARCEL_KEY);
|
|
||||||
if (gesture != null) {
|
|
||||||
mGesturePad.setGesture(gesture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Dialog onCreateDialog(int id) {
|
|
||||||
LayoutInflater factory = LayoutInflater.from(this);
|
|
||||||
final View textEntryView = factory.inflate(R.layout.newgesture_dialog, null);
|
|
||||||
return new AlertDialog.Builder(GestureEntry.this).setTitle(
|
|
||||||
R.string.newgesture_text_entry).setView(textEntryView).setPositiveButton(
|
|
||||||
R.string.newgesture_dialog_ok, new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int whichButton) {
|
|
||||||
EditText edittext = (EditText) ((AlertDialog) dialog)
|
|
||||||
.findViewById(R.id.gesturename_edit);
|
|
||||||
String text = edittext.getText().toString().trim();
|
|
||||||
if (text.length() > 0) {
|
|
||||||
mGestureStore.addGesture(text, mGesturePad.getGesture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).setNegativeButton(R.string.newgesture_dialog_cancel,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int whichButton) {
|
|
||||||
}
|
|
||||||
}).create();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
super.onCreateOptionsMenu(menu);
|
|
||||||
menu.add(0, NEW_ID, 0, R.string.newgesture).setShortcut('0', 'n').setIcon(
|
|
||||||
android.R.drawable.ic_menu_add);
|
|
||||||
menu.add(0, VIEW_ID, 0, R.string.viewgesture).setShortcut('1', 'v').setIcon(
|
|
||||||
android.R.drawable.ic_menu_view);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
switch (item.getItemId()) {
|
|
||||||
case NEW_ID:
|
|
||||||
if (mGesturePad.getGesture() != null) {
|
|
||||||
showDialog(DIALOG_NEW_ENTRY);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VIEW_ID:
|
|
||||||
startActivityForResult(new Intent(this, GestureLibViewer.class), VIEW_ID);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
mGestureStore.load();
|
|
||||||
mGesturePad.clear(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
mGestureStore.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPrepareDialog(int id, Dialog dialog) {
|
|
||||||
super.onPrepareDialog(id, dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSaveInstanceState(Bundle outState) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
Gesture gesture = mGesturePad.getGesture();
|
|
||||||
if (gesture != null) {
|
|
||||||
outState.putParcelable(PARCEL_KEY, gesture);
|
|
||||||
}
|
|
||||||
mGestureStore.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void recognize(Gesture gesture) {
|
|
||||||
mChangedByRecognizer = true;
|
|
||||||
ArrayList<Prediction> predictions = mGestureStore.recognize(gesture);
|
|
||||||
ArrayAdapter<Prediction> adapter = new ArrayAdapter<Prediction>(this,
|
|
||||||
android.R.layout.simple_spinner_item, predictions);
|
|
||||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
||||||
mRecognitionResult.setAdapter(adapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008-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 com.android.gesture.example;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.Spinner;
|
|
||||||
import android.widget.AdapterView.OnItemSelectedListener;
|
|
||||||
import android.gesture.Gesture;
|
|
||||||
|
|
||||||
import android.gesture.GestureOverlayView;
|
|
||||||
import android.gesture.GestureLibraries;
|
|
||||||
import android.gesture.GestureLibrary;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GestureLibViewer gives an example on how to browse existing gestures and
|
|
||||||
* removing unwanted gestures.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class GestureLibViewer extends Activity {
|
|
||||||
|
|
||||||
private GestureOverlayView mGesturePad;
|
|
||||||
|
|
||||||
private Spinner mGestureCategory;
|
|
||||||
|
|
||||||
private GestureLibrary mGesureStore;
|
|
||||||
|
|
||||||
private ArrayList<Gesture> mGestures;
|
|
||||||
|
|
||||||
private int mCurrentGestureIndex;
|
|
||||||
|
|
||||||
private class RemoveGestureListener implements OnClickListener {
|
|
||||||
public void onClick(View v) {
|
|
||||||
if (mGestures.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = (String) mGestureCategory.getSelectedItem();
|
|
||||||
Gesture gesture = mGestures.get(mCurrentGestureIndex);
|
|
||||||
mGesureStore.removeGesture(name, gesture);
|
|
||||||
|
|
||||||
mGestures = mGesureStore.getGestures(name);
|
|
||||||
|
|
||||||
if (mGestures == null) {
|
|
||||||
// delete the entire entry
|
|
||||||
mCurrentGestureIndex = 0;
|
|
||||||
ArrayList<String> list = new ArrayList<String>();
|
|
||||||
list.addAll(mGesureStore.getGestureEntries());
|
|
||||||
Collections.sort(list);
|
|
||||||
ArrayAdapter<String> adapter = new ArrayAdapter<String>(GestureLibViewer.this,
|
|
||||||
android.R.layout.simple_spinner_item, list);
|
|
||||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
||||||
mGestureCategory.setAdapter(adapter);
|
|
||||||
} else {
|
|
||||||
if (mCurrentGestureIndex > mGestures.size() - 1) {
|
|
||||||
mCurrentGestureIndex--;
|
|
||||||
}
|
|
||||||
gesture = mGestures.get(mCurrentGestureIndex);
|
|
||||||
mGesturePad.setGesture(gesture);
|
|
||||||
mGesturePad.invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.gestureviewer);
|
|
||||||
|
|
||||||
// create the area for drawing a gesture
|
|
||||||
mGesturePad = (GestureOverlayView) findViewById(R.id.drawingpad);
|
|
||||||
mGesturePad.setEnabled(false);
|
|
||||||
|
|
||||||
// init the gesture library
|
|
||||||
mGesureStore = GestureLibraries.fromFile(GestureEntry.GESTURE_FILE_NAME);
|
|
||||||
mGesureStore.load();
|
|
||||||
|
|
||||||
mGestureCategory = (Spinner) findViewById(R.id.spinner);
|
|
||||||
ArrayList<String> list = new ArrayList<String>();
|
|
||||||
if (!mGesureStore.getGestureEntries().isEmpty()) {
|
|
||||||
list.addAll(mGesureStore.getGestureEntries());
|
|
||||||
Collections.sort(list);
|
|
||||||
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
|
|
||||||
android.R.layout.simple_spinner_item, list);
|
|
||||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
||||||
mGestureCategory.setAdapter(adapter);
|
|
||||||
mGestures = mGesureStore.getGestures(list.get(0));
|
|
||||||
mCurrentGestureIndex = 0;
|
|
||||||
Gesture gesture = mGestures.get(mCurrentGestureIndex);
|
|
||||||
mGesturePad.setGesture(gesture);
|
|
||||||
}
|
|
||||||
|
|
||||||
mGestureCategory.setOnItemSelectedListener(new OnItemSelectedListener() {
|
|
||||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
|
||||||
mGestures = mGesureStore.getGestures((String) mGestureCategory.getSelectedItem());
|
|
||||||
if (!mGestures.isEmpty()) {
|
|
||||||
mCurrentGestureIndex = 0;
|
|
||||||
Gesture gesture = mGestures.get(mCurrentGestureIndex);
|
|
||||||
mGesturePad.setGesture(gesture);
|
|
||||||
}
|
|
||||||
mGesturePad.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onNothingSelected(AdapterView<?> parent) {
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
Button remove = (Button) findViewById(R.id.remove);
|
|
||||||
remove.setOnClickListener(new RemoveGestureListener());
|
|
||||||
|
|
||||||
Button next = (Button) findViewById(R.id.next);
|
|
||||||
next.setOnClickListener(new OnClickListener() {
|
|
||||||
public void onClick(View v) {
|
|
||||||
if (mCurrentGestureIndex >= mGestures.size() - 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mCurrentGestureIndex++;
|
|
||||||
Gesture gesture = mGestures.get(mCurrentGestureIndex);
|
|
||||||
mGesturePad.setGesture(gesture);
|
|
||||||
mGesturePad.invalidate();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Button previous = (Button) findViewById(R.id.previous);
|
|
||||||
previous.setOnClickListener(new OnClickListener() {
|
|
||||||
public void onClick(View v) {
|
|
||||||
if (mCurrentGestureIndex >= 1 && !mGestures.isEmpty()) {
|
|
||||||
mCurrentGestureIndex--;
|
|
||||||
Gesture gesture = mGestures.get(mCurrentGestureIndex);
|
|
||||||
mGesturePad.setGesture(gesture);
|
|
||||||
mGesturePad.invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
|
||||||
mGesureStore.save();
|
|
||||||
setResult(RESULT_OK);
|
|
||||||
finish();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
mGesureStore.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSaveInstanceState(Bundle outState) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
mGesureStore.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,225 +0,0 @@
|
|||||||
import java.io.File;
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts text-based letter stores to binary-based stores.
|
|
||||||
*/
|
|
||||||
public class Converter {
|
|
||||||
private final File mFile;
|
|
||||||
private static final short VERSION_NUMBER = 1;
|
|
||||||
|
|
||||||
Converter(File file) {
|
|
||||||
mFile = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void convert() {
|
|
||||||
boolean read = false;
|
|
||||||
|
|
||||||
String[] classes = null;
|
|
||||||
int iCount = 0;
|
|
||||||
int hCount = 0;
|
|
||||||
int oCount = 0;
|
|
||||||
float[][] iWeights = null;
|
|
||||||
float[][] oWeights = null;
|
|
||||||
|
|
||||||
BufferedReader reader = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
reader = new BufferedReader(new FileReader(mFile));
|
|
||||||
|
|
||||||
long start = System.nanoTime();
|
|
||||||
|
|
||||||
String line = reader.readLine();
|
|
||||||
int startIndex = 0;
|
|
||||||
int endIndex;
|
|
||||||
endIndex = line.indexOf(" ", startIndex);
|
|
||||||
iCount = Integer.parseInt(line.substring(startIndex, endIndex));
|
|
||||||
|
|
||||||
startIndex = endIndex + 1;
|
|
||||||
endIndex = line.indexOf(" ", startIndex);
|
|
||||||
hCount = Integer.parseInt(line.substring(startIndex, endIndex));
|
|
||||||
|
|
||||||
startIndex = endIndex + 1;
|
|
||||||
endIndex = line.length();
|
|
||||||
oCount = Integer.parseInt(line.substring(startIndex, endIndex));
|
|
||||||
|
|
||||||
classes = new String[oCount];
|
|
||||||
line = reader.readLine();
|
|
||||||
startIndex = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < oCount; i++) {
|
|
||||||
endIndex = line.indexOf(" ", startIndex);
|
|
||||||
classes[i] = line.substring(startIndex, endIndex);
|
|
||||||
startIndex = endIndex + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
iWeights = new float[hCount][];
|
|
||||||
for (int i = 0; i < hCount; i++) {
|
|
||||||
iWeights[i] = new float[iCount + 1];
|
|
||||||
line = reader.readLine();
|
|
||||||
startIndex = 0;
|
|
||||||
for (int j = 0; j <= iCount; j++) {
|
|
||||||
endIndex = line.indexOf(" ", startIndex);
|
|
||||||
iWeights[i][j] = Float.parseFloat(line.substring(startIndex, endIndex));
|
|
||||||
startIndex = endIndex + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
oWeights = new float[oCount][];
|
|
||||||
for (int i = 0; i < oCount; i++) {
|
|
||||||
oWeights[i] = new float[hCount + 1];
|
|
||||||
line = reader.readLine();
|
|
||||||
startIndex = 0;
|
|
||||||
for (int j = 0; j <= hCount; j++) {
|
|
||||||
endIndex = line.indexOf(" ", startIndex);
|
|
||||||
oWeights[i][j] = Float.parseFloat(line.substring(startIndex, endIndex));
|
|
||||||
startIndex = endIndex + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
long end = System.nanoTime();
|
|
||||||
System.out.println("time to read text file = " +
|
|
||||||
((end - start) / 1000.0f / 1000.0f) + " ms");
|
|
||||||
|
|
||||||
read = true;
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
close(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read) {
|
|
||||||
boolean wrote = false;
|
|
||||||
DataOutputStream out = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
out = new DataOutputStream(new FileOutputStream(mFile));
|
|
||||||
|
|
||||||
out.writeShort(VERSION_NUMBER);
|
|
||||||
out.writeInt(iCount);
|
|
||||||
out.writeInt(hCount);
|
|
||||||
out.writeInt(oCount);
|
|
||||||
|
|
||||||
for (String aClass : classes) {
|
|
||||||
out.writeUTF(aClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (float[] weights : iWeights) {
|
|
||||||
for (float weight : weights) {
|
|
||||||
out.writeFloat(weight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (float[] weights : oWeights) {
|
|
||||||
for (float weight : weights) {
|
|
||||||
out.writeFloat(weight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out.flush();
|
|
||||||
|
|
||||||
wrote = true;
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
close(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wrote) {
|
|
||||||
DataInputStream in = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
in = new DataInputStream(new BufferedInputStream(new FileInputStream(mFile)));
|
|
||||||
|
|
||||||
long start = System.nanoTime();
|
|
||||||
|
|
||||||
in.readShort();
|
|
||||||
iCount = in.readInt();
|
|
||||||
hCount = in.readInt();
|
|
||||||
oCount = in.readInt();
|
|
||||||
|
|
||||||
classes = new String[oCount];
|
|
||||||
for (int i = 0; i < classes.length; i++) {
|
|
||||||
classes[i] = in.readUTF();
|
|
||||||
}
|
|
||||||
|
|
||||||
iWeights = new float[hCount][];
|
|
||||||
for (int i = 0; i < iWeights.length; i++) {
|
|
||||||
iWeights[i] = new float[iCount];
|
|
||||||
for (int j = 0; j < iCount; j++) {
|
|
||||||
iWeights[i][j] = in.readFloat();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
oWeights = new float[oCount][];
|
|
||||||
for (int i = 0; i < oWeights.length; i++) {
|
|
||||||
oWeights[i] = new float[hCount];
|
|
||||||
for (int j = 0; j < hCount; j++) {
|
|
||||||
oWeights[i][j] = in.readFloat();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
long end = System.nanoTime();
|
|
||||||
System.out.println("time to read binary file = " +
|
|
||||||
((end - start) / 1000.0f / 1000.0f) + " ms");
|
|
||||||
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
close(in);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void close(Closeable reader) {
|
|
||||||
if (reader != null) {
|
|
||||||
try {
|
|
||||||
reader.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
String fileName = args[0];
|
|
||||||
if (fileName != null) {
|
|
||||||
File file = new File(fileName);
|
|
||||||
if (!file.exists()) {
|
|
||||||
printHelp(fileName);
|
|
||||||
} else {
|
|
||||||
new Converter(file).convert();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
printHelp(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void printHelp(String name) {
|
|
||||||
if (name == null) {
|
|
||||||
System.out.println("You must specify the name of the file to convert:");
|
|
||||||
} else {
|
|
||||||
System.out.println("The specified file does not exist: " + name);
|
|
||||||
}
|
|
||||||
System.out.println("java Converter [filename]");
|
|
||||||
System.out.println("");
|
|
||||||
System.out.println("\t[filename]\tPath to the file to convert. The file is replaced by "
|
|
||||||
+ "the conversion result.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user