android.support.v7.widget.SearchViewで音声検索ができるようにする

## 概要
- android.support.v7.widget.SearchViewで音声検索まわりでハマったことなどをメモ代わりに書きます

## 通常の検索
- まずは音声検索抜きで検索ボックスを表示します
- 例として、MainActivityに設置していきます

```xml:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="labeneko.com.searchtest" >
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <!-- launchMode="singleTop"を指定し、MainActivityを再利用して新しいintentを作成。
        MainActivity#onNewIntentが呼ばれる。 -->
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <!-- Search Intentを受け取れるようにする -->
                <action android:name="android.intent.action.SEARCH" />
            </intent-filter>
            <!-- 入力した文字列を受け取るActivityのnameを設定する -->
            <meta-data android:name="android.app.default_searchable"
                android:value=".MainActivity" />
            <meta-data android:name="android.app.searchable"
                android:resource="@xml/searchable"/>
        </activity>
    </application>
</manifest>
```

```java:MainActivity.java
public class MainActivity extends ActionBarActivity {

    private SearchView searchView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        searchView = (SearchView) findViewById(R.id.search_view);
        searchView.setIconified(false);
        searchView.setIconifiedByDefault(false);

        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        searchView.setSearchableInfo(searchManager
                .getSearchableInfo(getComponentName()));
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                // queryを用いて処理を行う
                return false;
            }

            @Override
            public boolean onQueryTextChange(String s) {
                return false;
            }
        });
    }

    @Override
    protected void onNewIntent(Intent intent) {
        setIntent(intent);
        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            String query = intent.getStringExtra(SearchManager.QUERY);
            boolean submit = false;
            searchView.setQuery(query, submit);
        }
    }
}
```
```xml:activity_main.xml
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/darker_gray">
    <android.support.v7.widget.SearchView
        android:id="@+id/search_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:layout_margin="16dp"/>
</RelativeLayout>
```

```xml:searchable.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- label,hintは直接文字列で指定すると正常な挙動をしないようです -->
<searchable
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_name"
    android:hint="@string/search_hint" />
```

```xml:strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">SearchTest</string>
    <string name="hello_world">Hello world!</string>
    <string name="search_hint">入力してください</string>
</resources>
```

- これで通常の検索ができるようになります

![9b88a3f031ad7e8bdfd83206dfbcc8a2.png](https://qiita-image-store.s3.amazonaws.com/0/61162/210792f8-c6c2-0635-dc76-e1f9fd6c6c15.png)


# 音声検索ができるようにする
- 音声検索を有効にするには下記のようにコードを修正します

```xml:searchable.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- 末尾にvoiceSearchModeを追加 -->
<searchable
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_name"
    android:hint="@string/search_hint"
    android:voiceSearchMode="showVoiceSearchButton|launchRecognizer" />
```

```java:MainActivity.java
    ...
    @Override
    protected void onNewIntent(Intent intent) {
        setIntent(intent);
        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            String query = intent.getStringExtra(SearchManager.QUERY);
            // searchViewに音声入力の結果を入れる
            // 音声入力後にそのまま別のActivityに飛ばす等する際はここで処理をする
            boolean submit = false;
            searchView.setQuery(query, submit);
        }
    }
```
- 以上の変更で音声検索ができるようになります

![209e059682fba21ecb30d581f01d3842.png](https://qiita-image-store.s3.amazonaws.com/0/61162/c5e4b130-725d-d15e-add3-82c59b43e1cb.png)
![a456ba255c4d838aaaaddb0b13ef6057.png](https://qiita-image-store.s3.amazonaws.com/0/61162/6edc0d5a-c267-612c-3cbf-037aa384c659.png)


## 下線が邪魔だと感じだら
- 前に音声検索無し版の記事を書きましたのでご参考にしてください(android.support.v7.widget.SearchViewで下線を消す)
 - http://qiita.com/labeneko/items/8b163df905624d4c40a9
- SearchViewに背景色を設定しても、下線は消えません。また、SearchView自体には下線の表示を制御するxmlの指定等存在しません。
- この線はSearchViewの内部を構成している要素の一つである`search_plate`と`submit_area`に背景色を追加することで消すことができます。背景色はtransparentでも可です。

```Java:MainActivity.java
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...

        // 以下のコードを追加
        // テキスト入力欄
        searchView.findViewById(android.support.v7.appcompat.R.id.search_plate)
                .setBackgroundColor(getResources().getColor(android.R.color.transparent));
        // 音声検索ボタンが属するボックス
searchView.findViewById(android.support.v7.appcompat.R.id.submit_area)
                .setBackgroundColor(getResources().getColor(android.R.color.transparent));
    }
```

- これで下線も消せました

![112ba6473d636dd60ebdc5a57bf5e707.png](https://qiita-image-store.s3.amazonaws.com/0/61162/15f8e47c-91d0-8c12-3dee-f68842b5bfbb.png)


- 音声検索には他の方法やライブラリ等あるようなので、適宜調べていきたいと思います

# 参考
- http://developer.android.com/guide/topics/search/search-dialog.html