2010年3月3日水曜日

Android SearchManager 検索ボックスを使うぜ!

Gmail アプリで menu から検索を押すと、上にニュッて検索ボックスがでてきます。
ちなみに、検索ボタン(ハードのボタンね)を押しても出てきます。
エミュレータだと F5 です。

こんなやつ。過去の入力が候補として出てきてくれます。



これを実装してみたので方法をまとめておきます~。

公式な reference はこちら
http://developer.android.com/intl/ja/reference/android/app/SearchManager.html

Quick Search Box については、こちら
http://android-developers.blogspot.com/search/label/Quick%20Search%20Box

これの大事なところをピックアップしつつ訳しました。。。が、長いので

ようはまとめると
ここのまとめが全部を含んでいます。なので以下に必ず目を通してください。

 (0. 特定のボタンから検索バーを呼び出す処理を追加)
    ボタンのアイコンの画像は
    android.R.drawable.ic_search_category_default を使う



    (ボタンの文字列は SearchManager.MENU_KEY)
    ボタンが押された時の処理に以下を実装

onSearchRequested();



 1.検索用 Activity を用意する
 (Main の Activity でもいいし、専用の Activity を用意してもいい)


   onCreate() で、
    1. ACTION_SEARCH Intent を受け取って処理する
    2. Quick Search Box から検索した場合の処理を追加
      この場合、ACTION_VIEW の Intent で呼び出され、
      Flag が FLAG_ACTIVITY_NEW_TASK (= 0x10000000)
      になっている
   
   onNewIntent() で、
    検索用 Activity から 検索ボックスを呼び出したときの処理を追加


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

final Intent queryIntent = getIntent();
final String queryAction = queryIntent.getAction();

// ACTION_SEARCH の Intent で呼び出された場合
if (Intent.ACTION_SEARCH.equals(queryAction)) {
doSearchWithIntent(queryIntent);
}

// Quick Search Box から呼び出された場合
if (Intent.ACTION_VIEW.equals(queryAction)){
if(queryIntent.getFlags() == Intent.FLAG_ACTIVITY_NEW_TASK) {
doSearchWithIntent(queryIntent);
}
}
}

// 検索用 Activity から呼び出されたとき
@Override
protected void onNewIntent(Intent intent) {
doSearchWithIntent(intent);
}

private void doSearchWithIntent(final Intent queryIntent) {
// 検索文字列は SearchManager.QUERY というキーに入っている
final String queryString = queryIntent.getStringExtra(SearchManager.QUERY);
doSearchWithQuery(queryString);
}



 2.検索UIのXMLファイルを用意する

  res/xml/ フォルダに searchable.xml ファイルを作成する
  (ファイル名はなんでもいいです)


<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_label"
android:hint="@string/search_hint" />


 3.検索UIのXMLファイルへのリファレンスと ACTION_SEARCH Intent を
 受け取る宣言を AndroidManifest.xml に入れる



<activity android:name="MySearchActivity"
android:label="Search"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>


 ・検索を起動する Activity と処理する Activity を同じにする場合は
  AndroidManifest.xml の activity タグに
    android:launchMode="singleTop"
  を追加し、
  onNewIntent() を override して、intent がアップデートされた
  ときの処理を入れる
  
 ・metadata で提供する値は、ローカルの各検索 Activity にだけ
  適用される。よって、同じアプリ内でも Activity ごとに異なる
  特徴の検索を行うことができる。
  その場合は、各activity に上記の宣言を入れる


 4.検索キーワードの入力候補を設定する

  4.1 SearchRecentSuggestionsProvider を 拡張した Provider を
   作成する


  こんな感じ

import android.content.SearchRecentSuggestionsProvider;

public class YourSuggestionProviderClass extends SearchRecentSuggestionsProvider {

public YourSuggestionProviderClass(){
setupSuggestions("myproviderauthority", YourSuggestionProviderClass.DATABASE_MODE_QUERIES);
}
}

  myproviderauthority にはパッケージ名などを使います。


  4.2 作成した Provider を manifest で宣言する



<provider android:name="YourSuggestionProviderClass"
android:authorities="myproviderauthority"
android:syncable="false" />



  4.3 Activity の検索 UI の XML ファイル(searchable.xml)の
    searchable タグで Provider について宣言する
 


<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_label"
android:hint="@string/search_hint"

android:searchSuggestAuthority="myproviderauthority"
android:searchSuggestSelection=" ? "

