Sunday, November 18, 2018

IKEA TRADFRI review - a layman's smart home

I recently bought a few parts of the IKEA TRADFRI collection to get a taste of the future everyone's talking about: smart home. To get to know the system I bought the gateway, remote control, power plug and a light bulb.

Hardware

The components look very good if you like the usual minimalistic IKEA style (I do). They are mostly white and made of plastic that doesn't look too shiny but also doesn't look cheap. In fact, I wouldn't mind to have the gateway standing in the middle of my living room beneath the TV (on an IKEA shelf, obviously).

The IKEA website and also the local guidance at the store made it sound like you have to buy the (quite expensive) remote control in order to pair devices, which sounded ridiculous to me. I bought it anyway to make sure I can go through the whole setup. After setting it all up I understood that in fact I don't need THAT remote control, but I need SOME remote control from the TRADFRI collection. Since I bought the power plug in a bundle with a nice, small remote control I am able to return the expensive remote control now since there is no point in having it for me. After all the idea was to have a smart home, which means less physical controls and use apps instead!

Setup... not necessarily suited for your grandmother


Setup was mostly easy as the app explains what you need to do for each step. The manuals delivered with the product were surprisingly bad as there was 1. a lot of stuff that is not relevant (certifications, warranties, etc) and 2. the usual IKEA-style manuals don't fit such a product very well as pictures are not always enough to cover all the information that is necessary.

After ditching the manuals completely and relying on the instructions given by the app instead I was able to go through the setup. Overall it is more complicated than I'm used to from other IKEA products (which are non-tech products of course), but still better than the setup of other more geeky products. I could imagine a layman to set this up if he dedicates some time and effort into it.

However the thing that made the setup take much longer than expected for me is that there's a certain amount of randomness to the setup. I had to repeat some of the steps once or twice until it finally went through. For example, after setting up the second device I had to pair the first device again for some reason. I'm pretty sure that this was due to an error on my side, but there was no indication what went wrong. A person that is less technically versed might very well have given up halfway through...

Usage and features

After setting it all up the excitement went through the roof. The official app is a pleasure to use, very intuitive and responsive. I've seen much worse apps from big-name companies (look at the Playstation app for example...).

What you get by default is what you would expect: you see the state of each device (turned on / off, etc) and change those settings in a breeze. There's also presets to change the color of a light bulb to match your mood, i.e. "relax" to make it a very dim, warm light.

The real fun started for me when I discovered the Google Home integration. Again the setup for that was not flawless as I had to restart it a few times, but eventually it worked out fine. Afterwards all my devices showed up in the Google Home app, which offers similar features to the app offered by IKEA itself: turn on / off devices, see their current state, change brightness (but not the color!).

The thing that made me whee was when I tried to use this using the Google Assistant: "OK Google, turn on the living room lights." - "Ok, turned on the living room lights" - BOOM! But that's not all: with the IKEA app you are only able to control devices while you are connected to the same WiFi network. Guess what? With Google Home / Assistant you can do the same from anywhere in the world - no further setup required! Not sure if you turned off the lights before leaving home? No problem, you can check it from remote and turn it off if necessary.

The other thing I'm using is the power plug, which controls my towel heater in the bathroom. So lazy me being lazy, I can use an app while sitting on the couch to pre-heat the bathroom. Welcome to the future, you lazy idiot! :)

Conclusion

I'm really happy to own these products now and I'm considering where to apply them next. In my opinion it doesn't make sense to equip your main lightning with smart bulbs as they won't work if somebody turns them off using the physical switch anyway. So in the "worst" case you try to turn it on using the app but it doesn't work because someone used the physical switch to turn it off earlier. That completely defeats the purpose of the whole thing in my opinion. I could imagine to use a few more of the smart power plugs though as they are very versatile and can turn an old-fashioned device into a semi-smart one.

Designing a good on-boarding experience for an Android app

After noticing that most users of one of my apps are uninstalling the app shortly after installing it I set out to redesign the on-boarding experience of the app. Having made good experience there before, I created a competition on 99designs asking for suggestions. Most of the proposals suggested using either a wizard-style introduction or a descriptive landing page that is shown every time the app is opened. After some back and forth with designers participating in the competition I decided to implement both: on first start a three page introduction is shown to the user. On subsequent launches a landing page is shown that tries to summarize the core features of the app to make sure the user remembers why he installed the app in the first place.

