0
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?

More than 1 year has passed since last update.

AndroidAdvent Calendar 2023

Day 9

DreamServiceでエオルゼア時計スクリーンセーバーを作る

Posted at

はじめに

この話は『 ThinkSmart View for Zoom 』という製品の新古品を結構安いお店で買ったところから始まります。
とりあえずROMイメージをごにょごにょして(保障対象外です)APKのインストールができるようになりましたが、何に使いましょうか…。
そうだね、エオルゼア時計だね!(お約束)
せっかくなのでスクリーンセーバー化して、いつでも見れるようにしましょう。

コード

アドベントカレンダー進行というわけで、ガシガシとコーディングしていきましょう。

レイアウトXML

簡易的な割に長いので折りたたんでいます
daydream.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal|center_vertical"
    android:background="#000000"
    android:gravity="center_vertical"
    android:orientation="vertical">

    <TextView
        android:id="@+id/title_lt"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:text="Local Time"
        android:textAlignment="center"
        android:textColor="#FFFFFF"
        android:textSize="50dp" />

    <TextView
        android:id="@+id/local_clock"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"
        android:text="00:00:00"
        android:textAlignment="center"
        android:textColor="#FFFFFF"
        android:textSize="100sp" />

    <Space
        android:layout_width="match_parent"
        android:layout_height="50dp" />

    <TextView
        android:id="@+id/title_et"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:text="Eorzea Time"
        android:textAlignment="center"
        android:textColor="#FFFFFF"
        android:textSize="50dp" />

    <TextView
        android:id="@+id/eorzea_clock"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"
        android:text="00:00:00"
        android:textAlignment="center"
        android:textColor="#FFFFFF"
        android:textSize="100sp" />

</LinearLayout>

DreamService用 Javaコード

Daydream.java
package jp.rainyvillage.android.daydreamtest2;
import android.service.dreams.DreamService;
import android.util.Log;

import java.util.Timer;

public class Daydream extends DreamService {
    private Timer dispUpdateTimer;
    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        setInteractive(true);
        setFullscreen(true);
        setContentView(R.layout.daydream);

    }

    @Override
    public void onDreamingStarted() {
        super.onDreamingStarted();
        this.dispUpdateTimer = new Timer();
        this.dispUpdateTimer.schedule(new DispUpdateTimerTask(this), 0, 500);
    }

    @Override
    public void onDreamingStopped() {
        super.onDreamingStopped();
        if (this.dispUpdateTimer != null) {
            this.dispUpdateTimer.cancel();
        }
    }
}

表示更新用TimerTask

DispUpdateTimerTask.java
package jp.rainyvillage.android.daydreamtest2;

import android.util.Log;
import android.view.View;
import android.widget.TextView;

import java.util.Calendar;
import java.util.TimeZone;
import java.util.TimerTask;

public class DispUpdateTimerTask extends TimerTask {
    private static final long SEC_OF_MIN = 60;
    private static final long SEC_OF_HOUR = SEC_OF_MIN * 60;
    private static final long SEC_OF_DAY = SEC_OF_HOUR * 24;
    Daydream daydream;
    Calendar calendarDefault;
    Calendar calendarTokyo;
    public DispUpdateTimerTask (Daydream daydream) {
        super();
        this.daydream = daydream;
        this.calendarDefault = Calendar.getInstance();
        this.calendarDefault.setTimeZone(TimeZone.getDefault());
        this.calendarTokyo = Calendar.getInstance();
        this.calendarTokyo.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));
    }
    public void run () {
        TextView localClock = (TextView)daydream.findViewById(R.id.local_clock);
        TextView eorzeaClock = (TextView)daydream.findViewById(R.id.eorzea_clock);

        long now = System.currentTimeMillis();
        calendarDefault.setTimeInMillis(now);
        int localSec = calendarDefault.get(Calendar.SECOND);
        int localMin = calendarDefault.get(Calendar.MINUTE);
        int localHour = calendarDefault.get(Calendar.HOUR) + (12 * calendarDefault.get(Calendar.AM_PM));
        String strLocalClock = String.format("%02d:%02d:%02d", localHour, localMin, localSec);

        calendarTokyo.setTimeInMillis(now);
        long dayOfWeek = calendarTokyo.get(Calendar.DAY_OF_WEEK) - 1;
        long hour = calendarTokyo.get(Calendar.HOUR) + (12 * calendarTokyo.get(Calendar.AM_PM));
        long min = calendarTokyo.get(Calendar.MINUTE);
        long sec = calendarTokyo.get(Calendar.SECOND);
        long weekSec = (SEC_OF_DAY * dayOfWeek) + (SEC_OF_HOUR * hour) + (SEC_OF_MIN * min) + sec;
        long eorzeaWeekSec = (long)(weekSec * (1440f / 70f));
        int eorzeaMin = (int)((eorzeaWeekSec / SEC_OF_MIN) % 60);
        int eorzeaHour = (int)((eorzeaWeekSec / SEC_OF_HOUR) % 24);
        String strEorzeaHourMin = String.format("%02d:%02d:--", eorzeaHour, eorzeaMin);

        localClock.setText(strLocalClock);
        eorzeaClock.setText(strEorzeaHourMin);
    }
}

AndroidManifest

AndroidManifest.xml
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.rainyvillage.android.daydreamtest2">
    <uses-sdk android:targetSdkVersion="17" android:minSdkVersion="17"/>
    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:allowBackup="false">

        <service
            android:name=".Daydream"
            android:exported="true"
            android:label="@string/app_name"
            android:icon="@mipmap/ic_launcher"
            android:permission="android.permission.BIND_DREAM_SERVICE">
            <intent-filter>
                <action android:name="android.service.dreams.DreamService" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>
    </application>
</manifest>

解決が難航したところ

アプリを実機に転送すると、スクリーンセーバーの一覧に表示はされるのですが、選択することができませんでした。
StackOverflowのこの記事を参照したところ、API level 21以上の場合はDreamServiceのパーミッションを与える記述をマニフェストに入れなければならないそうです。
※上記のマニフェストファイルには記述済みです。

動作の様子

スクリーンショット 実機での写真
Screenshot_20231209-213354.png DSC00692.JPG

さいごに

ほかにもいろいろなエオルゼア時計を作っているので、ぜひご覧ください☆

0
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
0
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?