android:searchSuggestIntentAction="android.intent.action.VIEW" />


  android:searchSuggestAuthority と android:searchSuggestSelection
  は必須です。
  android:searchSuggestIntentAction はオプショナルです。



  4.4 検索 Activity で ユーザー生成のクエリを捕えて、
    saveRecentQuery(String, String) で記録する


final String queryString = queryIntent.getStringExtra(SearchManager.QUERY);

SearchRecentSuggestions suggestions =
new SearchRecentSuggestions(this, "myproviderauthority",
YourSuggestionProviderClass.DATABASE_MODE_QUERIES);
suggestions.saveRecentQuery(queryString, null);



 5. 検索候補を Quick Search Box へ公開する
  検索UIのXMLファイル の searchable タグに以下を追加


android:includeInGlobalSearch="true"
android:searchSettingsDescription="@string/settings_description"

  settings_description で定義した値は、
  ・2.1 以前  
   Home画面で
   [Menu]ー[設定]ー[検索]ー[検索対象]での、自分のアプリ
   の下に出る文字列
  ・2.2 以降
   Home画面で[検索キー]ー[検索ボックス左の g マークをタップ]
   ー[左上の設定ボタン]での、自分のアプリの下に出る文字列

  こんな感じで追加される(Libraroid が追加されている)


 7.検索用以外の Activity で検索キーなどが押されたときに、
  検索用 Activity の検索処理を呼び出すようにする


<application>
<meta-data android:name="android.app.default_searchable"
android:value=".MySearchActivity" />


</application>


  過去の入力が候補として出るようになりました!


  Quick Search Box での検索にも引っかかる
  一番下に "Libraroid: 1" と出ている


  もっと見るをタップするとこんな感じに



  Quick Search Box でよく Libraroid の結果を選ぶと
  最初にでてくるようになります。
  これをタップした場合は、ACTION_VIEW の
  FLAG_ACTIVITY_NEW_TASK (= 0x10000000)
  が呼ばれます。




ということで、

公式な reference
http://developer.android.com/intl/ja/reference/android/app/SearchManager.html
の訳はここから、


1. Developer Guide (何ができるの?どうなるの?)

これを使うと、アプリは
 ・どのように検索を呼び出すか
 ・ダイアログの見た目
 ・検索結果のどのタイプが利用可能なのか
 (ユーザーのタイプとして利用可能な入力候補を含む)

をカスタマイズすることができます。

"検索可能でないアプリであっても、Quick Search Box
(システムの 'global search')のトリガーになる、
検索の呼び出しをデフォルトでサポートしてます。"
 ・・・これは知らなかった。
* 2.2 からなくなりました。(追記 2010.12.11)


2. How Search Is Invoked (どうやって呼び出すの?)

"不可能または不適切でない限り、すべてのアプリケーションは、検索のUIの呼び出しをサポートする必要があります。"
 ・・・すごいこと書いてあるな。google先生。実装しろってことね。

"検索コマンドとは、(一般的に) menu の中の「検索」やショートカットキー「S」や検索ボタン(ハードキー)が押されたというコマンドのことです。"
 ・・・ハードキーボートがついている端末持ってないから
    ショートカットキー試せない。。。><
    今なら IS01 がある〜(追記 2010.12.11)


"もし、検索が可能な実装をしていない場合は、Quick Search Box のような 'global search' が呼び出されます。この場合、検索ボタンを押すとブラウザが開いて web base の検索を行います。"

実装してるとこんな感じ。


実装してないとこんな感じ。ここで検索ボタンを押すとブラウザに飛ばされる。



* この上にニュッと出るやつを "検索UI" と言ってます。


"一般的に、この検索コマンドを受け取って、検索UIを表示・操作する SearchManager を呼び出す実装は、 Activity もしくは Activity が base のクラスに対して行います。"
"もちろん検索コマンド以外から(例えば特定のキー操作など)も SearchManager を呼び出すことができます。"

"検索UIはフローティングウィンドウとして表示され、Activity stack のいかなる変化も引き起こさない。もしユーザーが検索をキャンセルした場合は、以前の Activity が再度現れる。"

"ユーザが検索を起動すると、検索 Intent が送られる。そして、自分のアプリの Activity は pause されて、一般的な intent 処理シーケンスがアクティブになる。"


