Skip to content

Commit b373fa0

Browse files
authored
Merge pull request #2 from hegocre/improvement/watchButtons
Implement hardware buttons on Wear OS
2 parents 83e41ec + eb13e89 commit b373fa0

6 files changed

Lines changed: 124 additions & 16 deletions

File tree

.github/workflows/android.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: Android CI
22

33
on:
44
push:
5-
branches: [ master ]
5+
branches: [ main ]
66
pull_request:
7-
branches: [ master ]
7+
branches: [ main ]
88

99
jobs:
1010
build:
@@ -24,11 +24,11 @@ jobs:
2424
run: ./gradlew clean && ./gradlew assembleDebug
2525
- uses: actions/upload-artifact@v2
2626
with:
27-
name: app-debug-mobile.apk
28-
path: app/build/outputs/apk/debug/app-debug-mobile.apk
27+
name: mobile-debug.apk
28+
path: mobile/build/outputs/apk/debug/mobile-debug.apk
2929
- name: Build wear with Gradle
30-
run: ./gradlew clean && ./gradlew :mobile:assembleDebug
30+
run: ./gradlew clean && ./gradlew :wear:assembleDebug
3131
- uses: actions/upload-artifact@v2
3232
with:
33-
name: app-debug-wear.apk
34-
path: app/build/outputs/apk/debug/app-debug-wear.apk
33+
name: wear-debug.apk
34+
path: wear/build/outputs/apk/debug/wear-debug.apk

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22

