Enabling third party input methods in Android on Chrome OS

At the moment, the default choice of input methods for Android apps in Chrome OS seems to be limited to either the physical keyboard, or the built-in Chrome OS virtual keyboard. Installing a third party Android IME and clicking on its 'Enable' button (which, on Android phones and tablets, usually brings up the Languages and Input dialog where third party IMEs can be enabled), brings up CrOS' own 'Languages and Input' settings dialog, usually found at chrome://settings/languages, rendering it impossible to choose a third party input method for Android apps this way.

However, I found that it is possible to enable third party input methods (such as 'Hacker's Keyboard' or 'Gboard') via the shell/terminal. Once the third party input method has been added to the list of enabled Android input methods, it can be selected as the default input method for Android apps.

I already had 'Hacker's Keyboard' (HK) installed on the Android instance but had not been able to enable it, as it didn't seem to be possible to open the Android 'Languages and Input' settings dialog. 

One thing I tried first of all was editing /system/etc/permissions/cheets.xml, as, in that file I noticed this:

   <!-- Disallow third-party IME apps in favor of ARC IME. -->
    <unavailable-feature name="android.software.input_methods" />

However, it turns out that editing this isn't necessary.

I discovered the following while playing around in the Android terminal emulator (Doing it that way requires root). However, I also tested doing it through Chrome OS via adb, which should be possible without a rooted Android instance. Here's what I did:

1. Enabled ADB debugging in the Android Developer options

2. Opened Chrome OS shell (Ctrl_Alt+T, type shell), and connected to the Android instance with:

adb connect

3. Agreed to the RSA authentication dialog popup (ticked the box).

4. To check currently enabled input methods I entered:

adb shell settings get secure enabled_input_methods

which returned: org.chromium.arc.ime/.ArcInputMethodService

5. Added HK to the list of enabled input methods by entering the following into the Chrome OS shell (all one line):

adb shell settings put secure enabled_input_methods org.pocketworkstation.pckeyboard/.LatinIME:org.chromium.arc.ime/.ArcInputMethodService

I then opened the Hacker's Keyboard app via the search button/launcher,`and tapped 'Set input method', which brought up the Android IME picker, where HK was now visible. Picked it as the default, and hit the "show keyboard when a physical keyboard is active" switch and it appeared!

Here's what it looks like in Firefox in tablet mode:

Caution is advised if enabling third party Android input methods this way - I found that HK mostly seemed to function as expected in tablet mode, working perfectly with some Android apps that I tried such as Firefox, e.g. popping up when a text input box was highlighted, then disappearing when I tapped away from the text input box allowing me to navigate by touch normally by dragging to scroll, tapping links, etc, and reappearing if an input box was highlighted again. 

However, in other apps, e.g. Terminal Emulator, the interaction seemed perhaps a little buggy; scrolling initially didn't work (but started working after I did a few things (fiddled with the 'Window Size and Orientation' settings in Android's 'Developer Options/maximised HKs parent app/rebooted), and after closing the keyboard, it didn't immediately pop up again when tapping in an input field.

Due to the latter issue, I found it necessary to customize the settings a little; in the Chrome OS shell, I entered

adb shell am start -n  org.pocketworkstation.pckeyboard/.PrefScreenActions

which brought up HKs 'Gesture and key actions' preference page. For the gesture 'Swipe Left', I chose 'Launch Settings', and for the gesture 'Swipe Right', I chose 'Close keyboard'. I then went back to the Hacker's Keyboard app and disabled extra languages for ease of swiping left/right over the spacebar.

Finally, I opened up the keyboard's main settings dialog by swiping left over the spacebar area, and ticked the 'Use permanent notification' box so that, should it not pop up automatically in any Android apps, it may still be activated simply by tapping the notification.

Rather than setting up a swipe gesture, for the purpose of opening the settings dialog to enable the permanent notification, I could instead have entered

 adb shell am start -n  org.pocketworkstation.pckeyboard/.LatinIMESettings

to bring it (HKs main settings dialog activity) up.

For testing purposes, I also tried installing Gboard from the Play Store. Again, it can be chosen as a default input method for Android apps, once its string has been added to enabled_input_methods:


i.e. in my case I entered (all one line):

adb shell settings put secure enabled_input_methods org.pocketworkstation.pckeyboard/.LatinIME:org.chromium.arc.ime/.ArcInputMethodService:com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME

Gboard worked OK but was not perfect; sometimes taking over the screen - the lack of a 'back' button in tablet mode being something of an issue (swiping down not seeming to work to disable it).

I think I'll keep Hacker's Keyboard enabled for the moment, if I get time I might try out some alternatives. All in all, it works quite well. The only real issue now is that I haven't figured out if there's a way to get it auto-resizing properly e.g. on screen rotate, with the current OS version. I just reverted to CrOS v59 temporarily to check something unrelated, and the auto-resizing works perfectly in v59 (Android 6.0.1) with every app I tested, so it's either a vagary of the current N multiwindow support, or one of the settings that I changed in 'Developer options'.

Running a shell command with a single click on a shelf shortcut on Chrome OS

I wanted to find a way to execute a shell command on a Chromebook via a single click on a bookmarked icon in the shelf. After a bit of research, I discovered a way to do it. It involves setting up the Chromebook as a ssh host, which is perhaps overkill, and could potentially have security implications, but also means I can access the chromebook's shell via ssh from my Android phone/tablet (or any other computer), which could be useful some day.

Here's how I did it on a freshly powerwashed device (in Developer mode). Not all of the below steps are strictly necessary; as ever, YMMV.

Briefly, what I did was: 

Installed Secure Shell extension; setup sshd on the Chromebook; added public key from ConnectBot (Android app) to ~/.ssh/authorized_keys in order to test connection; created profile to connect to chronos@localhost/my local IP address in Secure Shell extension; generated keys on Chromebook (in  ~/.ssh); added generated public key to ~/.ssh/authorized_keys; imported newly-generated private/public key pair within Secure Shell app (one by one); created bookmark link to chronos@localhost profile in shelf, and, finally, added required command to 'arguments' field of profile in Secure Shell.

A more detailed description follows.

1. Installed Secure Shell extension

Installed Secure Shell extension from https://chrome.google.com/webstore/detail/secure-shell/pnhechapfaindjhompbnflcldabbghjo?hl=en

2. (a) Added ssh upstart job to /etc/init/

Entered the following in the shell:

sudo ln -s /usr/share/chromeos-ssh-config/init/openssh-server.conf /etc/init/openssh-server.conf

The above file, openssh-server.conf, will auto-start sshd at boot, and, additionally, will add a firewall rule which opens port 22, enabling ssh access to the device from external networks. This firewall rule is only required if connecting from another device - to use ssh purely within the Chromebook, it is not necessary to open port 22. Therefore, if not intending to connect to the Chromebook from another device via ssh, one may create a .conf in /etc/init omitting this part. For instance, for purely accessing localhost, the following works for me:

sudo su -
echo "start on starting system-services


exec /usr/sbin/sshd

end script" > /etc/init/openssh-server.conf 
chmod 644 /etc/init/openssh-server.conf

2. (b) Registered and initialised upstart job

sudo initctl reload-configuration
sudo initctl start openssh-server 

The above pair of shell commands registered and then initialised the open ssh server. After entering the commands, the server was running in the background.

3. (a) Optional: Tested the connection with ConnectBot on Android tablet (Nexus 9)

This step is not actually necessary (unless you specifically want to control your Chromebook in the shell with an Android device).

Rebooted Chrome OS, launched ConnectBot, generated Pubkey, long-pressed on newly-generated key, chose Copy public key. Mailed it to self. Opened Gmail on the Chromebook, copied key from email, opened shell tab (non-root) and added the key to Chrome OS as follows:

(*DOUBLETAP* indicates a double tap on the touchpad to paste the key)

touch ~/.ssh/authorized_keys
echo *DOUBLETAP* > ~/.ssh/authorized_keys
chmod 600  ~/.ssh/authorized_keys

Created a new host profile in ConnectBot; set the second field as chronos@ (my local IP address); left all other fields as default.

Connected to the profile...

chronos@localhost / $

Success! Disconnected ConnectBot. Back in the host profile, edited the field "Post-login automation". to add a shell command:


Connected to the profile...

The Chromebook sleeps!

Long pressed the N9 homescreen to bring up the "Add Widget" dialog. Dragged ConnectBot to homescreen. Chose chronos@ from the pop-up list of hosts. Tapped the new homescreen shortcut...

The Chromebook sleeps!

Unfortunately, the current implementation of Android on Chrome OS doesn't appear to support  creating homescreen 'widget shortcuts'. So it seemed that another approach was required in order to create the one-click shortcut.

3. (b) Connected to the Chromebook... from the Chromebook

Opened Secure Shell extension in Chrome with the keyboard shortcut Ctrl+Alt+T, typed ssh, in omnibar, hit Tab, hit Enter.

Clicked on "New Connection"

Typed chronos@localhost

Clicked on "Connect"

At this point, it only seemed to be possible to connect  after setting a password for chronos (passwd chronos), and then the password had to be entered manually at every connection. No good for automation. 

Some further setup seemed to be required.

Generated a new key:

cd ~/.ssh/


Added the generated key to ~/.ssh/authorized_keys

cat /home/chronos/user/.ssh/id_rsa.pub >> /home/chronos/user/.ssh/authorized_keys

Copied the keys to ~/Downloads

cp -a /home/chronos/user/.ssh/id_rsa* /home/chronos/user/Downloads/

Opened Secure Shell

Chose 'Import'

Navigated to private key in the file explorer (/home/chronos/user/Downloads/id_rsa). Clicked on it.

Chose 'Import', again

Navigated to public key in the file explorer (/home/chronos/user/Downloads/id_rsa.pub). Clicked on it.

Tried connecting to the chronos@localhost profile in Secure Shell again and... Boom!

chronos@localhost / $

4. Bookmarked the extension

With the Secure Shell profile command prompt tab open (which looks identical to the regular shell command prompt tab, except that in the address bar, rather than ending with crosh.html, the address ends with a profile number):

Three dot menu at top right>More tools>Add to shelf (open as window)

This created a clickable shelf bookmark icon.

5. Added the shell command

So now it was possible to open a shell command prompt with a single click, the final part of the puzzle was to add the command of interest. This turned out to be a piece of cake, once the syntax was correct. All that needed to be added to the saved Secure Shell profile was 

-- thecommand

...to the SSH Arguments field.

So, after adding 

-- powerd_dbus_suspend

to the SSH Arguments field for my chronos@localhost profile, the final result is a bookmark in the shelf which, when clicked, sends the Chromebook to sleep. Since I added it to the 9th position on the shelf, it can also be triggered with the keyboard shortcut: Alt+9.

I am not sure if it will be possible to set it up so that the command runs without opening a window, but it does at least seem to remember the window size and position, so the window can be hidden away at the side, or rolled up' into a small bar. I think it might be possible to set it up so the command runs in the background but I haven't looked into this yet.

Other use cases: Crouton etc.

Over on xda, user DandyRandyMarsh posted that he was able to successfully use this procedure to set up a shelf shortcut to open single apps within a crouton chroot in a window, simply by following the above and adding the relevant crouton command to the SSH Arguments field. He shared his example, a shortcut to enter steam;

-- sudo enter-chroot xiwi steam

One thing to bear in mind with this is that if your setup requires a password to sudo, you may need to change the command slightly. I haven't tested it out too much, but in my case, with a password prompt for sudo and a chroot on an external drive, I can open Firefox within my Ubuntu chroot in a xiwi window with a shelf shortcut after adding 

-t -- echo mypassword | sudo -S sh /media/removable/3/bin/enter-chroot xiwi firefox

to the Arguments field.

Similarly, I set up a shelf shortcut to open my chrooted Ubuntu desktop in a window with the argument

-t -- echo mypassword | sudo -S sh /media/removable/3/bin/startxfce4

Another way to do it is to save the string to a file in /usr/bin, then just put -- thefile as the argument. This is what I did with a few commands that I find it tedious to regularly open up a prompt and enter in, such as the ectool command(s) to switch off the bright LEDs on the side of the device:

sudo ectool led power off
sudo ectool led battery off

Customizing the icons

Of course, no-one wants a bunch of generic black squares darkening their desktop, so, in order to customize the shelf icon for these shortcuts, a few extra steps are necessary. 

Although the trick of injecting a favicon via js only seems to work for websites, and customizing the icon for Secure Shell itself might be pretty pointless as it'd be the same for all shortcuts (and get lost after the extension updates), we can set custom icons for our shell shortcuts as follows:

When you add shortcuts to the shelf on Chrome OS like this, a minimal app is created for each one, with its own manifest.json, and icon.pngs. Initially, the shell shortcuts were getting created with blank pngs as the icons by default (appearing as a black box with P in the center). 

So, all we need to do, is get some icons, find the right directory for our shelf shortcut app, then copy our new icons into it...

For instance, here's how I made a nice shiny icon for my single app shelf shortcut to Firefox.

(a) Prepared icons

Created a temporary directory in ~/Downloads to store my icons. 

Prepared a set of six icons in ~/Downloads/firefox. (I downloaded mine from findicons.com). 
To avoid any manifest editing, saved them as *size*.png

e.g. 32.png; 48.png; 64.png; 96.png; 128.png; 256.png

(b) Located correct directory to copy icons into; copied icons into folder:

Easy way:

As long as a somewhat unique name was chosen for the shelf shortcut, the easiest way to locate its directory is probably

cd ~/Extensions
grep -r thenameoftheshelfshortcut

Navigate to the Icons subdir, check its contents and copy over the new icons i.e. in my case:

cd thenameoftheshelfshortcut
cd */icons
sudo cp ~/Downloads/firefox/* .

Other way:

If a generic name was chosen, and grepping it brings up too many results to go through,
another way to locate the correct directory is as follows:

(It is probably easiest to do this directly after clicking "add to shelf")

To change directory into the most recently modified extension icon subfolder automatically, the following works for me. 

cd ~/Extensions/&&cd $(ls -v1td */ | sed '/\Temp/d' | head -1)/&& cd $(ls -v1td */ | head -1)/icons&&ls -al

