package com.sinovoice.pathfinder; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import android.content.res.Configuration; import android.inputmethodservice.InputMethodService; import android.inputmethodservice.Keyboard; import android.os.Handler; import android.os.Message; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import com.sinovoice.hcicloudsdk.api.hwr.HciCloudHwr; import com.sinovoice.hcicloudsdk.common.HciErrorCode; import com.sinovoice.hcicloudsdk.common.hwr.HwrRecogResult; import com.sinovoice.hcicloudsdk.common.hwr.HwrRecogResultItem; import com.sinovoice.pathfinder.hcicloud.hwr.HWRManager; import com.sinovoice.pathfinder.hcicloud.hwr.HciCloudHwrHelper; import com.sinovoice.pathfinder.hcicloud.hwr.OnHwrStateChangedListener; import com.sinovoice.pathfinder.hcicloud.sys.HciCloudSysHelper; public class Pathfinder extends InputMethodService implements OnHwrStateChangedListener{ private static final String TAG = Pathfinder.class.getSimpleName(); /** * �첽��ȡ������Ȩ���͵��Ϣ��msg.what */ public static final int MSG_WHAT_CHECK_AUTH_FINISH = 1; public static final int MSG_WHAT_ASR_RESULT = 2; private InputMethodManager mInputMethodManager; private MyHandler mHandler; //hcicloud sys private HciCloudSysHelper mCloudSysHelper; private boolean mHciSysInited; //hcicloud hwr private HciCloudHwrHelper mCLoudHwrHelper; private boolean mHciHwrInited; private HWRManager mHwrManager; /** * ���뷨�ļ�����ͼ */ private SVInputView mInputView; /** * ��ѡ����ͼ */ private CandidateView mCandidateView; private CompletionInfo[] mCompletions; private StringBuilder mComposing = new StringBuilder(); private boolean mCompletionOn; private String mWordSeparators; @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate()"); mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); mWordSeparators = getResources().getString(R.string.word_separators); mHandler = new MyHandler(this); mCloudSysHelper = HciCloudSysHelper.getInstance(); mCLoudHwrHelper = HciCloudHwrHelper.getInstance(); mHwrManager = HWRManager.instance(); mHwrManager.init(this); //hcicloud sys init int errorCode = mCloudSysHelper.init(this); if (errorCode == HciErrorCode.HCI_ERR_NONE) { mHciSysInited = checkExpireTimeAndCapkeys(); Log.d(TAG, "mHciSysInited: " + mHciSysInited); }else{ Log.e(TAG, "sys init fatal. errorCode: " + errorCode); return; } //hcicloud hwr init if(mHciSysInited){ initHwr(); }else{ Log.w(TAG, "δ����initHwr()�����������Ҫ�����ȡ��Ȩ�������initHwr()"); } } /** * ��ʼ�����Ƶ�hwr��� */ private void initHwr() { int errorCode = mCLoudHwrHelper.init(getApplicationContext()); if (errorCode == HciErrorCode.HCI_ERR_NONE) { mHciHwrInited = true; Log.d(TAG, "mHciHwrInited: " + mHciHwrInited); }else{ Log.e(TAG, "hwr init fatal. errorCode: " + errorCode); return; } //Hwr Manager mHwrManager.prepareRecog(); mHwrManager.setOnHwrRecogResultChangedListener(this); } @Override public View onCreateInputView() { mInputView = (SVInputView) getLayoutInflater().inflate(R.layout.input, null); mInputView.init(this); return mInputView; } @Override public View onCreateCandidatesView() { mCandidateView = new CandidateView(this); mCandidateView.setService(this); mCandidateView.setHandler(mHandler); return mCandidateView; } @Override public void onStartInputView(EditorInfo info, boolean restarting) { super.onStartInputView(info, restarting); setCandidatesViewShown(true); } @Override public void onStartInput(EditorInfo attribute, boolean restarting) { super.onStartInput(attribute, restarting); // Reset our state. We want to do this even if restarting, because // the underlying state of the text editor could have changed in any way. mComposing.setLength(0); updateCandidates(); mCompletionOn = false; mCompletions = null; } /** * Deal with the editor reporting movement of its cursor. */ @Override public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) { super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart, candidatesEnd); // If the current selection in the text view changes, we should // clear whatever candidate text we have. if (mComposing.length() > 0 && (newSelStart != candidatesEnd || newSelEnd != candidatesEnd)) { mComposing.setLength(0); updateCandidates(); InputConnection ic = getCurrentInputConnection(); if (ic != null) { ic.finishComposingText(); } } } /** * This tells us about completions that the editor has determined based * on the current text in it. We want to use this in fullscreen mode * to show the completions ourself, since the editor can not be seen * in that situation. */ @Override public void onDisplayCompletions(CompletionInfo[] completions) { if (mCompletionOn) { mCompletions = completions; if (completions == null) { setSuggestions(null, false, false); return; } List<String> stringList = new ArrayList<String>(); for (int i = 0; i < completions.length; i++) { CompletionInfo ci = completions[i]; if (ci != null) stringList.add(ci.getText().toString()); } setSuggestions(stringList, true, true); } } @Override public void onFinishInput() { super.onFinishInput(); // Clear current composing text and candidates. mComposing.setLength(0); updateCandidates(); // We only hide the candidates window when finishing input on // a particular editor, to avoid popping the underlying application // up and down if the user is entering text into the bottom of // its window. setCandidatesViewShown(false); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //�Ļ�����л�ʱ�����Ļ�ķ���������д��ģʽ�������д������д if(newConfig.orientation == Configuration.ORIENTATION_PORTRAIT || newConfig.orientation == Configuration.ORIENTATION_SQUARE){ mHwrManager.setSpliteMode(HciCloudHwr.HCI_HWR_SPLIT_MODE_OVERLAP); }else if(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){ mHwrManager.setSpliteMode(HciCloudHwr.HCI_HWR_SPLIT_MODE_LINE); }else{ //do nothing } } @Override public void onDestroy() { super.onDestroy(); mInputMethodManager = null; // ����release������� // hwr release mHwrManager.release(); while(!mHwrManager.isReleaseSuccess()){ try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } mHwrManager = null; mCLoudHwrHelper.release(); mCLoudHwrHelper = null; //��ϵͳrelease mCloudSysHelper.release(); mCloudSysHelper = null; mHandler = null; } /** * �����Ȩ�ļ��Ĺ���ʱ�䣬�Լ�����Ƿ���� * * @return */ private boolean checkExpireTimeAndCapkeys() { //�����Ȩ�ļ��Ĺ���ʱ�� int errorCode = mCloudSysHelper.checkExpireTime(); if (errorCode != HciCloudSysHelper.ERRORCODE_NONE) { Log.w(TAG, "checkExpireTime error, errorCode = " + errorCode); checkAuthByThread(); return false; } else { // �����Ȩ�ɹ� } //��鱾����Ȩ�ļ����Ƿ����Ӧ��ʹ�õ����capkeys errorCode = mCloudSysHelper.checkCapkeysEnable(); if (errorCode != HciCloudSysHelper.ERRORCODE_NONE) { Log.w(TAG, "checkCapkeysEnable error, errorCode = " + errorCode); checkAuthByThread(); return false; } return true; } /** * ���̣߳������ȡ��Ȩ */ private void checkAuthByThread() { Log.i(TAG, "checkAuthByThread"); new Thread(new Runnable() { @Override public void run() { int errorCode = mCloudSysHelper.checkAuthByNet(); // check��ɺ����Ϣ����߳� Message message = mHandler.obtainMessage(MSG_WHAT_CHECK_AUTH_FINISH, errorCode, errorCode); mHandler.sendMessage(message); } }).start(); } public void pickSuggestionManually(int index, String text) { mComposing.setLength(0); mComposing.append(text); if (mCompletionOn && mCompletions != null && index >= 0 && index < mCompletions.length) { CompletionInfo ci = mCompletions[index]; getCurrentInputConnection().commitCompletion(ci); if (mCandidateView != null) { mCandidateView.clear(); } } else if (mComposing.length() > 0) { // If we were generating candidate suggestions for the current // text, we would commit one of them here. But for this sample, // we will just commit the current text. commitTyped(getCurrentInputConnection()); } } /** * Helper function to commit any text being composed in to the editor. */ private void commitTyped(InputConnection inputConnection) { if (mComposing.length() > 0) { inputConnection.commitText(mComposing, mComposing.length()); mComposing.setLength(0); updateCandidates(); } } /** * Update the list of available candidates from the current composing * text. This will need to be filled in by however you are determining * candidates. */ private void updateCandidates() { if (!mCompletionOn) { if (mComposing.length() > 0) { ArrayList<String> list = new ArrayList<String>(); list.add(mComposing.toString()); setSuggestions(list, true, true); } else { setSuggestions(null, false, false); } } } public void setSuggestions(List<String> suggestions, boolean completions, boolean typedWordValid) { // if (suggestions != null && suggestions.size() > 0) { // setCandidatesViewShown(true); // } else if (isExtractViewShown()) { // setCandidatesViewShown(true); // }else{ // setCandidatesViewShown(false); // } if (mCandidateView != null) { mCandidateView.setSuggestions(suggestions, completions, typedWordValid); } } private void handleBackspace() { final int length = mComposing.length(); if (length > 0) { mComposing.setLength(0); getCurrentInputConnection().commitText("", 0); updateCandidates(); } else { keyDownUp(KeyEvent.KEYCODE_DEL); } } /** * Helper to send a key down / key up pair to the current editor. */ private void keyDownUp(int keyEventCode) { getCurrentInputConnection().sendKeyEvent( new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode)); getCurrentInputConnection().sendKeyEvent( new KeyEvent(KeyEvent.ACTION_UP, keyEventCode)); } //�ӿ�OnHwrRecogResultChangedListener�Ļص����� @Override public void onResultChanged(HwrRecogResult hwrRecogResult) { if(hwrRecogResult == null){ Log.e(TAG, "hwrRecogResult is null"); return; } ArrayList<HwrRecogResultItem> hwrRecogResultItems = hwrRecogResult.getResultItemList(); if(hwrRecogResultItems == null){ Log.e(TAG, "hwrRecogResultItems is null"); return; } ArrayList<String> suggestions = new ArrayList<String>(); for (int index = 0; index < hwrRecogResultItems.size(); index++) { String result = hwrRecogResultItems.get(index).getResult(); suggestions.add(result); if(index == 0){ mComposing.setLength(0); mComposing.append(result); } } setSuggestions(suggestions, true, true); } @Override public void onStartWriteNewWord() { String suggestion = mCandidateView.getFirstSuggestions(); if(!TextUtils.isEmpty(suggestion)){ pickSuggestionManually(0, suggestion); } } private String getWordSeparators() { return mWordSeparators; } public boolean isWordSeparator(int code) { String separators = getWordSeparators(); return separators.contains(String.valueOf((char)code)); } public void onKeyDelegate(int primaryCode, int[] keyCodes) { if (isWordSeparator(primaryCode)) { // Handle separator if (mComposing.length() > 0) { commitTyped(getCurrentInputConnection()); } sendKey(primaryCode); } else if (primaryCode == Keyboard.KEYCODE_DELETE) { handleBackspace(); } else { handleCharacter(primaryCode, keyCodes); } } /** * Helper to send a character to the editor as raw key events. */ private void sendKey(int keyCode) { switch (keyCode) { case '\n': keyDownUp(KeyEvent.KEYCODE_ENTER); break; default: getCurrentInputConnection().commitText(String.valueOf((char) keyCode), 1); break; } } private void handleCharacter(int primaryCode, int[] keyCodes) { getCurrentInputConnection().commitText(String.valueOf((char) primaryCode), 1); } static class MyHandler extends Handler{ private WeakReference<Pathfinder> mOuter; public MyHandler(Pathfinder service){ mOuter = new WeakReference<Pathfinder>(service); } @Override public void handleMessage(Message msg) { Pathfinder pathfinder = mOuter.get(); if(pathfinder == null){ Log.e(TAG, "pathfinder is null."); return; } switch (msg.what) { case MSG_WHAT_CHECK_AUTH_FINISH: int errorCode = msg.arg1; if (errorCode == HciErrorCode.HCI_ERR_NONE) { pathfinder.mHciSysInited = pathfinder.checkExpireTimeAndCapkeys(); Log.d(TAG, "handlerMessage(), mHciSysInited: " + pathfinder.mHciSysInited); if(pathfinder.mHciSysInited){ pathfinder.initHwr(); } } break; case MSG_WHAT_ASR_RESULT: String asrResult = (String) msg.obj; Log.i(TAG, "handler, asr result = " + asrResult); pathfinder.getCurrentInputConnection().commitText(asrResult, 1); pathfinder.updateCandidates(); break; default: break; } super.handleMessage(msg); } } }