Android

親フラ検知機を作る ②Android編

はじめに

この記事は、「親フラ検知機を作る ①仕組み編」の続き。

動作

AndroidではUDPを受け取って、その受け取った値によって以下の動作を行います。

'W'を受信 => 画面を特定のWEBページに強制推移
'D'を受信 => 人が近づいていることを画面に通知

コード

説明はコメントの通りです。

UDPを受信

UDP.kt
package com.akakou.sample.oyanoteki

import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
import java.io.IOException


object UDP {
    var ip = InetAddress.getByName("192.168.xxx.255") // ここは自分のネットワークに合わせて
    var port = 5000

    fun receive() : Byte {
        // UDPの受信
        val socket = DatagramSocket(port)
        val buffer = ByteArray(1024)
        val packet = DatagramPacket(buffer, 0, buffer.size)

        val result = try {
            socket.receive(packet)
            buffer[0]
        } catch (e: IOException) {
            0.toByte()
        }

        socket.close()

        return result
    }
}

サービス

MainService.kt
package com.akakou.sample.oyanoteki

import android.content.Intent
import android.app.IntentService
import android.net.Uri

import android.widget.Toast
import android.os.Handler
import android.os.Looper
import kotlinx.coroutines.experimental.delay
import java.lang.Thread.sleep
import kotlin.concurrent.thread


class MainService : IntentService("MainService") {
    var intent: Intent? = null

    override fun onHandleIntent(intent: Intent?) {
        val handler = Handler(Looper.getMainLooper())
        handler.post {
            Toast.makeText(applicationContext, "あなたの部屋を守ります", Toast.LENGTH_SHORT).show()
        }

        while (true) {
            try {
                var data = UDP.receive()  // UDPを受信

                if (data == 'W'.toByte()) {
                    // もし受信したデータが'W'だったら、
                    // Toastを表示する。
                    handler.post {
                        Toast.makeText(applicationContext, "奴が近づいている…\n気をつけろ…", Toast.LENGTH_SHORT).show()
                    }
                }

                if (data == 'D'.toByte()) {
                    // もし受信したデータが'D'だったら、
                    // Yahooニュースをブラウザで開く
                    val uri = Uri.parse("https://news.yahoo.co.jp/hl?c=bus")
                    val intent = Intent(Intent.ACTION_VIEW, uri)
                    startActivity(intent)
                }

            } catch (err: Exception) {
                handler.post {
                    Toast.makeText(applicationContext, "$err", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }
}

アクティビティ

MainActivity
package com.akakou.sample.oyanoteki

import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity


class MainActivity : AppCompatActivity() {
    private var serviceIntent : Intent? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // サービスを起動
        serviceIntent = Intent(this, MainService::class.java)
        startService(serviceIntent)
    }
}

デバッグ

デバッグ用のコードを同じネットワーク上のPCで実行する。
(FWの設定で躓かないように)

コード

以下のようなスクリプトを書いた。

client.py
from socket import *
import sys

HOST = ''
PORT = 5000
ADDRESS = "192.168.xxx.255"

s = socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)

while True:
    msg = input("> ")
    s.sendto(msg.encode(), (ADDRESS, PORT))
    if msg == ".":
        break

s.close()
sys.exit()

実行結果

以下のような入力をして正しく動作したか確認する。

> W
> D
>

正しく動作すれば、警告が表示された後、画面がYahooニュースに切り替わるはずである。

次回予告

次回からは@Tsukkeyが、ESP32①(ドア開閉検知)に関する部分をやると思います。