During a quick search for libraries AppIntro seemed most up-to-date and offered most of the features that I'd expect. Implementation turned out to be straightforward for the most part, but making the design match what was agreed on during the design competition turned out tricky:

Changing the next-button to show text instead of an image

By default the library shows an arrow to indicate the next-button. The designer intended to show "NEXT" as text instead, which I think makes it a little more obvious for unexperienced users what to do when looking at the introduction screen. Since that was not a feature of the library I had to hack it in: Changing the next-button to show text instead of an image in AppIntro

Show image above description text

Something that surprised me is that by default the library shows your description text at the top and the image below that. At least for my purpose this didn't make much sense as the image was mainly used as decoration to spice up the screen a bit. Again, I came up with a workaround myself: Show image above description text in AppIntro

OutOfMemory crash

As soon as I launched an update with the library included crash reports started to trickle in via Firebase. The stacktrace looked like this:
Fatal Exception: java.lang.OutOfMemoryError
       at android.graphics.BitmapFactory.nativeDecodeAsset(BitmapFactory.java)
       at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:483)
       at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:351)
       at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:773)
       at android.content.res.Resources.loadDrawable(Resources.java:1937)
       at android.content.res.Resources.getDrawable(Resources.java:664)
       at androidx.appcompat.widget.ResourcesWrapper.getDrawable(ResourcesWrapper.java:130)
       at androidx.appcompat.widget.TintResources.getDrawable(TintResources.java:46)
       at androidx.core.content.ContextCompat.getDrawable(ContextCompat.java:479)
       at androidx.appcompat.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:203)
       at androidx.appcompat.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:191)
       at androidx.appcompat.content.res.AppCompatResources.getDrawable(AppCompatResources.java:102)
       at androidx.appcompat.widget.AppCompatImageHelper.setImageResource(AppCompatImageHelper.java:86)
       at androidx.appcompat.widget.AppCompatImageView.setImageResource(AppCompatImageView.java:94)
       at com.github.paolorotolo.appintro.AppIntroBaseFragment.onCreateView(AppIntroBaseFragment.java:111)
This is a known issue when using drawables the lazy way: I only added the drawables in one resolution instead of scaling it down for low-end devices. This causes some devices to run out of memory while scaling down the images at runtime. Fortunately I found a plugin called "Android Drawable Importer" that does all of this for you in Android Studio. Here's a tutorial for installing and using the plugin.

Changing color of status bar to match screen background

This turned out to be surprisingly complicated! The background of my introduction was white, so I wanted the status bar to match that, to make the image more of an eye catcher. I quickly found a way to make the status bar transparent, but that left the icons there to be invisible (white on white...). Some research and a lot of trial-and-error later I ended up using a custom theme for the activity, which falls back to a black status bar on old devices, but uses black-on-white icons on newer devices! Here's the necessary XML for newer devices and the one for old ones.

Eventually the redesign turned out fine and I was happy to use the AppIntro library. If you want to see the result take a look at the screenshots for OpenDocument Reader on Google Play.

Friday, February 9, 2018

Remove access for user from multiple files on Google Drive

Sometimes people leave a project and you want to make sure they don't have access to any of your potentially confidential documents, or make further changes to important data you collected in spreadsheets. A friend of mine recently faced such an issue and I tried to solve his pain. At first I came across an article to remove access to multiple documents via the Google Drive website. This worked, but turns into a tedious task if you have lots of files!

I turned to Google Apps Script for a solution because I had a nice experience with it in the past. I was able to build a script within a very short time that does exactly what I need, but has some drawbacks:
  • does not work for files which are owned (created) by the user you want to remove
  • you need to manually run the script a lot of times, because there is a limit for how long a script can run continuously. Since Apps Script operates quite slow, you easily reach that limit. However, the script goes on where it stopped the next time you run it!


To use this create a new project at https://script.google.com/, copy the script into it, enter the email of the user you want to remove and run it. At some point it will tell you that the script failed, but you can run it again at this point. You will have to repeat that a lot of times, so be patient...

One could further improve this with a simple UI and triggers to re-run the script automatically before it reaches the time limit, but it did the trick for me so I thought I'd share it here!

Monday, January 1, 2018

Building a website wrapper in Cordova

