Skip to content

Commit d7dfd91

Browse files
committed
Harden repo setup and Wear tile launch
1 parent 7181b61 commit d7dfd91

8 files changed

Lines changed: 124 additions & 20 deletions

File tree

‎.gitattributes‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
* text=auto
2+
3+
*.bat text eol=crlf
4+
*.gradle text eol=lf
5+
*.kts text eol=lf
6+
*.kt text eol=lf
7+
*.md text eol=lf
8+
*.xml text eol=lf
9+
*.yml text eol=lf
10+
*.toml text eol=lf

‎.github/dependabot.yml‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: gradle
4+
directory: /
5+
schedule:
6+
interval: weekly
7+
8+
- package-ecosystem: github-actions
9+
directory: /
10+
schedule:
11+
interval: weekly

‎.github/workflows/android.yml‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Android
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
concurrency:
12+
group: android-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
build:
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v4
22+
23+
- name: Set up JDK 21
24+
uses: actions/setup-java@v4
25+
with:
26+
distribution: temurin
27+
java-version: "21"
28+
29+
- name: Set up Android SDK
30+
uses: android-actions/setup-android@v3
31+
with:
32+
packages: "platforms;android-36 build-tools;36.0.0 platform-tools"
33+
34+
- name: Set up Gradle
35+
uses: gradle/actions/setup-gradle@v4
36+
37+
- name: Grant gradlew execute permission
38+
run: chmod +x ./gradlew
39+
40+
- name: Build
41+
run: ./gradlew --no-daemon build

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ captures/
1111
*.apk
1212
*.aab
1313
*.keystore
14+
*.jks

‎README.md‎

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# WatchDevTools
22

3-
Quick-access Wear OS tile for developer settings. Provides shortcut buttons to Developer options, Bluetooth settings, and Wi-Fi settings — all one swipe away without navigating through the full settings menu.
3+
Quick-access Wear OS tile for developer settings. Provides shortcut buttons to Developer options, Bluetooth settings, and Wi-Fi settings - all one swipe away without navigating through the full settings menu.
44

55
## Features
66

7-
- **Dev Options Shortcut** — Jump directly to Android Developer settings (for wireless debugging, USB debugging, etc.)
8-
- **Bluetooth Settings** — One-tap access to Bluetooth configuration
9-
- **Wi-Fi Settings** — Quick navigation to Wi-Fi setup
7+
- **Dev Options Shortcut** - Jump directly to Android Developer settings (for wireless debugging, USB debugging, etc.)
8+
- **Bluetooth Settings** - One-tap access to Bluetooth configuration
9+
- **Wi-Fi Settings** - Quick navigation to Wi-Fi setup
1010

1111
## Installation
1212

@@ -17,7 +17,7 @@ Add the tile to your Wear OS device manually:
1717
3. Find and select **DevTools**
1818
4. The tile is now in your carousel
1919

20-
No app drawer icon—this is purely a tile-based utility.
20+
No app drawer icon - this is purely a tile-based utility.
2121

2222
## Building
2323

