185c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet/* 285c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet * Copyright (C) 2014 The Android Open Source Project 385c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet * 485c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 585c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet * in compliance with the License. You may obtain a copy of the License at 685c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet * 785c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet * http://www.apache.org/licenses/LICENSE-2.0 885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet * 985c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet * Unless required by applicable law or agreed to in writing, software distributed under the License 1085c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 1185c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet * or implied. See the License for the specific language governing permissions and limitations under 1285c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet * the License. 1385c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet */ 1485c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichetpackage android.support.v17.leanback.widget; 1585c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 16ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Guimport android.Manifest; 1785c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichetimport android.content.Context; 1825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichetimport android.content.Intent; 1910960072d3c1f9c7f42f9ae77adbfb12f9aed138Jerome Poichetimport android.content.pm.PackageManager; 20a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichetimport android.content.res.Resources; 21a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichetimport android.graphics.Color; 22514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichetimport android.graphics.drawable.Drawable; 23a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichetimport android.media.AudioManager; 24a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichetimport android.media.SoundPool; 25ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Guimport android.os.Build; 2625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichetimport android.os.Bundle; 2785c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichetimport android.os.Handler; 2885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichetimport android.os.SystemClock; 2925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichetimport android.speech.RecognitionListener; 3025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichetimport android.speech.RecognizerIntent; 3125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichetimport android.speech.SpeechRecognizer; 3285c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichetimport android.text.Editable; 33514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichetimport android.text.TextUtils; 3485c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichetimport android.text.TextWatcher; 3585c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichetimport android.util.AttributeSet; 360075dfe4e812a633be39018e1d6a85e5c6e58de5Jerome Poichetimport android.util.Log; 37a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichetimport android.util.SparseIntArray; 3825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichetimport android.view.LayoutInflater; 39a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichetimport android.view.ViewGroup; 40e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichetimport android.view.inputmethod.CompletionInfo; 41c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichetimport android.view.inputmethod.EditorInfo; 42c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichetimport android.view.KeyEvent; 4385c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichetimport android.view.MotionEvent; 4485c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichetimport android.view.View; 45514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichetimport android.widget.ImageView; 4625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichetimport android.view.inputmethod.InputMethodManager; 4785c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichetimport android.widget.RelativeLayout; 48c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichetimport android.widget.TextView; 4985c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 50ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Guimport android.support.v17.leanback.R; 51ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu 5225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichetimport java.util.ArrayList; 53e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichetimport java.util.List; 5425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 5585c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet/** 56a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * A search widget containing a search orb and a text entry view. 5710960072d3c1f9c7f42f9ae77adbfb12f9aed138Jerome Poichet * 58ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * <p> 59ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * Note: When {@link SpeechRecognitionCallback} is not used, i.e. using {@link SpeechRecognizer}, 60ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * your application will need to declare android.permission.RECORD_AUDIO in manifest file. 61ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * If your application target >= 23 and the device is running >= 23, it needs implement 62ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * {@link SearchBarPermissionListener} where requests runtime permission. 63ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * </p> 6485c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet */ 6585c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichetpublic class SearchBar extends RelativeLayout { 6699ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas static final String TAG = SearchBar.class.getSimpleName(); 6799ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas static final boolean DEBUG = false; 6885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 6999ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas static final float FULL_LEFT_VOLUME = 1.0f; 7099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas static final float FULL_RIGHT_VOLUME = 1.0f; 7199ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas static final int DEFAULT_PRIORITY = 1; 7299ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas static final int DO_NOT_LOOP = 0; 7399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas static final float DEFAULT_RATE = 1.0f; 7425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 7585c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet /** 76a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Interface for receiving notification of search query changes. 7785c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet */ 7885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet public interface SearchBarListener { 7985c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 8085c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet /** 813c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet * Method invoked when the search bar detects a change in the query. 823c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet * 833c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet * @param query The current full query. 8485c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet */ 853c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet public void onSearchQueryChange(String query); 863c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet 873c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet /** 8810960072d3c1f9c7f42f9ae77adbfb12f9aed138Jerome Poichet * <p>Method invoked when the search query is submitted.</p> 8910960072d3c1f9c7f42f9ae77adbfb12f9aed138Jerome Poichet * 9010960072d3c1f9c7f42f9ae77adbfb12f9aed138Jerome Poichet * <p>This method can be called without a preceeding onSearchQueryChange, 9110960072d3c1f9c7f42f9ae77adbfb12f9aed138Jerome Poichet * in particular in the case of a voice input.</p> 923c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet * 933c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet * @param query The query being submitted. 943c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet */ 953c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet public void onSearchQuerySubmit(String query); 963c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet 973c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet /** 983c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet * Method invoked when the IME is being dismissed. 993c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet * 1003c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet * @param query The query set in the search bar at the time the IME is being dismissed. 1013c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet */ 1023c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet public void onKeyboardDismiss(String query); 103ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu 104ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu } 105ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu 106ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu /** 107ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * Interface that handles runtime permissions requests. App sets listener on SearchBar via 108ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * {@link #setPermissionListener(SearchBarPermissionListener)}. 109ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu */ 110ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu public interface SearchBarPermissionListener { 111ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu 112ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu /** 113ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * Method invoked when SearchBar asks for "android.permission.RECORD_AUDIO" runtime 114ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * permission. 115ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu */ 116ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu void requestAudioPermission(); 117ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu 11885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 11985c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 120e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet private AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener = 121e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet new AudioManager.OnAudioFocusChangeListener() { 122e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet @Override 123e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet public void onAudioFocusChange(int focusChange) { 1247c8283f6542b1045377e88566d363b4c2c83088bCraig Stout stopRecognition(); 125e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet } 126e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet }; 127e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet 12899ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas SearchBarListener mSearchBarListener; 12999ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas SearchEditText mSearchTextEditor; 13099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas SpeechOrbView mSpeechOrbView; 131514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet private ImageView mBadgeView; 13299ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas String mSearchQuery; 133490691bd414dbb2093dc6cb56ae63ae9b04e70e3Craig Stout private String mHint; 134514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet private String mTitle; 135514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet private Drawable mBadgeDrawable; 13699ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas final Handler mHandler = new Handler(); 13725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet private final InputMethodManager mInputMethodManager; 13899ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas boolean mAutoStartRecognition = false; 139a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet private Drawable mBarBackground; 140a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet 141a6c18317f09969688b7d329a5b4ce35c8d648e4fCraig Stout private final int mTextColor; 142a6c18317f09969688b7d329a5b4ce35c8d648e4fCraig Stout private final int mTextColorSpeechMode; 143a6c18317f09969688b7d329a5b4ce35c8d648e4fCraig Stout private final int mTextHintColor; 144a6c18317f09969688b7d329a5b4ce35c8d648e4fCraig Stout private final int mTextHintColorSpeechMode; 145a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet private int mBackgroundAlpha; 146a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet private int mBackgroundSpeechAlpha; 147a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet private int mBarHeight; 148a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet private SpeechRecognizer mSpeechRecognizer; 149361955cd7c040bf30330c8e21d9016c747a94473Craig Stout private SpeechRecognitionCallback mSpeechRecognitionCallback; 150a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet private boolean mListening; 15199ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas SoundPool mSoundPool; 15299ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas SparseIntArray mSoundMap = new SparseIntArray(); 15399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas boolean mRecognizing = false; 154c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet private final Context mContext; 155e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet private AudioManager mAudioManager; 156ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu private SearchBarPermissionListener mPermissionListener; 15785c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 15885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet public SearchBar(Context context) { 15985c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet this(context, null); 16085c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 16185c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 16285c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet public SearchBar(Context context, AttributeSet attrs) { 16385c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet this(context, attrs, 0); 16485c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 16585c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 16685c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet public SearchBar(Context context, AttributeSet attrs, int defStyle) { 16785c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet super(context, attrs, defStyle); 168c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet mContext = context; 16910960072d3c1f9c7f42f9ae77adbfb12f9aed138Jerome Poichet 1702ad1027496fefed641f91f3cde2f8c8b468bca0cJérôme Poichet Resources r = getResources(); 17125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 17225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet LayoutInflater inflater = LayoutInflater.from(getContext()); 17325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet inflater.inflate(R.layout.lb_search_bar, this, true); 17425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 1752ad1027496fefed641f91f3cde2f8c8b468bca0cJérôme Poichet mBarHeight = getResources().getDimensionPixelSize(R.dimen.lb_search_bar_height); 176a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet RelativeLayout.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 177a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet mBarHeight); 178a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet params.addRule(ALIGN_PARENT_TOP, RelativeLayout.TRUE); 179a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet setLayoutParams(params); 180a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet setBackgroundColor(Color.TRANSPARENT); 181a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet setClipChildren(false); 182a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet 18385c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet mSearchQuery = ""; 18425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mInputMethodManager = 18525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE); 1862ad1027496fefed641f91f3cde2f8c8b468bca0cJérôme Poichet 187a6c18317f09969688b7d329a5b4ce35c8d648e4fCraig Stout mTextColorSpeechMode = r.getColor(R.color.lb_search_bar_text_speech_mode); 188a6c18317f09969688b7d329a5b4ce35c8d648e4fCraig Stout mTextColor = r.getColor(R.color.lb_search_bar_text); 189a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet 190a6c18317f09969688b7d329a5b4ce35c8d648e4fCraig Stout mBackgroundSpeechAlpha = r.getInteger(R.integer.lb_search_bar_speech_mode_background_alpha); 191a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet mBackgroundAlpha = r.getInteger(R.integer.lb_search_bar_text_mode_background_alpha); 192a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet 193a6c18317f09969688b7d329a5b4ce35c8d648e4fCraig Stout mTextHintColorSpeechMode = r.getColor(R.color.lb_search_bar_hint_speech_mode); 194a6c18317f09969688b7d329a5b4ce35c8d648e4fCraig Stout mTextHintColor = r.getColor(R.color.lb_search_bar_hint); 195e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet 196e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 19785c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 19885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 19985c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet @Override 20085c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet protected void onFinishInflate() { 20185c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet super.onFinishInflate(); 20285c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 203a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet RelativeLayout items = (RelativeLayout)findViewById(R.id.lb_search_bar_items); 204a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet mBarBackground = items.getBackground(); 205a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet 2063c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet mSearchTextEditor = (SearchEditText)findViewById(R.id.lb_search_text_editor); 207514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet mBadgeView = (ImageView)findViewById(R.id.lb_search_bar_badge); 208514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet if (null != mBadgeDrawable) { 209514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet mBadgeView.setImageDrawable(mBadgeDrawable); 210514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet } 211514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet 21285c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet mSearchTextEditor.setOnFocusChangeListener(new OnFocusChangeListener() { 21385c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet @Override 21485c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet public void onFocusChange(View view, boolean hasFocus) { 21525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "EditText.onFocusChange " + hasFocus); 21685c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet if (hasFocus) { 21785c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet showNativeKeyboard(); 21885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 219936867a6a063492207bd3cd68a1aa870dd5c9da5Craig Stout updateUi(hasFocus); 22085c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 22185c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet }); 222f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu final Runnable mOnTextChangedRunnable = new Runnable() { 223f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu @Override 224f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu public void run() { 225f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu setSearchQueryInternal(mSearchTextEditor.getText().toString()); 226f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu } 227f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu }; 22885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet mSearchTextEditor.addTextChangedListener(new TextWatcher() { 22985c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet @Override 23085c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { 23185c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 23285c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 23385c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet @Override 23485c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { 23522e46a46e20c53b2e2d23dca792534ee3434c954Dake Gu // don't propagate event during speech recognition. 23622e46a46e20c53b2e2d23dca792534ee3434c954Dake Gu if (mRecognizing) { 23722e46a46e20c53b2e2d23dca792534ee3434c954Dake Gu return; 23822e46a46e20c53b2e2d23dca792534ee3434c954Dake Gu } 239f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu // while IME opens, text editor becomes "" then restores to current value 240f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu mHandler.removeCallbacks(mOnTextChangedRunnable); 241f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu mHandler.post(mOnTextChangedRunnable); 24285c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 24385c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 24485c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet @Override 24585c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet public void afterTextChanged(Editable editable) { 24685c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 24785c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 24885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet }); 2493c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet mSearchTextEditor.setOnKeyboardDismissListener( 250c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichet new SearchEditText.OnKeyboardDismissListener() { 251c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichet @Override 252c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichet public void onKeyboardDismiss() { 253c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichet if (null != mSearchBarListener) { 254c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichet mSearchBarListener.onKeyboardDismiss(mSearchQuery); 255c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichet } 2563c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet } 257c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichet }); 25825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 259c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichet mSearchTextEditor.setOnEditorActionListener(new TextView.OnEditorActionListener() { 260c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichet @Override 261c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichet public boolean onEditorAction(TextView textView, int action, KeyEvent keyEvent) { 26225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "onEditorAction: " + action + " event: " + keyEvent); 26325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet boolean handled = true; 264e2047098f696c81f6435cdd588a62d8ab5829c7dCraig Stout if ((EditorInfo.IME_ACTION_SEARCH == action || 265e2047098f696c81f6435cdd588a62d8ab5829c7dCraig Stout EditorInfo.IME_NULL == action) && null != mSearchBarListener) { 266e2047098f696c81f6435cdd588a62d8ab5829c7dCraig Stout if (DEBUG) Log.v(TAG, "Action or enter pressed"); 26725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet hideNativeKeyboard(); 26825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mHandler.postDelayed(new Runnable() { 26925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 27025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void run() { 27125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "Delayed action handling (search)"); 272a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet submitQuery(); 27325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 27425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet }, 500); 27525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 27625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } else if (EditorInfo.IME_ACTION_NONE == action && null != mSearchBarListener) { 27725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "Escaped North"); 27825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet hideNativeKeyboard(); 27925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mHandler.postDelayed(new Runnable() { 28025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 28125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void run() { 28225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "Delayed action handling (escape_north)"); 28325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mSearchBarListener.onKeyboardDismiss(mSearchQuery); 28425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 28525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet }, 500); 28625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } else if (EditorInfo.IME_ACTION_GO == action) { 28725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "Voice Clicked"); 28825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet hideNativeKeyboard(); 28925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mHandler.postDelayed(new Runnable() { 29025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 29125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void run() { 29225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "Delayed action handling (voice_mode)"); 29325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mAutoStartRecognition = true; 29425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mSpeechOrbView.requestFocus(); 29525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 29625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet }, 500); 29725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } else { 29825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet handled = false; 29925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 30025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 30125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet return handled; 30225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 30325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet }); 30425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 30525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mSearchTextEditor.setPrivateImeOptions("EscapeNorth=1;VoiceDismiss=1;"); 30625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 30725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mSpeechOrbView = (SpeechOrbView)findViewById(R.id.lb_search_bar_speech_orb); 30825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mSpeechOrbView.setOnOrbClickedListener(new OnClickListener() { 30925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 31025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void onClick(View view) { 311c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet toggleRecognition(); 31225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 31325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet }); 31425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mSpeechOrbView.setOnFocusChangeListener(new OnFocusChangeListener() { 31525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 31625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void onFocusChange(View view, boolean hasFocus) { 31725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "SpeechOrb.onFocusChange " + hasFocus); 31825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (hasFocus) { 31925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet hideNativeKeyboard(); 32025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (mAutoStartRecognition) { 32125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet startRecognition(); 32225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mAutoStartRecognition = false; 32325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 32425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } else { 32525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet stopRecognition(); 3263c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet } 327936867a6a063492207bd3cd68a1aa870dd5c9da5Craig Stout updateUi(hasFocus); 328c9422fb7ac972aee1f05c5ec0f07c2ec24cc771bJerome Poichet } 3293c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet }); 330514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet 331936867a6a063492207bd3cd68a1aa870dd5c9da5Craig Stout updateUi(hasFocus()); 332514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet updateHint(); 3330075dfe4e812a633be39018e1d6a85e5c6e58de5Jerome Poichet } 3340075dfe4e812a633be39018e1d6a85e5c6e58de5Jerome Poichet 3350075dfe4e812a633be39018e1d6a85e5c6e58de5Jerome Poichet @Override 3360075dfe4e812a633be39018e1d6a85e5c6e58de5Jerome Poichet protected void onAttachedToWindow() { 3370075dfe4e812a633be39018e1d6a85e5c6e58de5Jerome Poichet super.onAttachedToWindow(); 338c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet if (DEBUG) Log.v(TAG, "Loading soundPool"); 339c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet mSoundPool = new SoundPool(2, AudioManager.STREAM_SYSTEM, 0); 340c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet loadSounds(mContext); 34185c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 34285c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 343c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet @Override 344c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet protected void onDetachedFromWindow() { 3457c8283f6542b1045377e88566d363b4c2c83088bCraig Stout stopRecognition(); 346c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet if (DEBUG) Log.v(TAG, "Releasing SoundPool"); 347c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet mSoundPool.release(); 348c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet super.onDetachedFromWindow(); 349c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet } 350c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet 35185c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet /** 352a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Sets a listener for when the term search changes 35385c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet * @param listener 35485c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet */ 35585c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet public void setSearchBarListener(SearchBarListener listener) { 35685c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet mSearchBarListener = listener; 35785c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 35885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 35985c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet /** 360a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Sets the search query 36185c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet * @param query the search query to use 36285c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet */ 36385c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet public void setSearchQuery(String query) { 36422e46a46e20c53b2e2d23dca792534ee3434c954Dake Gu stopRecognition(); 365963e336e8839f26c739007242caf7ca4e50e792dCraig Stout mSearchTextEditor.setText(query); 366361955cd7c040bf30330c8e21d9016c747a94473Craig Stout setSearchQueryInternal(query); 367361955cd7c040bf30330c8e21d9016c747a94473Craig Stout } 368361955cd7c040bf30330c8e21d9016c747a94473Craig Stout 36999ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas void setSearchQueryInternal(String query) { 370963e336e8839f26c739007242caf7ca4e50e792dCraig Stout if (DEBUG) Log.v(TAG, "setSearchQueryInternal " + query); 371e33fac64498a83e1138b0e0aad732ea29e2f8a81Jerome Poichet if (TextUtils.equals(mSearchQuery, query)) { 37285c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet return; 37385c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 37485c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet mSearchQuery = query; 375361955cd7c040bf30330c8e21d9016c747a94473Craig Stout 37685c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet if (null != mSearchBarListener) { 3773c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet mSearchBarListener.onSearchQueryChange(mSearchQuery); 37885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 37985c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 38085c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 3813c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet /** 382a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Sets the title text used in the hint shown in the search bar. 383514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet * @param title The hint to use. 384514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet */ 385514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet public void setTitle(String title) { 386514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet mTitle = title; 387514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet updateHint(); 388514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet } 389514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet 390514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet /** 391514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet * Returns the current title 3923c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet */ 393514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet public String getTitle() { 394514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet return mTitle; 395514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet } 396514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet 397514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet /** 398963e336e8839f26c739007242caf7ca4e50e792dCraig Stout * Returns the current search bar hint text. 399963e336e8839f26c739007242caf7ca4e50e792dCraig Stout */ 400963e336e8839f26c739007242caf7ca4e50e792dCraig Stout public CharSequence getHint() { 401490691bd414dbb2093dc6cb56ae63ae9b04e70e3Craig Stout return mHint; 402963e336e8839f26c739007242caf7ca4e50e792dCraig Stout } 403963e336e8839f26c739007242caf7ca4e50e792dCraig Stout 404963e336e8839f26c739007242caf7ca4e50e792dCraig Stout /** 405a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Sets the badge drawable showing inside the search bar. 406514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet * @param drawable The drawable to be used in the search bar. 407514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet */ 408514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet public void setBadgeDrawable(Drawable drawable) { 409514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet mBadgeDrawable = drawable; 410514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet if (null != mBadgeView) { 411514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet mBadgeView.setImageDrawable(drawable); 412514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet if (null != drawable) { 413514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet mBadgeView.setVisibility(View.VISIBLE); 414514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet } else { 415514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet mBadgeView.setVisibility(View.GONE); 416514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet } 417514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet } 418514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet } 419514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet 420514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet /** 421514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet * Returns the badge drawable 422514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet */ 423514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet public Drawable getBadgeDrawable() { 424514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet return mBadgeDrawable; 4253c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet } 4263c2998d502e4e2586d0bfc52ff5d1f2725fa9e6dJerome Poichet 427e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichet /** 428a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Updates the completion list shown by the IME 429e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichet * 430e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichet * @param completions list of completions shown in the IME, can be null or empty to clear them 431e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichet */ 432e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichet public void displayCompletions(List<String> completions) { 433c738357d90fcc7876415ee16d7fe935510229d4aJerome Poichet List<CompletionInfo> infos = new ArrayList<>(); 434e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichet if (null != completions) { 435e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichet for (String completion : completions) { 436e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichet infos.add(new CompletionInfo(infos.size(), infos.size(), completion)); 437e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichet } 438e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichet } 439c738357d90fcc7876415ee16d7fe935510229d4aJerome Poichet CompletionInfo[] array = new CompletionInfo[infos.size()]; 440c738357d90fcc7876415ee16d7fe935510229d4aJerome Poichet displayCompletions(infos.toArray(array)); 441c738357d90fcc7876415ee16d7fe935510229d4aJerome Poichet } 442e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichet 443c738357d90fcc7876415ee16d7fe935510229d4aJerome Poichet /** 444c738357d90fcc7876415ee16d7fe935510229d4aJerome Poichet * Updates the completion list shown by the IME 445c738357d90fcc7876415ee16d7fe935510229d4aJerome Poichet * 446c738357d90fcc7876415ee16d7fe935510229d4aJerome Poichet * @param completions list of completions shown in the IME, can be null or empty to clear them 447c738357d90fcc7876415ee16d7fe935510229d4aJerome Poichet */ 448c738357d90fcc7876415ee16d7fe935510229d4aJerome Poichet public void displayCompletions(CompletionInfo[] completions) { 449c738357d90fcc7876415ee16d7fe935510229d4aJerome Poichet mInputMethodManager.displayCompletions(mSearchTextEditor, completions); 450e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichet } 451e5f2388b8d24876ebbd6daf302487bf452245d50Jerome Poichet 4524fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet /** 453a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Sets the speech recognizer to be used when doing voice search. The Activity/Fragment is in 4544fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet * charge of creating and destroying the recognizer with its own lifecycle. 4554fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet * 4564fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet * @param recognizer a SpeechRecognizer 4574fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet */ 4584fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet public void setSpeechRecognizer(SpeechRecognizer recognizer) { 4597c8283f6542b1045377e88566d363b4c2c83088bCraig Stout stopRecognition(); 4604fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet if (null != mSpeechRecognizer) { 4614fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet mSpeechRecognizer.setRecognitionListener(null); 4624fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet if (mListening) { 463e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet mSpeechRecognizer.cancel(); 4644fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet mListening = false; 4654fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet } 4664fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet } 4674fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet mSpeechRecognizer = recognizer; 468361955cd7c040bf30330c8e21d9016c747a94473Craig Stout if (mSpeechRecognitionCallback != null && mSpeechRecognizer != null) { 469361955cd7c040bf30330c8e21d9016c747a94473Craig Stout throw new IllegalStateException("Can't have speech recognizer and request"); 470361955cd7c040bf30330c8e21d9016c747a94473Craig Stout } 471361955cd7c040bf30330c8e21d9016c747a94473Craig Stout } 472361955cd7c040bf30330c8e21d9016c747a94473Craig Stout 473a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout /** 474a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Sets the speech recognition callback. 475a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout */ 476361955cd7c040bf30330c8e21d9016c747a94473Craig Stout public void setSpeechRecognitionCallback(SpeechRecognitionCallback request) { 477361955cd7c040bf30330c8e21d9016c747a94473Craig Stout mSpeechRecognitionCallback = request; 478361955cd7c040bf30330c8e21d9016c747a94473Craig Stout if (mSpeechRecognitionCallback != null && mSpeechRecognizer != null) { 479361955cd7c040bf30330c8e21d9016c747a94473Craig Stout throw new IllegalStateException("Can't have speech recognizer and request"); 480361955cd7c040bf30330c8e21d9016c747a94473Craig Stout } 4814fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet } 4824fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet 48399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas void hideNativeKeyboard() { 48425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mInputMethodManager.hideSoftInputFromWindow(mSearchTextEditor.getWindowToken(), 48525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet InputMethodManager.RESULT_UNCHANGED_SHOWN); 48625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 48725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 48899ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas void showNativeKeyboard() { 48985c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet mHandler.post(new Runnable() { 49085c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet @Override 49185c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet public void run() { 49285c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet mSearchTextEditor.requestFocusFromTouch(); 49385c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet mSearchTextEditor.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), 49485c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 49585c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet mSearchTextEditor.getWidth(), mSearchTextEditor.getHeight(), 0)); 49685c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet mSearchTextEditor.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), 49785c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 49885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet mSearchTextEditor.getWidth(), mSearchTextEditor.getHeight(), 0)); 49985c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 50085c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet }); 50185c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet } 50285c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet 503514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet /** 504514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet * This will update the hint for the search bar properly depending on state and provided title 505514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet */ 5062ad1027496fefed641f91f3cde2f8c8b468bca0cJérôme Poichet private void updateHint() { 507514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet String title = getResources().getString(R.string.lb_search_bar_hint); 508514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet if (!TextUtils.isEmpty(mTitle)) { 509a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet if (isVoiceMode()) { 510a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet title = getResources().getString(R.string.lb_search_bar_hint_with_title_speech, mTitle); 511a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet } else { 512a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet title = getResources().getString(R.string.lb_search_bar_hint_with_title, mTitle); 513a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet } 514a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet } else if (isVoiceMode()) { 515a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet title = getResources().getString(R.string.lb_search_bar_hint_speech); 516514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet } 517490691bd414dbb2093dc6cb56ae63ae9b04e70e3Craig Stout mHint = title; 518490691bd414dbb2093dc6cb56ae63ae9b04e70e3Craig Stout if (mSearchTextEditor != null) { 519490691bd414dbb2093dc6cb56ae63ae9b04e70e3Craig Stout mSearchTextEditor.setHint(mHint); 520490691bd414dbb2093dc6cb56ae63ae9b04e70e3Craig Stout } 521514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet } 522514bdd5473ae7f4da990d6035422d0784c6c344eJerome Poichet 52399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas void toggleRecognition() { 524c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet if (mRecognizing) { 525c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet stopRecognition(); 526c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet } else { 527c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet startRecognition(); 528c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet } 529c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet } 530c8737e35c611362db621b25656b57be0c2b8a306Jerome Poichet 531f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu /** 532ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * Returns true if is not running Recognizer, false otherwise. 533ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * @return True if is not running Recognizer, false otherwise. 534ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu */ 535ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu public boolean isRecognizing() { 536ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu return mRecognizing; 537ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu } 538ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu 539ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu /** 540a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * Stops the speech recognition, if already started. 541f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu */ 542f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu public void stopRecognition() { 543e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet if (DEBUG) Log.v(TAG, String.format("stopRecognition (listening: %s, recognizing: %s)", 544e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet mListening, mRecognizing)); 545e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet 54622e46a46e20c53b2e2d23dca792534ee3434c954Dake Gu if (!mRecognizing) return; 547e2047098f696c81f6435cdd588a62d8ab5829c7dCraig Stout 548c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas // Edit text content was cleared when starting recognition; ensure the content is restored 549e2047098f696c81f6435cdd588a62d8ab5829c7dCraig Stout // in error cases 550e2047098f696c81f6435cdd588a62d8ab5829c7dCraig Stout mSearchTextEditor.setText(mSearchQuery); 551490691bd414dbb2093dc6cb56ae63ae9b04e70e3Craig Stout mSearchTextEditor.setHint(mHint); 552e2047098f696c81f6435cdd588a62d8ab5829c7dCraig Stout 55322e46a46e20c53b2e2d23dca792534ee3434c954Dake Gu mRecognizing = false; 5544fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet 555e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet if (mSpeechRecognitionCallback != null || null == mSpeechRecognizer) return; 556e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet 55725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mSpeechOrbView.showNotListening(); 55825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 55925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (mListening) { 56025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mSpeechRecognizer.cancel(); 561e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet mListening = false; 562e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet mAudioManager.abandonAudioFocus(mAudioFocusChangeListener); 56325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 564e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet 565e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet mSpeechRecognizer.setRecognitionListener(null); 56625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 56725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 568f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu /** 569ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * Sets listener that handles runtime permission requests. 570ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu * @param listener Listener that handles runtime permission requests. 571f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu */ 572ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu public void setPermissionListener(SearchBarPermissionListener listener) { 573ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu mPermissionListener = listener; 574ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu } 575ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu 576f52e0718c20bedc86f0b67f6b3660e737d787bd4Dake Gu public void startRecognition() { 577e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet if (DEBUG) Log.v(TAG, String.format("startRecognition (listening: %s, recognizing: %s)", 578e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet mListening, mRecognizing)); 579e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet 58022e46a46e20c53b2e2d23dca792534ee3434c954Dake Gu if (mRecognizing) return; 58122e46a46e20c53b2e2d23dca792534ee3434c954Dake Gu if (!hasFocus()) { 58222e46a46e20c53b2e2d23dca792534ee3434c954Dake Gu requestFocus(); 58322e46a46e20c53b2e2d23dca792534ee3434c954Dake Gu } 584361955cd7c040bf30330c8e21d9016c747a94473Craig Stout if (mSpeechRecognitionCallback != null) { 585490691bd414dbb2093dc6cb56ae63ae9b04e70e3Craig Stout mSearchTextEditor.setText(""); 586490691bd414dbb2093dc6cb56ae63ae9b04e70e3Craig Stout mSearchTextEditor.setHint(""); 587361955cd7c040bf30330c8e21d9016c747a94473Craig Stout mSpeechRecognitionCallback.recognizeSpeech(); 588ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu mRecognizing = true; 589361955cd7c040bf30330c8e21d9016c747a94473Craig Stout return; 590361955cd7c040bf30330c8e21d9016c747a94473Craig Stout } 5914fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet if (null == mSpeechRecognizer) return; 592ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu int res = getContext().checkCallingOrSelfPermission(Manifest.permission.RECORD_AUDIO); 593ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu if (PackageManager.PERMISSION_GRANTED != res) { 594ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu if (Build.VERSION.SDK_INT >= 23 && mPermissionListener != null) { 595ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu mPermissionListener.requestAudioPermission(); 596ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu return; 597ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu } else { 598ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu throw new IllegalStateException(Manifest.permission.RECORD_AUDIO + 599ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu " required for search"); 600ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu } 601ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu } 6024fbaf9b54d7f9723f3ec5c320db9cea887eeff7bJerome Poichet 603ce06f6b530f22e1e7839d068d5dd8ea3e4af8262Dake Gu mRecognizing = true; 604e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet // Request audio focus 605e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet int result = mAudioManager.requestAudioFocus(mAudioFocusChangeListener, 606e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet // Use the music stream. 607e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet AudioManager.STREAM_MUSIC, 608e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet // Request exclusive transient focus. 609e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); 610e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet 611e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet 612e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { 613e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet Log.w(TAG, "Could not get audio focus"); 614e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet } 61525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 616a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet mSearchTextEditor.setText(""); 617a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet 61825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet Intent recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 61925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 62025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, 62125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); 62225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet recognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true); 62325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 62425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mSpeechRecognizer.setRecognitionListener(new RecognitionListener() { 62525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 62625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void onReadyForSpeech(Bundle bundle) { 62725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "onReadyForSpeech"); 6289d9f969b5f37b4454b49f74125521c82a8bf88c4Tim Kilbourn mSpeechOrbView.showListening(); 6299d9f969b5f37b4454b49f74125521c82a8bf88c4Tim Kilbourn playSearchOpen(); 63025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 63125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 63225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 63325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void onBeginningOfSpeech() { 63425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "onBeginningOfSpeech"); 63525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 63625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 63725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 63825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void onRmsChanged(float rmsdB) { 63925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "onRmsChanged " + rmsdB); 64025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet int level = rmsdB < 0 ? 0 : (int)(10 * rmsdB); 64125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mSpeechOrbView.setSoundLevel(level); 64225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 64325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 64425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 64525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void onBufferReceived(byte[] bytes) { 64625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "onBufferReceived " + bytes.length); 64725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 64825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 64925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 65025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void onEndOfSpeech() { 65125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "onEndOfSpeech"); 65225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 65325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 65425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 65525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void onError(int error) { 65625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "onError " + error); 65725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet switch (error) { 658e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet case SpeechRecognizer.ERROR_NETWORK_TIMEOUT: 659e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet Log.w(TAG, "recognizer network timeout"); 660e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet break; 661e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet case SpeechRecognizer.ERROR_NETWORK: 662e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet Log.w(TAG, "recognizer network error"); 663e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet break; 664e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet case SpeechRecognizer.ERROR_AUDIO: 665e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet Log.w(TAG, "recognizer audio error"); 66625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet break; 66725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet case SpeechRecognizer.ERROR_SERVER: 668e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet Log.w(TAG, "recognizer server error"); 669e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet break; 670e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet case SpeechRecognizer.ERROR_CLIENT: 671e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet Log.w(TAG, "recognizer client error"); 67225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet break; 67325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet case SpeechRecognizer.ERROR_SPEECH_TIMEOUT: 674e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet Log.w(TAG, "recognizer speech timeout"); 67525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet break; 676e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet case SpeechRecognizer.ERROR_NO_MATCH: 677e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet Log.w(TAG, "recognizer no match"); 678e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet break; 679e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet case SpeechRecognizer.ERROR_RECOGNIZER_BUSY: 680e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet Log.w(TAG, "recognizer busy"); 681e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet break; 682e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS: 683e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet Log.w(TAG, "recognizer insufficient permissions"); 68425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet break; 68525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet default: 68625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet Log.d(TAG, "recognizer other error"); 68725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet break; 68825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 68925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 69022e46a46e20c53b2e2d23dca792534ee3434c954Dake Gu stopRecognition(); 691a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet playSearchFailure(); 69225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 69325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 69425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 69525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void onResults(Bundle bundle) { 69625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (DEBUG) Log.v(TAG, "onResults"); 69725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet final ArrayList<String> matches = 69825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); 69925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet if (matches != null) { 700e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet if (DEBUG) Log.v(TAG, "Got results" + matches); 70125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 70225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mSearchQuery = matches.get(0); 70325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mSearchTextEditor.setText(mSearchQuery); 704a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet submitQuery(); 70525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 706e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet 70722e46a46e20c53b2e2d23dca792534ee3434c954Dake Gu stopRecognition(); 708a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet playSearchSuccess(); 70925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 71025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 71125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 71225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void onPartialResults(Bundle bundle) { 713a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout ArrayList<String> results = bundle.getStringArrayList( 714a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout SpeechRecognizer.RESULTS_RECOGNITION); 715a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (DEBUG) Log.v(TAG, "onPartialResults " + bundle + " results " + 716a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout (results == null ? results : results.size())); 717a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (results == null || results.size() == 0) { 718a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout return; 719a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout } 720a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 721a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout // stableText: high confidence text from PartialResults, if any. 722a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout // Otherwise, existing stable text. 723a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout final String stableText = results.get(0); 724a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (DEBUG) Log.v(TAG, "onPartialResults stableText " + stableText); 725a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout 726a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout // pendingText: low confidence text from PartialResults, if any. 727a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout // Otherwise, empty string. 728a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout final String pendingText = results.size() > 1 ? results.get(1) : null; 729a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout if (DEBUG) Log.v(TAG, "onPartialResults pendingText " + pendingText); 73025aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 731a088f574b916685bd0a75ff613ac2009a3bad483Craig Stout mSearchTextEditor.updateRecognizedText(stableText, pendingText); 73225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 73325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 73425aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet @Override 73525aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet public void onEvent(int i, Bundle bundle) { 73625aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 73725aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 73825aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet }); 73925aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 740e2bc82a1c02f667901bd96e244afa7dc0232b354Jerome Poichet mListening = true; 74125aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet mSpeechRecognizer.startListening(recognizerIntent); 74225aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet } 74325aacd3f5896ec09053739cc731bdbab3a6f2b81Jerome Poichet 74499ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas void updateUi(boolean hasFocus) { 745936867a6a063492207bd3cd68a1aa870dd5c9da5Craig Stout if (hasFocus) { 746a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet mBarBackground.setAlpha(mBackgroundSpeechAlpha); 747936867a6a063492207bd3cd68a1aa870dd5c9da5Craig Stout if (isVoiceMode()) { 748936867a6a063492207bd3cd68a1aa870dd5c9da5Craig Stout mSearchTextEditor.setTextColor(mTextHintColorSpeechMode); 749936867a6a063492207bd3cd68a1aa870dd5c9da5Craig Stout mSearchTextEditor.setHintTextColor(mTextHintColorSpeechMode); 750936867a6a063492207bd3cd68a1aa870dd5c9da5Craig Stout } else { 751936867a6a063492207bd3cd68a1aa870dd5c9da5Craig Stout mSearchTextEditor.setTextColor(mTextColorSpeechMode); 752936867a6a063492207bd3cd68a1aa870dd5c9da5Craig Stout mSearchTextEditor.setHintTextColor(mTextHintColorSpeechMode); 753936867a6a063492207bd3cd68a1aa870dd5c9da5Craig Stout } 754a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet } else { 755a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet mBarBackground.setAlpha(mBackgroundAlpha); 756a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet mSearchTextEditor.setTextColor(mTextColor); 757a6c18317f09969688b7d329a5b4ce35c8d648e4fCraig Stout mSearchTextEditor.setHintTextColor(mTextHintColor); 758a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet } 759a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet 760a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet updateHint(); 761a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet } 762a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet 7632ad1027496fefed641f91f3cde2f8c8b468bca0cJérôme Poichet private boolean isVoiceMode() { 764a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet return mSpeechOrbView.isFocused(); 765a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet } 766a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet 76799ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas void submitQuery() { 768a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet if (!TextUtils.isEmpty(mSearchQuery) && null != mSearchBarListener) { 769a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet mSearchBarListener.onSearchQuerySubmit(mSearchQuery); 770a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet } 771a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet } 772a9b678302ddee2149e5605afd429c74ba5625c24Jerome Poichet 773a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet private void loadSounds(Context context) { 774a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet int[] sounds = { 775decb4e284bb5befddcc3812564dab41049fca303Jaekyun Seok R.raw.lb_voice_failure, 776decb4e284bb5befddcc3812564dab41049fca303Jaekyun Seok R.raw.lb_voice_open, 777decb4e284bb5befddcc3812564dab41049fca303Jaekyun Seok R.raw.lb_voice_no_input, 778decb4e284bb5befddcc3812564dab41049fca303Jaekyun Seok R.raw.lb_voice_success, 779a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet }; 780a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet for (int sound : sounds) { 781a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet mSoundMap.put(sound, mSoundPool.load(context, sound, 1)); 782a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet } 783a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet } 784a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet 785a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet private void play(final int resId) { 786a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet mHandler.post(new Runnable() { 787a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet @Override 788a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet public void run() { 789a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet int sound = mSoundMap.get(resId); 790a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet mSoundPool.play(sound, FULL_LEFT_VOLUME, FULL_RIGHT_VOLUME, DEFAULT_PRIORITY, 791a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet DO_NOT_LOOP, DEFAULT_RATE); 792a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet } 793a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet }); 794a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet } 795a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet 79699ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas void playSearchOpen() { 797decb4e284bb5befddcc3812564dab41049fca303Jaekyun Seok play(R.raw.lb_voice_open); 798a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet } 799a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet 80099ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas void playSearchFailure() { 801decb4e284bb5befddcc3812564dab41049fca303Jaekyun Seok play(R.raw.lb_voice_failure); 802a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet } 803a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet 804a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet private void playSearchNoInput() { 805decb4e284bb5befddcc3812564dab41049fca303Jaekyun Seok play(R.raw.lb_voice_no_input); 806a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet } 807a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet 80899ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas void playSearchSuccess() { 809decb4e284bb5befddcc3812564dab41049fca303Jaekyun Seok play(R.raw.lb_voice_success); 810a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet } 811a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet 812f6221e91bd3f0f584893baadcb9f8cf5621dce3bCraig Stout @Override 813f6221e91bd3f0f584893baadcb9f8cf5621dce3bCraig Stout public void setNextFocusDownId(int viewId) { 814f6221e91bd3f0f584893baadcb9f8cf5621dce3bCraig Stout mSpeechOrbView.setNextFocusDownId(viewId); 815f6221e91bd3f0f584893baadcb9f8cf5621dce3bCraig Stout mSearchTextEditor.setNextFocusDownId(viewId); 816f6221e91bd3f0f584893baadcb9f8cf5621dce3bCraig Stout } 817a1798f408d3acafffc93cce1b309a54dce52d22dJérôme Poichet 81885c10faf654848a8aacd1e61760b3e24a1902a83Jerome Poichet} 819