将语音搜索集成到Google Now中

原文标题:Use Voice Search to integrate with Google Now

原文链接:http://antonioleiva.com/voice_search_google_now/

原文作者:Antonio Leiva(http://antonioleiva.com/about/

原文发布:2015-10-14

Android最棒的能力之一就是可以将我们的APP以不同的方式集成到它的生态链中。APP相互之间可以进行“交流”,这给予我们极大的灵活性来创建独特的应用体验。

集成Google应用就是一个典型的例子。有很多不同的特性可以帮助我们提升APP的知名度,如APP索引或一组强大的语音功能

语音搜索

尽管,在APP中实现语音搜索的过程与任何其他语音功能类似,但是,在这篇文章中,我还是会聚焦在怎样在APP中实现语音搜索功能。你也可以在Play Music中尝试这个例子:

  • 好,GooglePlay Music中,搜索Beatles

这句指令将在Play Music APP中开启搜索Beatles。

怎样实现语音搜索

当语音搜索启动后,我们的APP将收到一个查询文字的Intent,我们必须捕捉和分析这段文字。所以,这第一部分是指定哪个Activity接收这条Intent:

1 <activity android:name=".MainActivity" android:launchMode="singleTask" >
2     <intent-filter>
3         <action android:name="com.google.android.gms.actions.SEARCH_ACTION"/>
4         <category android:name="android.intent.category.DEFAULT"/>
5     </intent-filter>
6 </activity>

这个动作(action)称为com.google.android.gms.actions.SEARCH_ACTION,所以我们说MainActivity是处理这类Intent。另外,我用singleTask启动模式,这样MainActivity就仅仅创建一次。否则,每次收到这条Intent就要创建一个新的Activity实例。

接下来的一步是要在MainActivity内进行处理它。当我们用singleTask模式时,在Activity的两个不同位置上可以接收Intent:首先是用getIntent()创建Activity,接着是onNewIntent方法中。这样就要创建一个处理方法在需要它的时候调用它:

1     private static final String ACTION_VOICE_SEARCH = "com.google.android.gms.actions.SEARCH_ACTION";
2   ...
3     private void handleVoiceSearch(Intent intent) {
4         if (intent != null && ACTION_VOICE_SEARCH.equals(intent.getAction())) {
5             String query = intent.getStringExtra(SearchManager.QUERY);
6             setSearchViewVisible(true);
7             searchView.setQuery(query, true);
8         }
9     }

这个方法检查Intent是否为空(null)或者是否是在收到查询文字前要检测的动作,它是Intent内部的额外动作。查询的额外动作关键字是SearchManager.QUERY。

在searchView后,设置查询,提交执行查询。其方法是onNewIntent:

1 @Override protected void onNewIntent(Intent intent) {
2     super.onNewIntent(intent);
3     handleVoiceSearch(intent);
4 }

UI也准备好(在我们的例子中,当菜单弹出时,我们访问SearchView),你稍后将看到。

在我的例子中,UI是基于工具栏(Toolbar)内部的SearchView。你可以在前面的文章中看到怎样实现SearchView,不过我还是稍作解释怎样做。首先,产生菜单动作(menu action):

1 <menu xmlns:android="http://schemas.android.com/apk/res/android"
2       xmlns:app="http://schemas.android.com/apk/res-auto">
3     <item
4         android:id="@+id/action_search"
5         android:title="@string/action_search"
6         android:icon="@drawable/ic_search"
7         app:actionViewClass="android.support.v7.widget.SearchView"
8         app:showAsAction="ifRoom" />
9 </menu>

然后,在菜单弹出时,你请求SearchView:

 1 @Override public boolean onCreateOptionsMenu(Menu menu) {
 2     getMenuInflater().inflate(R.menu.main, menu);
 3
 4     MenuItem searchItem = menu.findItem(R.id.action_search);
 5     searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
 6
 7     searchView.setOnSearchClickListener(new View.OnClickListener() {
 8         @Override public void onClick(View v) {
 9             setSearchViewVisible(true);
10         }
11     });
12
13     searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
14         @Override public boolean onQueryTextSubmit(String query) {
15             Toast.makeText(MainActivity.this, query, Toast.LENGTH_LONG).show();
16             searchView.clearFocus();
17             return true;
18         }
19
20         @Override public boolean onQueryTextChange(String newText) {
21             return false;
22         }
23     });
24
25     handleVoiceSearch(getIntent());
26
27     return true;
28 }
29
30 private void setSearchViewVisible(boolean visible) {
31
32     if (searchView.isIconified() == visible) {
33         searchView.setIconified(!visible);
34     }
35
36     if (getSupportActionBar() != null) {
37         getSupportActionBar().setDisplayHomeAsUpEnabled(visible);
38     }
39 }