■ What you need to do. (で、結局なにすればいいの?)

 まず、呼び出された検索を扱う方法を選ぶべし。大きくわけて次の4つ(一部かぶってるけど)

 * 検索UIを直接呼び出す "検索ボタン" や "menu item" などをアプリ
  に入れて、検索コマンドを自分で受ける

 * type-to-search (文字入力で検索を呼び出す)の機能を提供する。この場合、
  ユーザーがある文字を入力したときに自動で検索が呼び出される。

 * もし、あなたのアプリが検索機能を実装していなくても、"検索ボタン"
  や "menu item" を通して、global search を実行できる。
  2.2 からなくなったけどね!(追記 2010.12.11)

 * 完全に検索できない。これはとってもレアケース。
  2.2 からなくなったから、もはやレアじゃなくね?(追記 2010.12.11)


■ How to define a search menu. (検索メニューをどうやって決める?)

 menu に検索 item を追加するのにとっても便利なリソースが提供されてます。

 次の2つ
  * android.R.drawable.ic_search_category_default
   検索用に使えるアイコン(多分使えよ!ってことだと思う)
  * SearchManager.MENU_KEY は推奨されるアルファベットの
   ショートカット(普通はたぶん s)


■ How to invoke search directly. (どうやって検索を直接よびだす?)

 "ボタン"(検索ハードキーではないよ!) や "menu item" から検索を直接呼ぶには、onSearchRequested を呼べばOK!


onSearchRequested();



■ How to implement type-to-search.
 (文字入力で検索起動をどうやって実装する?)


 アプリの Activity をセットしている間に、setDefaultKeyMode を呼ぶべし!


// search within your activity
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
// search using platform global
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_GLOBAL);


DEFAULT_KEYS_SEARCH_LOCAL は自分のアプリ(Activity)内で検索
DEFAULT_KEYS_SEARCH_GLOBAL は global search で検索

このエントリを書いた 2010年3月には手元のハードキーボードつきの端末がなかったので検証できなかったのですが、今 IS01 で試したら、EditText とかにフォーカスされていない状態でタイプすると、LOCAL のときは Activity に実装した検索が起動されて、GLOBAL のときは Global Search が起動しました!(追記 2010.12.11)


■ How to enable global search with Quick Search Box
 (Quick Search Box で global search を有効にする方法)
 
 アプリや Activity 内での検索に加えて、device と web を横断的に検索できる Quick Search Box というのがある。

 この検索バーも Quick Search Box


 platform-global search を呼び出すためにも Search Manager を使うことができる。

 これを実現する方法は、次の2つ

  * アプリや Activity 内で、global search を意味する検索を定義する。
   (これについては、Searchability Metadata の章で詳しく説明する。)
   簡単に言うと、自分のアプリに対するデフォルト検索を "*" と定義した
    single meta-data entry を AndroidManifest.xml に追加する。
   これは、アプリ指定の検索 Activity が提供されていないことを
   システムに示す。よって、システムは代わりに platfrom-global search
   による検索を立ち上げる。

  * 単純になにもしない。onSearchRequested() のデフォルトの
   実装は global search のトリガーになる。
   2.2 からはこれだけだとトリガーになりません
   (もちろん、startSearch(String, boolean, Bundle, boolean)
   直接呼ぶことで、いつでも検索のトリガーになれる。この方法は
   ローカル検索を提供していて、かつ global 検索にアクセスしたい
   場合には最も使いやすい方法)


■ How to disable search from your activity
 (Activity からの検索を利用不可にするには…)

 検索は system-wide な特徴で、ユーザーはそれがすべての contexts
 で利用可能なことを期待(予測)する。
 もし、自分の UI デザインで、検索の起動を完全に不可能にするには、
 次の様に onSearchRequeted を override する。
   ・・・なんだろう。ゲームアプリとかかな?


@Override
public boolean onSearchRequested() {
return false;
}



