1a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout/* 2a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * Copyright (C) 2014 The Android Open Source Project 3a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * 4a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * in compliance with the License. You may obtain a copy of the License at 6a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * 7a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * http://www.apache.org/licenses/LICENSE-2.0 8a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * 9a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * Unless required by applicable law or agreed to in writing, software distributed under the License 10a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * or implied. See the License for the specific language governing permissions and limitations under 12a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * the License. 13a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout */ 14a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutpackage android.support.v17.leanback.widget; 15a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 16a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.support.v17.leanback.R; 17a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.animation.ObjectAnimator; 18a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.content.Context; 19a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.graphics.Bitmap; 20a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.graphics.BitmapFactory; 21a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.graphics.Canvas; 22a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.graphics.Paint; 23a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.text.SpannableStringBuilder; 24a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.text.Spanned; 25a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.text.SpannedString; 26a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.text.style.ForegroundColorSpan; 27a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.text.style.ReplacementSpan; 28a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.util.AttributeSet; 29a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.util.Log; 30a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.util.Property; 31a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.view.View; 32a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.view.accessibility.AccessibilityNodeInfo; 33a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.widget.EditText; 34a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport android.widget.TextView; 35a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 36a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport java.util.List; 37a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport java.util.Random; 38a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport java.util.regex.Matcher; 39a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutimport java.util.regex.Pattern; 40a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 41a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout/** 42a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * Shows the recognized text as a continuous stream of words. 43a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout */ 44a088f574b916685bd0a75ff613ac2009a3bad483Craig Stoutclass StreamingTextView extends EditText { 45a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 46a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private static final boolean DEBUG = false; 47a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private static final String TAG = "StreamingTextView"; 48a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 49a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private static final float TEXT_DOT_SCALE = 1.3F; 50a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private static final boolean DOTS_FOR_STABLE = false; 51a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private static final boolean DOTS_FOR_PENDING = true; 52a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private static final boolean ANIMATE_DOTS_FOR_PENDING = true; 53a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 54a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private static final long STREAM_UPDATE_DELAY_MILLIS = 50; 55a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 56a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private static final Pattern SPLIT_PATTERN = Pattern.compile("\\S+"); 57a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 58a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private static final Property<StreamingTextView,Integer> STREAM_POSITION_PROPERTY = 59a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout new Property<StreamingTextView,Integer>(Integer.class, "streamPosition") { 60a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 61a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout @Override 62a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout public Integer get(StreamingTextView view) { 63a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout return view.getStreamPosition(); 64a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 65a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 66a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout @Override 67a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout public void set(StreamingTextView view, Integer value) { 68a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout view.setStreamPosition(value); 69a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 70a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout }; 71a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 72a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private final Random mRandom = new Random(); 73a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 74a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private Bitmap mOneDot; 75a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private Bitmap mTwoDot; 76a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 77a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private int mStreamPosition; 78a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private ObjectAnimator mStreamingAnimation; 79a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 80a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout public StreamingTextView(Context context, AttributeSet attrs) { 81a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout super(context, attrs); 82a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 83a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 84a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout public StreamingTextView(Context context, AttributeSet attrs, int defStyle) { 85a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout super(context, attrs, defStyle); 86a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 87a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 88a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout @Override 89a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout protected void onFinishInflate() { 90a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout super.onFinishInflate(); 91a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 92a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mOneDot = getScaledBitmap(R.drawable.lb_text_dot_one, TEXT_DOT_SCALE); 93a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mTwoDot = getScaledBitmap(R.drawable.lb_text_dot_two, TEXT_DOT_SCALE); 94a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 95a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout reset(); 96a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 97a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 98a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private Bitmap getScaledBitmap(int resourceId, float scaled) { 99a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resourceId); 100a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout return Bitmap.createScaledBitmap(bitmap, (int) (bitmap.getWidth() * scaled), 101a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout (int) (bitmap.getHeight() * scaled), false); 102a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 103a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 104a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout public void reset() { 105a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (DEBUG) Log.d(TAG, "#reset"); 106a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 107a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mStreamPosition = -1; 108a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout cancelStreamAnimation(); 109a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout setText(""); 110a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 111a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 112a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout public void updateRecognizedText(String stableText, String pendingText) { 113a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (DEBUG) Log.d(TAG, "updateText(" + stableText + "," + pendingText + ")"); 114a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 115a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (stableText == null) { 116a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout stableText = ""; 117a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 118a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 119a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout SpannableStringBuilder displayText = new SpannableStringBuilder(stableText); 120a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 121a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (DOTS_FOR_STABLE) { 122a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout addDottySpans(displayText, stableText, 0); 123a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 124a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 125a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (pendingText != null) { 126a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int pendingTextStart = displayText.length(); 127a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout displayText.append(pendingText); 128a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (DOTS_FOR_PENDING) { 129a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout addDottySpans(displayText, pendingText, pendingTextStart); 130a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } else { 131a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int pendingColor = getResources().getColor( 132a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout R.color.lb_search_plate_hint_text_color); 133a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout addColorSpan(displayText, pendingColor, pendingText, pendingTextStart); 134a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 135a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 136a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 137a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout // Start streaming in dots from beginning of partials, or current position, 138a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout // whichever is larger 139a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mStreamPosition = Math.max(stableText.length(), mStreamPosition); 140a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 141a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout // Copy the text and spans to a SpannedString, since editable text 142a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout // doesn't redraw in invalidate() when hardware accelerated 143a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout // if the text or spans havent't changed. (probably a framework bug) 144a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout updateText(new SpannedString(displayText)); 145a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 146a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (ANIMATE_DOTS_FOR_PENDING) { 147a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout startStreamAnimation(); 148a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 149a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 150a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 151a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private int getStreamPosition() { 152a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout return mStreamPosition; 153a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 154a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 155a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private void setStreamPosition(int streamPosition) { 156a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mStreamPosition = streamPosition; 157a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout invalidate(); 158a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 159a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 160a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private void startStreamAnimation() { 161a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout cancelStreamAnimation(); 162a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int pos = getStreamPosition(); 163a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int totalLen = length(); 164a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int animLen = totalLen - pos; 165a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (animLen > 0) { 166a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (mStreamingAnimation == null) { 167a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mStreamingAnimation = new ObjectAnimator(); 168a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mStreamingAnimation.setTarget(this); 169a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mStreamingAnimation.setProperty(STREAM_POSITION_PROPERTY); 170a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 171a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mStreamingAnimation.setIntValues(pos, totalLen); 172a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mStreamingAnimation.setDuration(STREAM_UPDATE_DELAY_MILLIS * animLen); 173a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mStreamingAnimation.start(); 174a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 175a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 176a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 177a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private void cancelStreamAnimation() { 178a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (mStreamingAnimation != null) { 179a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mStreamingAnimation.cancel(); 180a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 181a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 182a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 183a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private void addDottySpans(SpannableStringBuilder displayText, String text, int textStart) { 184a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout Matcher m = SPLIT_PATTERN.matcher(text); 185a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout while (m.find()) { 186a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int wordStart = textStart + m.start(); 187a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int wordEnd = textStart + m.end(); 188a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout DottySpan span = new DottySpan(text.charAt(m.start()), wordStart); 189a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout displayText.setSpan(span, wordStart, wordEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 190a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 191a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 192a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 193a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private void addColorSpan(SpannableStringBuilder displayText, int color, String text, 194a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int textStart) { 195a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout ForegroundColorSpan span = new ForegroundColorSpan(color); 196a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int start = textStart; 197a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int end = textStart + text.length(); 198a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout displayText.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 199a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 200a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 201a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout /** 202a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * Sets the final, non changing, full text result. This should only happen at the very end of 203a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * a recognition. 204a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * 205a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * @param finalText to the view to. 206a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout */ 207a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout public void setFinalRecognizedText(CharSequence finalText) { 208a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (DEBUG) Log.d(TAG, "setFinalRecognizedText(" + finalText + ")"); 209a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 210a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout updateText(finalText); 211a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 212a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 213a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private void updateText(CharSequence displayText) { 214a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout setText(displayText); 215a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout bringPointIntoView(length()); 216a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 217a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 218a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout /** 219a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout * This is required to make the View findable by uiautomator 220a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout */ 221a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout @Override 222a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 223a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout super.onInitializeAccessibilityNodeInfo(info); 224a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout info.setClassName(StreamingTextView.class.getCanonicalName()); 225a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 226a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 227a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private class DottySpan extends ReplacementSpan { 228a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 229a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private final int mSeed; 230a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout private final int mPosition; 231a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 232a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout public DottySpan(int seed, int pos) { 233a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mSeed = seed; 234a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mPosition = pos; 235a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 236a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 237a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout @Override 238a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout public void draw(Canvas canvas, CharSequence text, int start, int end, 239a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout float x, int top, int y, int bottom, Paint paint) { 240a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 241a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int width = (int) paint.measureText(text, start, end); 242a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 243a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int dotWidth = mOneDot.getWidth(); 244a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int sliceWidth = 2 * dotWidth; 245a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int sliceCount = width / sliceWidth; 246a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int excess = width % sliceWidth; 247a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int prop = excess / 2; 248a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout boolean rtl = isLayoutRtl(StreamingTextView.this); 249a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 250a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mRandom.setSeed(mSeed); 251a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout int oldAlpha = paint.getAlpha(); 252a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout for (int i = 0; i < sliceCount; i++) { 253a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (ANIMATE_DOTS_FOR_PENDING) { 254a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (mPosition + i >= mStreamPosition) break; 255a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 256a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 257a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout float left = i * sliceWidth + prop + dotWidth / 2; 258a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout float dotLeft = rtl ? x + width - left - dotWidth : x + left; 259a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 260a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout // give the dots some visual variety 261a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout paint.setAlpha((mRandom.nextInt(4) + 1) * 63); 262a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 263a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (mRandom.nextBoolean()) { 264a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout canvas.drawBitmap(mTwoDot, dotLeft, y - mTwoDot.getHeight(), paint); 265a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } else { 266a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout canvas.drawBitmap(mOneDot, dotLeft, y - mOneDot.getHeight(), paint); 267a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 268a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 269a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout paint.setAlpha(oldAlpha); 270a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 271a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 272a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout @Override 273a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout public int getSize(Paint paint, CharSequence text, int start, int end, 274a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout Paint.FontMetricsInt fontMetricsInt) { 275a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout return (int) paint.measureText(text, start, end); 276a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 277a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 278a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 279a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout public static boolean isLayoutRtl(View view) { 280a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { 281a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout return View.LAYOUT_DIRECTION_RTL == view.getLayoutDirection(); 282a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } else { 283a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout return false; 284a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 285a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 286a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 287a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout public void updateRecognizedText(String stableText, List<Float> rmsValues) {} 288a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout} 289