GetWildDay 6

Android端末にGetWildを歌わせる

More than 1 year has passed since last update.

GetWild Advent Calendar 2016の6日目です!!


はじめに

このカレンダーに参加を決めて何を書くか考えている時に、パッと浮かんだのはこちらの記事でした!

そこで、同じようにAndroid端末が盗まれそうになったらできないかなーと思い、Wearと連携させることで実現できるのではないかと開発を始めました。


概要


  • AndroidMobileに接続されているWearから歌をリクエストするとMobileが歌います

  • AndroidMobileがWearから離れすぎて接続が切れるとMobileが歌います


動画


pic.twitter.com/pwUvb6jc5G

— futabooo (@futabooo) 2016年12月4日


コード


Mobile側

Mobile側で特定のServiceを起動している状態でのみ歌うようにします。

ServiceがWearからのMessageを受け取れるようにManifestに下記を追加します。


AndroidManifest.xml

<service android:name=".GetWildListenerService">

<intent-filter>
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED"/>
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
<data
android:host="*"
android:scheme="wear"/>
</intent-filter>
</service>

dataタグの中ではoptionとしてandroid:pathPrefix="/prefix"も使えるので、もっと細かいことがしたい場合は使えそうです。

WearableListenerService

GetWildListenerServiceはこんな感じです。

歌うときだけ音量MAXにしています。

onPeerDisconnectedonMessageReceivedがそれぞれMobileとWearの接続が切れたとき、Messageを受け取った時に呼ばれるメソッドです。


GetWildListenerService.java

public class GetWildListenerService extends WearableListenerService {

private TextToSpeech tts;

private AudioManager audioManager;
private int originalVol;
private int maxVol;

@Override
public void onCreate() {
super.onCreate();

// 歌う時に音量MAXにするために
audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
originalVol = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
maxVol = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);

tts = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
Log.d(TAG, "tts onInit");
}
});
}

@Override
public void onDestroy() {
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, originalVol, 0);
super.onDestroy();
}

@Override
public void onPeerDisconnected(Node node) {
super.onPeerDisconnected(node);
Log.d(TAG, "onPeerDisconnected");
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, maxVol, 0);
startSing();
}

@Override
public void onMessageReceived(MessageEvent messageEvent) {
super.onMessageReceived(messageEvent);
Log.d(TAG, "onMessageReceived");
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, maxVol, 0);
startSing();
}

private void startSing() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
if (!sp.getBoolean("isEnable", false)) {
return;
}

getWildAndTough(Locale.ENGLISH, getString(R.string.lyrics_get_wild_and_tough));
getWildAndTough(Locale.JAPAN, getString(R.string.lyrics_1));
getWildAndTough(Locale.ENGLISH, getString(R.string.lyrics_get_wild_and_tough));
getWildAndTough(Locale.JAPAN, getString(R.string.lyrics_2));
getWildAndTough(Locale.ENGLISH, getString(R.string.lyrics_get_chance_and_luck));
getWildAndTough(Locale.JAPAN, getString(R.string.lyrics_3));
getWildAndTough(Locale.ENGLISH, getString(R.string.lyrics_get_chance_and_luck));
getWildAndTough(Locale.JAPAN, getString(R.string.lyrics_4));
}

private void getWildAndTough(Locale locale, String string) {
// 日本語遅すぎなので歌っぽくするために
if (locale == Locale.JAPAN) {
tts.setSpeechRate(2.0f);
} else if (locale == Locale.ENGLISH) {
tts.setSpeechRate(1.0f);
}

tts.setLanguage(locale);
tts.speak(string, TextToSpeech.QUEUE_ADD, null, "1");
}
}



Wear側

Waer側からはMobileに対してメッセージを送る実装をします。

sendMessage"/get-wild"がAndroidManifestでoptionとして追加可能なprefix部分です。


WearMainActivity.java

public class WearMainActivity extends Activity {

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

WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
@Override
public void onLayoutInflated(WatchViewStub stub) {
Button button = (Button) stub.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
// Mobile側へメッセージを送る
GoogleApiClient client = new GoogleApiClient.Builder(getApplicationContext()).addApi(Wearable.API).build();
client.blockingConnect(100, TimeUnit.MILLISECONDS);
NodeApi.GetConnectedNodesResult result = Wearable.NodeApi.getConnectedNodes(client).await();
List<Node> nodes = result.getNodes();
if (nodes.size() > 0) {
client.blockingConnect(100, TimeUnit.MILLISECONDS);
Wearable.MessageApi.sendMessage(client, nodes.get(0).getId(), "/get-wild", null);
client.disconnect();
}
client.disconnect();
}
}).start();
}
});
}
});
}
}



おわりに

どれぐらいの距離を離れると接続が切れるのか試すことができませんでしたorz

Bluetoothの接続可能な距離って結構長いんですねw

TextToSpeechのチューニングしだいでもっと歌っぽくできそうです。

今回作ったものはここに置いてあります

https://github.com/futabooo/getwild


参考

https://developer.android.com/reference/android/speech/tts/TextToSpeech.html

https://developer.android.com/training/wearables/data-layer/messages.html