怎样尝试

由于APP需要发布到Play商店中,Google Now才能检测到APP,所以我们还不能直接从Google Now尝试这个例子。但是,我们可以用ADB来调试它。这条命令是:

  • adb shell am start -a com.google.android.gms.actions.SEARCH_ACTION -e query searchquery app_package

对于从我的代码库下载的例子,就可以这样做:

  • adb shell am start -a com.google.android.gms.actions.SEARCH_ACTION -e query VoiceSearch com.antonioleiva.googlenowsearch

在APP完全关闭和启动时,都可以尝试本例了。这样,就可以测试两种可能的途径了。

附加说明:Kotlin语言的实现

你可能知道,因为我认为Kotlin语言可以非常好替代Java语言,Kotlin可以使我们的代码更简洁、可读性更好,所以这些天讨论了许多Kotlin语言的特性。作为例子,我将简化onCreateOptionsMenu,你可以在同一个代码库中找到完整的代码。

实现扩展函数的能力可以帮助我们减少冗长代码。例如,可以为Menu创建一个扩展函数,基于action id找到ActionView,返回层级视图:

1 inline fun <reified T : View?> Menu.findCompatActionView(actionRes: Int): T {
2     val searchItem = findItem(actionRes)
3     return MenuItemCompat.getActionView(searchItem) as T
4 }

现在可以这样做:

1 searchView = menu.findCompatActionView(R.id.action_search)

另一个扩展函数可以以清晰的方式帮助我们编写OueryTextListener:

 1 fun SearchView.onQueryText(submit: (String) -> Boolean = { false }, textChange: (String) -> Boolean = { false }) {
 2
 3     this.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
 4
 5         override fun onQueryTextSubmit(query: String): Boolean = submit(query)
 6
 7         override fun onQueryTextChange(newText: String): Boolean = textChange(newText)
 8
 9     })
10 }

这个函数接收一对函数,一个用于侦听器中的每个方法,并给出它们的默认值。这样我们仅需要定义我们要用的。如果我们仅仅要第一个函数(对于第二个我们用默认的),现在我就可以这样做:

1 searchView.onQueryText ({
2     longToast(it)
3     searchView.clearFocus()
4     true
5 })

最终,这个函数就是这样的:

 1 override fun onCreateOptionsMenu(menu: Menu): Boolean {
 2     menuInflater.inflate(R.menu.main, menu)
 3
 4     searchView = menu.findCompatActionView(R.id.action_search)
 5     searchView.setOnSearchClickListener { setSearchViewVisible(true) }
 6
 7     searchView.onQueryText ({
 8         longToast(it)
 9         searchView.clearFocus()
10         true
11     })
12
13     intent?.let { handleVoiceSearch(it) }
14
15     return true
16 }

如你所见,如果在这个位置上(例如:在一个常规activity创建上),Intent可以为null,就必须在使用它之前检查它是否为null。用let函数,可以避免if条件的创建,在对象调用时不为null,就可只进入对象内部。

如果你对Kotlin有兴趣,可以搜索Kotlin文章,或购买我编写的《Android开发者的Kotlin》一书。

时间: 2024-10-07 06:28:50

将语音搜索集成到Google Now中的相关文章

讯飞语音云助力赶集网推出语音搜索 推动生活服务智能应用

近日,全球首个免费开放的智能语音交互平台与国内最大分类信息门户网站之赶集网完美联姻,由讯飞语音云为赶集网手机客户端提供语音搜索本地生活服务功能,用户可通过赶集生活新版APP体验该全新功能. 讯飞语音云,致力于为开发者打造一站式智能人机交互解决方案,免费开放了全球领先的语音识别.语音合成和语义理解等核心技术,让应用具备能听会说会思考的能力:同时开放了业界领先的应用统计分析平台,简单集成,便可全面掌控应用的发展趋势:与此同时,语音唤醒.个性化彩铃.应用分发等能力也相继开放,与开发者携手共赢,共创精彩

从Google Earth 中下载三维模型

