I'm Nicholas FitzRoy-Dale, a software developer from Sydney, Australia. I'm interested in embedded systems and operating system research, code optimisation, 8-bit music, rock climbing, shiny things...
Update 2: A better (and probably, the final) implementation of this idea is now available here.
Update: I implemented this idea. It works even better than I thought because Android lets you auto-start apps when NFC cards are scanned. More info (and APK) here.
I like the KeePassX password manager, but it's a hassle to enter my password all the time, especially on a phone. Also, I frequently have to enter the password in places with video surveillance. This feels pretty unsafe.
My phone supports NFC so it would be pretty easy to just store the password on an NFC tag. But of course if someone scans the tag they have my password.
Proposed solution therefore is:
Pad the password to 127 bytes (or some other arbitrary amount). Prepend the password length (or stick a 0 at the end or whatever).
Generate 128 bytes of random numbers.
XOR the padded password with the random numbers to produce an encrypted padded password. Store that on the phone.
Store the random numbers on an NFC fob.
This means that I could scan the fob, the phone would XOR the random values with the encrypted password, and then use the result to unlock my KeepassX database.
If someone stole (or scanned) the fob, they would just get random data. If someone stole my phone they would also just get random data (effectively). The key and the ciphered data are the same length, so knowing one cannot possibly help you deduce the other.
Of course, someone could just steal my phone and scan the fob. While that could happen it seems pretty unlikely as my phone and my keys are always in different places. Also they would have to know that this is how I store my passwords, which they wouldn't unless I were being specifically targeted, which seems unlikely.
Can anyone see any problems with this scheme? If not I might implement it in KeepassDroid.
I'm pleased to release a Vim plugin that I've been working on for a little while. File Pirate is a file picker for Vim. When summoned, it pops up a Vim window and displays all files which match the search term you type. Select a result and press enter, and the file is loaded. The focus is on speed of search and loading: looking for files shouldn't make you wait and take you out of flow.
There are lots of these sorts of plugins already. I wrote this one because I am currently working with a large directory structure (~50000 files) and existing plugins were very, very slow. File Pirate is fast -- for 50k files, you shouldn't notice any delay when performing a search.
Screenshot:
The other interesting thing about File Pirate is that it tries to be asynchronous -- searching and indexing happens in the background, so the user interface is always responsive. This is unusual in Vim, which is single-threaded.
It's known to work on GUI and console Vims on Mac and Linux. There's lots more information at the github link, so give it a go if you use Vim on large code bases.
I just finished coaxing the HxC USB Floppy Emulator code to run on my Mac. It was a bit annoying, and in the middle of it I was going through my usual Linux guilt complex about how much easier this would be on Linux and how annoying it was that the Mac was so incompatible with Linux.
But then I got over it and realised that it was going to work. This code base written for an entirely different operating system was going to work, and all it took was a bit of build system tweaking. That's amazing. The hardest part was understanding the HxC code base. *
Now it's all working and I'm listening to music disks on my Amiga 1200, using an emulated floppy disk drive consisting of an FPGA connected via an FTDI chip to my Mac's USB port.
That it worked at all is really cool. Thanks to HxC, LibUSB, and FTDI. Your stuff works perfectly.
* It's mostly great, but, hey, HxC people, if you get an error opening the chip, how about reporting it? I'd even settle for you not reporting it but not saying "Device OK!" in a cheery but totally bullshit fashion on startup. Put it this way: if the device is unplugged, it's not OK. Yes, I'll send a patch.
Hardware SID Player: An 8-bit computer for playing Commodore 64 music
I like SID tunes -- music files written to be played by Commodore 64 computers. Back when the C64 was released they sounded much, much better than any other home computer. Nowadays, well, they're an acquired taste -- here are some to listen to while you read this post:
The really interesting thing about SID tunes is that they are actually computer programs. Back then, there was no standard way to specify how sounds should be played, so each C64 composer had their own way of doing things. Every SID file you download contains not just a list of notes, note lengths, and effects -- the actual music -- but also contains a "play routine", which is a computer program written for the 6510 microprocessor which was the heart of a Commodore 64. That means that in order to play SID files, you either need a 6510 processor or you need to emulate one. All SID players (such as SIDAmp for Windows or SIDPLAY for the Mac) are actually Commodore 64 emulators -- or, at least, partial emulators.
The other interesting thing about SID tunes is that the sound chip which plays them (called the Sound Interface Device, which gave its name to the tunes) is a mixture of digital and analogue circuitry. Some people claim that the SID is so difficult to simulate that no software-based SID player could recreate the sound of a real chip. I'm not that discriminating -- software-based SID players sound just fine to me -- but I wanted to see how hard it would be to get sound out of the real thing.
The rest of this post is about how I made it, and how you can make one too.
Basic theory
To play SIDs using hardware, you fundamentally need three things:
A 6510 processor
A SID chip
RAM to store the song
With the SID tune stored in RAM, it is simply a matter of ensuring the processor, SID chip, and RAM are connected appropriately, then starting the processor and listening to the dulcet tones of the SID. Or so the theory goes.
Unfortunately, these components aren't super common. The first thing to do was to obtain the chips.
Sourcing the chips
6510 chips are difficult to find. They are a custom version of the popular 6502 microprocessor made specifically for the Commodore 64. Fortunately, it turns out that the majority of SID tunes out there -- perhaps all of them -- don't need the special features of the 6510. So I found I could get away with using a plain 6502, which are available on eBay.
The SID chip is a different story. SID chips were made for the Commodore 64, and production of SIDs stopped in 1993. You can find SID chips on eBay, but they are fairly expensive -- expect to pay between £10 and £50. Funnily enough, you can sometimes find complete Commodore 64s selling for less than individual SID chips on eBay.
Finally, we need RAM. I chose the 431000 series of RAM chips, because they are readily available on eBay. 431000s contain 128K of RAM, which you'll note is twice as much as a commodore 64. That's not a problem: I simply left the highest address line tied to ground, which meant that the upper 64k of RAM on the chip was never accessed and never used.
Designing the circuit
The 6502 processor has an address bus and a data bus. The address bus is 16 bits wide -- enough to address 64 kilobytes -- and the data bus is 8 bits wide. It is simple enough to hook the processor to the RAM -- simply connect each wire of the address bus to the appropriate pin on the RAM, and do the same for the data bus. Make sure to hook the control wires as well, so that the RAM knows whether the processor is reading or writing.
Now the 6502 will be able to read and write to the RAM, but we have two problems. First, how do we connect the SID? And, second, how do we upload SID tunes to the RAM?
Let's deal with the first problem first: connecting the SID. The basic problem is that we have more than one device which the CPU would like to communicate with -- in this case, it's just RAM and the SID chip. The typical 8-bit solution for this problem is called an address decoder.
My address decoder
The SID chips sits at addresses 0xD400 to 0xD700 in the Commodore 64 memory (as per the C64 memory map). This simply means that if the C64 wants to access the first byte of SID memory, it will set the 15th, 14th, 12th, and 10th bits of the address bus to "high", and the remaining bits to "low". Why those bits? Well, D in binary is 1101 and 4 in binary is 0100, so 0xD400 represented as a 16-bit address in binary is 1101 0100 0000 0000.
That means that our address decoder is conceptually like this:
If bits 15, 14, 12, and 10 are set to 1, and bits 13 and 11 are set to 0, then access the SID.
Otherwise, access the RAM.
If you represented this as a logical expression, you could do it like this:
SID = AND (A15, A14, A12, A10, NOT(A13), NOT(A11))
Basically, if that big expression is true, then select the SID. If it's false, select the RAM.
There are chips which will do this for us. The 74HC04 hex inverter is 6 NOT gates in one chip, and the 4068 is an AND gate with 8 inputs, i.e. if all 8 inputs are true then the output is true. So we simply connect A13 and A14 to two of the NOT gates on the 74HC04, and connect the outputs of the NOT gates, as well as A15, A14, A12, and A10, to the AND gate. We then have two "spare" inputs to the AND gate which I just connect directly to +5V. And voila -- an address decoder! We can connect the output of this address decoder directly to the SID and RAM chips! Well, almost -- it turns out that the "chip select" lines on the SID chip and on the RAM are "active low". So we connect the SID chip to the address decoder via a spare NOT gate, and connect the RAM to the address decoder directly.
If you looked at the C64 memory map, you will see that this address decoder isn't much like a real C64 -- in some cases, it will access RAM when it should be accessing a device. It turns out that this doesn't matter: most SIDs make use of these other devices, so it doesn't matter that they're not there. This makes sense conceptually -- why would a SID tune need to access stuff related to the display, or the cassette drive? (This isn't strictly true actually -- but I'll get back to this later.)
Also, this type of address decoder is oldschool even for the C64 era. The C64 used a custom chip for its address decoder, and normally one would use a CPLD or similar. I did it using discrete logic for fun.
Now for the next problem: getting SIDs into the system, and running the 6502.
Interlude: SID upload and timers
We still have three problems to solve.
First is the problem of getting SID tunes into the RAM, as alluded to above. As currently designed, the system doesn't have any input devices -- so there is no way to program it.
Second is related to things the 6502 needs to run. At the very least, it needs a clock signal. The Commodore 64 ran at 1 MHz (or a little bit less in PAL regions) so we need something that will supply a 1 MHz clock. SID tunes themselves tend to be tied to the display's refresh rate -- which means that we also need some kind of interrupt occurring at 50 Hz (for PAL regions) or 60 Hz (for NTSC regions).
I solved all of these problems using a microcontroller -- specifically, an 8-bit PIC.
The second problem -- timers -- is the simpler one. 8 bit PIC microcontrollers have a PWM module which can be configured to supply a 1MHz signal easily enough. This signal can be directly connected to the 6502's clock input. The other frequency -- 50 or 60 Hz -- is a bit low for the PWM module, but is easy enough to do in software. We end up with two wires connecting the PIC to the CPU: one to the clock pin, for the 1 MHz signal, and the other to the interrupt pin, for the 50 or 60 Hz "vertical blank interrupt" which is what SID tunes generally use.
The other problem -- getting SID tunes into RAM -- is a nightmare.
The simplest solution is simply to connect the PIC to RAM. That would mean connecting the PIC to all 16 address bus lines, and all 8 data bus lines. The PIC I chose (an 18F14K50) doesn't have enough outputs to do this, but that's not such a difficulty because there are chips which do a serial-to-parallel conversion, such as the 74HC164 (search "74hc164 PIC" for some simple examples). However, there is a much bigger problem with this simple solution, and that is that most 6502s can't tristate their address bus.
Tristating the address bus
The problem is that we would want the PIC to put information onto the address bus -- that is, set some bits to "high" and some bits to "low" as it uploaded the SID tune to RAM (and note that I haven't actually got the SID tune to the PIC, either -- that's another problem). The problem with doing this -- i.e., putting voltages onto the address bus -- is that the 6502 expects to be the only thing that can do that. If two devices do it, then it can result in damage to the 6502.
Some processors can avoid this by "tristating" their address bus pins, which means they can essentially disconnect themselves from the bus, putting themselves into a state called "High-Z". This prevents damage and lets other devices control the bus. However, the 6502 can't do this. Interestingly enough, the 6510 CAN do it -- it's one of the few differences between the 6510 and the 6502. However, I was stuck with a 6502 and had to work around this problem. I can't decide whether my solution is good, or very horrible.
My solution uses the PIC to manually clock the 6502 "blind", supplying a program that instructs the 6502 to write its own SID file to RAM. Here's how it works:
I connect the PIC to the data bus. This is totally acceptable, because all 6502s can tristate the data bus.
I then use the PIC to start the 6502, raising and lowering the PIC's clock line so that the 6502 runs for exactly 6 cycles. This is the number of cycles that the 6502 requires to boot up, according to the data sheet.
The first thing that the 6502 does is attempt to read two bytes from addresses 0xFFFC and 0xFFFD. These two bytes are the "reset vector" -- an address to jump to to begin executing code when the 6502 is reset. In a Commodore 64, these bytes are stored in ROM. For my computer, I use the PIC to put the special address 0xFF00 on the data lines, instructing the 6502 to begin executing code at address 0xFF00.
The 6502 then dutifully puts 0xFF00 on the address bus lines and attempts to read a byte on the data bus. This is the first byte of code. I use the PIC to put 0xA9 on the data bus. This is the 6502 instruction LDA, which tells the 6502 to store the next byte that it reads in register A.
The 6502 then reads another byte, which is the argument to LDA. I use the PIC to put the first byte of the SID program on the data bus.
The 6502 then reads another byte, which is the next code instruction to execute. I use the PIC to put 0x8D on the data bus. This is the 6502 instruction STA, which tells the 6502 to store the value of register A in memory (you can see where this is going).
The 6502 then reads another two bytes. These form the 16-bit parameter to STA, which is the address to store the value in register A. I put the starting address of the SID program on the address bus.
I repeat steps 4 to 7 until all bytes of the SID program have been stored.
This method is sort of horrible, but it's also quite neat, because it means that I don't have to figure out a way to connect 16 lines from the PIC to the address bus (it would have been possible, using shift registers and special chips which can essentially tristate the bus externally, but messy).
The main issue with this method is that the PIC can't manually clock the 6502 fast enough to do all of this at 1 MHz. In fact, it runs several times slower than that. This wouldn't be a problem, but the 6502 uses dynamic RAM for its registers -- clock it too slowly, and it forgets the values in its registers. Fortunately, the PIC could manually clock the 6502 fast enough that this wasn't a problem.
The second issue is that I had to add a couple of wires to my address decoder. The new logic for the address decoder looks like this:
If the PIC has requested control, and the CPU is trying to read data, disable both the RAM and the SID.
Otherwise, if it's a SID address, enable the SID.
Otherwise, enable the RAM.
The beauty of this approach is that the CPU can be reading from the PIC, and writing to the RAM -- until the SID tune has been fully uploaded, and then the PIC can essentially disconnect itself from the system entirely.
Playing the tunes
We still haven't got SID tunes into the PIC. But not to worry -- there are plenty of ways to get data into a PIC. One of the simplest is to use the PIC's serial port. I decided to be a bit fancy about this and use Bluetooth. There are pre-made modules on eBay, selling for about 5 US dollars, which provide a Bluetooth serial interface -- hook the serial part up to the PIC, and you can connect from a PC.
Then it was just a matter of writing a custom program for the PIC, defining a protocol for describing the SID tune over the serial interface (including, for example, the speed of playback -- 50 Hz or 60 Hz?), and writing a program for my laptop which would upload SIDs via this interface, and the board was almost ready to go.
There was one last thing. SID files don't play by themselves -- instead, they supply an address in memory called the "play routine" which should be called at either 50 Hz or 60 Hz. As described above, I had connected the PIC to the 6502's interrupt pin, so that the PIC could cause a 6502 interrupt at the appropriate time. My solution here was to write a small piece of 6502 code which I uploaded at the same time as the SID. The code contained a "cold start" routine, run once to initialise the SID, and also an interrupt handling routine, which simply called the SID play routine. (This code is contained in libsid.py avilable below, if you're interested.)
Circuit design and PCBs
As you can probably imagine, I wasn't keen to stay with the breadboarded prototype. I wanted real circuit boards. There are plenty of places which will print short-run circuit designs very cheaply. I chose ITead Studio. I designed my board using Altium, and after one false start with the Gerbers, and a long wait, my PCBs came back! It was time to get soldering.
RSIDs and other limitations
The player has a bunch of problems.
The first, and simplest, is that I made a couple of mistakes on the PCB -- essentially, I forgot to add a couple of connections. These were easy to fix with wire, but were a bit embarrassing.
The second problem is a bit more serious. There are two types of SID files. The original type, now called PSID ("Play SID", named after one of the first SID players), contains a play routine as described above, and a bit of meta-data describing the frequency at which the play routine should be called. However, people started to find this format limiting, and so the RSID ("Real SID") was born.
The RSID doesn't include a frequency at which the play routine should be called. Instead, it contains a setup routine which programs one of the Commodore 64's timer chips to deliver a custom playback speed -- or it simply uses its own delay loop, or does whatever else it likes: RSIDs assume that the system they are running on is a pretty-much complete Commodore 64. This obviously poses some problems for my SID player.
The RSID problem probably isn't as bad as it sounds. I suspect that some static analysis of RSID files will reveal that actually they only use a few C64 features. I could write a program which analyses the files and works out what features they use and how they use them, and then convert them into something appropriate for my SID player.
For example, imagine that an RSID starts by programming one of the Commodore 64 timers to interrupt at 25 Hz. It should be possible to recognise this code using static analysis. I could then simply instruct the SID player to run the appropriate code 25 times a second -- in effect, converting RSIDs into PSIDs. I haven't yet attempted this, because there are many, many PSIDs -- most C64 game music is PSID, for example.
Source code and Gerbers
All my code is open source and I hereby place it into the public domain. You can do whatever you like with it, but don't expect that it will do anything at all and certainly don't expect support. Feel free to email me, though -- I'll help whenever I can.
Code for PIC18F14K50 (including Makefile, C code, an hex file) -- should be portable to most 8-bit PICs.
If you do assemble one yourself, please do get in touch as there are a couple of things I haven't touched on here (most importantly, an amplifier for the SID output) which could otherwise ruin your day.
Please do also let me know if you spot a mistake in this write-up. I'm sure there are at least a couple.
While working with OpenCL, two things came to light that weren't obvious from the documentation.
The first is that OpenCL kernels are subject to a timeout, which appears to be five seconds.
That's kind of reasonable -- I had wondered how OS X managed to multiplex GPU resources between OpenCL programs and graphics tasks, and it turns out that it doesn't: it simply can't use the GPU while an OpenCL program is running. So it puts a five-second limit on the kernel.
The second thing is not reasonable: when Mac OS X times the kernel out, the user interface doesn't recover. That is, the UI never updates again. The system is totally fine otherwise, as I can connect to it via SSH and shut it down.
This is a nasty bug, as it makes writing long-running kernels quite tedious. Perhaps it's a Mac driver issue (Radeon HD 6750M in my case).
The solution for development is to avoid the problem by testing the kernel on a computer which doesn't have a timeout -- I'm now using a headless Linux box to do it (apparently no connected display = no timeout on Windows, Linux, and OS X).
And now that I know about the timeout, I can work around it (by ensuring the kernel doesn't run for longer than 5s, and continously restarting it with new data).
(I have to say that I haven't tested this thoroughly, just observed that a) a kernel which takes 4s works fine and a kernel which takes slightly longer does not, and b) 5s seems to be a standard timeout for OpenCL kernels)
Today I finished my second hardware SID player. This is kind of a sneak peek: I'm planning on writing up the entire process, from conception, through to breadboarding, circuit design, layout, assembly, and case.
This device contains a 6502 processor, the same one (almost!) as was used in the Commodore 64. It also contains the Commodore 64's well-known MOS 6581 chip, also known as the Sound Interface Device, which gave the C64 its distinctive sound. It plays real Commodore 64 sound files (SID files), which it receives via a Bluetooth serial connection.
SID files are interesting because they are actually raw binary 6502 code. In order to play the sound file you need a 6502 processor. All software SID players emulate a 6502 -- this includes a real one instead.
I recently made a little temperature logger, based on the DS18B20 temperature sensor and the Minimus AVR USB v1. This is a super cheap device: you can get DS18B20s for under £2 on eBay, probably cheaper in bulk, and my Minimus V1 was £2.50.
To set it up, get the hex file onto your Minimus. I use dfu-programmer: put the device into DFU mode by pressing reset, pressing the button that isn't reset, releasing reset, and then releasing the other button; then run dfu-programmer at90usb162 flash logger.hex.
Connect the DS18B20: the data line should go into PORTD6. Connect power and ground lines appropriately.
To start logging, reset the device (if it's in DFU mode), then press the hardware button. The blue light will start flashing to indicate that it's recording. Memory is full when the blue light is solid.
When connected to a computer, the device presents a USB serial interface. Connect to it at 57600 bps, and press ? to see a menu. Most importantly, buttons 1 to 9 will change the recording frequency, and 'd' will show the data.
The device logs to its internal EEPROM, which is quite small (1024 bytes). At the default logging frequency of once every 15 seconds, you get almost four and a half hours of recording. (One byte per measurement, 4 bytes used for EEPROM header).
Update: If you check out the Github repo and compile the code, you can instead choose to log to a 24Cxxx series external EEPROM. Connect the EEPROM so that A0=A1=A2=GND (ie, it is device 0 on the bus), connect the data line to PD1, and connect the clock line to PD0 -- or edit logger.c (for the device number) or i2cmaster.S (for the ports). If you do this, you'll want to change MAX_EEPROM_LOCATION in logger.c: it is currently set up for a 24C128 (i.e., 16 kilobytes of EEPROM).
It would be better to have the device show up as a USB mass storage device (i.e. a disk) rather than a USB serial port. I might work on that later.
Welcome to a short series of posts about modifying Android applications. The application to be used as a guinea pig in this case is Viber, a VOIP application for Android.
Assumed knowledge: some programming experience, access to a UNIX environment (such as Linux or OS X), and a rooted Android phone.
A short visual lesson in why the Android permissions system fails for complex apps
Android permissions provide a fine-grained way for applications to request elevated privilges. They are great when apps only request one or two permissions -- for example, you might be okay with your music player connecting to the Internet but you might not be okay with it reading your contacts list. However, for sufficiently-large applications, the system breaks down.
On the left is Viber's permission list, which is, I hope you will agree, somewhat ridiculous. If you can't be bothered reading that, and I don't blame you, the summary is that Viber is essentially asking for complete control of my phone. It can access my contacts, send SMSes, make calls, access the Internet -- basically do whatever it likes.
Avoiding the whole question of whether these permissions are justified, the question then becomes: do I trust this app to use its many powers for good? I'm sure the Viber people are excellent and don't want to do anything nasty with my phone, but even the best-intentioned software has bugs.
If I don't trust the app, the only choice Google Play gives me is not to install the app. Trust the app and let it do everything, or don't use it at all? These aren't great choices. Fortunately, if you have a rooted device and are willing to write some code, these aren't your only options.
Over the course of this series we'll look at modifying Viber so that it doesn't need a bunch of these permissions. In this introduction, you'll set up the tools you need to modify Android apps, and make a very small change to Viber, to prevent it from adding a shortcut to your home screen.
Setting up your environment
JDK
You'll need a Java development environment installed.
ADB
You'll need ADB, which lets you do various useful things to your phone from your computer. ADB comes with the Android SDK, which I encourage you to install. This page on the CyanogenMod Wiki contains more information on installing the Android SDK and getting ADB set up.
Make sure ADB works and verify that you have a rooted device by running
adb shell
You should get a root prompt on your phone.
Viber
Install Viber on your device.
On your computer, create a working directory. I created ~/tmp/viber.
You'll now want to get the Viber APK onto your computer. Unfortunately, depending on your device, it could be in various places. Try:
adb shell ls /data/app |grep -i viber
If you see something like com.viber.voip-1.apk, then you're set. Change to your new working directory and use ADB to download the APK from your device.
~$ cd tmp/viber
~/tmp/viber$ adb pull /data/app/com.viber.voip-1.apk com.viber.voip-orig.apk
If, however, you don't see Viber installed in /data/app, it could be installed on the SD card. On my phone, SD card apps are available from /mnt/asec. Try:
Apktool is a nice program which saves a lot of time when working with APKs. Download it from here.
Opening the APK
An APK is a zip file containing everything required by the app. So in theory you could just unzip it, but instead we will use apktool. As well as unzipping the APK, apktool will run Baksmali (a disassembler) over the code, and will also convert the Manifest file to a text format (it's stored in the APK in compiled form).
~/tmp/viber$ apktool d com.viber.voip-orig.apk apk
This produces a bunch of files in the apk directory. The decompiled source code is in the smali directory. Have a look around and familiarise yourself a little with the assembly language being used. For this, the best resource is the Smali wiki, but there is not a huge amount of information there. Smali is based on Jasmin, so it may be worth reading up on the Jasmin instruction set also.
Application signing
You have to sign your modified app using your own key. If you've done Android development before, you will have a debug key in ~/.android/debug.keystore and you can use this. If not, you should create a key using keytool:
Keytool asks you for a password, and then asks a whole lot of questions which it will use to fill in the key. It doesn't really matter how you answer these questions. If you're only planning on using this keystore for your Viber modifications (recommended) then you can leave them blank, and you can also choose a very simple password.
Sanity check -- does it work?
To check that everything is working up to this point, we'll now re-build the app, without any changes.
Run apktool to rebuild the APK.
~/tmp/viber$ apktool b apk com.viber.voip.apk
Then, sign the APK with your new key. If you're using the debug key, do this:
Now run it on your device (you may want to turn on airplane mode first).
Modifying the APK: removing the shortcut-adding code
When you first run Viber, it adds a shortcut to your home screen. Let's stop it from doing that.
A quick search for "android shortcut api" reveals A stackoverflow.com post with code to create a shortcut on the launcher desktop. The key part of that code is this Intent:
com.android.launcher.action.INSTALL_SHORTCUT
That looks like an obvious thing to search for in the code, so let's do that:
Great! The shortcut code seems to reside in a single file. Open that file in your favourite text editor.
~/tmp/viber$ vim apk/smali/com/viber/voip/IdleActivity.smali
You'll see that the INSTALL_SHORTCUT code is called from a method named "setupShortcut":
.method public setupShortcut(Z)V
The method parameters are encoded in the Java JNI format, as described on the Smali wiki. Referencing that, you can see that setupShortcut takes a single Boolean as parameter (the Z) and returns void (the V).
Let's delete the entire method body. Delete the entire method, from the line beginning with .method public setupShortcut to the line beginning with .end method. Replace it with this:
.method public setupShortcut(Z)V
.locals 0
.parameter "sendBroadcast"
return-void
.end method
This is basically the minimum we need. The locals line tells the assembler that the method doesn't use any local variables. The parameter line identifies the method argument, and the return-void line does what it suggests -- unlike Java, Smali methods must always return something explicitly, even if it is void.
Relaunch the app on your phone, and you will see that it does not create a shortcut on your desktop any more. To be doubly sure, you can also remove the appropriate permission lines from apk/AndroidManifest.xml -- they're the ones that have SHORTCUT in the name -- and reinstall. Now the application can't possibly create shortcuts, even if we missed something.
In the next entry, we'll get a little more complicated, by preventing Viber from accessing your contact list.
Here's a preview of a really simple Android app I'm working on, called Profligate Spending. I am working on a tight budget at the moment, and I need to keep track of my discretionary spending (something I'm quite bad at). This is the app I'm going to use to do it.
When it's done, you'll be able to enter a maximum spend for the day, week, or month. When you buy things you'll put the amount into the app, and it will then tell you whether you're going over budget or not. It will remember previous days' spends, so you can save up for large purchases.
The "put the amount into the app" part is where all finance tracking apps fall down, because nobody wants to do that. I am making it as frictionless as possible: entering small amounts is five presses (one to launch the app, three to enter an amount in pence, and one to add it). Still, I think it requires a motivated user.
If you have any ideas for apps like this, let me know. It's a pity my first non-work app is for something as dull as personal finances, but, well. Actually, the more fun I can make it, the more I will use it -- so please send any ideas about that my way, too.