@@ -31,25 +31,36 @@ To build and install directly to a connected watch:
3131
./gradlew installDebug
3232
```
3333

34+
## Release Builds
35+
36+
Release APKs/AABs must be signed with your private Android signing key. Keep signing properties and keystores outside git; the repository ignores `local.properties`, `*.keystore`, `*.jks`, `*.apk`, and `*.aab`.
37+
38+
Before publishing a release:
39+
40+
1. Update `versionCode` and `versionName` in `app/build.gradle.kts`
41+
2. Build the release artifact with `./gradlew assembleRelease`
42+
3. Sign the artifact using your local signing configuration
43+
3444
## Configuration
3545

3646
- **Min SDK:** 30 (Wear OS 7.0)
3747
- **Compile SDK:** 36
3848
- **Target SDK:** 35
3949
- **Language:** Kotlin
4050
- **Architecture:** Wear OS Protolayout (tile-based UI)
51+
- **Tested on:** Samsung Galaxy Watch6 Classic LTE SM-R965F
4152

4253
## Development Notes
4354

4455
- The app uses `androidx.wear.tiles` and Protolayout for tile rendering
4556
- Resource caching is managed via `RESOURCES_VERSION`; bump this constant when layout schema changes
4657
- Tile buttons invoke `LaunchDevOptionsActivity`, which routes the appropriate Settings intent and immediately finishes
47-
- No UI is painted (NoDisplay theme)—the launcher activity exists only to bridge tile clicks to system intents
58+
- No UI is painted (NoDisplay theme) - the launcher activity exists only to bridge tile clicks to system intents
4859

4960
## Package
5061

5162
- **Application ID:** `com.fredapps.watchdevtools`
52-
- **Version:** 0.1.0
63+
- **Version:** 1.0.0
5364
- **Namespace:** fredapps
5465

5566
## License

‎app/src/main/AndroidManifest.xml‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@
99
android:roundIcon="@drawable/ic_devtools"
1010
android:theme="@android:style/Theme.DeviceDefault">
1111

12+
<meta-data
13+
android:name="com.google.android.wearable.standalone"
14+
android:value="true" />
15+
1216
<!--
13-
Hidden activity. Tile-only app — this activity is not listed in the
17+
Hidden activity. Tile-only app - this activity is not listed in the
1418
launcher, but it's triggered by the tile's buttons to fire the
1519
Developer options intent and finish immediately.
1620
-->
@@ -23,7 +27,7 @@
2327

2428
<!--
2529
Tile carousel shortcut. The user adds this manually via long-press on
26-
an existing tile → Add → DevTools (Wear OS doesn't allow third-party
30+
an existing tile -> Add -> DevTools (Wear OS doesn't allow third-party
2731
apps to programmatically place tiles in the carousel).
2832
-->
2933
<service

‎app/src/main/kotlin/com/fredapps/watchdevtools/DevOptionsTileService.kt‎

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
/*
2+
* SPDX-License-Identifier: GPL-3.0-only
3+
*/
4+
15
package com.fredapps.watchdevtools
26

37
import android.provider.Settings
48
import android.util.Log
5-
import androidx.concurrent.futures.ResolvableFuture
9+
import androidx.concurrent.futures.CallbackToFutureAdapter
610
import androidx.wear.protolayout.ActionBuilders
711
import androidx.wear.protolayout.ColorBuilders.argb
812
import androidx.wear.protolayout.DimensionBuilders.dp
@@ -18,7 +22,7 @@ import androidx.wear.tiles.TileBuilders.Tile
1822
import androidx.wear.tiles.TileService
1923
import com.google.common.util.concurrent.ListenableFuture
2024

21-
// Bump this string whenever the layout schema changes — it forces the Wear OS
25+
// Bump this string whenever the layout schema changes - it forces the Wear OS
2226
// renderer to discard cached visuals and re-fetch from us.
2327
private const val RESOURCES_VERSION = "4"
2428
private const val TAG = "DevOptionsTile"
@@ -30,8 +34,8 @@ private const val WHITE = 0xFFFFFFFF.toInt()
3034
/**
3135
* Tile with three quick-toggle shortcuts: Dev options (for wireless debugging),
3236
* Bluetooth settings, and Wi-Fi settings. None of these can actually flip the
33-
* toggle from a third-party app on modern Android — Bluetooth and Wi-Fi both
34-
* require user consent — but landing on the right settings page is one tap
37+
* toggle from a third-party app on modern Android - Bluetooth and Wi-Fi both
38+
* require user consent - but landing on the right settings page is one tap
3539
* away from the toggle.
3640
*
3741
* Each button's [ActionBuilders.LaunchAction] points at the same
@@ -44,8 +48,13 @@ class DevOptionsTileService : TileService() {
4448
requestParams: RequestBuilders.ResourcesRequest
4549
): ListenableFuture<ResourceBuilders.Resources> {
4650
Log.i(TAG, "onTileResourcesRequest version=${requestParams.version}")
47-
return ResolvableFuture.create<ResourceBuilders.Resources>().apply {
48-
set(ResourceBuilders.Resources.Builder().setVersion(RESOURCES_VERSION).build())
51+
val resources = ResourceBuilders.Resources.Builder()
52+
.setVersion(RESOURCES_VERSION)
53+
.build()
54+
55+
return CallbackToFutureAdapter.getFuture { completer ->
56+
completer.set(resources)
57+
"DevOptionsTileService#onTileResourcesRequest"
4958
}
5059
}
5160

@@ -101,7 +110,10 @@ class DevOptionsTileService : TileService() {
101110
)
102111
.build()
103112

104-
return ResolvableFuture.create<Tile>().apply { set(tile) }
113+
return CallbackToFutureAdapter.getFuture { completer ->
114+
completer.set(tile)
115+
"DevOptionsTileService#onTileRequest"
116+
}
105117
}
106118

107119
/**

‎app/src/main/kotlin/com/fredapps/watchdevtools/LaunchDevOptionsActivity.kt‎

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/*
2+
* SPDX-License-Identifier: GPL-3.0-only
3+
*/
4+
15
package com.fredapps.watchdevtools
26

37
import android.app.Activity
@@ -9,9 +13,9 @@ import androidx.wear.tiles.TileService
913

1014
/**
1115
* No-UI launcher. Fires the Developer options intent and immediately finishes
12-
* so the user lands directly in Settings → Developer options, where Wireless
16+
* so the user lands directly in Settings -> Developer options, where Wireless
1317
* debugging is one swipe away. Falls back to the top-level Settings activity if
14-
* Developer options haven't been unlocked yet (build-number tap × 7).
18+
* Developer options haven't been unlocked yet (build-number tap x 7).
1519
*
1620
* As a side effect, asks the system to re-fetch our tile's content. The Wear
1721
* OS tile carousel aggressively caches tile layouts; without an explicit
@@ -22,8 +26,7 @@ class LaunchDevOptionsActivity : Activity() {
2226
override fun onCreate(savedInstanceState: Bundle?) {
2327
super.onCreate(savedInstanceState)
2428
TileService.getUpdater(this).requestUpdate(DevOptionsTileService::class.java)
25-
val action = intent.getStringExtra(EXTRA_SETTINGS_ACTION)
26-
?: Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS
29+
val action = supportedSettingsAction(intent.getStringExtra(EXTRA_SETTINGS_ACTION))
2730
try {
2831
startActivity(Intent(action).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
2932
} catch (_: ActivityNotFoundException) {
@@ -37,5 +40,16 @@ class LaunchDevOptionsActivity : Activity() {
3740
companion object {
3841
/** Tile buttons pass the settings action to launch via this extra. */
3942
const val EXTRA_SETTINGS_ACTION = "settings_action"
43+
44+
private val SUPPORTED_SETTINGS_ACTIONS = setOf(
45+
Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS,
46+
Settings.ACTION_BLUETOOTH_SETTINGS,
47+
Settings.ACTION_WIFI_SETTINGS,
48+
)
49+
50+
private fun supportedSettingsAction(action: String?): String =
51+
action
52+
?.takeIf { it in SUPPORTED_SETTINGS_ACTIONS }
53+
?: Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS
4054
}
4155
}

0 commit comments

Comments
 (0)