■ Managing focus and knowing if search is active
 (focus の操作と検索がアクティブか知る方法)


 検索UIは Activity とは切り分けられていない。
 なので、検索UIが呼び出されたり開放されたとき、自分の Activity は
 (典型的には)一時停止(paused, resumed)される。
 もしくは、" Application Fundamentals: Activity Lifecycle " 内で
 定義されたメソッドによって通知(notified)される。

 検索UIは他のシステムUIエレメント
 (例えば、notifications, screen locks, system alerts など)と
 同じ方法で扱われる。

 ● 検索UIが現れたとき、自分の Activity は input focus を失う

 ● 検索 Activity が開放されたとき、次の3つの結果が可能である。

  * ユーザーが単純に検索UIをキャンセルした場合:
    自分の Activity は再び input focus を得て、前の続きになる。
    検索ダイアログが開放された通知を直接受け取りたい場合は、
    setOnDismissListener(SearchManager.OnDismissListener)
    と 
    setOnCancelListener(SearchManager.OnCancelListener)
    を見てね。

  * ユーザーが検索を立ち上げ、これが、検索 Intent の受け取りと
   処理のために他の activity への切り替えを要求した場合: 
    自分の Activity は、 activity pause もしくは stop 通知
    である通常のシーケンスを受け取る

  * ユーザーが検索を立ち上げ、現在の Activity が検索 Intent の
   受取手だった場合 :
    自分の Activity は onNewIntent() メソッドを介して通知
    を受け取る。

 このリストは、自分の Activity が検索UIと相互作用する方法を明確に
 するために提供されている。
 検索 Activity と 検索 Intent のより詳しい内容は次の章で提供される。


3. Implementing Search for Your App
 (自分のアプリに検索を実装する方法)

 次の6ステップを実行すればOK!

  1. 上記で説明した "検索の呼び出し" を実装する
   (ここの括弧の内容がウケるな。。。"ぶっちゃけると、
    意味かぶってるけどね。でも"search-invoking" じゃなくて
    "searchable" って感じなの" だって)

  2. 検索文字列を受け取って、結果のリストに変換する Activity
   を実装する。これは、最初に表示される Activity でもいいし、
   検索結果用の Activity でもいい。
   検索可能なアプリでは、この機能をもつ Activity を必ず1つは
   持っていなければならない。

  3. 検索可能な Activity 内の onCreate() で、ACTION_SEARCH
   Intent を受け取って処理する実装を入れる。
   検索キーワード (query string) は
   getStringExtra(SearchManager.QUERY) を呼ぶことで
   得られる。

 コードはこんな感じ


@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);

final Intent queryIntent = getIntent();
final String queryAction = queryIntent.getAction();
if (Intent.ACTION_SEARCH.equals(queryAction)) {
doSearchWithIntent(queryIntent);
}
}

private void doSearchWithIntent(final Intent queryIntent) {
final String queryString = queryIntent.getStringExtra(SearchManager.QUERY);
doSearchWithQuery(queryString);
}



  4. 自分の検索 Activity を識別・サポートする。
   検索の設定パラメータを提供する XML file を用意し、
   これへのリファレンスを manifest の Activity entry に入れる。
   さらに、ACTION_SEARCH intent を受け取れるという定義を
   intent-filter に追加する。
   詳しくは SearchabilityMetadata

  5. 検索 Activity への global reference を提供する
   metadata entry も manifest に必要。
   これは、デフォルトの検索 context として自分のアプリを
   使うために、自分のアプリの 他の Activity からの検索を
   検索 Activity の検索UIに紐付ける。
   詳しくは SearchabilityMetadata

  6. 最後に、launchMode flag に singleTop を指定することで、
   検索結果 Activity を single-top にする。
   これは、ある Activity からの検索処理として、Activity stack
   上のそれらの pile を生成せずに、同じ Activity を起動する
   ことをシステムに許可する。
   これをした場合、 onNewIntent を override して、intent が
   アップデートされた (新しい query を受け取った)ときの処理を
   入れなければならない。
   詳しくは
   Exposing Search Suggestions to Quick Search Box



4. Search Suggestions (検索の入力候補)

 検索システムの特徴の1つが "検索キーワードの候補"
 各アプリは、異なる、ユニークな正しい方法で、候補を実装する。
 候補たくさんのソースから書かれる、例えば

  * 実際の検索結果 (例えば、アドレス帳の名前など)
  * 最近入力された検索キーワード
  * 最近みたデータや結果
  * 文脈上適切なクエリや結果
  * 可能な結果のまとめ

 一度、アプリ検索候補を提供するために設定されると、それらの同じ
 候補は system-wide Quick Search Box で(簡単に)利用可能にできる。
 そうすると、中央の目立つ場所からそのコンテンツへより早く
 アクセスできるようになる。

 候補の主な形式はクエリ候補として知られており、それはユーザーが
 すでにタイプしているクエリテキストに基づく。
 これは一般的に利用可能なデータとの部分一致である。

 特定の状況 
  ー クエリとしてまだ何もタイプされていない場合、ー
   アプリは zero-query 候補を提供するかどうかを選ぶこともできる。
   これらは、典型的に同じデータソースから記述される。
   しかし、利用可能な部分クエリテキストが無いと、それらは
   他のファクター(もっとも最近のクエリ or 結果)に基づいた
   重み付けになる。


