Skip to content

Commit 2d78133

Browse files
authored
Merge pull request #24 from matejdro/sports_customization
App customization packets
2 parents 432b1f1 + c1ca569 commit 2d78133

File tree

8 files changed

+176
-5
lines changed

8 files changed

+176
-5
lines changed

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
kotlin.code.style=official
22

33
group=io.rebble.libpebblecommon
4-
version=0.0.25
5-
org.gradle.jvmargs=-Xms2G -Xmx2G
4+
version=0.0.26
5+
org.gradle.jvmargs=-Xms2G -Xmx2G
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package io.rebble.libpebblecommon.util
2+
3+
/**
4+
* Convert android bitmap into common multiplatform bitmap.
5+
*
6+
* Only supported for [android.graphics.Bitmap.Config.ARGB_8888] formats
7+
*/
8+
actual class Bitmap(private val androidBitmap: android.graphics.Bitmap) {
9+
init {
10+
if (androidBitmap.config != android.graphics.Bitmap.Config.ARGB_8888) {
11+
throw IllegalArgumentException("Only ARGB_8888 bitmaps are supported")
12+
}
13+
}
14+
15+
actual val width: Int
16+
get() = androidBitmap.width
17+
actual val height: Int
18+
get() = androidBitmap.height
19+
20+
/**
21+
* Return pixel at the specified position at in AARRGGBB format.
22+
*/
23+
actual fun getPixel(x: Int, y: Int): Int {
24+
return androidBitmap.getPixel(x, y)
25+
}
26+
27+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package io.rebble.libpebblecommon.packets
2+
3+
import io.rebble.libpebblecommon.protocolhelpers.PebblePacket
4+
import io.rebble.libpebblecommon.protocolhelpers.ProtocolEndpoint
5+
import io.rebble.libpebblecommon.structmapper.SBytes
6+
import io.rebble.libpebblecommon.structmapper.SFixedString
7+
import io.rebble.libpebblecommon.structmapper.SUByte
8+
import io.rebble.libpebblecommon.structmapper.SUShort
9+
import io.rebble.libpebblecommon.util.Bitmap
10+
import io.rebble.libpebblecommon.util.DataBuffer
11+
12+
class AppCustomizationSetStockAppTitleMessage(
13+
appType: AppType,
14+
newName: String
15+
) : PebblePacket(ProtocolEndpoint.APP_CUSTOMIZE) {
16+
val appType = SUByte(m, appType.value)
17+
val name = SFixedString(m, 30, newName)
18+
}
19+
20+
class AppCustomizationSetStockAppIconMessage(
21+
appType: AppType,
22+
icon: Bitmap
23+
) : PebblePacket(ProtocolEndpoint.APP_CUSTOMIZE) {
24+
// First bit being set signifies that this is icon packet instead of name packet
25+
val appType = SUByte(m, appType.value or 0b10000000u)
26+
val bytesPerLine = SUShort(m, endianness = '<')
27+
28+
/**
29+
* No idea what flags are possible. Stock app always sends 4096 here.
30+
*/
31+
val flags = SUShort(m, 4096u, endianness = '<')
32+
33+
/**
34+
* Offset is not supported by app. Always 0.
35+
*/
36+
val originY = SUShort(m, 0u, endianness = '<')
37+
val originX = SUShort(m, 0u, endianness = '<')
38+
39+
val width = SUShort(m, endianness = '<')
40+
val height = SUShort(m, endianness = '<')
41+
42+
val imageData = SBytes(m)
43+
44+
init {
45+
val width = icon.width
46+
val height = icon.height
47+
48+
this.width.set(width.toUShort())
49+
this.height.set(height.toUShort())
50+
51+
val bytesPerLine = ((width + 31) / 32) * 4
52+
val totalBytes = bytesPerLine * height
53+
54+
val dataBuffer = DataBuffer(totalBytes)
55+
56+
for (y in 0 until height) {
57+
for (lineIntIndex in 0 until bytesPerLine / 4) {
58+
var currentInt = 0
59+
val startX = lineIntIndex * 32
60+
val pixelsToTraverse = 32.coerceAtMost(width - startX)
61+
62+
for (innerX in 0 until pixelsToTraverse) {
63+
val x = startX + innerX
64+
65+
val pixelValue = icon.getPixel(x, y)
66+
val valueWithoutAlpha = pixelValue and 0x00FFFFFF
67+
68+
val pixelBit = if (valueWithoutAlpha > 0) {
69+
1
70+
} else {
71+
0
72+
}
73+
74+
currentInt = currentInt or (pixelBit shl innerX)
75+
}
76+
77+
dataBuffer.putInt(currentInt)
78+
}
79+
}
80+
81+
val imageBytes = dataBuffer.array()
82+
imageData.set(imageBytes, imageBytes.size)
83+
84+
this.bytesPerLine.set(bytesPerLine.toUShort())
85+
}
86+
}
87+
88+
enum class AppType(val value: UByte) {
89+
SPORTS(0x00u),
90+
GOLF(0x01u),
91+
}

src/commonMain/kotlin/io/rebble/libpebblecommon/services/SystemService.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package io.rebble.libpebblecommon.services
22

33
import io.rebble.libpebblecommon.PacketPriority
44
import io.rebble.libpebblecommon.ProtocolHandler
5-
import io.rebble.libpebblecommon.getPlatform
6-
import io.rebble.libpebblecommon.packets.*
5+
import io.rebble.libpebblecommon.packets.PhoneAppVersion
6+
import io.rebble.libpebblecommon.packets.SystemPacket
7+
import io.rebble.libpebblecommon.packets.WatchFactoryData
8+
import io.rebble.libpebblecommon.packets.WatchVersion
79
import io.rebble.libpebblecommon.protocolhelpers.PebblePacket
810
import io.rebble.libpebblecommon.protocolhelpers.ProtocolEndpoint
911
import io.rebble.libpebblecommon.structmapper.SInt
@@ -83,4 +85,4 @@ class SystemService(private val protocolHandler: ProtocolHandler) : ProtocolServ
8385
}
8486
}
8587

