Dali Clock 2.42: Android!

Robin Müller-Cajar and I have ported Dali Clock to Android! Finally!

It's not in an app store or anything, because I don't know anything about that crap, so you have to manually install the .apk file. I assume everyone reading this knows how to do that.

It runs as both a normal application and as a "Daydream" service. Select Settings / Display / Daydream / Dali Clock, and it will run automatically as a kind of screen saver when the device is docked or charging. Android 4.2 or newer is required.

Like the iOS version, there is no preferences panel. Swipe left or down to decrease the number of digits; swipe right or up to increase. Tap to momentarily display the date. Double-tap to toggle 12- and 24-hour mode.

Let me know what performance is like on your various devices.

The emulator doesn't seem to be able to emulate more than one Android device, so I haven't witnessed it doing its thing on a tablet or a Google TV or anything like that.

Hopefully it will track your locale's rules about the order in which day, month and year appear, and whether 24-hour time is the default.

I'd sure appreciate some advice from experienced Android developers about what we did wrong, since this is my first trip down this road. In particular, the android/Makefile is a horror show. Do I really need to type in a password every time I want to build the .apk file?

I'm also suffering PTSD at just how many useless subdirectories this effort resulted in. I'm sure that some of this is unavoidable Java insanity, plus a layer of Android insanity on top, but seriously? It goes fourteen levels deep!

I would like to make pinching do the same as swiping, but I couldn't figure out how one does pinch gestures on Android.

When changing the device's orientation, it takes a long time to react. I don't know if that's because I'm doing something wrong, or if that's just how Android is. (I've only seen this thing running in the emulator, not on a real device.)

So far, I have not discovered any way to get Android Studio on OSX to show me the output of Log.d() or Log.i(), which makes all of this incredibly difficult to debug! Even when I do "adb -e log cat", nothing shows up. Well, a lot of crap shows up, just nothing I printed. Does this happen to everyone, or am I just lucky?

Oh, also, Joshua Wise ported it to the Pebble Smart Watch. The source for that is in this release too.

That's probably not the watch you were wondering about, right?

So it turns out that an Apple Watch port of Dali Clock would be kind of pointless, because the Apple does not allow you to build custom watch faces at all. No, really.

And as far as I can tell, the only way to get custom graphics onto the watch is to basically package up and hand it the equivalent of an anim-GIF. So the way that would work is, you'd launch an app on your watch, which would launch an app on your phone, which would then start spraying image frames at the watch over bluetooth as quickly as possible -- which they say is something like 10 FPS when they are looping. In the case where every frame is different forever, who knows.

Tags: , , , ,