■ Overview of how suggestions are provided
 (どのように候補を提供する?)


 候補は Cotent Provider を介してアクセスする。

 search manager が特定の Activity を検索用と識別すると、
 候補のソースも存在するかどうか metadata を確かめる。
 もし候補が提供されているなら、次のステップが行われる。

  * metadeta 内のフォーマット情報を使って、ユーザーの
   クエリテキストをフォーマッテイングして候補の
   Content Povider に送る。

  * 候補の Content Provider は 可能な候補の Cursor を作成する。

  * search manager は Cursor の各行のデータを表示するための
   リストを追加し、ユーザーへ候補を表示する。

  * もし、ユーザーがなにかキーを打ったなど、クエリが変化したら、
   上のステップはリピートされて、候補リストがアップデートされ
   表示される。

  * もし、ユーザが "GO" ボタンをクリック(タップ)したら、候補は
   無視され、通常の ACTION_SEARCH タイプの Intent による検索が
   立ち上がる

  * もし、ユーザーが候補リストにフォーカスする操作をした場合、
   ユーザーが候補から候補へナビゲートしている間、クエリテキストは
   アップデートされる
   ユーザーはアップデートされたクエリをクリック(タップ)できる。
   もしユーザーが入力フォームへ戻る処理をすると、元々タイプ
   されていたクエリが再ストアされる。

  * もし、ユーザーが特定の候補をクリック(タップ)すると、
   Cursor と metadeta 内で見つかった値の組み合わせが
   Intent とシンクロするのに使われる。
   そして、それをアプリへ送る。
   Activity のデザインと検索の実装方法に応じて、これは
   ACTION_SEARCH か ACTION_VIEW か特定のデータを直接
   表示するか、のいずれかになる。


■ Simple Recent-Query-Based Suggestions
 (最近のクエリに基づいた候補)


 Android framework は 最近のクエリを保持し返すための
 Search Suggestion provider を提供している。

 (多くのアプリにとってはこれで十分)
 使う方法は次のステップでOK

  * 上記のセクションでかかれたクエリ検索を実装してテストする。
  * 自分のアプリ内で SearchRecentSuggestionsProvider
   拡張した Provider を生成
  * 自分の provider について定義した manifest entry を作る
  * 自分の検索 Activity の XML 設定ファイルに provider についての
   情報を入れる
  * 検索 Activity で ユーザー生成のクエリを捕えて、
   saveRecentQuery(String, String) で記録する。

 より詳しい実装については SearchRecentSuggestionsProvider を参照


SearchRecentSuggetionsProvider

 このスーパークラスは自分のアプリの簡単な検索候補 provider を
 作るためのものです。
 最近の入力クエリ and/or 最近の view に基づいた候補を生成する。

 このクラスを使うために、次のことを行わなければならない
  * SearchManager で記述された test query search を実装.
   (この provider は標準的な ACTION_SEARCH Intent を通して
    すべての候補クエリを送る)

  * SearchRecentSuggestionsProvider を拡張して
   Content Provider を自分のアプリ内に作る
   このクラスはすごくシンプル。典型的にはコンストラクタが
   1つだけ。
   しかし、コンストラクタはすごく重要な責任がある:
   setupSuggestions(String myauthorities, int mode)
   を呼ぶときに、自分の検索 Activity の要求とマッチする
   provider を設定する

   よって、こんな感じ

import android.content.SearchRecentSuggestionsProvider;

public class YourSuggestionProviderClass extends SearchRecentSuggestionsProvider {

public YourSuggestionProviderClass(){
setupSuggestions("your.suggestion.authority", YourSuggestionProviderClass.DATABASE_MODE_QUERIES);
}
}


  * 自分の provider を定義した entry を manifest に入れる。
   典型的には、次のようなかんじ



<provider android:name="YourSuggestionProviderClass"
android:authorities="your.suggestion.authority" />


  * コードから直接この content provider のインスタンスを
   作らないこと!
   これは検索ダイアログが候補を探すときに、システムの
   Content Resolver によって自動的に行われる。

  * これを行う Content Resolver のために、検索 Activity の
   XML 設定に content provider の情報を入れる。
   こんな感じで


