Gestion des appels téléphoniques
Recherches avec SearchManager
L’une des sociétés à l’origine de l’alliance Open Handset – Google – dispose d’un petit moteur de recherche dont vous avez sans doute entendu parler. Il n’est donc pas étonnant qu’Android intègre quelques fonctionnalités de recherche. Plus précisément, les recherches avec Android ne s’appliquent pas seulement aux données qui se trouvent sur l’appareil, mais également aux sources de données disponibles sur Internet. Vos applications peuvent participer à ce processus en déclenchant elles-mêmes des recherches ou en autorisant que l’on fouille dans leurs données. Cette fonctionnalité étant assez récente dans Android, les API risquent d’être modifiées : surveillez les mises à jour.La chasse est ouverte Android dispose de deux types de recherches : locales et globales. Les premières effectuent la recherche dans l’application en cours tandis que les secondes utilisent le moteur de Google pour faire une recherche sur le Web. Chacune d’elles peut être lancée de différentes façons : ● Vous pouvez appeler onSearchRequested() à partir d’un bouton ou d’un choix de menu afin de lancer une recherche locale (sauf si vous avez redéfini cette méthode dans votre activité). ● Vous pouvez appeler directement startSearch() pour lancer une recherche locale ou globale en fournissant éventuellement une chaîne de caractères comme point de départ. ● Vous pouvez faire en sorte qu’une saisie au clavier déclenche une recherche locale avec setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL) ou globale avec setDefaultKeyMode(DEFAULT_KEYS_SEARCH_GLOBAL). Dans tous les cas, la recherche apparaît comme un ensemble de composants graphiques disposés en haut de l’écran, votre activité apparaissant en flou derrière eux (voir Figures 36.1 et 36.2). Recherches personnelles À terme, il existera deux variantes de recherches disponibles : ● les recherches de type requête, où la chaîne recherchée par l’utilisateur est passée à une activité qui est responsable de la recherche et de l’affichage des résultats ; ● les recherches de type filtre, où la chaîne recherchée par l’utilisateur est passée à une activité à chaque pression de touche et où l’activité est chargée de mettre à jour une liste des correspondances. Cette dernière approche étant encore en cours de développement, intéressons-nous à la première. Création de l’activité de recherche Pour qu’une application puisse proposer des recherches de type requête, la première chose à faire consiste à créer une activité de recherche. Bien qu’il soit possible qu’une même activité puisse être ouverte à partir du lanceur et à partir d’une recherche, il s’avère que cela trouble un peu les utilisateurs. En outre, utiliser une activité séparée est plus propre d’un point de vue technique. L’activité de recherche peut avoir l’aspect que vous souhaitez. En fait, à part examiner les requêtes, elle ressemble, se comporte et répond comme toutes les autres activités du système. La seule différence est qu’une activité de recherche doit vérifier les intentions Figure 36.2 Les composants de la recherche globale d’Android avec une liste déroulante montrant les recherches précédentes.
L’art du développement
Android fournies à onCreate() (via getIntent()) et à onNewIntent() pour savoir si l’une d’elles est une recherche, auquel cas elle effectue la recherche et affiche le résultat. L’application Search/Lorem, par exemple, commence comme un clone de l’application du Chapitre 8, qui affichait une liste des mots pour démontrer l’utilisation du conteneur ListView. Ici, nous la modifions pour pouvoir rechercher les mots qui contiennent une chaîne donnée. L’activité principale et l’activité de recherche partagent un layout formé d’une ListView et d’un TextView montrant l’entrée sélectionnée : L’essentiel du code des activités se trouve dans une classe abstraite LoremBase : abstract public class LoremBase extends ListActivity { abstract ListAdapter makeMeAnAdapter(Intent intent); private static final int LOCAL_SEARCH_ID = Menu.FIRST+1; private static final int GLOBAL_SEARCH_ID = Menu.FIRST+2; private static final int CLOSE_ID = Menu.FIRST+3; TextView selection; ArrayList items=new ArrayList(); @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); selection=(TextView)findViewById(R.id.selection); try { XmlPullParser xpp=getResources().getXml(R.xml.words); while (xpp.getEventType()!=XmlPullParser.END_DOCUMENT) { Livre Android.book Page 344 Dimanche, 8. novembre 2009 12:23 12 customer 27921 at Fri Mar 11 19:19:45 +0100 2011 Propriété de Albiri Sigue Chapitre 36 Recherches avec SearchManager 345 if (xpp.getEventType()==XmlPullParser.START_TAG) { if (xpp.getName().equals(« word »)) { items.add(xpp.getAttributeValue(0)); } } xpp.next(); } } catch (Throwable t) { Toast .makeText(this, « Echec de la requete : » + t.toString(), 4000) .show(); } setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); onNewIntent(getIntent()); } @Override public void onNewIntent(Intent intent) { ListAdapter adapter=makeMeAnAdapter(intent); if (adapter==null) { finish(); } else { setListAdapter(adapter); } } public void onListItemClick(ListView parent, View v, int position, long id) { selection.setText(items.get(position).toString()); } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(Menu.NONE, LOCAL_SEARCH_ID, Menu.NONE, « Recherche locale ») .setIcon(android.R.drawable.ic_search_category_default); menu.add(Menu.NONE, GLOBAL_SEARCH_ID, Menu.NONE, « Recherche globale ») .setIcon(R.drawable.search) .setAlphabeticShortcut(SearchManager.MENU_KEY); menu.add(Menu.NONE, CLOSE_ID, Menu.NONE, « Fermeture ») .setIcon(R.drawable.eject) .setAlphabeticShortcut(’f’); return(super.onCreateOptionsMenu(menu)); } Livre Android.book Page 345 Dimanche, 8. novembre 2009 12:23 12 customer 27921 at Fri Mar 11 19:19:45 +0100 2011 Propriété de Albiri Sigue 346 L’art du développement Android @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case LOCAL_SEARCH_ID: onSearchRequested(); return(true); case GLOBAL_SEARCH_ID: startSearch(null, false, null, true); return(true); case CLOSE_ID: finish(); return(true); } return(super.onOptionsItemSelected(item)); } } Cette activité prend en charge tout ce qui est lié à l’affichage d’une liste de mots, y compris l’extraction des mots à partir du fichier XML. En revanche, elle ne fournit pas le ListAdapter à placer dans la ListView – cette tâche est déléguée aux sous-classes. L’activité principale – LoremDemo – utilise simplement un ListAdapter pour la liste de mots : package com.commonsware.android.search; import android.content.Intent; import android.widget.ArrayAdapter; import android.widget.ListAdapter; public class LoremDemo extends LoremBase { @Override ListAdapter makeMeAnAdapter(Intent intent) { return(new ArrayAdapter(this, android.R.layout.simple_list_item_1, items)); } }
Modification du manifeste
Bien que ce code implémente la recherche, il n’est pas intégré au système de recherche d’Android. Pour ce faire, vous devez modifier le fichier AndroidManifest.xml : Livre Android.book Page 347 Dimanche, 8. novembre 2009 12:23 12 customer 27921 at Fri Mar 11 19:19:45 +0100 2011 Propriété de Albiri Sigue 348 L’art du développement Android Les modifications nécessaires sont les suivantes : 1. L’activité LoremDemo reçoit un élément meta-data avec un attribut android:name valant android.app.default_searchable et un attribut android:value contenant la classe qui implémente la recherche (.LoremSearch). 2. L’activité LoremSearch reçoit un filtre d’intention pour android.intent.action.SEARCH, afin que les intentions de recherche puissent être sélectionnées. LoremSearch reçoit l’attribut android:launchMode = « singleTop », ce qui signifie qu’une seule instance de cette activité sera ouverte à un instant donné, afin d’éviter que tout un lot de petites activités de recherche encombre la pile des activités.
L’activité
LoremSearch reçoit un élément meta-data doté d’un attribut android:name valant android.app.searchable et d’un attribut android:value pointant vers une ressource XML contenant plus d’informations sur la fonctionnalité de recherche offerte par l’activité (@xml/searchable). Actuellement, cette ressource XML fournit deux informations : ● le nom qui doit apparaître dans le bouton du domaine de recherche à droite du champ de saisie, afin d’indiquer à l’utilisateur l’endroit où il recherche (android:label) ; ● le texte qui doit apparaître dans le champ de saisie, afin de donner à l’utilisateur un indice sur ce qu’il doit taper (android:hint). Livre Android.book Page 348 Dimanche, 8. novembre 2009 12:23 12 customer 27921 at Fri Mar 11 19:19:45 +0100 2011 Propriété de Albiri Sigue Chapitre 36 Recherches avec SearchManager 349 Effectuer une recherche Android sait désormais que votre application peut être consultée, connaît le domaine de recherche à utiliser lors d’une recherche à partir de l’activité principale et l’activité sait comment effectuer la recherche. Le menu de cette application permet de choisir une recherche locale ou une recherche globale. Pour effectuer la première, on appelle simplement onSearchRequested() ; pour la seconde, on appelle startSearch() en lui passant true dans son dernier paramètre, afin d’indiquer que la portée de la recherche est globale. En tapant une lettre ou deux, puis en cliquant sur le bouton, on lance l’activité de recherche et le sous-ensemble des mots contenant le texte recherché s’affiche. Le texte tapé apparaît dans la barre de titre de l’activité, comme le montre la Figure 36.3. Vous pouvez obtenir le même effet en commençant à taper dans l’activité principale car elle est configurée pour déclencher une recherche locale. Figure 36.3 L’application Lorem, montrant une recherche locale.