22 November 2018

Android RxJava .delay() method


This is a weird one but it took up most of my day, so I thought I'd post it here for posterity. This article describes the problem very well:

https://dev.to/dbottillo/rxjava-a-story-about-delay-and-schedulers-j48

.delay(200, TimeUnit.MILLISECONDS)

In short calling .delay on a rxjava observable causes very strange results. The reason is because delay forces a change to the subscribeOn type. Why it does this is a mystery to me. However luckily the solution is very simple.

.delay(200, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())




28 August 2018

Raspberry Pi Photo Slideshow

I decided I wanted to use a Raspberry Pi to run a slideshow device, similar to the old scrolling photo screens. I needed something with an HDMI port that would scroll through my chosen photos with no user interaction. Raspberry Pi was a good choice for me as I already had two, they are low power and cheap. Plus if I lost one it would be considerably less painful than losing a laptop.

So first thing first I needed to sort the hardware out. I already had a Raspberry Pi 2 and a Raspberry Pi 1 so I wanted to use them. I wasn’t initially sure how the 1 would perform, but eager to see. The only other difference should be the SD card in the 1 and the micro SD card in the 2. Thankfully this made no difference to the process at all.

Next thing was the operating system. I downloaded Raspbian stretch with desktop and installed it on the SD card. Then of course fired it up and ran through the setup process. I deliberately didn’t set a password so the raspberry could log straight in. All of this was pretty straightforward.

Next I added the photos. The quickest way to do this was shut the raspberry down and plug the SD card into my laptop and copy the images onto the SD card. I put the images in /home/pi/Pictures/

Next I needed the slideshow part. For this I found a nice little tutorial:

This boils down to the following commands:

sudo apt-get install feh

Feh is a simple image viewer. Next we need a screensaver application that will show the images and scroll through them.

sudo apt-get install xscreensaver

This needs a little configuration. So goto start -> Preferences -> Screen Saver
Set the blank out time to 720. As the above article mentions this is the maximum time that you can force the screensaver can run for.

Test it out by running this command:

feh -Y -x -q -D 5 -B black -F -Z -z -r /home/pi/Pictures/

To exit press q.

Now we need to setup the pi so it starts the slideshow when it boots up, meaning all we have to do is power it up and it’s away. This bit got a bit more tricky. First we create an executable file with the feh command in so it can be run. I created this file at /home/pi/ and called it superscript. I gave it all permissions:

    Sudo chmod 777 superscript

Try running this a few times and make sure it works, it’s easier to diagnose problems now than it is later.

Lastly we need to run out superscript file on startup. To do this goto this folder:

    /etc/xdg/autostart/

And create a file called imageStartup.desktop

Add the following contents:

[Desktop Entry]
Type=Application
Name=imageStartup
Comment=All your base are belong to me
NoDisplay=false
Exec=/home/pi/superscript
NotShownIn=GNOME;KDE;XFCE;

Give this permissions as well and you are all set! On restart your images should loop.

Enjoy.

12 July 2018

Firebase Realtime Database - Custom Rules - Admin Write Permissions


Firebase is cool. Firebase realtime database is also cool. Rules...they are way less cool.

I joke, but protecting your Firebase realtime data is of course important and not to be under-estimated. I wanted to setup Firebase realtime database rules so only the database administrator (me) could enter or edit data. This took me a while to figure out as it involves not only setting the correct rules, but editing the metadata of the user.

Right so let's jump straight in, we're going to set the database rules to allow only edits by an administrator:

"rules":{
        "dinosaurs":{
            ".read":"auth != null",
            ".write":"auth.token.admin === true"
        }


You can see we've granted write permissions only if the user is an administrator. That was pretty easy. Sadly actually configuring which user is an admin is much harder.

First goto your Firebase console and click on the Authentication section, you should be on the user's tab. Locate the user you want to make an administrator and copy their User UUID.

To set this user as an administrator you'll need to use the Firebase Admin SDK. This isn't an Android SDK and so I'm afraid we're going to have to break into some NodeJS.

I'm not going to go into setting up NodeJS here, as it's a huge pain in the neck. Once you've got NodeJS setup, install the firebase Admin SDK as such:
https://firebase.google.com/docs/admin/setup?authuser=0

$ npm install firebase-admin --save

Now you'll need to return to your Firebase console and create a service key. In the settings section, goto service accounts and download a private key. You'll need to create one for NodeJS and you'll need to copy it to the NodeJS folder you're about to create. The path from the index.js file needs to be relative, mine is justin the root. As we won't be sharing this project, it should be fine, but you should never publicly host or share your private key.
Now you should be ready to run a NodeJS script which will set this user as an admin.

Create a standard node project and edit the index.js file. Add the following code:

var admin = require('firebase-admin');

var serviceAccount = require('./service_key.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: '*****'
});


admin.auth().setCustomUserClaims('#######', {admin: true}).then(() => {
// The new custom claims will propagate to the user's ID token the
// next time a new one is issued.
});

Replace the *** with your database url and #### with the UUID you copied earlier and run your nodeJs project.

That's it. Your user should now be an administrator, it can take a while to propagate, so try logging on and off a few times if it doesn't work right away.

What you've done here is set a custom Claim on that user. Basically some meta-data that describes that user as an admin. Your database rules will only allow administrators to edit that data. Here's a bit more info should you wish to take Calims further:
https://firebase.google.com/docs/auth/admin/custom-claims?authuser=0

Good luck, and have fun with Firebase.