aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/res/values/strings.xml4
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java76
-rw-r--r--java/src/com/android/inputmethod/research/LogStatement.java9
-rw-r--r--java/src/com/android/inputmethod/research/LogUnit.java9
-rw-r--r--java/src/com/android/inputmethod/research/MotionEventReader.java2
-rw-r--r--java/src/com/android/inputmethod/research/Replayer.java33
-rw-r--r--java/src/com/android/inputmethod/research/ReplayerService.java65
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java11
8 files changed, 138 insertions, 71 deletions
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 8822e8d18..bab612b28 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -313,6 +313,10 @@
<!-- TODO: remove translatable=false attribute once text is stable -->
<string name="research_log_uploader_name" translatable="false">Research Uploader Service</string>
+ <!-- Name for the research replaying service to be displayed to users. [CHAR LIMIT=50] -->
+ <!-- TODO: remove translatable=false attribute once text is stable -->
+ <string name="research_log_replayer_name" translatable="false">Research Replayer Service</string>
+
<!-- Preference for input language selection -->
<string name="select_language">Input languages</string>
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java
index 28655a930..ab810a580 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java
@@ -28,7 +28,6 @@ import android.view.View;
import com.android.inputmethod.keyboard.PointerTracker;
import com.android.inputmethod.latin.CoordinateUtils;
import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.ResizableIntArray;
import com.android.inputmethod.latin.SuggestedWords;
/**
@@ -44,16 +43,17 @@ import com.android.inputmethod.latin.SuggestedWords;
* @attr ref R.styleable#KeyboardView_gestureFloatingPreviewRoundRadius
*/
public class GestureFloatingPreviewText extends AbstractDrawingPreview {
- private static final class GesturePreviewTextParams {
- public final int mGesturePreviewTextSize;
- public final int mGesturePreviewTextColor;
+ protected static final class GesturePreviewTextParams {
public final int mGesturePreviewTextOffset;
public final int mGesturePreviewTextHeight;
- public final int mGesturePreviewColor;
public final float mGesturePreviewHorizontalPadding;
public final float mGesturePreviewVerticalPadding;
public final float mGesturePreviewRoundRadius;
- public final Paint mTextPaint;
+
+ private final int mGesturePreviewTextSize;
+ private final int mGesturePreviewTextColor;
+ private final int mGesturePreviewColor;
+ private final Paint mPaint = new Paint();
private static final char[] TEXT_HEIGHT_REFERENCE_CHAR = { 'M' };
@@ -73,37 +73,36 @@ public class GestureFloatingPreviewText extends AbstractDrawingPreview {
mGesturePreviewRoundRadius = mainKeyboardViewAttr.getDimension(
R.styleable.MainKeyboardView_gestureFloatingPreviewRoundRadius, 0.0f);
- final Paint textPaint = new Paint();
- textPaint.setAntiAlias(true);
- textPaint.setTextAlign(Align.CENTER);
- textPaint.setTextSize(mGesturePreviewTextSize);
- mTextPaint = textPaint;
+ final Paint textPaint = getTextPaint();
final Rect textRect = new Rect();
textPaint.getTextBounds(TEXT_HEIGHT_REFERENCE_CHAR, 0, 1, textRect);
mGesturePreviewTextHeight = textRect.height();
}
- }
- protected final GesturePreviewTextParams mParams;
- protected int mPreviewWordNum;
- protected final RectF mGesturePreviewRectangle = new RectF();
- protected int mHighlightedWordIndex;
+ public Paint getTextPaint() {
+ mPaint.setAntiAlias(true);
+ mPaint.setTextAlign(Align.CENTER);
+ mPaint.setTextSize(mGesturePreviewTextSize);
+ mPaint.setColor(mGesturePreviewTextColor);
+ return mPaint;
+ }
- private static final int PREVIEW_TEXT_ARRAY_CAPACITY = 10;
- // These variables store the positions of preview words. In multi-preview mode, the gesture
- // floating preview at most shows PREVIEW_TEXT_ARRAY_CAPACITY words.
- protected final ResizableIntArray mPreviewTextXArray = new ResizableIntArray(
- PREVIEW_TEXT_ARRAY_CAPACITY);
- protected final ResizableIntArray mPreviewTextYArray = new ResizableIntArray(
- PREVIEW_TEXT_ARRAY_CAPACITY);
+ public Paint getBackgroundPaint() {
+ mPaint.setColor(mGesturePreviewColor);
+ return mPaint;
+ }
+ }
- protected SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
- public final int[] mLastPointerCoords = CoordinateUtils.newInstance();
+ private final GesturePreviewTextParams mParams;
+ private final RectF mGesturePreviewRectangle = new RectF();
+ private int mPreviewTextX;
+ private int mPreviewTextY;
+ private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
+ private final int[] mLastPointerCoords = CoordinateUtils.newInstance();
public GestureFloatingPreviewText(final View drawingView, final TypedArray typedArray) {
super(drawingView);
mParams = new GesturePreviewTextParams(typedArray);
- mHighlightedWordIndex = 0;
}
public void setSuggetedWords(final SuggestedWords suggestedWords) {
@@ -114,13 +113,6 @@ public class GestureFloatingPreviewText extends AbstractDrawingPreview {
updatePreviewPosition();
}
- protected void drawText(final Canvas canvas, final String text, final float textX,
- final float textY, final int color) {
- final Paint paint = mParams.mTextPaint;
- paint.setColor(color);
- canvas.drawText(text, textX, textY, paint);
- }
-
@Override
public void setPreviewPosition(final PointerTracker tracker) {
final boolean needsToUpdateLastPointer =
@@ -142,14 +134,11 @@ public class GestureFloatingPreviewText extends AbstractDrawingPreview {
|| TextUtils.isEmpty(mSuggestedWords.getWord(0))) {
return;
}
- final Paint paint = mParams.mTextPaint;
- paint.setColor(mParams.mGesturePreviewColor);
final float round = mParams.mGesturePreviewRoundRadius;
- canvas.drawRoundRect(mGesturePreviewRectangle, round, round, paint);
+ canvas.drawRoundRect(
+ mGesturePreviewRectangle, round, round, mParams.getBackgroundPaint());
final String text = mSuggestedWords.getWord(0);
- final int textX = mPreviewTextXArray.get(0);
- final int textY = mPreviewTextYArray.get(0);
- drawText(canvas, text, textX, textY, mParams.mGesturePreviewTextColor);
+ canvas.drawText(text, mPreviewTextX, mPreviewTextY, mParams.getTextPaint());
}
/**
@@ -162,11 +151,10 @@ public class GestureFloatingPreviewText extends AbstractDrawingPreview {
}
final String text = mSuggestedWords.getWord(0);
- final Paint paint = mParams.mTextPaint;
final RectF rectangle = mGesturePreviewRectangle;
final int textHeight = mParams.mGesturePreviewTextHeight;
- final float textWidth = paint.measureText(text);
+ final float textWidth = mParams.getTextPaint().measureText(text);
final float hPad = mParams.mGesturePreviewHorizontalPadding;
final float vPad = mParams.mGesturePreviewVerticalPadding;
final float rectWidth = textWidth + hPad * 2.0f;
@@ -180,10 +168,8 @@ public class GestureFloatingPreviewText extends AbstractDrawingPreview {
- mParams.mGesturePreviewTextOffset - rectHeight;
rectangle.set(rectX, rectY, rectX + rectWidth, rectY + rectHeight);
- final int textX = (int)(rectX + hPad + textWidth / 2.0f);
- final int textY = (int)(rectY + vPad) + textHeight;
- mPreviewTextXArray.add(0, textX);
- mPreviewTextYArray.add(0, textY);
+ mPreviewTextX = (int)(rectX + hPad + textWidth / 2.0f);
+ mPreviewTextY = (int)(rectY + vPad) + textHeight;
// TODO: Should narrow the invalidate region.
getDrawingView().invalidate();
}
diff --git a/java/src/com/android/inputmethod/research/LogStatement.java b/java/src/com/android/inputmethod/research/LogStatement.java
index 090c58e27..1d83e1a86 100644
--- a/java/src/com/android/inputmethod/research/LogStatement.java
+++ b/java/src/com/android/inputmethod/research/LogStatement.java
@@ -29,13 +29,12 @@ class LogStatement {
"PointerTrackerCallListenerOnCodeInput";
public static final String KEY_CODE = "code";
public static final String VALUE_RESEARCH = "research";
- public static final String TYPE_LATIN_KEYBOARD_VIEW_ON_LONG_PRESS =
- "LatinKeyboardViewOnLongPress";
+ public static final String TYPE_MAIN_KEYBOARD_VIEW_ON_LONG_PRESS =
+ "MainKeyboardViewOnLongPress";
public static final String ACTION = "action";
public static final String VALUE_DOWN = "DOWN";
- public static final String TYPE_LATIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENTS =
- "LatinKeyboardViewProcessMotionEvents";
- public static final String KEY_LOGGING_RELATED = "loggingRelated";
+ public static final String TYPE_MOTION_EVENT = "MotionEvent";
+ public static final String KEY_IS_LOGGING_RELATED = "isLoggingRelated";
// Name specifying the LogStatement type.
private final String mType;
diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java
index 608fab3f1..2e732fc6c 100644
--- a/java/src/com/android/inputmethod/research/LogUnit.java
+++ b/java/src/com/android/inputmethod/research/LogUnit.java
@@ -453,13 +453,12 @@ import java.util.List;
// Look for the long press that started the invocation of the research key code input.
final int indexOfLastLongPressBeforeResearchKey =
- findLastIndexBefore(LogStatement.TYPE_LATIN_KEYBOARD_VIEW_ON_LONG_PRESS,
+ findLastIndexBefore(LogStatement.TYPE_MAIN_KEYBOARD_VIEW_ON_LONG_PRESS,
indexOfLastResearchKey);
// Look for DOWN event preceding the long press
final int indexOfLastDownEventBeforeLongPress =
- findLastIndexContainingKeyValueBefore(
- LogStatement.TYPE_LATIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENTS,
+ findLastIndexContainingKeyValueBefore(LogStatement.TYPE_MOTION_EVENT,
LogStatement.ACTION, LogStatement.VALUE_DOWN,
indexOfLastLongPressBeforeResearchKey);
@@ -471,8 +470,8 @@ import java.util.List;
final LogStatement logStatement = mLogStatementList.get(index);
final String type = logStatement.getType();
final Object[] values = mValuesList.get(index);
- if (type.equals(LogStatement.TYPE_LATIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENTS)) {
- logStatement.setValue(LogStatement.KEY_LOGGING_RELATED, values, true);
+ if (type.equals(LogStatement.TYPE_MOTION_EVENT)) {
+ logStatement.setValue(LogStatement.KEY_IS_LOGGING_RELATED, values, true);
}
}
return true;
diff --git a/java/src/com/android/inputmethod/research/MotionEventReader.java b/java/src/com/android/inputmethod/research/MotionEventReader.java
index 36e75be1c..26a1d7f55 100644
--- a/java/src/com/android/inputmethod/research/MotionEventReader.java
+++ b/java/src/com/android/inputmethod/research/MotionEventReader.java
@@ -101,7 +101,7 @@ public class MotionEventReader {
jsonReader.endObject();
if (logStatementType != null && time != null && x != null && y != null && actionType != null
- && logStatementType.equals("MainKeyboardViewProcessMotionEvent")
+ && logStatementType.equals("MotionEvent")
&& !loggingRelated) {
replayData.mActions.add(actionType);
replayData.mXCoords.add(x);
diff --git a/java/src/com/android/inputmethod/research/Replayer.java b/java/src/com/android/inputmethod/research/Replayer.java
index 4cc2a5814..611abb288 100644
--- a/java/src/com/android/inputmethod/research/Replayer.java
+++ b/java/src/com/android/inputmethod/research/Replayer.java
@@ -1,22 +1,23 @@
/*
* Copyright (C) 2012 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
+ * 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
+ * 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.
+ * 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.inputmethod.research;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
@@ -40,6 +41,14 @@ public class Replayer {
private boolean mIsReplaying = false;
private KeyboardSwitcher mKeyboardSwitcher;
+ private Replayer() {
+ }
+
+ private static final Replayer sInstance = new Replayer();
+ public static Replayer getInstance() {
+ return sInstance;
+ }
+
public void setKeyboardSwitcher(final KeyboardSwitcher keyboardSwitcher) {
mKeyboardSwitcher = keyboardSwitcher;
}
@@ -49,7 +58,7 @@ public class Replayer {
private static final int COMPLETION_TIME_MS = 500;
// TODO: Support historical events and multi-touch.
- public void replay(final ReplayData replayData) {
+ public void replay(final ReplayData replayData, final Runnable callback) {
if (mIsReplaying) {
return;
}
@@ -72,7 +81,7 @@ public class Replayer {
// The adjustment needed to translate times from the original recorded time to the current
// time.
final long timeAdjustment = currentStartTime - origStartTime;
- final Handler handler = new Handler() {
+ final Handler handler = new Handler(Looper.getMainLooper()) {
// Track the time of the most recent DOWN event, to be passed as a parameter when
// constructing a MotionEvent. It's initialized here to the origStartTime, but this is
// only a precaution. The value should be overwritten by the first ACTION_DOWN event
@@ -113,8 +122,12 @@ public class Replayer {
Log.d(TAG, "queuing event at " + msgTime);
}
}
+
final long presentDoneTime = replayData.mTimes.get(numActions - 1) + timeAdjustment
+ COMPLETION_TIME_MS;
handler.sendMessageAtTime(Message.obtain(handler, MSG_DONE), presentDoneTime);
+ if (callback != null) {
+ handler.postAtTime(callback, presentDoneTime + 1);
+ }
}
}
diff --git a/java/src/com/android/inputmethod/research/ReplayerService.java b/java/src/com/android/inputmethod/research/ReplayerService.java
new file mode 100644
index 000000000..88d9033cf
--- /dev/null
+++ b/java/src/com/android/inputmethod/research/ReplayerService.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 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.inputmethod.research;
+
+import android.app.IntentService;
+import android.content.Intent;
+import android.util.Log;
+
+import com.android.inputmethod.research.MotionEventReader.ReplayData;
+
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Provide a mechanism to invoke the replayer from outside.
+ *
+ * In particular, makes access from a host possible through {@code adb am startservice}.
+ */
+public class ReplayerService extends IntentService {
+ private static final String TAG = ReplayerService.class.getSimpleName();
+ private static final String EXTRA_FILENAME = "com.android.inputmethod.research.extra.FILENAME";
+ private static final long MAX_REPLAY_TIME = TimeUnit.SECONDS.toMillis(60);
+
+ public ReplayerService() {
+ super(ReplayerService.class.getSimpleName());
+ }
+
+ @Override
+ protected void onHandleIntent(final Intent intent) {
+ final String filename = intent.getStringExtra(EXTRA_FILENAME);
+ if (filename == null) return;
+
+ final ReplayData replayData = new MotionEventReader().readMotionEventData(
+ new File(filename));
+ synchronized (this) {
+ Replayer.getInstance().replay(replayData, new Runnable() {
+ @Override
+ public void run() {
+ synchronized (ReplayerService.this) {
+ ReplayerService.this.notify();
+ }
+ }
+ });
+ try {
+ wait(MAX_REPLAY_TIME);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Timeout while replaying.", e);
+ }
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index 096f03202..da410010f 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -184,10 +184,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private Suggest mSuggest;
private MainKeyboardView mMainKeyboardView;
// TODO: Check whether a superclass can be used instead of LatinIME.
- private LatinIME mLatinIME;
+ /* package for test */ LatinIME mLatinIME;
private final Statistics mStatistics;
private final MotionEventReader mMotionEventReader = new MotionEventReader();
- private final Replayer mReplayer = new Replayer();
+ private final Replayer mReplayer = Replayer.getInstance();
private Intent mUploadIntent;
private Intent mUploadNowIntent;
@@ -783,7 +783,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public void run() {
final ReplayData replayData =
mMotionEventReader.readMotionEventData(mUserRecordingFile);
- mReplayer.replay(replayData);
+ mReplayer.replay(replayData, null);
}
}, 1000);
}
@@ -1162,7 +1162,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
*
*/
private static final LogStatement LOGSTATEMENT_MAIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENT =
- new LogStatement("MotionEvent", true, false, "action", "MotionEvent", "loggingRelated");
+ new LogStatement("MotionEvent", true, false, "action",
+ LogStatement.KEY_IS_LOGGING_RELATED, "motionEvent");
public static void mainKeyboardView_processMotionEvent(final MotionEvent me, final int action,
final long eventTime, final int index, final int id, final int x, final int y) {
if (me != null) {
@@ -1179,7 +1180,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
final ResearchLogger researchLogger = getInstance();
researchLogger.enqueueEvent(LOGSTATEMENT_MAIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENT,
- actionString, MotionEvent.obtain(me), false);
+ actionString, false /* IS_LOGGING_RELATED */, MotionEvent.obtain(me));
if (action == MotionEvent.ACTION_DOWN) {
// Subtract 1 from eventTime so the down event is included in the later
// LogUnit, not the earlier (the test is for inequality).