今まで自作のプログラムコードでレンダリングするWatch Faceを使用していました。
https://github.com/matsudamper/WearOS-WatchFace
それをプログラムコードを使用しないWatch Face Formatで作り直しました。
https://github.com/matsudamper/WearOS-WatchFaceFormat
背景
Wear OS 5からコードを使用して文字盤をレンダリングする事は不可能になりました。
https://support.google.com/wearos/thread/284572445
全てXMLで記述する必要があります。
https://android-developers.googleblog.com/2023/05/introducing-watch-face-format-for-wear-os.html
SamsungのWatch Face Studioを使用してWatch Face Format準拠のWatch Faceを作成する事もできます。
現時点では既存のテンプレートを選択するとコードが含まれるApp Bundleが出力されるので注意。
https://developer.samsung.com/watch-face-studio/user-guide/index.html
思うこと
プログラムコードでレンダリングするのはパフォーマンスが悪いのはわかる。XML直で書くのは辛い。Complication Slot
や目盛り、中心から角度でぐるっとforをや変数を使って定義したいのでWatch Face Studioは微妙。
対応
DSLを作成して変数、テンプレート化をできるようにした。 Gradle Pluginでビルド時にXMLを生成されるようにした。(使ってない要素は定義してないけど)
この様にComposeっぽく大文字関数にしてみた。
@Suppress("FunctionName") internal fun SceneScope.Slots( width: Int, height: Int, ) { val slotCount = 6 val slotSize = (width * height) / 1500 val slotMargin = slotSize * 1.05 val angleStep = 360 / slotCount for (i in 0 until slotCount) { val angle = i * angleStep + (angleStep / 2) ComplicationSlot( x = ((width - slotSize) / 2) + (cos(Math.toRadians(angle.toDouble())) * slotMargin).toInt(), y = ((height - slotSize) / 2) + (sin(Math.toRadians(angle.toDouble())) * slotMargin).toInt(), width = slotSize, height = slotSize, slotId = i, supportedTypes = listOf( ComplicationSlotSupportedType.RANGED_VALUE, ComplicationSlotSupportedType.SMALL_IMAGE, ComplicationSlotSupportedType.LONG_TEXT, ComplicationSlotSupportedType.SHORT_TEXT, ComplicationSlotSupportedType.MONOCHROMATIC_IMAGE, ComplicationSlotSupportedType.PHOTO_IMAGE, ComplicationSlotSupportedType.EMPTY, ), isCustomizable = true, ) { DefaultProviderPolicy( primaryProvider = "com.fitbit.FitbitMobile/com.fitbit.complications.calories.CaloriesComplicationDataSourceService", defaultSystemProviderType = ComplicationSlotSupportedType.RANGED_VALUE, defaultSystemProvider = DefaultProvider.STEP_COUNT, ) BoundingOval( x = 0, y = 0, width = slotSize, height = slotSize, outlinePadding = 2, ) Complication(type = ComplicationSlotSupportedType.RANGED_VALUE) { RangeValueLayout( slotSize = slotSize, ) } } } }
出力されたXMLは1.4万行程。こんなの直で書いてられない。
https://github.com/matsudamper/WearOS-WatchFaceFormat/blob/a6f5341ef1e7c0e715f9c6426a986bfdc5e7a7ae/app/src/main/res/raw/watchface.xml
条件分岐もXML。
おわりに
型が違うというドキュメントの不備を見つけた。あんまり自前でXML組む人居ないのかな…
https://issuetracker.google.com/issues/358594663
1時間位溶かした。Watch Face Studioで出力した結果をapk analyzerで確認してドキュメントの方の不具合が発覚した。