1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Nothing Phoneの背面についてるライトをいじれるSDKが公開されてたので試す【Glyph Interface】Glyph Developer Kit

Last updated at Posted at 2024-09-05

NothingPhoneの背面に無駄に搭載されているライト「Glyph Interface」をいじれるSDKが公開されていることを今日知りました

Phone(2a)をメインで使用しているので試してみます

今回作ったもの

環境

  • Windows11 64bit 23H2
  • Android Studio Koala Feature Drop 2024.1.2
  • Nothing Phone(2a) 国内版
  • Nothing OS 2.6

セットアップ

プロジェクトはEmptyViewsActivityテンプレートから言語をJavaに、MinimumSDKはNothingPhone以外サポートする必要がないので、API31(Android12)にして作成しました
(Javaなのは私がkotlin未履修のためです。kotlinできる方は適宜読み替えてください)
ちなみにSDKのGitHubリポジトリのReadmeにあるサンプルコードもJavaになっていました

NothingPhoneの開発者オプションからデバッグを有効化しようとすると「Glyph Interfaceのデバッグモード」という項目があるのを発見したので有効にします
Screenshot_20240905-092944.png

GlyphいじれるSDKをアプリで利用するには公式Webページから申請できるAPIキーが必要なのですが、このオプションを有効後48時間はキーを取得せずともテストキーで開発できるようです

試す

GlyphいじいじSDKはどこかのリポジトリに上がっているわけではなくjarファイルで提供されているのでプロジェクトに追加します
↓参考

GlyphいじいじSDKの利用には権限とAPIキーの記述が必要なので、AndroidManifest.xmlに書きます

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application>
        省略
        <!-- 権限 -->
        <uses-permission android:name="com.nothing.ketchum.permission.ENABLE"/>
    </application>

    <!-- APIキー書くところ -->
    <meta-data android:name="NothingKey" android:value="test"/>
</manifest>

ちなみに書き忘れると怖いエラーが出ます(一敗)

Error
java.lang.SecurityException: Not allowed to bind to service Intent { act=com.nothing.thirdparty.bind_glyphservice pkg=com.nothing.thirdparty cmp=com.nothing.thirdparty/.GlyphService }

Glyphインターフェースの操作はGlyphManagerクラスのインスタンスからいじいじするようなので、まずGlyphManagerクラスのインスタンスを作成→初期化、終了時には解放しないといけないようなのでアプリ終了時に開放する処理をreadmeをパクりながら書いてみました

MainActivity.java
package com.example.firstglyph;

import android.content.ComponentName;
import android.os.Bundle;
import android.util.Log;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import com.nothing.ketchum.Common;
import com.nothing.ketchum.GlyphException;
import com.nothing.ketchum.GlyphFrame;
import com.nothing.ketchum.GlyphManager;

public class MainActivity extends AppCompatActivity {

    GlyphManager gManager = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        GlyphManager.Callback gcallback = new GlyphManager.Callback() {
            @Override
            public void onServiceConnected(ComponentName componentName) {
                if (Common.is20111()) gManager.register(Common.DEVICE_20111);
                if (Common.is22111()) gManager.register(Common.DEVICE_22111);
                if (Common.is23111()) gManager.register(Common.DEVICE_23111);
                try {
                    gManager.openSession();
                } catch(GlyphException e) {
                    Log.e(gManager.toString(), e.getMessage());
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                try {
                    gManager.closeSession();
                } catch (GlyphException e) {
                    throw new RuntimeException(e);
                }
            }
        };

        gManager = GlyphManager.getInstance(getApplicationContext());
        gManager.init(gcallback);
    }

    @Override
    public void onDestroy()
    {
        try {
            gManager.closeSession();
        } catch (GlyphException e) {
            throw new RuntimeException(e);
        }
        gManager.unInit();
        super.onDestroy();
    }
}

まずこれをNothingPhoneにつないで動かして、起動できることを確認します
この時点ではGlyphインターフェースにはなにも変化はありません

とりあえず光らせる

適当にボタンを配置して、ボタンを押すとPhone(2a)の左下のGlyphが光るようにしてみます
各Glyphの名前は、GlyphいじいじSDKのreadmeに掲載されています
Frame 7
左下のやつはAのようなので、こんな感じに書きます

button1 = findViewById(R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ///ここが光らせる処理
                GlyphFrame.Builder builder = gManager.getGlyphFrameBuilder();
                GlyphFrame frame = builder.buildChannelA().build();
                gManager.toggle(frame);
            }
        });

IMG_20240905_172142.jpg

おおお!光った!!!!!

光らせる処理をonCreateとかonResumeに書けばアプリ起動すれば勝手に光らせられるのでは?と思い試したのですが、なぜかそれでは光りませんでした
なんで

光らせる部分の長さを調節する

また、Phone(2a)のGlyphのCは光っている部分の長さを調節することができます
ハードウェア的には消灯含め25段階あるようです

適当にボタンを追加して、Cを半分だけ光らせるコードを書いてみます

button2 = findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                GlyphFrame.Builder builder = gManager.getGlyphFrameBuilder();
                GlyphFrame frame = builder.buildChannelC().build();
                try {
                    //たぶん0~100で長さ調整できる
                    gManager.displayProgress(frame, 50);
                } catch (GlyphException e) {
                    throw new RuntimeException(e);
                }
            }
        });

IMG_20240905_174416.jpg

撮影環境の問題でよくわかりませんが、実物は下半分のみがしっかり点灯しています
オプションで上から伸ばしていくこともできるようです

SDKのreadmeにはCの中央や一部分だけ光らせる機能があるらしき記述がされているのですが、使い方がわからず試せていません

アニメーション

GlyphのBを「3秒間かけて明るさをゆっくり変化させた後に一秒待機を3回繰り返す」ようにするには

button3 = findViewById(R.id.button3);
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                GlyphFrame.Builder builder = gManager.getGlyphFrameBuilder();
                GlyphFrame frame = builder.buildChannelB().buildInterval(1000).buildCycles(3).buildPeriod(3000).build();
                gManager.animate(frame);
            }
        });

こんな感じになります
(動画を張り付けるのが面倒だったので、実際の動作は君の目で確かめてください)

注意点

フォアグラウンド動作限定?

readmeには「Only foreground applications are allowed to be used.」という記述があります
これが規約なのか技術的な制約なのかは不明ですが、Glyphをカスタマイズしまくって裏で常駐させるアプリには使えなさそうです。ぜひとも常駐できるようにしていただきたい
(ただし私の手元で試した限りだとWorkerを使ったバックグラウンド処理でも動きはしました)

ライセンス不明

このSDK、公式サイトにもリポジトリにもライセンスの記載が見当たりません

おわりに

発売日以降全く使っていなかったGlyph Interfaceがちょっとだけ輝きました

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?