【Android Wear】Watch Faceの作成

# はじめに
xmlを用いたWatch Faceの作成方法について紹介。
Android StudioのNew Project→Watch Faceでのプロジェクト作成だと、非推奨クラス(`CanvasWatchFaceService`)を使用することになるので1から作成した(2022/09/27時点)。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/969e9bbd-58d5-7854-8604-eb44581cf57f.png" width="30%">

# 作成方法
### 依存関係の宣言
`build.gradle(:app)`ファイルにWatchFace用の依存関係を追加
```build.gradle
dependencies {
	implementation 'androidx.wear.watchface:watchface:1.1.1'
}
```

### レイアウトの作成
WatchFaceに表示するレイアウトの作成
```custom_watch_face.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:app="http://schemas.android.com/apk/res-auto"
	xmlns:tools="http://schemas.android.com/tools"
	android:layout_width="match_parent"
	android:background="#FF000000"
	android:layout_height="match_parent">

	<TextView
		android:id="@+id/time"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:textSize="52sp"
		android:textColor="#FFFFFFFF"
		app:layout_constraintBottom_toBottomOf="parent"
		app:layout_constraintEnd_toEndOf="parent"
		app:layout_constraintStart_toStartOf="parent"
		app:layout_constraintTop_toTopOf="parent"
		tools:text="12:34"/>
</androidx.constraintlayout.widget.ConstraintLayout>
```

### Rendererクラスの作成
XMLのレイアウトを描画する処理を記述
```CustomWatchFaceRenderer.kt
class CustomWatchFaceRenderer(
	context: Context,
	surfaceHolder: SurfaceHolder,
	currentUserStyleRepository: CurrentUserStyleRepository,
	watchState: WatchState
) : Renderer.CanvasRenderer2<Renderer.SharedAssets>(
	surfaceHolder,
	currentUserStyleRepository,
	watchState,
	CanvasType.HARDWARE,
	16L,
	false
) {
	private val binding = CustomWatchFaceBinding.inflate(LayoutInflater.from(context))

	override suspend fun createSharedAssets() = object : SharedAssets {
		override fun onDestroy() {}
	}

	override fun renderHighlightLayer(canvas: Canvas, bounds: Rect, zonedDateTime: ZonedDateTime, sharedAssets: SharedAssets) {}

	override fun render(canvas: Canvas, bounds: Rect, zonedDateTime: ZonedDateTime, sharedAssets: SharedAssets) {
		if (renderParameters.watchFaceLayers.contains(WatchFaceLayer.COMPLICATIONS_OVERLAY)) {
			binding.root.measure(
				View.MeasureSpec.makeMeasureSpec(bounds.width(), View.MeasureSpec.EXACTLY),
				View.MeasureSpec.makeMeasureSpec(bounds.height(), View.MeasureSpec.EXACTLY)
			)
			binding.root.layout(0, 0, bounds.width(), bounds.height())
			binding.time.text = String.format("%02d:%02d", zonedDateTime.hour, zonedDateTime.minute)
			binding.root.draw(canvas)
		}
	}
}
```

### WatchFaceServiceの作成
先ほど作成したRendererクラスを使ってWatchFaceServiceを作成

```CustomWatchFaceService.kt
class CustomWatchFaceService : WatchFaceService() {
	override suspend fun createWatchFace(surfaceHolder: SurfaceHolder, watchState: WatchState, complicationSlotsManager: ComplicationSlotsManager, currentUserStyleRepository: CurrentUserStyleRepository) =
		WatchFace(WatchFaceType.DIGITAL, CustomWatchFaceRenderer(applicationContext, surfaceHolder, currentUserStyleRepository, watchState))
}
```

### Wallpaperの作成
`res/xml/watch_face.xml`の作成
```watch_face.xml
<?xml version="1.0" encoding="UTF-8"?>
<wallpaper/>
```

### プレビュー画像の配置
`res/drawable/preview.png`を配置

### マニフェストファイルの変更
WatchFace一覧に先ほど作成したWatchFaceを表示させる。
パーミッションに`WAKE_LOCK`を追加
WatchFaceServiceに`CustomWatchFaceService`を指定
```AndroidManifest.xml
<manifest ...>

	<uses-permission android:name="android.permission.WAKE_LOCK"/>
	...

	<application ...>
		...

		<service
			android:name=".CustomWatchFaceService"
			android:label="Custom Watch Face"
			android:permission="android.permission.BIND_WALLPAPER"
			android:exported="true">
			<meta-data
				android:name="android.service.wallpaper"
				android:resource="@xml/watch_face"/>
			<meta-data
				android:name="com.google.android.wearable.watchface.preview"
				android:resource="@drawable/preview"/>
			<meta-data
				android:name="com.google.android.wearable.watchface.preview_circular"
				android:resource="@drawable/preview"/>

			<intent-filter>
				<action android:name="android.service.wallpaper.WallpaperService"/>
				<category android:name="com.google.android.wearable.watchface.category.WATCH_FACE"/>
			</intent-filter>
		</service>
	</application>
</manifest>
```

# 参考サイト

処理関連：

https://developer.android.com/training/wearables/watch-faces/service?hl=ja

依存関係関連：

https://developer.android.com/jetpack/androidx/releases/wear-watchface?hl=ja

サンプルコード：

https://github.com/android/wear-os-samples/tree/main/WatchFaceKotlin