# Zhen's Voice App - Readme ###### tags: `Zhen` `Android` `Android Studio` 這裡是Voice App的內容說明文件,一些參考資料和每日更新如下 https://hackmd.io/qC6DvXmUSFabkgIgLlV_7g?both=# ## 語音的部分 這邊統一使用RecognizerIntent作為應用延伸,範例影片如下: {%youtube wcrRjqCgnl8 %} ### Google語音套件 - RecognizerIntent [RecognizerIntent for Java in Android](https://developer.android.com/reference/android/speech/RecognizerIntent) * 所屬在*java.lang.Object*下的*android.speech.RecognizerIntent* * 需要透過Intent來啟動語音輸入 ### RecognizerIntent實作 #### 1. 匯入相關套件 因為Alt+Enter其實就好了,這步驟可省略 ``` java Java= import android.content.Intent; import java.util.ArrayList; //用來儲存多個辨識結果 import android.speech.RecognizerIntent; //語音辨識套件 ``` #### 2. 點擊圖示來啟動RecognizerIntent介面 先在onCreat()取得圖示speak並建立其監聽事件,RecognizerIntent應該要在每一次圖示被點擊時啟動,所以我們把它寫進監聽事件裡 ``` java Java= @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //取得ImageView which id==speak textView = (TextView) this.findViewById(R.id.text); ImageView speak = (ImageView) findViewById(R.id.speak); //如果麥克風圖示(speak)被點擊 speak.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //放RecongnizerIntent相關設定 } }); } ``` #### 3. 開啟語音辨識功能並送出辨識請求給Google *RecognizerIntent.ACTION_RECOGNIZE_SPEECH* 是指啟動一activity,他會提示user開始說話並通過語音識別器發送語音,結果也會透過這個activity返回,返回結果會存放進intent變成array文字檔 ```java Java= //創建一個intent存放語音識別器回傳的文字檔 Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); ``` #### 4. 設定語音辨識模型 RecognizerIntent.EXTRA_LANGUAGE_MODEL * EXTRA_LANGUAGE_MODEL RecognizerIntent.LANGUAGE_MODEL_FREE_FORM - Use a language model based on free-form speech recognition. LANGUAGE_MODEL_WEB_SEARCH - Use a language model based on web search terms. ```java Java= intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "請說~"); try{ startActivityForResult(intent,200); }catch (ActivityNotFoundException a){ //網路連接失敗或沒讀取到則顯示錯誤訊息 Toast.makeText(getApplicationContext(),"Intent problem", Toast.LENGTH_SHORT).show(); } ``` #### 啟用使用INTERNET權限(實機測試可不加) 因為必須將錄製的語音送到Google的伺服器進行辨識,所以APP需要有網路的使用權限 ###### 在AndroidManifast.xml檔案中加入uses-permission ```xml= <manifest> <application> ... </application> <!--給予internet權限--> <uses-permission android:name="android.permission.INTERNET" /> </manifest> ``` 那為什麼實機測試不用呢?因為一般我們的輸入法已經幫我們下載好離線翻譯,因此不會真正的傳到google伺服器唷 最終語音流程和simple code如下 ![](https://i.imgur.com/nTdbmWp.jpg =250x550)![](https://i.imgur.com/cGWcVvU.jpg =250x550) ![](https://i.imgur.com/xx06yST.jpg =250x550)![](https://i.imgur.com/tHzUwig.jpg =250x550) ``` java Java= @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //取得ImageView which id==speak textView = (TextView) this.findViewById(R.id.text); ImageView speak = (ImageView) findViewById(R.id.speak); //如果麥克風圖示(speak)被點擊 speak.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); //創建一個intent存放"錄到的音訊"的文字檔 intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "請說~"); try{ startActivityForResult(intent,200); }catch (ActivityNotFoundException a){ //網路連接失敗或沒讀取到則顯示錯誤訊息 Toast.makeText(getApplicationContext(),"Intent problem", Toast.LENGTH_SHORT).show(); } } }); } ``` 官方文件可能有點啊砸,中文精簡版可以看[這篇](https://ithelp.ithome.com.tw/m/articles/10194014) ## 畫面的部分 ### 標題列和狀態列的顯示或隱藏 APP預設都是顯示的,但一撥放影片若不是全螢幕時,標題列和狀態列就會壓縮畫面空間,所以我們在onCreate()加入兩行程式將它們隱藏 ```java Java= //設定隱藏標題 getSupportActionBar().hide(); //設定隱藏狀態 getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN); ``` ### 畫面顯示方向 Andriod 預設的方向為直式,但常因為手機偵測到轉向,View就會跟著畫面做比例變動位置~~強迫症的心態炸裂~~,這時工程師就要想辦法讓畫面維持水水的樣子。~~以下是會讓人爆炸的app~~ {%youtube LNsfVZ62NkA %} **一般會做的兩種方式** * **關掉手機的自動轉向** * **強制手機的畫面轉向** 前者是最簡單快速的做法,但你怎麼能保證使用者不手動~~手濺~~切回來呢?再來第二個問題就是雖然關掉了自動轉向,但手機還是會偵測到轉向,此時沒有用後者強制設定的話,影片可能會自動暫停哦~ 下面會說明**強制應用方向的3大種類**,因為想要從語音機器人那邊一切換(啟動)到此就是"橫屏",所以強制轉向的方法設置在onCreate() #### 1. 強制豎屏 SCREEN_ORIENTATION_PORTRAIT 讓app介面維持在直向顯示,一般購物app會設定 e.g.蝦皮 ```java Java= @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//強制豎屏 } ``` ![](https://i.imgur.com/WdODR8f.png =230x400)![](https://i.imgur.com/iX6okBE.png =400x230) #### 2. 強制橫屏 SCREEN_ORIENTATION_LANDSCAPE 讓app介面維持在橫向顯示,**此為範例所用** 發現她會給你warring ```java Java= @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//強制橫屏 } ``` ![](https://i.imgur.com/iKwYKdO.png =400x230)![](https://i.imgur.com/7Xzb11v.png =230x400) #### 3. 螢幕不隨手機旋轉 SCREEN_ORIENTATION_NOSENSOR 讓app畫面忽略物理感應器的方向,好處是可以從code內用條件設定e.g.縱向顯示A、橫向顯示B,但仔細想想你看影片也只會長時間直的或橫的,有點多此一舉XD ```java Java= @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);//螢幕不隨手機旋轉 } ``` 其實總共有10來種更多的螢幕畫面的感測方式,就不贅述了~~懶癌末期~~ 詳細可以看[Android手動切換屏幕方向](https://www.jianshu.com/p/1903511d677f),有更多的說明與應用! #### 強制轉向的warning message 後來發現Andriod Studio會偵測這是不良寫法,原因是為了讓所有體驗者有更好的視覺享受,但我們這邊先忽略XD ~~反正他一樣能跑~~ 另外系統建議的SCREEN_ORIENTATION_UNSPECIFIED,意思是未指定,也是Android本身的默認值 ![](https://i.imgur.com/aGsscAl.jpg) ## 影片的部分 嵌入影片的方式有三種,以下說明 ### VideoView嵌入 * 優點:只要知道影片的實際位置就可使用(雲端也可以)、內建功能完善(暫停切換至某時間點等功能應有盡有) * 缺點:YOUTUBE影片不會讓你知道他的實體位置~~放棄吧騷年~~ ### YoutubeAPI串接 * 優點:因為是官方提供的api,不太會有改版即失效的問題 * 缺點:使用或超過流量需要付費 ### WebView嵌入 * 優點:像是寫html一樣,照著[iframe標籤](https://www.w3schools.com/html/html_youtube.asp)的寫法走就好 * 缺點:使用嵌入的方式會讓原本影片的標籤無法使用 **11/01** app加上[**網路權限**](######在AndroidManifast.xml檔案中加入uses-permission)後,WebView可以正常撥放影片,示意如下 * **虛擬機** ![](https://i.imgur.com/Ccw8YxQ.png) * **實機** ![](https://i.imgur.com/sBVd8ab.jpg) 沒有什麼比較要注意的地方,就是要記得[Java的特殊字元](https://www.itread01.com/p/552090.html)要記得轉成下面的寫法 ![](https://i.imgur.com/WDcfYXG.png =500x500) 將以下code加入onCreate即可顯示 ```java Java= //你的iframe格式放入網址和設定影片大小 String html="<iframe width=\"420\" height=\"315\" src=\"https://www.youtube.com/embed/zkpvaIRwiBI\"></iframe>"; WebView webView = (WebView) findViewById(R.id.webview); WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setSupportZoom(true); webSettings.setBuiltInZoomControls(true); webSettings.setJavaScriptCanOpenWindowsAutomatically(true); webSettings.setAppCacheEnabled(true); webView.setWebViewClient(new WebViewClient()); webView.loadData(html, "text/html", "utf-8"); ```