If the above one-liner worked correctly, a list of blank icons (*.png) should be visible. The file creation time/dates should be checked, and if they match the time the shortcut was added to the shelf, the directory is the right one, and new icons can simply be copied over these, e.g.

sudo cp ~/Downloads/firefox/* .

If the one-liner didn't work;  the icons directory can be located manually i.e.

ls -ltr ~/Extensions 

The most recently added folder is at the bottom. Then, 

cd themostrecentlyaddedfolder

(or, the folder modified at the date/time that the shortcut was "added to shelf"). Then,

cd */icons
sudo cp ~/Downloads/firefox/* .

I repeated the above with a set of Ubuntu icons for my startxfce4 shortcut, and a few other Linux programs I use via crouton, for good measure.

Then just did sudo restart ui, and enjoyed the shiny new shelf icons!

I hope that these changes will get picked up by CrOS's extension sync, thus getting backed-up and restored automatically. At this point I am not sure if that will be the case, though. 


(1) https://www.dereckson.be/blog/2015/01/15/chromebook-run-a-ssh-server-on-chrome-os/

(2) https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/master/chromeos-base/openssh-server-init/openssh-server-init-0.0.1.ebuild

(3) https://chromium.googlesource.com/apps/libapps/+/master/nassh/doc/FAQ.md

(4) https://groups.google.com/a/chromium.org/forum/#!msg/chromium-hterm/UpQRttX_LJk/Wj241kcSCAAJ

Configuring a gamepad manually for Android on Chrome OS

In order to play Android games on Chrome OS with a wireless Xbox 360 gamepad I found that, while the gamepad worked well in some games, for others it seemed that some configuration was required.

I wanted to play the game "War Robots" but when I opened it up I discovered that, while I could move and aim, the buttons to fire were incorrectly mapped.

First of all, I tried creating /system/usr/keylayout/Vendor_045e_Product_0719.kl on the Android filesystem, as this was what had worked for me to configure this gamepad on my Nexus 9. However, editing the Android keylayout didn't seem to do anything on the Chromebook. I had a look around the device and found that in the list of CrOS installable packages at /etc/portage/make.profile/package.installable, the following was included: games-util/joystick-1.4.2.

Accordingly, I emerged joystick-1.4.2 and played around with jstest and jscal.

The set of commands to emerge these binaries:

sudo su -
emerge joystick

Turned out I that with this I was able to easily swap gamepad button mappings around.

First of all I dumped the current mapping with

jscal -q /dev/input/js0

which gave the following output
jscal -u 6,0,1,2,3,4,5,15,304,305,307,308,310,311,314,315,316,317,318,704,705,706,707 /dev/input/js0

In order to determine which number corresponded to which button, I tried

jstest /dev/input/js0

However, when I pressed some buttons on the gamepad, numbers for the buttons were displayed which did not correspond with the set above. So I tried evtest

emerge evtest



No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0:      cros_ec
/dev/input/event1:      ROCKCHIP-I2S Headset Jack
/dev/input/event2:      RockchipHDMI HDMI Jack
/dev/input/event3:      gpio-keys.10
/dev/input/event4:      Elan Touchpad
/dev/input/event5:      Elan Touchscreen
/dev/input/event6:      Xbox 360 Wireless Receiver
/dev/input/event7:      Xbox 360 Wireless Receiver
/dev/input/event8:      Xbox 360 Wireless Receiver
/dev/input/event9:      Xbox 360 Wireless Receiver
Select the device event number [0-9]:


Hooray! Pressing the buttons on the gamepad gives useful output, such as

code 311 (BTN_TR), value 1
code 315 (BTN_START), value 1

and so on

Armed with this information I was easily able to fix the mapping in War Robots, which had one "Fire" button mapped to "Start" and another "Fire" button mapped to "Back". I found a number of reports online suggesting that this is a current issue with (lack of) controller support in the game itself, rather than any quirk of running Android on Chrome OS.

jscal original dump of mappings:
jscal -u 6,0,1,2,3,4,5,15,304,305,307,308,310,311,314,315,316,317,318,704,705,706,707 /dev/input/js0
Mod for War Robots;
swapped Start (315) with R1 (311) and Back (314) with L1 (310):
jscal -u 6,0,1,2,3,4,5,15,304,305,307,308,314,315,310,311,316,317,318,704,705,706,707 /dev/input/js0
Opened up the game. Now L1 and R1 are the fire buttons!

Saved the config. to a file with:

jscal -q /dev/input/js0 > /usr/local/WR_gamepad.sh

Unfortunately I also had another issue to fix. There is a fair amount of play in both the analog axis of my controller, the right one particularly, meaning that with the controller at rest, it's sometimes still pointing to the right slightly. In order to stop the annoying 'camera moving to the right without me moving it' issue, I needed to calibrate the dead zones.

Back to jscal:

jscal -c

(went through the calibration, which involves pressing each button/moving each axis once)


Calibrated axis:

Setting correction to:
Correction for axis 0: broken line, precision: 0.
Coeficients: -338, -338, 16555, 16217
Correction for axis 1: broken line, precision: 0.
Coeficients: -8, -8, 16388, 16380
Correction for axis 2: broken line, precision: 0.
Coeficients: 126, 126, 4260750, 4161663
Correction for axis 3: broken line, precision: 0.
Coeficients: -64, -64, 16416, 16352
Correction for axis 4: broken line, precision: 0.
Coeficients: 55, 55, 16357, -16357
Correction for axis 5: broken line, precision: 0.
Coeficients: 111, 128, 4836527, 4227201

Dumped the above corrections with

jscal -p /dev/input/js0
which gave the following output:
jscal -s 6,1,0,-338,-338,16555,16217,1,0,-8,-8,16388,16380,1,0,126,126,4260750,4161663,1,0,-64,-64,16416,16352,1,0,55,55,16357,-16357,1,0,111,128,4836527,4227201 /dev/input/js0
Dumped it to a file:

jscal -p /dev/input/js0 > /usr/local/jscal.sh

First attempt at editing dead zones.


Original file contents (as above):

jscal -s 6,1,0,-338,-338,16555,16217,1,0,-8,-8,16388,16380,1,0,126,126,4260750,4161663,1,0,-64,-64,16416,16352,1,0,55,55,16357,-16357,1,0,111,128,4836527,4227201 /dev/input/js0

Changed the 4th and 5th values (axis 0) and the 22nd and 23rd values (axis 3) from -338,-338 and -64, -64 respectively to +/- ~3000 (Axis 0 and 3 are L-<  >+R on the two analogs).

New file contents:
jscal -s 6,1,0,-3038,3038,16555,16217,1,0,-8,-8,16388,16380,1,0,126,126,4260750,4161663,1,0,-3064,3064,16416,16352,1,0,55,55,16357,-16357,1,0,111,128,4836527,4227201 /dev/input/js0
sh /usr/local/jscal.sh

Opened up the game. Still some drift in the right-hand analog. Let's have a look at what's going on with jstest:

jstest /dev/input/js0

Moving the analogs different ways, dropping them to center, and watching the values change in jstest confirms that while there is play in both sticks, the right hand side of the right hand stick is particularly loose.

Second attempt at modifying the calibration

vi /usr/local/jscal.sh

Tried -3064,10064 on axis 3.

sh /usr/local/jscal.sh

Opened up the game. This one works quite well! I probably set it a little too high, but at least there's no right hand drift at all, now.

Final file contents:
jscal -s 6,1,0,-3038,3038,16555,16217,1,0,-8,-8,16388,16380,1,0,126,126,4260750,4161663,1,0,-3064,10064,16416,16352,1,0,55,55,16357,-16357,1,0,111,128,4836527,4227201 /dev/input/js0  
Added a shebang as it appears that a rule can be added to udev on other Linux systems, and the calibration file placed in /usr/local/bin, meaning that it would auto-calibrate whenever the gamepad is plugged in. I would expect this to would work on Chrome OS also, though I imagine it'd get wiped out when the system auto-updates. For now, I'll just pop open a shell and run sh /usr/local/jscal.sh when I want to play Android games with the Xbox 360 joypad, and, similarly, sh /usr/local/WR_gamepad.sh when I want to play War Robots. 

Having tested with a few other games, it turns out that after manually editing the dead zone values, the next pair of values also needs to be changed in order for the full range of stick movement to be correctly recognised. Not an issue in WR, but it would be in some games. Testing the gamepad in "Modern Combat 5", I found that in addition to changing the dead zone value pairs to eliminate camera drift, I also had to increase the next set of values by a few thousand, in order for the game to recognize when I had moved the right analog stick all the way to the top/bottom/sides. (confirmed in jstest)

The following config seems to work well in MC5 to eliminate camera drift while still passing maximum values reasonably close to the original. It still doesn't quite give the proper maximum range, but seems close enough to work well for this game.
jscal -s 6,1,0,237,237,16266,16503,1,0,797,797,16153,16792,1,0,126,126,4260750,4161663,1,0,-3908,3908,18086,18694,1,0,-6989,6989,19894,19904,1,0,122,125,4400447,4129650 /dev/input/js0
My setup could use some further editing/fine tuning in order to achieve the best operating results (optimize the dead zones even more, could do with adding a "Jump" button in WR), but I'm happy enough with the config as is at the moment. 

I imagine that for other 360 gamepads needing to be configured, a slightly different set of values would probably need to be applied as, depending on the state of the analog sticks, the dead zone areas would most likely differ somewhat.

TL;DR version:
It's possible to change the button mappings on a 360 gamepad on Chrome OS by emerging joystick-1.4.2, dumping the values with jscal -q, changing some values, and applying them with jscal -u. Similarly, analog stick dead zone calibration can be dumped and applied with jscal -p and jscal -s respectively. The changes won't persist after the gamepad is removed, but by saving the edited values to a shell script, the fix is convenient to reapply. 

Customizing the Chrome OS boot animation

Somehow I prefer the look of the Chrome logo in black and white, so I thought I'd see if I could change the boot animation to one which was more aesthetically pleasing (for me).

It turns out that this is very simple and easy to do. Developer mode needs to be on, of course, and rootfs verification switched off.

The boot animation comprises 17 images, which can be found in PNG format in /usr/share/chromeos-assets/images_200_percent and /usr/share/chromeos-assets/images_100_percent,named boot_splash_frame1.png thru boot_splash_frame17.png.

The file at /etc/init/boot-splash.conf can be checked in order to see which set of images is being used (if in doubt, change one set and reboot to see if it sticks).

The images can then simply be copied out, edited, and replaced. Extra images can also be added, named boot_splash_frame18.png, boot_splash_frame19.png, and so on, extending the animation. It fades to the desktop after the usual period of time, more-or less, though. I copied frame 17 to frame 18, frame 16 to 19, 15, to 20, and so on, so the animation starts to reverse after it would usually finish.

In addition, the display frame interval can easily be changed in order to speedup or slowdown the animation. Look for --frame-interval in  /etc/init/boot-splash.conf (the first instance - the frecon command, is the relevant one on my device).

By default, the frame interval is set to 25.

Change it to 50 or 75 for a slightly slower animation. It is also possible to change the animation background screen colour hex code here as well (although sadly not the initial white boot screen, which is coded into the firmware & requires removal of the write-protect screw to modify). 

As an example, here's what I did:

mkdir ~/Downloads/Edited
mkdir ~/Downloads/Backup
cd /usr/share/chromeos-assets/images_100_percent
cp * ~/Downloads/Edited
cp * ~/Downloads/Backup

Opened boot splash files in image editor, made changes. The built-in image viewer in Chrome OS is rather limited so I downloaded the free app  'Image Editor' from the Play Store. Saved edited files to Downloads/Edited. Copied files back to /usr/share/chromeos-assets/images_100_percent

sudo cp ~/Downloads/Edited/boot_splash* /usr/share/chromeos-assets/images_100_percent

vi /etc/init/boot-splash.conf 

(changed frame interval from 25 to 50)

sudo reboot

Here's a GIF of what it looks like (if it shows up in a box, that's just due to it being a GIF):

Could be improved, but it's not too bad, for a first attempt, I think.

The edited PNGs forming the above can be downloaded here