android:searchSuggestAuthority="your.suggestion.authority"
android:searchSuggestSelection=" ? "

  * 自分の検索 Activity で、ユーザーが生成したクエリを捕えて、
   次の検索のために
   SearchRecentSuggestions.saveRecentQuery()
   を呼んで保存しておく


■ Creating a Customized Suggestions Provider
 (Suggetions Provider をカスタマイズする方法)

ぱす!


■ Configuring your Content Provider to Receive Suggestion Queries
 (候補のクエリを受け取るための Content Provider の設定)

 suggetion provider と communicate する方法
 
 自分のパッケージ(アプリ)が候補を提供する場合は、
 最初に Search Manager を決めなければならない。
 これは、seachable meta-data XML file の検査で実行される。

 android:searchSuggestAuthority
 が XML にある場合は候補を得て表示する

 各クエリは Uri を含み、Search Manager は Uri を次のように
 フォーマットする

   content:// your.suggest.authority / your.suggest.path / SearchManager.SUGGEST_URI_PATH_QUERY


 自分の Content Provider は2つの方法でクエリテキストを受け取ることができる

  * クエリは、検索引数として提供
   もし、android:searchSuggestSelection の値を定義し、
   文字列を含むなら、この文字列は Content Provider の
   クエリ関数に検索パラメータをパスする。
   '?' 文字を使って単一検索引数を定義しなければならない。
   ユーザーのクエリテキストは検索引数配列の最初の要素として
   自分のアプリにパスされる。

  * クエリは、Data Uri で提供
   もし、android:searchSuggestSelection の値を定義しないなら、
   Search Manager はユーザークエリの最後に "/" を追加する。
   クエリは Uri エンコーディングルールを使ってエンコードされる
   (デコードするのを忘れないでね!)
   (getPathSegments()
    getLastPathSegment() が助けになるよ)

 Content Provider へアクセスできるように permission を追加。
 manifest に android:readPermission を定義した場合は、
 "android.permission.GLOBAL_SEARCH" へのアクセスを
 android:readPermission に与える path-permission を含むことに
 よって、検索候補パスへのアクセスを提供しなければならない。
 
 search infrastructure に明示的に与えたアクセスは、それが自分の
 provider を保護している他のパーミッションの詳細を知らなくても
 検索候補にアクセスできることを保証する。 
 Content Provider はすでに search infrastructure を利用可能
 なので、パーミッションを必要としない。
 
 パーミッションで provider のアクセスを保護している例


<provider android:name="MyProvider" android:authorities="myprovider"
android:readPermission="android.permission.READ_MY_DATA"
android:writePermission="android.permission.WRITE_MY_DATA">
<path-permission android:path="/search_suggest_query"
android:readPermission="android.permission.GLOBAL_SEARCH" />
</provider>


■ Handling empty queries (入力がないときのクエリの扱い)

 方法はたくさんあるけど、ここでは2つ紹介

  * local data の単純な検索フィルターの場合、単にすべての
   データセットを与える(例えば:People)
  * クエリ検索の場合、最も最近のクエリを表示する。

 
■ The Format Of Intents Sent By Search Suggestions
 (検索候補によって送られる Intent の形式)

 これらの Intent を設定する方法はたくさんが、ここではいくつかを紹介

  * Launch a query
   このモデルでは、各候補は自分の検索 Activity が実行できる
   クエリを表し、Intent は ユーザーがクエリテキストを入力して
   "GO" ボタンを押したときに正しくフォーマットされる。
    o Action: ACTION_SEARCH
         provided using your XML metadata
     (android:searchSuggestIntentAction).
    o Data: empty (not used).
    o Query: query text supplied by the cursor.

  * 完全な Data Uri を使って結果に直接飛ぶ
   このモデルでは、ユーザーは特定の結果へ直接行く
    o Action: ACTION_VIEW
    o Data: a complete Uri, supplied by the cursor,
     that identifies the desired data.
    o Query: query text supplied with the suggestion
     (probably ignored)

  * シンクロした Data Uri を使って結果に直接飛ぶ
   これは上と同じ結果になるが、提供する Data Uri は異なる
    o Action: ACTION_VIEW
    o Data: The search manager will assemble a Data Uri
     using the following elements: a Uri fragment provided
     in your XML metadata
     (android:searchSuggestIntentData),
     followed by a single "/", followed by the value found
     in the SUGGEST_COLUMN_INTENT_DATA_ID entry
     in your cursor.
    o Query: query text supplied with the suggestion
     (probably ignored)

 このリストは網羅するものではないので自由にカスタマイズしてくだされ。


