This is the most valuable part of the repo: things that are documented nowhere and that each cost hours. If you are working on a Galaxy Watch without a Google account, this page saves you most of those hours.
Symptom: every app installation hangs or aborts — with Aurora Store just as much as with a store of your own. The confirmation dialog never even appears.
In the log:
SecurityException: Can't install packages while in secure FRP
Cause: the watch is stuck in factory reset protection mode, even though setup is finished — probably because it was set up without a Google account. In that state the PackageManager blocks everything.
Fix:
adb shell settings put global secure_frp_mode 0
adb shell settings put secure secure_frp_mode 0
After that, installing works normally. The value stays set; after a system
update it is worth checking again. Markt resets it itself on startup (it needs
WRITE_SECURE_SETTINGS for that, granted with adb pm grant).
Remember: when “the installation hangs”, always check
secure_frp_modefirst — do not suspect your own installer.
A foreground service has to show a notification. On One UI Watch, none of these helped:
IMPORTANCE_MINVISIBILITY_SECRETCATEGORY_SERVICEFOREGROUND_SERVICE_DEFERREDWhat works: put the notification on a blocked channel
(IMPORTANCE_NONE). It is then technically there, but it does not show up in
the list.
nm.createNotificationChannel(new NotificationChannel(
"app_stumm", "Dienst (stumm)", NotificationManager.IMPORTANCE_NONE));
An existing channel cannot be turned down afterwards — delete it if you need to and create it again with a new ID.
Check that nothing is really shown (more reliable than any gesture on the watch):
adb shell cmd notification list # does your own package show up?
Symptom: your own iPhone shows the advertising watch, a different iPhone shows nothing at all — even though it was never connected to the watch.
Two causes, and both matter:
a) The name was missing from the advertising packet. A BLE advertising packet holds 31 bytes. The 128-bit ANCS solicitation takes 18 of them, the flags 3 — that leaves about 8 characters for the name. “Galaxy Watch6 Classic (A5TR)” does not fit, so the name ended up in the scan response. A phone that already knows the device shows it anyway (it has the name cached) — a phone that does not know it will not list devices without a name in the advertising packet.
Fix: set a short Bluetooth name, then it fits in as well:
if (adapter.getName().length() > 8) adapter.setName("Herold");
new AdvertiseData.Builder()
.setIncludeDeviceName(true)
.addServiceSolicitationUuid(new ParcelUuid(ANCS_SERVICE))
.build();
If the packet still comes out too big, onStartFailure reports code 1 —
then try again without the name (Herold does this automatically).
b) The watch was never discoverable over classic Bluetooth.
ScanMode: SCAN_MODE_CONNECTABLE # <- not discoverable
In its Bluetooth settings, iOS lists practically only devices that are discoverable over classic Bluetooth. Plain BLE advertising is not enough for a phone that does not know the watch:
adb shell am start -a android.bluetooth.adapter.action.REQUEST_DISCOVERABLE \
--ei android.bluetooth.adapter.extra.DISCOVERABLE_DURATION 300
And: a connected device stops the advertising. So when pairing with phone B, turn Bluetooth off on phone A.
adb shell am broadcast -a com.google.android.wearable.app.DEBUG_SURFACE \
--es operation set-watchface \
--ecn component <paket>/<klasse>
A reply of Favorite Id=[..] Runtime=[..] means it is set.
--ecn, not --es component. With --es the watch stubbornly answers
“Either component name or watchface id are required.” — the extra has to be a
ComponentName.
AppNotSupported (code=2) — even for older versions that technically fit.adb shell content query --uri content://com.google.android.gsf.gservices \
--where "name='android_id'"
If nothing comes back, the watch has no Google device ID. Then push messages never reach the watch — apps that “send content to the device” (watch faces, cloud sync) do not work, no matter how often you press. Without an account there is no way to add this later.
This is the hardest limit in the whole project. If you need services like that, there is no way around a Google account.
restriction, compatibility and a successful delivery test do not
distinguish between a phone app and a watch app — Play will deliver WhatsApp
to the watch too./store/apps/category/ANDROID_WEAR and /store/apps/category/WATCH_FACE,
fetched through the web helpers.BatteryManager.isCharging() reports “no” while charging wirelessly. The
sticky battery intent is the one that is right:
Intent i = registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int plugged = i.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
int status = i.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean laedt = plugged != 0
|| status == BatteryManager.BATTERY_STATUS_CHARGING
|| status == BatteryManager.BATTERY_STATUS_FULL;
-3 = the watch is not being worn. Stop the measurement
immediately.ERROR = a loose watch or movement. If the heart rate shows
“–” for a long time, that is almost always the reason — not the code. The app
tells the user so.AMBIENT temperature is the case temperature of the sensor chip, not
the room air. Heat flux models for core body temperature fail on this. The
honest way: the deviation from a personal baseline taken over several nights.A naive analysis (“varies a lot → irregular”) raises false alarms on young, healthy people: while breathing, the heart rate varies a lot, but rhythmically.
The difference is in the pattern: predicting a beat from its neighbours across several intervals, plus spectral band power. If the variation is predictable, it is breathing. If it is chaotic and without a pattern, it is irregular. In between belongs an honest “not sure”.
Do not guess the thresholds — read them off many simulated series of
measurements and check them against real recordings (herold/test/).
uhr.sh --daemon reconnects endlessly, fights every other adb
access and sets off a storm of notifications on the watch. With connection
trouble, check your own machine first: pgrep -fl uhr.sh.KEYCODE_WAKEUP first, otherwise they come out black.
svc power stayon only works on the charging cable.am force-stop kills the notification service. After that it only comes
back by opening the app or by a restart — never leave it like that.zip … classes*.dex, not classes.dex.--target-sdk-version 29.