[Samsung Gear Fit] inportb:
Hello there! I'm new to these parts because I recently acquired a Gear Fit.

TL;DR: I took aooga's stuff (thanks!) and made it work on my CM 12 (5.0.2) phone. I hope it works for you. Get it here.

Anyway, I'm using a Galaxy Nexus running a cm 12 build from Ziyan, and I quickly realized that I needed to do some extra work. Unfortunately, zwegnet's patched Gear Fit Manager didn't work for me, and neither did aooga's very comprehensive guide, so I figured I'd try doing it myself. I see that some of you are interested in how this works, so I'm documenting my process for everyone's benefit (let's collaborate!).

You will learn the basics of:

how to debug using adb logcat

how to disassemble an app (specifically, a dex file) into smali

how to navigate and modify smali code

how to reassemble smali to dex and rebuild the app

how to sign an app for deployment

You will need:

adb

java runtime environment

smali/baksmali

signapk with test keys

I've collected some of the tools for you here; just add adb and java.

1. Debugging

So, we've got Gear Fit Manager and Gear Fitness installed... but Gear Fit Manager crashes! Darn it. How are we gonna connect a Gear Fit? Let's see.

First, let's pop open your favorite terminal (yes, we will be using the command line) and start streaming some logs:

adb logcat

There should be a bunch of text scrolling through the terminal. While that's going on, try to launch the offending app, and wait until it crashes. As soon as it crashes, hit Ctrl+C in the terminal to stop logging. Look, a fatal exception:

E/AndroidRuntime(32368): FATAL EXCEPTION: main
E/AndroidRuntime(32368): Process: com.samsung.android.wms, PID: 32368
E/AndroidRuntime(32368): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.samsung.android.wms/com.samsung.android.wms.app.base.ContentsActivity}: android.content.res.Resources$NotFoundException: Resource ID #0x0
E/AndroidRuntime(32368):	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
E/AndroidRuntime(32368):	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
E/AndroidRuntime(32368):	at android.app.ActivityThread.access$800(ActivityThread.java:144)
E/AndroidRuntime(32368):	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
E/AndroidRuntime(32368):	at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime(32368):	at android.os.Looper.loop(Looper.java:135)
E/AndroidRuntime(32368):	at android.app.ActivityThread.main(ActivityThread.java:5223)
E/AndroidRuntime(32368):	at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(32368):	at java.lang.reflect.Method.invoke(Method.java:372)
E/AndroidRuntime(32368):	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:898)
E/AndroidRuntime(32368):	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:693)
E/AndroidRuntime(32368): Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x0
E/AndroidRuntime(32368):	at android.content.res.Resources.getValue(Resources.java:1233)
E/AndroidRuntime(32368):	at android.content.res.Resources.getDrawable(Resources.java:756)
E/AndroidRuntime(32368):	at android.content.res.Resources.getDrawable(Resources.java:724)
E/AndroidRuntime(32368):	at com.samsung.android.wms.app.base.WingtipBaseActivity.brandGlowEffect(WingtipBaseActivity.java:136)
E/AndroidRuntime(32368):	at com.samsung.android.wms.app.base.WingtipBaseActivity.onCreate(WingtipBaseActivity.java:94)
E/AndroidRuntime(32368):	at com.samsung.android.wms.app.base.ContentsActivity.onCreate(ContentsActivity.java:139)
E/AndroidRuntime(32368):	at android.app.Activity.performCreate(Activity.java:5933)
E/AndroidRuntime(32368):	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
E/AndroidRuntime(32368):	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
E/AndroidRuntime(32368):	... 10 more

When you've been bug-hunting for a while, you start to notice these stack traces quite readily, even in a sea of irrelevant output. This one tells us that:

the offending app is named com.samsung.android.wms

a Resources$NotFoundException occurred, likely because the app requested a resource that did not exist

... and so on

Note that the stack trace appears in reverse-chronological order; that is, what happens later appears first. I often like to read these things backwards. Now, have a look at these lines:

E/AndroidRuntime(32368):	at android.content.res.Resources.getDrawable(Resources.java:724)
E/AndroidRuntime(32368):	at com.samsung.android.wms.app.base.WingtipBaseActivity.brandGlowEffect(WingtipBaseActivity.java:136)
E/AndroidRuntime(32368):	at com.samsung.android.wms.app.base.WingtipBaseActivity.onCreate(WingtipBaseActivity.java:94)

What happened?

a WingtipBaseActivity is created to display the app, and is being initialized in its onCreate method

... which calls brandGlowEffect

... which calls into the Android system

... which eventually leads to the crash

With the entire chain of events exposed to us, we could now look for the culprit! Why don't we examine WingtipBaseActivity.brandGlowEffect? It's the last thing the app does before passing control over to Android, and we're assuming that the app (not Android) is faulty.

2. Disassembly

To do this, we need to take a peek under Gear Fit Manager's hood. An apk file is just a zip file, so we already know how to unpack it. We're interested in the classes.dex within, which contains the executable code. dex is not a very human-readable format, so we need to disassemble it using baksmali.

Firstly, let's extract the classes.dex from the archive. Then, we could disassemble it by running:

java -jar baksmali.jar -o dexout classes.dex

3. Modification

This generates a folder full of disassembled code. Because we're interested in com.samsung.android.wms.app.base.WingtipBaseActivity, we'll look inside the file dexout/com/samsung/android/wms/app/base/WingtipBaseActivity.smali

There, on line 693, we see the method WingtipBaseActivity.brandGlowEffect getting called from WingtipBaseActivity.onCreate. This looks like some cosmetic fluff that we could dispense with, so let's just delete the line altogether and save the file. Sorry, Samsung, your brand's not gonna glow this time.

4. Reassembly

Now we could re-generate the classes.dex:

java -jar smali.jar -o classes.dex dexout

... and we'll drop the new classes.dex inside the apk.

5. Signing

But wait! We couldn't install this new apk yet — it needs to be signed. This is easy enough with signapk:

java -jar signapk.jar testkey.x509.pem testkey.pk8 GearFitManager.apk GearFitManager_signed.apk

6. Deploying

We need to uninstall the original app before we could install the new one, because they were signed using different keys (the original was signed using Samsung's keys). After that, we just need to install and test!

We've barely scratched the surface. I hope this helps someone, and I certainly hope we could team up to make something awesome. I've had a look at the more recent versions of Gear Fit Manager, and I have a feeling a lot more work would be required...