32 Responses:

  1. So the way that would work is, you'd launch an app on your watch, which would launch an app on your phone, which would then start spraying image frames at the watch over bluetooth as quickly as possible -- which they say is something like 10 FPS when they are looping.

    "Working", but not as we know it. Christ, what a gong show.

  2. Gabriel says:

    On my Nexus 4 running Android 5.0.1 it gets the time right (although opening it at midnight was confusing for a moment) but thinks it's March 11. Changing my OS date format doesn't seem to matter, but changing the date to January made it list the month as 00.

    12-hr mm-dd-yy were my initial settings and changing display formats in my settings didn't change the display when staying- although I didn't reboot, I did clear the cache and app data.

    I can reliably crash it by launching it, pressing home, going to the app drawer or icon on my home screen, and opening it again. If I use the task switcher to go back to it instead, no crash. Also no crash if I swipe it aside from the task switcher (which I guess kills it.) I'm not sure why these would be considered different ways of getting to the app.

    The slowness I see when rotating is mostly a delay in the numbers reappearing, and swiping is just laggy enough to make it difficult to understand what is happening. Normal animation performs fine.

    • YHVH says:

      I don't get that crash Android 4.2.2, agree slowness on re-orient. The font is jaggy or not aliased.

    • Probably because Java ridiculously thinks that Months are numbered 0-11 (while days and years use the actual number). Dates are one of the things Java fucked up the most.

    • Rodger says:

      I see the month problem as well, but otherwise it seems to work fine (Xperia X1 Compact/Android 4.4.4).

  3. mdhughes says:

    Known: There will be a native Apple Watch SDK.

    Probable, based on rumored leaks: Announced at WWDC, then released next spring.

    Total speculation: Developers will be able to make new watch faces.

    In the mean time, you could send each digit as a separate stack of images, and would only have to update every 10 seconds. Plenty of watch apps are going to be more wasteful than that.

    • jwz says:

      So, because the transition is not always from N → mod(N+1, 10) but, technically, to any other mod(N, 10), since you can do the "display current date" gesture at any time, that means the number of transitions you have to cache -- and "transitions" means "images encapsulating 30fps" -- is pretty large. Back in when dinosaurs ruled the Earth, and I had to make this shit work when running on 'X Terminals" speaking X11 protocol overhead over 38.4kbps modems with massive double stop bits, I cached this shit in server-side pixmaps and had 3 levels of cacheing: 0 (no cache), N→[N+1] (useful when machine or network was slow, and 3 was followed by 5 instead of 4), and [1-7]→[3-9] + 9→1 (full spectrum dominance). And back in the day, that was like... vast amounts of memory.

      AND MY POINT HERE IS IT IS NOT THE LITERAL NINETEEN EIGHTIES, WHY AM I STILL CONTEMPLATING CODING FOR XTERMS.

      I MEAN IF THE APPLE WATCH WAS THE APPLE][ WATCH, OK, I AM DOWN, OK, BUT IT IS NOT, COME ON.

      Yes, I have been drinking.

      • Nate says:

        This is what bugs me about technology recapitulation. Advances are almost never wholly a move forward.

        OS X: yay NeXTStep with reasonable Unix layer, boo Mach ports and process model.

        Web UIs: yay standards, boo same origin policy and only client/server comms

        Google: yay real systems research again, boo QUIC and SPDY Microsoft-style protocols (hey, we control both the client and server so time for single-source "innovation")

      • mdhughes says:

        You'd just replace the playing image stack when someone taps or swipes. You don't have to, and in fact cannot, respond in the watch code. It has no watch code, it's just UI like HTML if you could only manipulate the DOM and play animated GIFs like a tiny GeoCities.

        This whole mess is a lot like the first iPhone "sweet solution" of HTML. It'll pass.

        I ordered a watch but I'm not planning to ship anything for it until a native SDK date is given.

  4. phessler says:

    Works fine on my Yotaphone2 (Android 4.4.3), even when mirrored to the e-ink screen.

    This would be a super-cool module for either the Panel or as a native app on the second screen.

    • jwz says:

      I am sad to report that I don't know what any of those noun phrases mean.

    • Robin says:

      From what I gather the Yotaphone uses it's own API to draw to the second (e-ink) screen.

      I have to admit I have no experience at all with how to work with an API that will only work on some phones. Would that mean that we would need two separate APKs?

  5. Luke Lathrop says:

    Works great on my nexus 7(2013), with all the transition issues already mentioned not being too bad. Chromecast support would be really cool. of course, it works via the JavaScript version from chrome, or with screen mirroring, but I want more...

  6. mike says:

    You could consider genymotion as an almost-tolerable Android emulator. The one bundled with the SDK is not good; genymotion is still not great but significantly better; it supports a number of different device types and the performance is almost okay. Ignore the appeals to give them money and you'll be fine.

  7. So, so tempted to port this as an Android Wear watch face...

  8. Jens Knutson says:

    Thanks to you and Robin for the port! Performance looks pretty good on the latest Google Nexus phone. I'm an experienced Android dev, so here's my wall of text trying to address the issues you're seeing:

    * re: that makefile, I'm not really sure why that even exists? The project is already set up with Gradle (Android's standard build system), and creating debug builds with that does not require typing in the keystore password every time. From the Android project root: ./gradlew assembleDebug
    gradlew installDebug does what it sounds like, and gradlew tasks will show you entry points for everything else.

    * I'm only counting 9 levels of hierarchy at the deepest, though I realize that's only slightly better... There's no good way to really simplify that without build script hacking, which I'm sure you're just dying to do. Switching to "Android" instead of "Project" in the dropdown at the top of the Project view, and use of the "Copy Path" option in the right-click menu for files takes away most of this pain for me. Oral ingestion of liberal quantities of alcohol is also effective, albeit temporarily.

    * Pinch gestures are done like this.

    * Rotation generally isn't as fast or smooth as on iOS, because reasons, but it could be faster than it is now. I'll see if I can look into why it's slow later this weekend.

    * Re logs, I think you might just be lucky. Try this: adb logcat '*:D'

    Hope this helps!

    • jwz says:

      Yeah, the month number was off by one. Hooray. Also it wasn't supposed to be black and white, oops.

      Makefile: uh, I dunno? I just want to be able to type "make apk" and have an optimized, signed, ready-for-other-people-to install .apk file show up, without having to run a GUI. If there's some better way to do that than the mess of signing and zipalign and $ANDROID_HOME weirdness in the Makefile, that would be great.

      Hey, that adb thing works, thanks!

      • Matan says:

        Why insist on using make though?

        ./gradlew assemble gets you an apk, ./gradlew assembleDebug gets you a debug apk.

        You don't have to run a GUI.

        • jwz says:

          "make apk" does, in fact, just run "gradlew assembleRelease", which creates "DaliClock/app/build/outputs/apk/app-release-unsigned.apk".

          But since that is unsigned, I assume it is not the thing I should be putting on my web site for people to download and install. How do I get the signed version without all the jarsigner and password-prompting rigamarole in the Makefile?

          • Nick Lamb says:

            Two things. One, you need to tell gradle that you want this step to be done by the assembleRelease process instead of manually (or with some egregious Makefile hack). Two you need to tell gradle the passwords so that it doesn't need to prompt you. You obviously should not include such passwords in released source, but it's easy to have them provided by a user configuration or something on your build machine.

            http://developer.android.com/tools/publishing/app-signing.html is the extent of the official documentation about this

            Basically you should end up modifying android/DaliClock/app/build.gradle to add the sort of stuff in that description. I have not tried this and won't have time to today, but I've done similar things in the past.

            Also, I'm slightly intimidated by the presence of the file my-keystore.keystore. If that's the private key for the APK you've released uh, don't do that?

            • jwz says:

              Oops! Well, at least that file had a password on it...

              I tried following those instructions before, and I couldn't make it work. Someone who understands this crap is gonna have to send me a patch.

              Also, it really makes me die inside when I see instructions that say "make sure this file has a password on it, that's so super important, but then put that password in a plain text file, probably in the same fucking directory." As if that's any different from not having a password on the file in the first place.

              I just pushed out version 2.43. http://www.jwz.org/xdaliclock/

      • Also you can use 'adb lolcat' because.

  9. Jim says:

    Works fine on my Google Nexus 5, Android 5.1 phone. This is very little delay when I rotate the phone. On my phone I can set 12 or 24 hour time but there is no setting for date format. Thanks for the port.

  10. Lloyd Wood says:

    So what you're saying is that porting DaliClock to the Apple Watch has... complications?

  11. flodadolf says:

    Woot! Progress! Finally, the most multi-platform clock ever has reached Android!

    But I wonder what the difficulty might be in porting this back so it could run on earlier Android devices? I mean: I first had Daliclock on a 486, and time passed and it was running on my vastly-less-powerful Handspring Visor.

    Fast forward to 2015 and over there on the shelf, is an OG Droid on its desktop dock, being a dedicated clock. It has 600MHz worth of 256MB of accelerated graphics glory. But it's running (IIRC) Cyanogenmod 7, which loosely translates to Android 2.something, which is a number which is less than 4.something...and that's about as good as it gets on this device.

    Android 2.something support would allow us feeble users the ability to pick up a craptastic old tablet at the thrift store, smash the APK into it, and have an awesome wall clock for very small dollars.

    (And yes I know that you, Jamie, don't really care enough about Android to be bothered with pissing on it if it were on fire.)

    • jwz says:

      It's more that I don't understand enough about Android to know what makes this code require 4.x rather than 2.x. My hope would be "not much"? Maybe someone who does know will send me a patch...

      • Robin says:

        It requires Android 4.2 because that is when Google added the Daydream API. I just really like the Daydream API, which is why I wrapped the clock with a DreamService. Apart from that there is nothing in there that wouldn't run on Android 2.x.

        The user would just have to manually start the app on older Androids (and the app would have to make sure the screen never turns off).

        • flodadolf says:

          So, in theory: I can download / build an APK, and have it Just Work on an old device?

          Like, today? Or will it call it quits because Daydream doesn't exist?

          Re: Screen turning off. IIRC, it was possible (under Developer Options) to actually keep the screen always on while charging in 2.0.

          In 2.2, they kept the option, but changed the definition of "always on" to mean "dim to some useless and arbitrary level after small minutes of inactivity and stay that way forever or until disturbed."

          Meanwhile Maps could always do it, and obviously media players. DockClock seems to do just find with that over here on that OG Droid.

          But, AFAICT, a user can't do it -- not without specific hacks. I think I tricked Tasker into sort-of doing it once, but it was always unreliable....and it involved setting the screen timeout to a big number, which is always a lesser number than infinity and therefore not all that useful for a wall clock.

  12. This is good, though the swipe directions you note above are the reverse of how I'm actually seeing them work in the app. (Nexus 5; Android 4.4.4)

    A question/suggestion: I don't know if you want to get this complex with a sub-feature of a platform you don't use, but could you include a Daydream mode setting to dim the screen? (Android's built-in Daydream "Clock" has this, for example.)

  13. Bill Paul says:

    So, you likely won't care about this at all, but since like you I'm just an unfrozen caveman, I have a Blackberry Z10 rather than one of those more newfangled devices that are the rage with all the kids.

    But in addition to its own native apps, Blackberry OS 10 runs Android apps in emulation mode, and it seems to like xdaliclock just fine, including all the gestures. (I have OS release 10.3.1.1865 on my phone, which is the latest and and greatest.) It doesn't support "Daydream" services though. (The emulation is not sexy enough for that. It doesn't support replacement keyboard input apps either.)

    Only two observations:

    1) It also shows the "month off by one" bug, but all that means is that the Blackberry Android emulation is just as dain-bramaged as the real thing.

    2) There are two ways I can background the app: one is to swipe up from the bottom of the screen (which is how you background all apps in Blackberry OS 10), the other is to press the "back arrow" button which is displayed in a task bar at the bottom of the screen. Android apps tend to have this task bar, native BBOS 10 apps generally don't. There is a way to hide the task bar if you're so inclined.

    If I use the "back arrow" button in the task bar to background the app, then I can foreground it again later and after a second or so it resumes ok.

    But if I use the "swipe up from the bottom of the screen" method to background it, it will crash when I foreground it again (which on the Z10 means it shows the error "Unfortunately, xdaliclock has stopped" and you must click OK to exit).

    Note that in the case where it resumes successfully, it actually seems to re-launch when I foreground it again -- the screen goes black and it starts out with the digits as vertical bars again, just like at initial startup. When I do it the other way, resuming the app causes it to display the last time display that was visible on screen when I backgrounded it for a second or two before I get the "Unfortunately, xdaliclock as stopped" message.

    Based on earlier reports, it sounds like this behavior too is not unique to the Blackberry.