A friend of mine asked me to build an app for his company which has all its business logic implemented on a website. Besides me not being able to spend enough time to build native apps for Android and iOS for him, there was no API implemented anyway (website was all server-rendered). I decided to go with an approach that I already used for my previous company: enhance an existing website with native features using Apache Cordova.

Let's start with the easy part:

Wrapping a website with Cordova

That's easy! Create a new Cordova project and change config.xml as follows:

  • change src-attribute of content-tag to your website, e.g. https://tomtasche.at
  • add a new line below content-tag: <allow-navigation href="https://tomtasche.at/*" />
Now... no wait, we're done! I told you it was easy. What you get now is an app you can install on your device and eventually release on app stores*!
To make it even more appealing, your app will automatically benefit from changes to your website, since it is basically just a camouflaged browser accessing your website. No need to worry about updating the app separately.

Add native features to your website

This is where it gets interesting: we can leverage Cordova to add access to native device features like GPS, camera, sensors, files and many more. You may also use it to better interact with the system. For example you could make use of a seamless Facebook login if the user has the app installed on his device.
  1. To do this, you have to first install the plugins you plan to use as per the documentation and build your project afterwards
  2. If everything went well you should be able to copy the folder located at platforms/android/app/src/main/assets/www and host it somewhere (e.g. where your website is hosted too)
  3. Next include a script-tag on your website to load the cordova.js-file located in this directory
    • Make sure to only load it when your website is being accessed from Cordova! For example, you could load your website with an app-specific query parameter and store a cookie based on that.
  4. The last step is to call the Cordova plugins you installed as per their documentation and make use of them!
    • Again you should only attempt to call those plugins if your website is being accessed via your app. You could use feature detection to achieve that, i.e. check if the global variable of a plugin exists.
Using this approach you are able to create a hybrid app which shares the same codebase with your website. I would not recommend to do this for big projects, but for small companies which can't afford (money and timewise) to build a full-blown native app.

So let's recap what we have now:
  • An app that is ready for release without investing too much time. I was able to pull this off in one weekend (I spent two thirds of the time on figuring out how to do this - you won't have to do that yourself)
  • Reuse current codebase of an existing website, but enhance it with access to native features, therefore providing a better user experience
Check out my other blog post for some reasons why you would want to keep your hands off of Cordova!

*Apple might reject your app at this stage. You might be able to workaround this by adding native features to your website as described above!

Lessons learned using Cordova in 2017

I would not refer to myself as an expert in Cordova, but I already had the pleasure to work with it (extensively) in a few occasions over the last few years, including but not limited to prototypes for weird would-be projects of friends of mine, production apps for my own company, plugins for products of a company and production apps for other companies. Sounds like a lot? Well, no - most of those projects were based on a technique to wrap an existing website in Cordova drastically reducing the amount of code that needed to be written from scratch. But I can tell you tales of suffering from those projects - because Cordova is not pleasant to use in most cases. But it gets the job done... eventually. I guess.

Here's a few of the things that I learned:

Most updates break something

...be it a plugin, the build process or something else. If you're working with other developers it is crucial to use the same version of Cordova on all development machines! I should mention that this experience mostly comes from my projects being several months or years apart, which of course leads to breaking changes when updating from one major version to another. But that brings me to my next point:

Outdated plugins and documentation

There is a lot of very popular plugins that are simply no more maintained by the original author. The one that I had most problems with was phonegap-facebook-plugin (in retrospective I could have saved myself a lot of time by noticing the plugin still referring to "phonegap" rather than "cordova"). Thankfully there is a popular fork available which keeps maintaining the plugin, but that again is not compatible to the latest version of Cordova. Well, at least there is another fork for that which is a sign for how active the community is.
The same problem goes for documentation and the information available in general. While searching for a problem you are likely to dig up lots of articles from anno 2014. Not a problem per se, but reread the previous to paragraphs if you don't see why this is a problem for Cordova.

Weird bugs.

One more thing that almost cost me my sanity is that Cordova by default does not honor a website's viewport setting. An experienced web developer might have figured that out a lot faster, but it took me hours to understand why a website looked different when rendered in Cordova vs a browser. The solution was to use a plugin that was... well outdated and not compatible to the latest version of Cordova. :) Fortunately I was able to fix that easily.

I guess that's it for now. I was able to let the steam off! Please don't get me wrong: Cordova is great for some things, but I wish the whole developer experience would be more "consistent" in general.