■ Suggestion Rewriting.

 パス


5. Exposing Search Suggestions to Quick Search Box 
(検索候補を Quick Search Box へ公開する)


 searchable metadata file で

  android:includeInGlobalSearch = "true"

 にすることで、セットアップした検索候補を Quick Search Box で使えるようになる

 重要なお知らせ:デフォルトでは、自分のアプリは Quick Search Box
         の検索対象にはなりません。
         検索対象にするには、アプリをインストール後に
         [設定]ー[検索]ー[検索対象]で、自分のアプリに
         チェックを入れてもらう必要があります。

 Source Ranking: どれだけ自分のアプリの結果を選ばれたかで、
         自分アプリの検索結果の表示される位置かわる

 Search Settings: アプリケーションの名前の下に、そのアプリで何が
         検索できるかを示す必要がある。 
         searchable metadata の
         android:searchSettingsDescription で定義する。

 Shortcuts: パスww


6. Action Keys

ぱす


7. Searchability Metadata 
(ちょっとだけ自分のアプリの検索をカスタマイズ)

 アプリを検索可能にしておく

 metadata で提供する値は、ローカルの各検索 Activity にだけ
 適用される。 よって、同じアプリ内でも Activity ごとに
 異なる特徴の検索を行うことができる。

 自分のアプリのどのアクティビティが検索可能かを定義しなければ
 ならない。
 manifest の activity の項目で、次の2つを提供すべし

  * ACTION_SEARCH Intent を受けて処理できることを
   intent-filter に記述
  * (典型的に searchable.xml と呼ばれる) XML file への
   リファレンスを記述

 こんな感じ


<activity android:name="MySearchActivity"
android:label="Search"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>


 次に、../xml/ フォルダに manifest で指定した xml ファイルを作成する。

 こんな感じ

<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_label"
android:hint="@string/search_hint" />


■ Styleable Resources in your Metadata

表示される文字列をランドスケープとポートレイトで変えたい場合は、

  * .../res/values-land/strings.xml
  * .../res/values-port/strings.xml
  * .../res/values/strings.xml

 にそれぞれ値を入れる
 詳細は Resources and Internationalization: Alternate Resources


■ Metadata for non-searchable activities

 検索アプリの中の Activity ではあるが、それ自身には検索を
 実装したくない場合(検索用のActivityでの検索に飛ばしたい場合とか)
 は manifest に次のように記述する。
  * 検索 Activity の前に "." をつけて、同じパッケージにあることを
   明示するか、   value="*" として、デフォルトの検索
   Activity を呼び出すように指定


<application>
<meta-data android:name="android.app.default_searchable"
android:value=".MySearchActivity" />


</application>



■ Additional metadata for search suggestions

 検索候補を生成する content provider をシステムに公開するために
 XML ファイルに次の項目を追加する

 最初に、manifest に以下を追加



<provider android:name="YourSuggestionProviderClass"
android:authorities="your.suggestion.authority" />


 次に、searchable XML ファイルに次の追加



android:searchSuggestAuthority="your.suggestion.authority"


android:searchSuggestSelection="field =?"


android:searchSuggestIntentAction="intent action string"
android:searchSuggestIntentData="intent data Uri"



8. Passing Search Context

 検索を向上させるために、付加情報を検索 Activity に渡すことが
 できる。例えば、Map アプリでは、現在の位置情報を付加することで、
 検索精度をあげることができる。

 検索が呼び出されたときに Bundle object に保存できる長さの分だけ、
 データを渡すことができる。

 アプリのデータを Search Manager に渡すには、onSearchRequested
 を override する


@Override
public boolean onSearchRequested() {
Bundle appData = new Bundle();
appData.put...();
appData.put...();
startSearch(null, false, appData, false);
return true;
}


Search Manager からデータを受け取るには、 ACTION_SEARCH Intent から次の用に抜き出す


final Bundle appData = queryIntent.getBundleExtra(SearchManager.APP_DATA);
if (appData != null) {
appData.get...();
appData.get...();
}




----------------------

もし、この SearchManager クラスに直接アクセスしたい場合は、
インスタンスを作成するのではなく、

 context.getSystemService(Context.SEARCH_SERVICE)

すること。


 

0 件のコメント:

コメントを投稿