1.首先下载安装Google Earth和 Sketch Up (Sketch Up 201532位和64位下载地址:http://pan.baidu.com/s/1i3pCMjz) 2.由于国内限制google的访问,打开Google Earth后,选中模型无法获取其信息,所以这里提供一个Hosts文件,效果与FQ类似.将该文件替换 C:\Windows\System32\drivers\etc目录下的hosts文件(下载地址:http://pan.baidu.com/s/1c0cY43u).

在Google Map中使用地址获取坐标(适用小数据量)

近期手上有个95条数据的地址信息,想把地址转换成经纬度坐标,叠加在底图上.ESRI的online作为专业的云平台,号称提供地理编码服务,可能使用自己的数据制作Web map,于是转成CSV后试了下,结果只有4条记录转换成坐标了,并且都偏离了一个省的范围,基本上不可用.后来想在google earth上试下,使用地址搜索,也不知道是服务器慢,还是什么其他原因,earth的搜索功能简直处于瘫痪状态,打一个地址,10分钟能反应过来,结果基本上是找不到.无奈之下,又试了试google Map,Map上是

如何在Google Map中处理大量标记(ASP.NET)(转)

如何在Google Map中处理大量标记(ASP.NET)(原创-翻译) Posted on 2010-07-29 22:04 Happy Coding 阅读(8827) 评论(8) 编辑 收藏 在你有一个合理的标记数量的时候,使Google Map标记是很平常的.但是一旦你有几百个.甚至更多地标的时候,性能迅速的开始降低.在本文章中,我会告诉你一些提高性能的方法.同时我会放一个测试页面去比较它们的效率. 如果你是第一次使用Google Map的标记,我建议你先去了解一下在Google Map上

如何用Google APIs和Google的应用系统进行集成(1)----Google APIs简单介绍

Google的应用系统提供了很多的应用,比如 Google广告,Google 任务,Google 日历,Google blogger,Google Plus,Google 地图等等非常的多的应用,请见下图, 下图中列出的只是Google APIs中的冰山一角(Google API总共支持大约80几种不同种类和版本的Google API,我将在后面的章节中详细列出).有的时候,我们需要把这些系统的数据集成到我们自己的系统当中(自己开发的Web系统,或者其他的系统当中).这个时候,我们就不得不了解如

谷歌:调查显示美国青少年比成年人更喜欢使用语音搜索

谷歌今日发布了其移动语音研究(Mobile Voice Study)的调查报告,结果显示美国青少年比成年人更喜欢使用语音搜索,即使在浴室里时也会使用语音搜索.谷歌此项调查的目的是看不同年龄段的美国智能手机用户在语音搜索使用习惯上各自有何特点和区别.研究报告称,在年龄介于13岁到18岁之间的青少年当中,约有55%的人每天都要使用语音搜索:而在成年人中,约有56%的人表示使用语音搜索会令他们感觉自己很懂技术. 不管是青少年还是成年人,均有38%的人会在看电视的时候通过手机使用语音搜索,41%的人希望

Google Chrome中的高性能网络 (三)

使用预连接优化了TCP连接管理 已经预解析到了主机名,也有了由OmniBox和Chrome Predictor提供信号,预示着用户未来的操作.为什么再进一步连接到目标主机,在用户真正发起请求前完成TCP握手呢?这样就可省掉了另一个往返的延迟,轻易地就能为用户节省到上百毫秒.其实,这就是TCP预连接的工作. 通过访问chrome://dns 就可以看到TCP预连接的使用情况. 首先, Chrome检查它的socket pool里有没有目标主机可以复用的socket, 这些sockets会在sock

Google 云计算中的 GFS 体系结构(整理分析)

      google 公司的很多业务具有数据量巨大的特点,为此,google 公司研发了云计算技术.google 云计 算结构中的 google 文件系统是其云计算技术中的三大法宝之一.本文主要介绍了 google 公司根据自己公司应 用对文件系统的要求设计的 GFS 的体系结构,首先简单介绍了 google 云计算平台,然后介绍了 google 公司 设计的 GFS 框架,对其中的三类组件的功能.组件之间的交互和框架的特点进行了说明,接着通过介绍基于 GFS 框架构建的 google 文件

将SCONS工具集成到Python代码中

SCONS是Python的自动智能结构化编译工具,将来或许能代替Make. 在Windows或者Linux下,SConstruct文件相当于MakeFile,使用SCONS编译,需输入scons.bat(scons),后面带上编译选项options(如SConstruct所在的路径).观察scons.bat这个脚本,可以在其他Python代码中,将SCONS工具当作一个函数来调用.这个函数就是Scons.Script.main(),这个main函数将解析命令行中的编译选项,通过sys.argv[