86-
}
88+
}

src/commonMain/kotlin/io/rebble/libpebblecommon/services/appmessage/AppMessageService.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.rebble.libpebblecommon.services.appmessage
22

33
import io.rebble.libpebblecommon.ProtocolHandler
4+
import io.rebble.libpebblecommon.packets.AppCustomizationSetStockAppIconMessage
5+
import io.rebble.libpebblecommon.packets.AppCustomizationSetStockAppTitleMessage
46
import io.rebble.libpebblecommon.packets.AppMessage
57
import io.rebble.libpebblecommon.protocolhelpers.PebblePacket
68
import io.rebble.libpebblecommon.protocolhelpers.ProtocolEndpoint
@@ -21,6 +23,14 @@ class AppMessageService(private val protocolHandler: ProtocolHandler) : Protocol
2123
protocolHandler.send(packet)
2224
}
2325

26+
suspend fun send(packet: AppCustomizationSetStockAppIconMessage) {
27+
protocolHandler.send(packet)
28+
}
29+
30+
suspend fun send(packet: AppCustomizationSetStockAppTitleMessage) {
31+
protocolHandler.send(packet)
32+
}
33+
2434
fun receive(packet: PebblePacket) {
2535
if (packet !is AppMessage) {
2636
throw IllegalStateException("Received invalid packet type: $packet")
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package io.rebble.libpebblecommon.util
2+
3+
expect class Bitmap {
4+
val width: Int
5+
val height: Int
6+
7+
/**
8+
* Return pixel at the specified position at in AARRGGBB format.
9+
*/
10+
fun getPixel(x: Int, y: Int): Int
11+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.rebble.libpebblecommon.util
2+
3+
actual class Bitmap {
4+
actual val width: Int
5+
get() = throw UnsupportedOperationException("Not supported on iOS yet")
6+
actual val height: Int
7+
get() = throw UnsupportedOperationException("Not supported on iOS yet")
8+
9+
/**
10+
* Return pixel at the specified position at in AARRGGBB format.
11+
*/
12+
actual fun getPixel(x: Int, y: Int): Int {
13+
throw UnsupportedOperationException("Not supported on iOS yet")
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.rebble.libpebblecommon.util
2+
3+
actual class Bitmap {
4+
actual val width: Int
5+
get() = throw UnsupportedOperationException("Not supported on generic JVM")
6+
actual val height: Int
7+
get() = throw UnsupportedOperationException("Not supported on generic JVM")
8+
9+
/**
10+
* Return pixel at the specified position at in AARRGGBB format.
11+
*/
12+
actual fun getPixel(x: Int, y: Int): Int {
13+
throw UnsupportedOperationException("Not supported on generic JVM")
14+
}
15+
}

0 commit comments

Comments
 (0)