Enabling Mock Locations in Android on Chrome OS

On a Chromebook in Developer Mode, it appears to be possible to successfully enable mock locations for Android via the command prompt. I tested the method in Terminal Emulator (which requires root in Android), but it should also be possible to do in the Chrome OS shell via adb.

In Developer mode, with adb debugging switched on in the Android Developer options, if we connect to Android via adb in the Chrome OS shell
sudo su -
adb connect 100.115.92.2
We can then switch on mock locations via adb
adb shell settings put secure mock_location 1
If a suitable fake location Android app (e.g. https://play.google.com/store/apps/details?id=com.lexa.fakegps) is installed on the device, this can be set as the default mock locations app
adb shell appops set com.lexa.fakegps android:mock_location allow  
To set a different app as the mock locations app, change the package name/App ID (com.lexa.fakegps in the example above) to the appropriate package name (as shown on the app's Play Store URL).

After setting Fake GPS as the mock locations app, I was able to select my mock location in Fake GPS and e.g. Maps in Opera would successfully show the mock location, rather than my current location. I haven't really tested in many other apps at this time. 

I understand that some Android apps may specifically check if mock locations are being used. For those apps, I imagine further steps would probably be required, such as perhaps installing (possibly a different app such as GPS JoyStick) as a system app. This, however, would require remaking the Android rootfs container as a R/W image. If this is required, the rooting script can be run, which, as part of the rooting process, replaces the Android read-only rootfs with a R/W copy.

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 apparently impossible to choose a third party input method for Android apps this way.

However, it is possible to enable third party input methods via adb in the shell, or with the Android 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' installed on the Android instance but had not been able to enable it, as it didn't seem to be possible to open up 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 was able to enable IMEs via the android shell 'settings' command, either in the Android terminal emulator (which requires root), or through Chrome OS via adb, which does not require a rooted Android instance.

Here's how I did the latter:

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 100.115.92.2
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 appending its ID to the latter string, i.e. entering
adb shell settings put secure enabled_input_methods org.chromium.arc.ime/.ArcInputMethodService:org.pocketworkstation.pckeyboard/.LatinIME
Edit: See the footnote at the bottom of this page for an alternate, perhaps easier, way to do this, and how to find the IDs for installed input methods

6. To set a new default, I 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!


To set the IME as default via adb: Rather than having to find the Android IME picker - after adding the ID of the input method to the 'enabled' list, I could have set it as the default with
adb shell settings put secure default_input_method [ID]
e.g. in this case:
adb shell settings put secure default_input_method org.pocketworkstation.pckeyboard/.LatinIME

7. Done! 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. 

In other apps, however, 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 Hacker's Keyboard's main settings dialog activity up.

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:

e.g. to have Gboard and the original CrOS virtual keyboard enabled and available to be chosen as default:
adb shell settings put secure enabled_input_methods org.chromium.arc.ime/.ArcInputMethodService:com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME
or to have both Hacker's Keyboard and Gboard enabled, in addition to the original CrOS virtual keyboard:
adb shell settings put secure enabled_input_methods org.chromium.arc.ime/.ArcInputMethodService:org.pocketworkstation.pckeyboard/.LatinIME: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). Edit: Although a 'back' button has now been implemented in CrOS in tablet mode, it is located in the shelf, which now seems to be getting pinned to the bottom of the screen, behind the keyboard.

I also tried out SwiftKey:
adb shell settings put secure enabled_input_methods org.chromium.arc.ime/.ArcInputMethodService:com.touchtype.swiftkey/com.touchtype.KeyboardService
This seemed to work quite well in portrait mode, but I did encounter some issues with graphics glitches in landscape mode.



Footnote: the 'ime' command (perhaps an easier method)


The above was what I did initially but it's not the only way. Similarly, it is possible, and perhaps easier, to enable input methods with the 'ime' command.

Installed input methods and their associated IDs (among other information) can be listed with
adb shell ime list -a
The IDs of currently enabled input methods can be listed with
adb shell ime list -s
An input method can be enabled with
adb shell ime enable [ID]
And an input method can be set as the default with
adb shell ime set [ID]

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

script

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@192.168.0.17 (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:

powerd_dbus_suspend

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@192.168.0.17 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, added the generated key to ~/.ssh/authorized_keys, and copied the keys to ~/Downloads.

cd ~/.ssh/
echo | ssh-keygen -P ''
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
cp -a ~/.ssh/id_rsa* ~/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
ls
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
ls
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.

Update regarding the latter: After an OS update, the only part that needed redoing was the SSH upstart job. After a powerwash, however, in addition to having to generate keys and add them to Secure Shell again, while the extension shortcuts (and Secure Shell profiles) themselves synced and restored OK , the icons did not. Next time, I'll see if adding a favicon URL instead of icon files works at all, and, if not, to restore them, I suppose I might have to add this into the customization scripts I run post-powerwash.

Sources:


(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


UPDATE: 

As of recent versions of Chrome OS, the procedure detailed below (using jscal) no longer works to remap keys for Android apps. The original post should now be considered deprecated and no longer applicable. 

 In some cases, Android apps will suffice to remap keys, and in other cases it may be possible to remap events in CrOS via evdev.


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:


shell

sudo su -
dev_install
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

evtest

Output:


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]:

6


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)


Output:


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.


vi/usr/local/jscal.sh


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
:wq!
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.


:wq!

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:

#!/bin/bash
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.

#!/bin/bash 
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.