スマートウォッチをリマインダ代わりにバイブレーションさせる：その２

前回、スマートウォッチをリマインダ代わりにバイブレーションさせました。（[スマートウォッチをリマインダ代わりにバイブレーションさせる](https://qiita.com/poruruba/items/f172dd99cf497761ce18)）
その際に、Webページから通知できるようにするため、WebAPIを用意しました。
今回はこれを利用して、複数のスマホの通知を集約します。

そもそも、スマートウォッチが何の関係もない別のアプリの通知を受信できることを不思議に思われるかもしれません。
これは、Androidの権限の設定により、Androidスマホに来たすべての通知をハンドリングできるように権限が与えられているためです。言われてみれば、確かにそうでないと例えばLINE通知を関係のないスマートウォッチに表示させることはできないですね。

今回は、別のスマホで受けた通知を普段持ち歩いているスマホに通知するようにします。
こうすると、スマホの複数持ちをしていても、1台のスマホに通知が集約され、通知が来たことに気づくことができます。

別の場所から通知することは、前回の投稿で実現できています。WebAPIを呼び出せばいいだけです。
残りの作成分は、スマホの通知をキャッチして、それをもとにWebAPIを呼び出す部分です。今回はこれを作ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/f20f0fd6-f5f3-77eb-d219-443939e803af.png)

ソースコードもろもろは以下にあります。
通知をアップロードするAndroidアプリケーションは「NotificationUploader」で、通知を受け取ってバイブレーションに転送するアプリケーションは「NotificationCenter」です。

poruruba/NotificationManager

https://github.com/poruruba/NotificationManager

# 実装する機能

実現するためには、以下の機能の実装が必要です。

①キャッチするアプリケーションを選択できるようにする
②すべての通知をキャッチする
③通知の内容をBodyに指定してWebAPIを呼び出す
④インストール後、通知へのアクセスを許可する

## ①キャッチするアプリケーションを選択できるようにする

詳細はこちらをご参照ください。
　[Androidの通知をM5Core2に転送する](https://qiita.com/poruruba/items/59416a860242d20acc3b)

スマホにインストールされているすべてのアプリケーションは次で取得できます。

```java:Android\NotificationUploader\app\src\main\java\com\example\notificationuploader\MainActivity.java
        packageManager = getPackageManager();
        List<ApplicationInfo> dataList = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
        for( int index = 0 ; index < dataList.size() ; index++ ){
            ApplicationInfo info = dataList.get(index);
            if( info.packageName.equals(getPackageName()) ){
                dataList.remove(index);
                break;
            }
        }
```

ただし、この前に、AndroidManifest.xmlに権限を設定しておく必要があります。

```xml:Android\NotificationUploader\app\src\main\AndroidManifest.xml
    <uses-permission
        android:name="android.permission.QUERY_ALL_PACKAGES"
        tools:ignore="QueryAllPackagesPermission" />
```

この中から転送したいアプリケーションを選択します。
選択したアプリケーションがどれかは、記憶しておく方が都合がよいので、Sqlite3で保持しておきます。ここら辺は難しくないと思います。詳細は、NotificationDbHelper.javaをご参照ください。

## ②すべての通知をキャッチする

詳細はこちらをご参照ください。
　[Androidの通知をM5Core2に転送する](https://qiita.com/poruruba/items/59416a860242d20acc3b)

NotificationListenerServiceを継承したクラスを作成します。。今回は、MyNotificationListenerService.javaという名前です。
通知があるとonNotificationPostedというメソッドが呼ばれます。
この中で、Sqlite3を使って、選択済みのアプリケーションの通知かどうかも判別しています。

一方で、さきほどの派生クラスにAndroidOSから通知してもらうために、以下をAndroidManifest.xmlに記載します。

```xml:Android\NotificationUploader\app\src\main\AndroidManifest.xml
        <service
            android:name=".MyNotificationListenerService"
            android:exported="false"
            android:label="@string/app_name"
            android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
            <intent-filter>
                <action android:name="android.service.notification.NotificationListenerService" />
            </intent-filter>
        </service>
```

## ③通知の内容をBodyに指定してWebAPIを呼び出す

さきほどのonNotificationPostedの中で、以下を呼び出しています。大した処理ではないです。
実際の通知内容からどのような文章で転送するかどうかは、いろいろあると思いますので、カスタマイズしてみてください。

```java:Android\NotificationUploader\app\src\main\java\com\example\notificationuploader\MyNotificationListenerService.java
                String message_body;
                if (tickerText != null) {
                    message_body = tickerText.toString();
                } else {
                    message_body = text.toString();
                    if (title != null)
                        message_body = title + ":" + message_body;
                    if (subText != null)
                        message_body = message_body + ":" + subText.toString();
                }
                long datetime = Calendar.getInstance().getTimeInMillis();
                JSONObject request = new JSONObject();
                request.put("client_id", MainActivity.CLIENT_ID);
                request.put("topic", MainActivity.TOPIC);
                request.put("title", appName);
                request.put("body", message_body);
                request.put("datetime", datetime);

                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            JSONObject response = HttpPostJson.doPost_withApikey(MainActivity.BASE_URL + "/notification-push-message", request, MainActivity.API_KEY, DEFAULT_TIMEOUT);
                            Log.d(TAG, "HttpPostJson.doPost_withApikey OK");
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
                thread.start();
```

## ④インストール後、通知へのアクセスを許可する

インストール後、通知へのアクセスを許可するように設定します。
アプリ内で許可設定することもできると思いますが、重要な設定なので、今回は手動で設定します。

Androidの「設定」から「通知」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/7749288b-e6e9-a31b-11c5-f9baddb47f11.png)

次に、「デバイスとアプリの通知」を選択し、インストールしたアプリがあると思います。それを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/3cde618d-f5d0-65c2-27a9-10519afa4c30.png)

そこで表示される「通知へのアクセスを許可」をOnにします。
これで、以降通知をアプリが受信できるようになります。

## 補足

なぜか、LINEアプリからの通知は、ほぼ同じ内容が2回来るんですよね。詳細不明です。

以上