この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
AIR for Androidでネイティブ拡張を試しました その2 の続きです。
今回はネイティブの音声認識を利用したサンプルを作成します。 ソースは前回作ったものを使います。
まずはネイティブ側の実装です。 その1で作ったSampleFREExtensionを以下のように修正します 前回と違う点はファンクションの名前とstatic変数にFREContextを格納しているところです。
package sample.ane;
import java.util.HashMap;
import java.util.Map;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREExtension;
import com.adobe.fre.FREFunction;
public class SampleFREExtension implements FREExtension {
public static FREContext context;
@Override
public FREContext createContext(String arg0) {
if(context == null) {
context = new FREContext() {
@Override
public Map<String, FREFunction> getFunctions() {
Map<String, FREFunction> result = new HashMap<String, FREFunction>();
result.put("recognizeSpeech", new MyFREFunction());
return result;
}
@Override
public void dispose() {}
};
}
return context;
}
@Override
public void dispose() {}
@Override
public void initialize() {}
}
次にMyFREFunctionのcallメソッド内を以下のように修正します。 処理としてはSampleActivityというアクティビティを呼び出しているだけになります。
package sample.ane;
import android.app.Activity;
import android.content.Intent;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREFunction;
import com.adobe.fre.FREObject;
import com.adobe.fre.FREWrongThreadException;
public class MyFREFunction implements FREFunction {
@Override
public FREObject call(FREContext arg0, FREObject[] arg1) {
try {
Activity activity = arg0.getActivity();
Intent intent = new Intent(activity, SampleActivity.class);
activity.startActivity(intent);
return null;
} catch (Exception e) {
try {
return FREObject.newObject(e.toString());
} catch (FREWrongThreadException e1) {}
}
return null;
}
}
次にcallメソッド内で呼び出しているSampleActivityを実装します。 onCreate内で暗黙的なIntentで音声認識の画面に遷移します。 結果をonActivityResult内で取得して検索結果を格納したStatusEventをFREContextにディスパッチします。 イベントをディスパッチしたらアクティビティを終了します。
実装が完了したら前回と同じようにjarファイルを作成して下さい。
package sample.ane;
import java.util.List;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognizerIntent;
public class SampleActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
"SampleActivity");
startActivityForResult(intent, 0);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 0 && resultCode == RESULT_OK) {
List<String> results = data.getStringArrayListExtra(
RecognizerIntent.EXTRA_RESULTS);
SampleFREExtension.context.dispatchStatusEventAsync(results.get(0), "result");
}
super.onActivityResult(requestCode, resultCode, data);
finish();
}
}
次にネイティブ拡張を修正します。 前回とは違いEventDispatcherをスーパークラスにしています。これはネイティブ側から受け取ったStatusEventをディスパッチするためです。 recognizeSpeechファンクションの戻り値はエラーが発生した場合のログ取得用で音声検索の結果はStatusEventから取得します。
実装できたら前回と同じ方法でANEファイルを作成します。
package sample.ane
{
import flash.events.EventDispatcher;
import flash.events.StatusEvent;
import flash.external.ExtensionContext;
public class SampleExtension extends EventDispatcher
{
private var context:ExtensionContext;
public function SampleExtension() {
context = ExtensionContext.createExtensionContext(
"sample", "type");
}
public function recognizeSpeech():String {
context.addEventListener(StatusEvent.STATUS, statusHandler);
return context.call("recognizeSpeech") as String;
}
private function statusHandler(event:StatusEvent):void {
dispatchEvent(event);
}
public function dispose() : void {
return context.dispose();
}
}
}
最後にAIRのソースコードです。 ボタンを押すと音声認識の画面に遷移します。 そこで何か音声を入力すると検索結果がTextAreaに表示されます。
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" applicationDPI="160">
<fx:Script>
<![CDATA[
import sample.ane.SampleExtension;
private var extension:SampleExtension;
protected function button1_clickHandler(event:MouseEvent):void
{
extension = new SampleExtension();
extension.addEventListener(StatusEvent.STATUS, statusHandler);
extension.recognizeSpeech();
}
private function statusHandler(event:StatusEvent):void {
textArea.text = event.code;
}
]]>
</fx:Script>
<s:VGroup width="100%" height="100%">
<s:Button width="100%" label="Recognize Speech" click="button1_clickHandler(event)"/>
<s:TextArea id="textArea" width="100%" height="100%"/>
</s:VGroup>
</s:Application>
最後にActivityを追加した場合はネイティブアプリ同様Activityを登録する必要があります。 アプリケーション記述ファイル(*-app.xml)の下の方にパーミッションなどを設定している箇所があるので、 以下のように修正します。
<android>
<colorDepth>16bit</colorDepth>
<manifestAdditions><![CDATA[
<manifest android:installLocation="auto">
<!--See the Adobe AIR documentation for more information about setting Google Android permissions-->
<!--android.permission.INTERNET 権限を削除すると、
デバイス上でアプリケーションをデバッグできなくなります-->
<uses-permission android:name="android.permission.INTERNET"/>
<!--<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>-->
<!--<uses-permission android:name="android.permission.READ_PHONE_STATE"/>-->
<!--<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>-->
<!--AIR の SystemIdleMode API にアクセスするには、DISABLE_KEYGUARD 権限と
WAKE_LOCK 権限を同時に切り替える必要があります-->
<!--<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>-->
<!--<uses-permission android:name="android.permission.WAKE_LOCK"/>-->
<!--<uses-permission android:name="android.permission.CAMERA"/>-->
<!--<uses-permission android:name="android.permission.RECORD_AUDIO"/>-->
<!--AIR の NetworkInfo API を使用するには、ACCESS_NETWORK_STATE 権限と
ACCESS_WIFI_STATE 権限を同時に切り替える必要があります-->
<!--<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>-->
<!--<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>-->
<application>
<activity>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="sample.ane.SampleActivity"></activity>
</application>
</manifest>
]]></manifestAdditions>
</android>