33
buildscript {
4-
ext.kotlin_version = '1.5.31'
4+
ext.kotlin_version = '1.6.10'
55
repositories {
66
google()
77
mavenCentral()
88
}
99
dependencies {
10-
classpath 'com.android.tools.build:gradle:7.0.3'
10+
classpath 'com.android.tools.build:gradle:7.0.4'
1111
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1212

1313
// NOTE: Do not place your application dependencies here; they belong

mobile/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ android {
1010
applicationId "es.hegocre.scorecounter"
1111
minSdkVersion 24
1212
targetSdkVersion 31
13-
versionCode 311030000
14-
versionName "1.0.3"
13+
versionCode 311040000
14+
versionName "1.0.4"
1515
}
1616

1717
buildTypes {
@@ -42,6 +42,6 @@ dependencies {
4242
implementation fileTree(include: ['*.jar'], dir: 'libs')
4343
implementation 'androidx.preference:preference-ktx:1.1.1'
4444
testImplementation 'junit:junit:4.13.2'
45-
implementation 'androidx.appcompat:appcompat:1.3.1'
45+
implementation 'androidx.appcompat:appcompat:1.4.0'
4646
implementation 'androidx.core:core-ktx:1.7.0'
4747
}

wear/build.gradle

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ android {
77

88
defaultConfig {
99
applicationId "es.hegocre.scorecounter"
10-
minSdkVersion 24
10+
minSdkVersion 25
1111
targetSdkVersion 31
12-
versionCode 311030101
13-
versionName "1.0.3"
12+
versionCode 311040100
13+
versionName "1.0.4"
1414
}
1515

1616
buildTypes {
@@ -45,4 +45,5 @@ dependencies {
4545
implementation 'androidx.wear:wear:1.2.0'
4646
compileOnly 'com.google.android.wearable:wearable:2.8.1'
4747
implementation 'androidx.core:core-ktx:1.7.0'
48+
implementation 'androidx.wear:wear-input:1.1.0'
4849
}

wear/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<uses-feature android:name="android.hardware.type.watch" />
66

77
<uses-permission android:name="android.permission.WAKE_LOCK" />
8+
<uses-permission android:name="android.permission.VIBRATE" />
89

910
<application
1011
android:allowBackup="true"

wear/src/main/java/es/hegocre/scorecounter/MainActivity.kt

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package es.hegocre.scorecounter
22

3-
import android.os.Bundle
3+
import android.content.Context
4+
import android.os.*
5+
import android.view.KeyEvent
46
import android.view.View
57
import androidx.core.content.ContextCompat
68
import androidx.databinding.DataBindingUtil
79
import androidx.fragment.app.FragmentActivity
810
import androidx.preference.PreferenceManager
911
import androidx.wear.ambient.AmbientModeSupport
12+
import androidx.wear.input.WearableButtons
1013
import es.hegocre.scorecounter.data.Score
1114
import es.hegocre.scorecounter.databinding.ActivityMainBinding
1215

@@ -16,6 +19,8 @@ class MainActivity : FragmentActivity(), AmbientModeSupport.AmbientCallbackProvi
1619
private lateinit var ambientController: AmbientModeSupport.AmbientController
1720
private var needsBurnProtect = false
1821

22+
private val buttonsAvailable = mutableListOf(false, false, false)
23+
1924
override fun onCreate(savedInstanceState: Bundle?) {
2025
super.onCreate(savedInstanceState)
2126
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
@@ -30,6 +35,10 @@ class MainActivity : FragmentActivity(), AmbientModeSupport.AmbientCallbackProvi
3035
loadScore(score, binding.add2Layout, binding.sub2Layout)
3136
}
3237

38+
buttonsAvailable[0] = WearableButtons.getButtonInfo(this, KeyEvent.KEYCODE_STEM_1) != null
39+
buttonsAvailable[1] = WearableButtons.getButtonInfo(this, KeyEvent.KEYCODE_STEM_2) != null
40+
buttonsAvailable[2] = WearableButtons.getButtonInfo(this, KeyEvent.KEYCODE_STEM_3) != null
41+
3342
ambientController = AmbientModeSupport.attach(this)
3443
}
3544

@@ -103,6 +112,103 @@ class MainActivity : FragmentActivity(), AmbientModeSupport.AmbientCallbackProvi
103112
}
104113
}
105114

115+
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
116+
return when (event?.repeatCount ?: 0) {
117+
0 -> {
118+
when (keyCode) {
119+
KeyEvent.KEYCODE_STEM_1 -> {
120+
binding.score1?.inc()
121+
vibrate()
122+
true
123+
}
124+
KeyEvent.KEYCODE_STEM_2 -> {
125+
if (buttonsAvailable[0]) binding.score2?.inc()
126+
else binding.score1?.inc()
127+
vibrate()
128+
true
129+
}
130+
KeyEvent.KEYCODE_STEM_3 -> {
131+
if (!(buttonsAvailable[0] && buttonsAvailable[1])) {
132+
if (buttonsAvailable[0] || buttonsAvailable[1])
133+
//Button 1 or 2 available
134+
binding.score2?.inc()
135+
else
136+
//No other button available
137+
binding.score1?.inc()
138+
}
139+
vibrate()
140+
true
141+
}
142+
else -> {
143+
super.onKeyDown(keyCode, event)
144+
}
145+
}
146+
}
147+
1 -> onKeyLongPress(keyCode, event)
148+
else -> super.onKeyDown(keyCode, event)
149+
}
150+
}
151+
152+
override fun onKeyLongPress(keyCode: Int, event: KeyEvent?): Boolean {
153+
return when (keyCode) {
154+
KeyEvent.KEYCODE_STEM_1 -> {
155+
binding.score1?.reset()
156+
vibrate()
157+
true
158+
}
159+
KeyEvent.KEYCODE_STEM_2 -> {
160+
if (buttonsAvailable[0])
161+
//Button 1 available
162+
binding.score2?.reset()
163+
else
164+
//Buttons 2 and/or 3 available
165+
binding.score1?.reset()
166+
167+
vibrate()
168+
true
169+
}
170+
KeyEvent.KEYCODE_STEM_3 -> {
171+
if (!(buttonsAvailable[0] && buttonsAvailable[1])) {
172+
if (buttonsAvailable[0] || buttonsAvailable[1])
173+
//Button 1 or 2 available
174+
binding.score2?.reset()
175+
else
176+
//No other button available
177+
binding.score1?.reset()
178+
}
179+
vibrate()
180+
true
181+
}
182+
else -> {
183+
super.onKeyDown(keyCode, event)
184+
}
185+
}
186+
}
187+
188+
@Suppress("deprecation")
189+
private fun Context.vibrate() {
190+
val vibrator =
191+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
192+
val vibratorManager =
193+
getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
194+
vibratorManager.defaultVibrator
195+
} else {
196+
getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
197+
}
198+
if (vibrator.hasVibrator()) {
199+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
200+
vibrator.vibrate(
201+
VibrationEffect.createOneShot(
202+
250,
203+
VibrationEffect.DEFAULT_AMPLITUDE
204+
)
205+
)
206+
} else {
207+
vibrator.vibrate(250)
208+
}
209+
}
210+
}
211+
106212
companion object {
107213
private const val BURN_IN_OFFSET_PX = 10
108214
}

0 commit comments

Comments
 (0)