by Darius Zarrabi. Filed under
.
Before we start
This has become a rather long contribution. The reason is that I own a 'Pulse' from T-Mobile Germany for 4 months now and have played with it now and then, and everytime I found something I thought might be worth to document, I wrote some lines. As a result, the following chapters have no linear structure and information may be outdated.
I am also aware that a 2.1 ROM is available for the Pulse, yet I am quite happy with the device as it is now with its 1.5 Android, so I will update, but not soon.
Table of contents:
I. Rooting it
II. Replacing the SD-card
III. T-Mobile Pulse as a Gateway or Modem
IV. SMS
V. MMS
VI. Audio and Video
VII. Virtual Keyboards
VIII. Android VNC Server
IX. Theming the Pulse (aka De-Magenta it)
X. Android Sources and a Common Kernel
XI. Bluetooth
XII. Accessing the internal Modem with Bluetooth
XIII. Eclipse and Android-SDK
XIV. Ubuntu
XV. MoDaCo's Android 2.1 v6r1 leaked beta longstory ROM
I. Rooting it
Again: T-Mobile UK has released a 2.1 update for the Pulse and attempts are being made these days to create a customised ROM based on it and to watch its performance, see here. However, I am still at 1.5. For a custom ROM based on the old stock-ROM, you may start reading here or here. The ROM I use at the moment is from here. Thanks to Paul.
II. Replacing the SD-card
An easy one, he?
Er, what can I say … this topic happened to be one of the most challenging, to my surprise. In my naivity, I was planning to dd the entire content of my old card to the new one, and then to take gparted. Problems began where I needed to realise that my card reader does not support SDHC-cards. You can however use the phone as a card reader. In recovery mode, enable USB-MS and whatch your kernel recognise /dev/sdX (for me, X=g). At this point, I dd'd my old (non-HC) card (in my card-reader) to the new one (in the phone). The phone should start with the new card left inside, as it should think that the old card is still inserted. I didn't try. Instead, I used gparted, moved /dev/sdg2 (the ext2-partition) to the end and doubled its size from 512 MB to 1 GB. Then I enlarged /dev/sdg1 to occupy the remaining space (15 GB). With this work being done, the phone got stuck in a boot loop, with logcat saying that it can neither access the vfat- nor the ext2-partition.
Since I left my old card unchanged, all data was safely stored, so I tried to partition the card using the recovery shell. After more than 3 hrs of watching the phone printing dots on the screen, I gave up. Into recovery mode again, I partitioned the card manually. To do so, open a terminal with adb shell and run
parted
parted /dev/block/mmcblk0
In the parted-shell, say help or print, remove partitions or create new ones using
parted/mkpartfs
mkpartfs primary fat32 0 14933
mkpartfs primary ext2 14933 15932
And that's it. The next step was to copy the contents of the old partitions to the new ones. I did this using adb while being still in recovery-mode. The vfat-partition is easy as it just contains user-data. The ext2-partition however holds the cache (which can be erased without danger), and in particular it also has the app-directoy, in which ap2sd-apps are stored. So, I copied all contents file by file, rebootet the phone and it in fact bootet!
But something still seemed to be corrupted, as I was getting tons of messages like this:
parted/mkpartfs
W/Database( 1150): Cannot read configuration file for seachable databases
Yes, it says "seachable" and using google you will find exactly nothing about this message.
I therefore tried some more things, like removing all files in dalvik's cache. By doing so and rebooting, I lost Google Maps and Titanium backup (I know the reason and its the file ownership). In recovery mode, I tried to fix uids and to repair ext2, everytime loosing even more apps.
Fortunately, I did make a nandroid-backup from the almost working setup (which was quite okay beside the database-warnings) and upon restoring it, recovery mode complained about md5 mismatches. At that point, I was lost.
I took the opportunity to play with my phone as it was messed up anyway. I even tried to re-apply the stock-T-Mobile ROM, because my phone has a little HW-problem which should be covered by its warranty. That didn't work, however, for some reason I no more remember.
Finally, I took an older nandroid-backup (including ext2), still stored on my old card, applied it, and voila: Everything is running smoothly now.
For you guys out there reading this it clearly means the following:
- Make a nandroid-backup (including ext2) before switching the card.
- Partition the new card using parted in recovery mode.
- Copy the contents of the old vfat-partition to the new one, including the nandroid-subfolders
- Apply a restore
So, yes, changing the card is easy, if you know how …
III. T-Mobile Pulse as a Router or Modem
For me, as a mobile worker, using the phone as a modem is vital. It is of course shipped with a Windows-application (Dialup), but the question was: How does that software work? Respectively, how do I use the device as a modem under Linux?
Don't get confused. As regards the question we're handling here, the phrase 'tethering' became quite popular, but in my opinion, it introduces too much misunderstanding. For me, tethering means to use the phone as a router, so that it forwards IP-packets and does some NAT on the outgoing interface (/dev/rmnet0). The internal interface can be wifi (where the phone either acts as a client or as an access point), an IP-interface over a serial Bluetooth line, or over USB. As regards BT and USB, we normally think of point-to-point-connections, yet we're not restricted to them. In all cases, the device can serve as a network access point, but that is beyond the scope of this posting.
Using the phone as a modem is something different, as by using this phrase, I really mean that old-fashioned AT-command-businnes with Hayes-compatible devices. But let's start with its router-capabilities.
Searching the Web leads to azilink, which works perfectly. The solution is to install an app on the Android, proving a non-encrypting VPN-server with NAT to which a host can connect (this may be called USB-tethering). This solution has one big advantage: It works independently of how the phone is connected. If a known WLAN-AP is reachable, it goes online using the access point rather than using GPRS. That is, at home, this setup just serves as a gateway to my LAN. And without any reconfiguration on my laptop, it allows me to use it as a router outside.
What is needed for this approach is that the device is connected via USB to the host. Then, one needs
adb, openvpn, azilink
The app is installed on the phone by either using the market or by pushing it from the host using
adb as an installer
adb install azilink-2.0.2.apk
Establishing the connection is then done by starting azilink on the phone and to select check service active there. On the host, do
establish connection
adb forward tcp:41927 tcp:41927
openvpn --config /path/to/azilink.ovpn
The connection can be terminated by killing openvpn with ^C.
As this approach makes the Pulse a router, I wondered about whether the phone is a simple Hayes-compatible machine as well. And actually it is. This can be deduced from sniffing the USB-port while "Dialup" (the Windows-app shipped with the phone) connects to the net. One clearly sees AT-commands passing the line. So, under Linux, the solution is to modprobe usbserial
usbserial
modprobe usbserial vendor=0x12d1 product=0x1501
(this establishes a serial line over USB) and that's it. If the device is, say, /dev/ttyUSB0, then you will see a modem there, and by using the following two scripts,
/etc/ppp/peers/gprs-usb
/dev/ttyUSB0
connect '/usr/sbin/chat -v -f /etc/ppp/gprs-chat'
crtscts
modem -detach
#noccp
defaultroute
usepeerdns
name "t-mobile"
#noauth
#ipcp-accept-remote
#ipcp-accept-locate
noipdefault
/etc/ppp/gprs-chat
'' ATZ OK
AT+CGDCONT=? +CGDCONT:
ATD*99#
CONNECT ''
you can easily dial into your provider's network:
pppd
/usr/sbin/pppd call gprs-usb
Technically, I prefer to use the device as a router rather than as a modem, but that is pointless, because I have a data-flatrate anyway. On the other side, I wonder why providers do it this way at all. All I can imagine is an accounting reason: In fact, your laptop gets its IP-address by establishing a PPP-connection to the provider using the phone's modem. And that of course differs from the IP your phone already has.
I am fine with that, because, if I do have networks to connect to, I can do that with my laptop without using the phone. The challenge begins where you are alone, with only your GSM-connection left. You can then use the internal modem via USB, as described. The Bluetooth-story is similar, but goes into a separate chapter (see below).
One final note: adb will not work when usbserial is loaded. Before adb-usage, remember to rmmod usbserial. In addition, if you get weired messages saying that the server cannot be started, restart it by typing
restart adb-server
adb kill-server
adb start-server
as root.
IV. SMS
Well. The point why I wanted to try Hayes-commands is exactly that I was hoping to send SMSs from my laptop or desktop rather than using the annoying phone's virtual keyboard. And that is perfectly working as well. As I've modprobed usbserial anyway, I only use this script:
sendsms
#!/bin/bash
TONUM=$1
TEXT=$2
PATH=/bin:/usr/sbin
echo \"\" "ATZ" > /tmp/message
echo OK "AT+CMGF=1" >> /tmp/message
echo OK 'AT+CSCA="'+491710760000'"' >> /tmp/message
echo OK 'AT+CMGS="'$TONUM'"' >> /tmp/message
echo \> \"$TEXT^Z\" >> /tmp/message
pppd ttyUSB0 115200 lcp-echo-failure 1 lcp-echo-interval 1 \
idle 1 lcp-restart 0 nocrtscts connect "chat -v -f /tmp/message"
rm /tmp/message
Sending an SMS is then done by
sending an SMS
sendsms 123456789 "Hello world.^JI am an SMS.^JGoodbye."
in a shell. The crucial point here is that the phone needs to be informed about the SMSC (SMS Center) to use. For T-Mobile in Germany it is +491710760000, more information about SMSCs can be found using a search engine. It is worth to talk to the phone using some terminal as the error messages usually contain useful hints.
V. MMS
So that was about sending SMS. Using the built-in app SMS/MMS however does more in that it organises the messages by using threads. In those threads, it also stores short and multimedia messages sent by the owner. As we were sending with the native Hayes-functionality, we cannot expect our SMS to be monitored by the app. What we can do, however, is to pull out all messages from the phone and store them locally. This task is very easy, because all information is properly stored in the app's database.
pull all sms/mms
Bash script. Needs
sqlite3, perl, awk, adb |
Click on icon to download —> |
 |
This is the script I use to fetch all messages from all threads thereby keeping the order by putting everything into appropriate directories. Nothing special about it beside the fact that I needed to understand the relations between the tables first. And some recalc of the dates, stored in epoch-time, was necessary. Nothing special, so don't expect too much.
VI. Audio and Video
There is nothing special about audio and video. As regards audio, the device is capable of playing .mp3 and .ogg and probably a few more like .aac … I didn't test yet and I am not going to test as long as there is no need.
The more interesting part is the built-in (= T-Mobile provided) Music-App, which frequently scans the content of the sdcard and so is aware of all media-files.
This is interesting. The app precisely knows where your media files are, yet choosing an arbitrary file of them as a ringtone will most likely not work - if you can set it at all.
Point 1: The stock ringtones are stored as .ogg in /system/media/audio/ringtones (and the same is true for alarms and notifications). Choosing Settings -> Sound & display -> Phone ringtone will allow you to choose from Android System only, which is simply offering the contents of /system/media/audio/ringtones.
Point 2: Installing a 3rd party app like Rings Extended will allow you you to choose any file accessible by a file manager - but: It will not work. Doing so, logcat will claim that it cannot access the file, saying something like
file descriptor error
E/MediaPlayerService( 777): Couldn't open fd for
> content://settings/system/ringtone
The message is misleading in that it complains about a location /settings/system/ringtone, which of course is not the location of the file to be played but rather the entry in the system's settings settings.db. This database in turn is part of com.android.providers.settings and is located in /data/data/com.android.providers.settings/databases/settings.db. The database contains a table named system and an attribute ringtone which points to the media-file. And the issue is that if the entry does not point to /media/external/audio, then the above error message will appear.
This clearly is a bug (surf the net for this, the bug is documented), but the workaround is quite easy: Put your files to /sdcard/media/ringtones/, use a 3rd party app like Rings Extended and choose your tone from there.
And now video. Question was: What type of video (containers, codecs) is the smartphone able to play? Well, the format recorded by the phone when using the camera is something like this:
mediainfo
General
Complete name : 28-03-2010 19.46.05.3gp
Format : MPEG-4
Format profile : 3GPP Media Release 4
Codec ID : 3gp4
File size : 516 KiB
Duration : 13s 424ms
Overall bit rate : 315 Kbps
Law rating : (empty)
Classification : (empty)
Video
ID : 3
Format : H.263
Format profile : BaseLine@4.0
Codec ID : s263
Duration : 13s 424ms
Bit rate mode : Variable
Bit rate : 300 Kbps
Width : 352 pixels
Height : 288 pixels
Display aspect ratio : 1.222
Frame rate mode : Variable
Frame rate : 5.810 fps
Minimum frame rate : 4.545 fps
Maximum frame rate : 8.696 fps
Bits/(Pixel*Frame) : 0.509
Stream size : 492 KiB (95%)
Writing library : pvmm Revision 1
Language : English
Audio
ID : 4
Format : AMR
Format/Info : Adaptive Multi-Rate
Format profile : Narrow band
Codec ID : samr
Duration : 13s 300ms
Bit rate mode : Constant
Bit rate : 12.8 Kbps
Channel(s) : 1 channel
Sampling rate : 8 000 Hz
Resolution : 13 bits
Stream size : 20.8 KiB (4%)
Writing library : pvmm
Language : English
but that doesn't say much. The device is capable of playing MP4-containers with an AVC/AAC-multiplexed stream up to a size of at least 512×288 and probably beyond, but the physical resolution of the screen is 480×320, so anything larger than 480×270 and 384×288 for 16:9 resp. 4:3 videos is overkill, because the device must scale the video then. On the other side, compression will work better when using 512×288 for 16:9 frames. The phone is quite happy with several profiles (baseline, main, etc.). The following options provide very good quality of the video, but transcoding will not be done in real-time. Note, however, that CABAC must be disabled for the Pulse.
ffmpeg
ffmpeg -i $infile -f mp4 -s "$width"x"$height" -vcodec libx264 -coder 0 -me_method tesa -flags +loop+aic+cbp+mv0+mv4 -partitions +parti4x4+partp8x8+partb8x8 -flags2 +wpred+bpyramid -trellis 1 -me_range 16 -mbd 2 -cmp 2 -subcmp 2 -g 250 -subq 9 -b $bitrate -maxrate $maxrate -qmax $qmax -i_qfactor 0.71 -rc_eq 'blurCplx^(1-qComp)' -level 41 -acodec libfaac -ab 92k -refs 6 -deblockalpha 0 -deblockbeta 0 -y $outfile
If the video is located anywhere in the LAN (and you have some player being aware of SMB-shares), the phone will not play it immediately and caches it first (files stored locally will not suffer this problem, of course). To start playing without downloading the whole file, it must be made "streamable", which means that hints need to be inserted and, even more important, it must not have b-frames. Note: It is not suffcient to tell x264 that B-frames must not be used as reference-frames (that is, not to use +bpyramid), instead, no b-frames are allowed at all. You can however leave +bpyramid in the command line, but then -bf must be added and followed by 0. To insert hints, there are various tools available, my preferred one is MP4Box:
MP4Box
MP4Box -hint $outfile
The quality of the video is steered by the options -bitrate, -maxrate, and -qmax. This is not the place to discuss best possible parameters, if there is such a place at all. Common videocasts often show a bitrate somewhere at 250 KBit/s, but that is way too less for watching a video on the phone in high quality. Though it depends on the material which is going to be transcoded, I recommend bitrates at 400 - 600 KBit/s with qmax between 25 and 35 (max quantization). If no B-frames are used, the size of the video-file will increase (or the quality decreases).
If pre-processing of the video is needed, I use mplayer to do that. First named pipes are created, into which mplayer writes its processing (like deinterlacing, smoothing, and resizing) in raw format:
mplayer writes into y4m- and wav-pipes
mkfifo video.yuv
mkfifo audio.wav
mplayer $infile -vf yadif,hqdn3d=4:4:2,scale=512:288 -vo yuv4mpeg:file=video.yuv -ao null -nosound -noframedrop &
mplayer $infile -ao pcm:file=audio.wav -vo null -noframedrop &
and then ffmpeg reads from the y4m-pipe using appropriate switches:
ffmpeg reads from y4m- and wav-pipe
ffmpeg -f yuv4mpegpipe -i video.yuv -i audio.wav -coder 0 -vcodec libx264 -crf 25 -me_method tesa -flags +loop+aic+cbp+mv0+mv4 -partitions +parti4x4+partp8x8+partb8x8 -flags2 +wpred+bpyramid -trellis 1 -me_range 16 -mbd 2 -cmp 2 -subcmp 2 -g 250 -subq 9 -qmax $qmax -i_qfactor 0.71 -rc_eq 'blurCplx^(1-qComp)' -level 41 -acodec libfaac -ab 92k -refs 6 -deblockalpha 0 -deblockbeta 0 -y $outfile
Here, I use a constant rate factor (crf) instead of setting the bitrate.
VII. Virtual Keyboards
I am adding this section because I came across some complaints saying that ConnectBot is not usable on the Pulse. In fact, the following screenshot (the one on the left hand side) shows that there is no "quick connect box". The second screenshot shows that, on addition, the virtual keyboard has no RETURN-key, so that one can enter an address, but that cannot be confirmed.
The solution is to switch to another keyboard. To do this, hold the touch-pad's button pressed while touching the virtual keyboard. Then, a set of options pops up, from which one chooses "input method" and select "Android Keyboard" rather than TouchPal.
The result looks like this:
which means that we now have a RETURN-key ("Fertig" at the right bottom).
VIII. Android VNC Server
We all know VNC, but on a phone it's really cool. It can be used to capture videos from what you do on the phone, but it can also be used just for fun. Get it from here, install it,
installation of androidvncserver
adb push androidvncserver /data
adb shell chmod 755 /data/androidvncserver
run it,
invokation of androidvncserver
adb shell /data/androidvncserver -t "/dev/input/event0"
and start a client with
vncviewer
adb forward tcp:5901 tcp:5901
vncviewer localhost:5901
or, without adb-forwarding, use the address to which the phone is connected via WLAN.
The following capture has been taken a few days after I got it, so it's still German and pink (magenta).
Get the Flash Player to see this player.
(328×506 px, 4.5 MB / 110 sec = 347 KBit/s overall bitrate)
Let me say here that the option -t "/dev/input/event0" makes it possible to use the mouse on the client-side to behave like the phone's trackpoint. In addition, ESC maps to the device's BACK button, Android's Home is Home on the PC and F1 on the host is Android's END.
IX. Theming the Pulse (aka De-Magenta it)
Well, theming is possibly a too strong word for what we're going to do, because we will only modifiy the existing (stock-) theme. But that is always the first step of any theming-approach. I am also well aware that there is Metamorph out there, yet MM will not do what we're going to do now, for several reasons.
The very first step was to switch to English.
So, we are going to de-magenta the phone in the sense that we try to get rid of the annoying T-Mobile standard color. The theme is okay and I am quite happy with it … if there only was a possibility to change the T-color easily …
From what we're going to do here, setting the wallpaper is the easiest task. Taking into account the relatively dark background of the standard-theme (which I will not change), some green would please my eyes, so I searched the web for a nice wallpaper, found this, turned it to green and ended up with this:
Thanks to the creator Danny Cohen for this really nice wallpaper. Now, the standard wallpaper size of the phone is 640 x 960 (2:3), as can be seen from several drawables in the resources of the installed apps. However, what you get to see is only a part of the picture and that in addition depends on how your Home is setup. The standard launcher provides 2×3 desktops. That can be extended to 3×3 by placing icons appropriately, but I will stay with 6. And this means that from the 640 x 960 picture only the below sketched area will ever be seen (note: I am talking about portrait mode, as the standard launcher does not provide landscape mode).
So, I scaled the original wallpaper to my needs and placed it into a black template as above, and the upper middle and the lower left and the upper right desktops now look like this:
We now understand what the additional lines in the above picture stand for.
Now let's see. Everything seems to be green, but on clicking somewhere, T-Mobiles's branding pops up:
That's a clear no-go and we're now going to make it look like this:
What I am describing here is the manual (and seriously laborious) way. It will however show how to handle things in general and will lead us to even more complex problems, being interesting in themselves.
The resources an application uses is stored in its res-folder. As an example, we pull T-Mobile's standard launcher from the phone,
Pulse's default launcher
adb pull /system/app/Launcher_B116SP01.apk ./
unzip it, and find the following icon in res/drawable/mainmenu_press.png
which is exactly one of the suspects. The question, of course, is: Can we just change it? And the answer is: Yes. The precise answer is: No, because it needs some work, but let's face it. Fortunately, we're not talking about an odex'd ROM (which I have) and we're not talking about signing applications! The task is in fact as easy as to replace the icon by another one, say, this:
Once this has been done, we repack the apk by saying
repack the launcher
zip -r0 launcher-new.zip ./
and transfer this zip back to the phone,
reinstall the launcher
adb push launcher-new.zip /system/app/Launcher_B116SP01.apk
To tell the truth, this sounds easy, but the limited space in /dev/block/mtdblock1 (mounted as /system) probably needs a reboot, just like this: We first remove the file, then we reboot,
deleting the standard launcher
adb shell mount -o remount,rw -t yaffs2 /dev/block/mtdblock1 /system
adb shell rm /system/app/Launcher_B116SP01.apk
adb shell reboot
The reason is that even after removing the file, you'll be unable to replace it by the modified version, because although the file has been removed, no additional space has been gained. And this in turn is due to the fact that the file is still in use (as the application is still running). So, we could either kill the app or reboot. After that, as soon as the "android"-logo appears, do
pushing the modified standard launcher
adb shell mount -o remount,rw -t yaffs2 /dev/block/mtdblock1 /system
adb push launcher-new.zip /system/app/Launcher_B116SP01.apk
adb shell mount -o remount,ro -t yaffs2 /dev/block/mtdblock1 /system
This works, because the space occupied by the original file has now been released and we're ready to push the modded file. Keep in mind that if you're not uploading the file at this stage, then the phone will probably not start correctly (depending on the app).
Again: It is as easy as this. Difficult tasks like de-odexing services.jar are covered elsewhere. There also is no need to resign the apps, it's just this. There are only two things to remember:
Apps /system/framework/framework-res.apk and /system/app/Community_B116SP01.apk must not be compressed. This is the reason for the -0 switch in the zip-command above. Other APKs you modify can be compressed. By just un- and re-zipping (where zip is now told to compress), I was able to gain some more space in /system without any loss in performance. This can be done for almost all APKs, beside the two just mentioned.
While writing this, it makes me laugh when I am thinking of all those Windows-users, claiming to have the solution by saying that they did this replacement using their favorite zip-GUI … as if that would change anything. There is no need to resign, nothing serious to consider during the zip-process. However, there is zipalign out there and I strongly recommend to use it after all work on the .apk has been done. Again: Regardless of how you've modified an .apk, zipalign is the last step. See below for a command line.
Second, all files must be placed with the original filenames at the original location (links do not work, which is precisely the reason for app2sd's existence, which I will not cover in this post).
If everything is so easy, where is the drawback, then?
The first problem is that T-Mobile's magenta appears almost everywhere. On a stock Pulse, I find not less than 33 APKs tweaked by the vendor (marked with names like in the above example: …-B116SP01.apk or whatever). The drawables contain up to more than 800 icons and placeholders (per APK!) with tons of opportunities to change something. And now that could be changed automatically (gimp in batch-mode is your friend, see below), but then there still remain some severe issues and these are stretchable PNGs.
If you only change the hue of the icons and re-zip, you will end up with something like this:
The reason for this is that during the conversion of the icon, information got lost about how the PNG is stretched properly to fit a given geometry. This however only affects a subset of the modified PNGs. These are exactly the stretchable ones and they always have an ending .9.png.
You may want to start here reading about 9-patches. The solution is to use a tool from the Android-SDK, called draw9patch. The just converted icon must be renamed from icon-name.9.png to icon-name.png. You then open draw9patch, which looks like this:
A quick side-note: draw9patch is a Java-application and does not work with Java 1.5, it insists on 1.6. This is funny, because the Android-sources insist on 1.5 to compile correctly … but well, changing the default Java-version appears to be easy on today's distributions (see below under installation of the sources).
Fine, now you either drag your icon icon-name.png and drop it to draw9patch's desktop or open it via the menu, to see an icon to which a 1-pixel transparent border has been added. It is this border in which you draw your guides which indicate how an icon will be stretched. I am not going into the details here as the best method to understand draw-9-patches is to use the tool and to play around with it.
So, let us assume that we've added the above guides and saved the image as icon-name.9.png (the tool will automatically rename the icon and add .9 to the filename). Then another step is necessary (see below) and after replacing the orignal icon in the .apk, we end up with this:
Note that I did only convert icons which show T-Mobile's magenta, so the icon on the left hand side is the original one where the one on the right hand side is mine … Something went wrong and it's precisely the guides. The correct ones to use are:
And now we understand why the above original icon rendered so badly. That is, it renders badly only if the icon is stretched vertically, which is not supposed to happen, if the correct guides on the right and the bottom are added. After this correction, everything is okay:
When I say laborious, then it is because we're talking about approximately 100 stretchable icons which need new guides after conversion. Now, the situation isn't too complex, because most of the icons tweaked by T-Mobile are in fact the standard icons from the Android-sources, so the guides can be taken from there. For the remaining few, I added them manually.
What I did, however, was to take care of future modifications, so I stored the quides (only the guides) to a template-folder and add them automatically everytime I run my script to re-color the icons. This is possible, because the tool will help you on finding the correct guides, but all it does, finally, is to write a file with dimensions (orig-width + 2) x (orig-height + 2) with the quides included. So there is no need to use draw9patch everytime, because for inserting the modified icon to the template I just take ImageMagick:
using ImageMagick to add the guides
convert -compose over -geometry +1+1 -composite template_file icon_file icon_with_guides_file
Am I going to say that I've managed to fully automate the process? No, because what we get, rather than the desired icon (below left), is the one on the right hand side below:

Unfortunately, this is the point, at which we need to intervene manually, using Eclipse. The magic is to copy the just created icons (with the guides) to some Android-project's resources and to export the project to an APK. The so created APK will then include the icons with the (visible) guides removed! The structure of the patches is still included in the PNGs, but they look just as if they where "normal" PNGs.
So, create a new Android-project in Eclipse, locate its folder on your harddisk, copy your .9.png to the respective res/drawable folder, clean your projects in Eclipse, so that the new files are recognized, and export the project as an unsigned application (right-click on project's root, choose Android Tools -> Export Unsigned Application Package).
My desktop in action:
Get the Flash Player to see this player.
(640×512 px, 3.9 MB / 50 sec = 650 KBit/s overall bitrate)
This is a reasonable amount of work to be done, isn't it? I can now switch to a default-color I like within minutes. That's good.
The following APKs need modifications:
list of APKs to be modified
/system/app/Browser_B115SP03.apk
/system/app/Calculator_B116SP01.apk
/system/app/Calendar_B116SP01.apk
/system/app/CalendarProvider_B116SP01.apk
/system/app/Camera_B116SP01.apk
/system/app/Community_B116SP01.apk
/system/app/Dialer_B116SP01.apk
/system/app/Email_B116.apk
/system/app/Launcher_B116SP01.apk
/system/app/Mms_B116SP01.apk
/system/app/Music_B116SP01.apk
/system/app/NotePad_B116.apk
/system/app/Phone_B116SP01.apk
/system/app/Settings_B115SP03.apk
/system/app/ShortCard_B116SP01.apk
/system/app/SoundRecorder_B116SP01.apk
/system/framework/framework-res.apk
from which the following contain .9.png files
list of APKs with .9.png files
/system/app/Calendar_B116SP01.apk
/system/app/Community_B116SP01.apk
/system/app/Email_B116.apk
/system/app/Launcher_B116SP01.apk
/system/app/Mms_B116SP01.apk
/system/app/NotePad_B116.apk
/system/app/Settings_B115SP03.apk
/system/app/ShortCard_B116SP01.apk
/system/framework/framework-res.apk
I probably went too far …
Here, we see that changing an icon's hue globally will affect nearby colors as well and so, not only the meganta play-button turns to green, but also the rest of, say, the music-icon. But in fact, only ShortCard_B116SP01.apk has this problem, so I needed to fix three icons manually (music, notepad, and picture):
For those of you being interested, this is the GIMP-script I use to modifiy the colors:
magtogreen.scm
(define (magtogreen pattern)
(let* ((filelist (cadr (file-glob pattern 1))))
(while (not (null? filelist))
(let* ((filename (car filelist))
(image (car (gimp-file-load RUN-NONINTERACTIVE filename filename)))
(drawable (car (gimp-image-get-active-layer image))))
(gimp-message filename)
(if (not (= 1 (car (gimp-drawable-is-rgb drawable))))(gimp-image-convert-rgb image))
(gimp-hue-saturation drawable 6 60 0 0)
(gimp-hue-saturation drawable 1 60 0 0)
(gimp-file-save RUN-NONINTERACTIVE image drawable filename filename)
(gimp-image-delete image))
(set! filelist (cdr filelist)))))
Just copy and paste the code to your editor and the correct formatting will reappear. The code converts the hue of the magenta-channel (6) to 60 and the red channel (1) to the same value, thereby turning them to green, which of course will also affect nearby colors, like in the example just given. However, the just mentioned icons are the only ones which show this problem, as all the others either contain magenta only or magenta with grey, for which the script does a perfect job.
To turn the colors into orange, I use
magtoorange.scm
(define (magtoorange pattern)
(let* ((filelist (cadr (file-glob pattern 1))))
(while (not (null? filelist))
(let* ((filename (car filelist))
(image (car (gimp-file-load RUN-NONINTERACTIVE filename filename)))
(drawable (car (gimp-image-get-active-layer image))))
(gimp-message filename)
(if (not (= 1 (car (gimp-drawable-is-rgb drawable))))(gimp-image-convert-rgb image))
(gimp-hue-saturation drawable 0 40 0 0)
(gimp-file-save RUN-NONINTERACTIVE image drawable filename filename)
(gimp-image-delete image))
(set! filelist (cdr filelist)))))
which now modifies the master-channel. Invokation is done by
GIMP in batch-mode
gimp -i -b '(magto'$COLOR' "*")' -b '(gimp-quit 0)'
where COLOR is green or orange (or whatever you name your code). Note that there is one line testing whether the image is RGB or indexed and if it is indexed, it turns it to RGB, allowing HUE-operations (btw.: it is this conversion from indexed to RGB which blows your framework-res up; mine went from 2.5 to 3 MB).
At this point, we've changed a few .apks and as announced above, we're now going to zipalign them, making sure that the directories in the ZIPs begin at easily accessible boundaries.
zipalign
zipalign -v 4 package.apk zipaligned_package.apk
zipalign is part of the Android-SDK and located in the tools folder.
Okay, now that all icons have been replaced, then what is the following?
What we see here is that we cannot steer everything by simply changing icons …
So, let's have a more sophisticated look at APK-contents. You may have realized that beside the drawable-* folders there are many others inside an APK, e.g. layout. In general, what we are interested in is everything that influences the look and feel. This includes fonts, default colours, animations, etc. These informations are stored in various .XML files, which unfortunately are saved in a binary format (the technical phrase is WBXML, iirc) rather than in human-readable form. But there is a possibility to turn them into ASCII-XML using this code:
AXMLPrinter2
java -jar /path/to/android-sdk-linux_86/tools/AXMLPrinter2.jar /path/to/unpacked/apk/res/layout/some.xml
This will output the XML-contents to stdout. For example, framework-res.apk's res/layout/status_bar.xml contains, beside others, this section:
framework-res/res/layout/status_bar.xml
<com.android.server.status.TickerView
android:id="@android:010201D4"
android:paddingTop="2.0dip"
android:paddingRight="10.0dip"
android:layout_width="0.0dip"
android:layout_height="-2"
android:layout_weight="1.0"
>
<TextView
android:textColor="#FFFFFFFF"
android:layout_width="-1"
android:layout_height="-2"
android:singleLine="true"
>
</TextView>
<TextView
android:textColor="#FFFFFFFF"
android:layout_width="-1"
android:layout_height="-2"
android:singleLine="true"
>
</TextView>
</com.android.server.status.TickerView>
It says the obvious, namely that the status_bar's default text-color is 0xFFFFFFFF. This presentation differs from the usual 3-byte RGB representation in that it consists of 4 bytes. The additional byte steers the opacity and it is the first one of the quadrupel. So, 0xFFFFFFFF stands for white text, being fully opaque, and 0x00FFFFFF is white text being fully transparent. 0x7F0000FF is blue text, half transparent, and so on.
Of course this number will be found in the binary-XML as well, you only need to know where to look at. The reason is that the just decoded XML cannot be re-converted to its binary form. This is done at creation time by Eclipse.
So, the question is, where is the location of this resource:
In fact, this bar appears quite often, not only in the Meridia-player above, but also with YouTube:
The orange button in the right hand picture is framework-res/res/drawable/btn_media_player_pressed.9.png. I know that because I came across it and did not change it because it has no magenta - and the gray handles can be identified as well … so where does the color come from?
The answer is that what we see is the standard Android progress dialogue. It's the same on all Androids. And in fact, the drawable folder in framework-res contains some interesting XMLs:
resources for progress-bar
progress_horizontal.xml
progress_large.xml
progress_medium.xml
progress_small_titlebar.xml
progress_small.xml
There are some more, yes, but they don't contain color-information. Using the above ASCII-view, one quickly finds that progress_horizontal.xml defines three shades of magenta:
which, when tinted with (or hue'd to) green as above using gimp, produces this:
Therefore, the procedure is to hexedit progress_horizontal.xml and to replace all appearences of 0xC8086B with 0x94c808, 0x99004F with 0x709A00, and 0xFF128C with 0xBFFF13 (two times each).
Side-note: I am using ghex2 or okteta. If you do so as well, you will need to search for 4F 00 99 rather than 99 00 4F etc.
The same as above applies to the circular progress dialogue, for which the remaining 4 XMLs are responsible. They all contain a certain shade of magenta, namely 0xE60085, which I change to 0xB8E600. The result is this:
For my orange theme, color-mappings are 0xC8086B -> 0xC88B08, 0x99004F -> 0x9A6900, and 0xFF128C -> 0xFFB413 in progress_horizontal.xml and 0xE60085 -> 0xE68D00 in the 4 other XMLs.
What remains to do is to fix the browser's URL-bar (the background is magenta, of course), To do this, edit browser_progress_drawable.xml in the browser's res/drawable folder. Here, the color-mappings are
0x99004F -> 0x709A00, 0xFF128C -> 0xBFFF13, and 0xCD096E -> 0x98CD09. For orange it is 0x99004F -> 0x9A6900, 0xFF128C -> 0xFFB413, and 0xCD096E -> 0xCD8F09.
There is another file indicating a magenta, which is browser_seekbar_horizontal.xml. The color defined there (0xAE206A) will be changed to 0x88AE20 for green and to 0xAE8120 for orange.
At the first sigh, my phone now seems to be magenta-free and in fact, after playing around for a day or so I couldn't see any more magenta … until I realised this:
This resource is located in resources.arsc, which is again a binary (compressed) file, included in framework-res.apk. To read all resources of an APK, we take
aapt
aapt dump --values resources framework-res.apk
That gives a rather long output, but we know what we're looking for. We're after something that steers the appearances of text, so let's lookup "text" and after a short search, we find the following section:
output of aapt
resource 0x0103003e android:style/TextAppearance: <bag> (PUBLIC)
Parent=0x00000000, Count=6
#0 (Key=0x01010095): (dimension) 16.000000sp
#1 (Key=0x01010097): (color) #00000000
#2 (Key=0x01010098): (attribute) 0x01010036
#3 (Key=0x01010099): (color) #fffe118c
#4 (Key=0x0101009a): (attribute) 0x0101009a
#5 (Key=0x0101009b): (color) #ff5c5cff
And there we are. Want to have a look at 0xFE118C? It's this:
Bah … My gimp-script will map it to this one:
that is, the annoying color 0xFE118C maps to 0xBEFE12 (green theme) resp. 0xFEB312 (orange). So, we modify the file resources.arsc using a hex-editor as above, by looking up 0xFE118C and changing it to the new value. Proof:
While we are at it: If you look for a HUAWEI-ROM which has no branding (no branding is the wrong saying, it has less), then go to their website and watch for ROMs they release. Say, go to here and look for ROMs. I cannot provide a static link, as they tend to change their download-area every day. In addition, bandwith is poor.
What if we need to change a resource that is not located in the ROM? Let's take ServoSearch as an example. I don't use it, but it is highly magentaised by T-Mobile. The application is located in /system/sd/app/com.db4o.servo.search.apk and tweaking it is performed as above. But contrary to the examples shown above, the .zip must be signed before deployment and before its installation, the old version must be removed. The steps to take are as follows:
resigning com.db4o.servo.search.apk
keytool -genkey -v -keystore mykeystore.keystore -alias Cert -keyalg RSA -validity 10000
jarsigner -verbose -keystore mykeystore.keystore com.db4o.servo.search.apk CERT
keytool and jarsigner are part of usual distros. After that, do
using adb to uninstall and install
adb uninstall com.db4o.servo.search
adb install your_modified_package.apk"
Now, is it safe to say that the phone is now magenta-free? No. I know that there are still shades of magenta defined somewhere. An example is camera.apk. In res/drawable/camera_zoombar_* and in res/drawable-finger/video_timebar_* we still find magentas, but I haven't come across those in daily usage. On the other side, there is this, what you see while cropping a picture:
And I am not aware where this color is coming from.
Just as reminder for me (need to remember that I must try the following):
smali
java -Xmx512M -jar /home/zarrabi/android/android-sdk-linux_86/tools/smali-1.2.2.jar ./ -o new-classes.dex
X. Android Sources and a Common Kernel
Initially, there was no reason for me to install the sources, but the limited BT-functionality of the phone forced me to do so. Here's how.
What I did first was to download the Android Sources together with a kernel. To do so, I created a directory android, went there and followed the steps at http://source.android.com/download. The last make will not work without further config: Android does not work with Java 1.6, but with 1.5. Java 1.5 is present on my machine, but I had to tell SuSE to use 1.5 as default. So, on SuSE, do
default java version to use
update-alternatives --config java
update-alternatives --config javac
in a console and chose from the menu. Other distributions provide other approaches. I now got (staying in the same directory) the kernel,
getting the common kernel
git clone git://android.git.kernel.org/kernel/common.git
Btw.: The entire repository is here.
The kernel is now located in common (a subfolder of android). According to source.android.com/download, a simple make will do the job, but it doesn't as long as you don't meet the dependencies. The current sources work with 32 bit tools, so make sure that not only the needed libs are installed but also their 32 bit variants together with the respective development-packages (aka sources).
With this setup, you can compile the kernel, modules and userspace-apps for the Pulse.
I did the complete compile and it took ages (= hours, so do that at night and go to bed). I also compiled the kernel, for which I needed the toolchain in prebuilt/linux-x86/toolchain (relative to android). I went to common (location of the kernel) and did
kernel-config from the phone
adb pull /proc/config.gz config.gz
gunzip config.gz
mv config .config
This will put an initial kernel-config to the kernel-directory. Cross-compilation of the kernel can then be done using the just mentioned toolchain
menuconfig
make CROSS_COMPILE=../prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- ARCH=arm menuconfig
Here, it is very important to change the config as follows: Goto System Type and choose system type to be Qualcomm MSM7X00A. This must be done for the Pulse, because it is an ARMv6 system. The differences between v5 and v6 may be small, but for kernel modules, the system on the phone will complain about the wrong system number and deny to insert a module.
The correct magic string is 2.6.27-perf preempt mod_unload ARMv6.
I then could make my own kernel using
kernel compilation
make CROSS_COMPILE=../prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- ARCH=arm clean
make CROSS_COMPILE=../prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- ARCH=arm
make CROSS_COMPILE=../prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- ARCH=arm modules
For example, in menuconfig I marked bnep.ko to be compiled as a module for insertion to the kernel on the phone.
XI. Bluetooth
I went this stony way, because I came along a tutorial saying that one needs bnep.ko as a module and pand and iptables as binaries. What I realised was that my MCR-ROM from MoDaCo already has bnep.ko built into the kernel. Same for iptables, which came together with the ROM. I only needed a binary copy of pand, which I compiled as mentioned above.
That is, to be precise, the tools in external/bluetooth/bluez/compat (paths are always relative to the Android-sources) do not compile out of the box, because there is no Android.mk located in that directory. That needed to be created first.
To begin with,
l2ping
l2ping <bt-address of phone>
worked of course, so I started pand on the phone
invokation of pand
pand -n --listen --role NAP
and on the host I did
sdptool
sdptool browse <bt-address of phone>
to give, beside other information,
output of sdptool
Service Name: Network Access Point
Service Description: BlueZ PAN Service
Service Provider: BlueZ PAN
Service RecHandle: 0x10005
Service Class ID List:
"Network Access Point" (0x1116)
Protocol Descriptor List:
"L2CAP" (0x0100)
PSM: 15
"BNEP" (0x000f)
Version: 0x0100
SEQ16: 800 806
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
Profile Descriptor List:
"Network Access Point" (0x1116)
Version: 0x0100
Next on the host I did
starting pand on the client
pand --connect <bt-address of phone>
This action caused both the phone and the host to provide a network interface named bnep0. Perfect! For a detailed description of pand see here. It is usually contained in the bluez-compat-package of your distribution, but, as said above, for the phone I needed the compiled binary.
Now, of course I could set the devices up, giving them IP-addresses and let them communicate, so that the host and the phone are connected, but the phone would still not forward IP packets and will not do masquerading.
As we all know, making a Linux-box to be a router first requires
forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
and iptables. What we normally do is to
iptables and masquerading
ifconfig bnep0 10.0.1.1 netmask 255.255.255.0 up
iptables -F
iptables -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -I FORWARD -s 10.0.1.0/24 -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -j MASQUERADE
iptables -t nat -A POSTROUTING -j ACCEPT
and it is exactly this what is failing. Trying to run iptables gives
kernel has no NAT-support
iptables v1.3.7: can't initialize iptables table `nat': iptables who? (do you need to insmod?)
Perhaps iptables or your kernel needs to be upgraded.
which simply means that ip_tables.ko has not been loaded (see also here). The problem is that it cannot be inserted. As I can make my own modules, I built ip_tables.ko, but dmesg complains again:
insmod ip_tables.ko
ip_tables: Unknown symbol xt_free_table_info
ip_tables: Unknown symbol xt_register_match
and some more. The solution is of course to resolve the dependencies, but insmod x_tables.ko immediately forces the phone to boot. Strange? Well, post #5 in this thread reports about this problem as well, so that seems to be a difficult one.
If Kernel-NATing is not available, then what about userspace-NAT? There are two solutions I am aware of. The first one is a tool called minewt, project page is here (though site is down) and it's downloadable from here. I did not manage to integrate it into the Android-sources, because the dependencies are a pain. The tool is delivered with an own (and quite old) version of libnet, libpcap, and tomcrypt. As libpcap and tomcrypt are part of the Android-sources, I tried to install a newer version of libnet first and to compile minewt against it, but that failed with tons of errors.
The same is true for vde (virtual distributet environment), which is the second method to do NAT in userspace (though vde provides a much more general approach): I gave up translating the Makefile to an Android.mk, again due to too much dependencies.
We're not talking about one-click-solutions anyway, so let's have a look at a possibility to get the mentioned tools to work. This is provided by installing Ubuntu on the phone (see below).
Once within the Ubuntu-environment, I installed some development packages like gcc, make, bison, etc. And then I went the usual way to compile a package, namely, via ./configure and make. Both mentioned packages compile without any probem (though I needed to meet some more dependendies). The build-process for minewt in fact unpacks the shipped libraries (see above) and compiles against them and, at least, the binary starts.
Now, the general usage of minewt is as follows (and you're running it from within the chroot-env).
minewt
minewt -vv -i 192.168.2.1 -d bnep0 -I 192.168.1.21 -r 192.168.1.4
provided the tool can figure out the routers (192.168.1.4) MAC-address itself. So, let's assume that we have one standard-interface over which the phone is connected (this is either rmnet0 for GSM or eth0 for WLAN). Let us also say that as above, bnep0 is our BT-interface, which we got by running pand. Then the above command will serve as a NAT-gateway for connections coming in from bnep0. By running tcpdump against eth0, I figured out that the destination-MAC of the Ethernet-frames consists of zeroes only, thereby being cancelled. It is exactly this what made me try to add the MAC to the command-line:
minewt -R
minewt -vv -i 192.168.2.1 -d bnep0 -I 192.168.1.21 -r 192.168.1.4 -R <MAC_of_router>
And the only answer from running the tool was bus error. Well, the source of minewt is a single C-file, so I had a look at it and hardcoded my router's MAC. The bus error was away, and minewt actually did some NATing! Yeah!
Unfortunately, it's not useable this way. A simple ping shows up to 70% packet loss, response times are two seconds and even more and you can clearly see from the output of minewt that it drops more than 70% of the requests.
Going with vde revealed the same. In principle, the three lines
vde
vde_switch -s /tmp/vdesocket
slirpvde /tmp/vdesocket-s -D
vde_pcapplug -s /tmp/vdesocket bnep0
should do the job, but as soon as a packet arrives at bnep0, slirpvde fails with - guess? - a bus error.
I mean, that's interesting. It seems as if everytime the actual NATing is being done (must be done for both the IP and the MAC, of course), both tools fail with exactly the same message. strace does not show any problems - until the bus error.
At this point I am really interested in compiling the code for the native Android (not chrooted), hoping to see something more … say a reboot?
XII. Accessing the internal Modem with Bluetooth
So that was about tethering again, this time BT-tethering (didn't I say I don't like the wording?). Again, I am not really sure about why I should tether at all. If my phone can connect, my laptop can do so as well, so where is the benefit? For me, the wireless solution would be to establish a serial line via Bluetooth and to use the phone as a normal modem afterwards. That's fine in the sense of convenience. Most of the time, the device will be connected USB anyway, you know, for charging reasons …
Starting pand is good, but, as mentioned, needs NATing. There is another daemon, dund, which serves as a dial up server (PPP) rather than an access point - with the same drawback: It starts pppd (if present on the system), lets you connect and provides an IP, and here, you need iptables again.
Now, as we know that there is a modem, why don't we use it? Well, the first question is: Where is it?
Answer: The device's internal modem is at /dev/smd0.
This is the way to proceed:
Install rfcomm on your device. The command is part of Android's source (see below). On the phone, say
rfcomm on the phone
rfcomm listen X Y
This creates a device /dev/rfcommX (where X is the device-number and Y is a channel number) and to which a host can connect to using
rfcomm on the host
rfcomm connect Z <bt-address> Y
where now Z is the device-number (/dev/rfcommZ) choosen on the host and <bt-address> is the phone's address. A serial line is established, without any further traffic.
The idea is to bridge /dev/rfcommX and /dev/smd0, hoping that the host will then see a modem on /dev/rfcommZ. Bridging two serial ports is easy, as we only need to cat the output of one device to the other, and vice versa, just like this:
bridging /dev/rfcommX and /dev/smd0
cat /dev/smd0 > /dev/rfcommX &
cat /dev/rfcommX > /dev/smd0
That in fact works, but automatic handling is complicated. See below: We want rfcomm watch to start our bridge and to cancel it after termination of the line. This can be done, of course, but needs some special care of which cat to kill when, including pid-handling. There is another way:
While watching the system-load being online via USB, I realised that such a bridge already exists. It is /system/bin/port-bridge and is started by init as a service:
/init.qcom.rc
service port-bridge /system/bin/port-bridge /dev/smd0 /dev/ttyHSUSB0 &
Obviously, the tool takes Unix device nodes as arguments, and clearly, the service is used to bridge the internal modem with the USB serial port. So, I did the self-evident
/system/bin/port-bridge
/system/bin/port-bridge /dev/smd0 /dev/rfcommX &
which gives
output of port-bridge
I:portbridge: smd_new_status is 42, smd_old_status =0
I:portbridge: Turning ON external port bits 42
I:portbridge: Turning ON SMD DTR bit
and in principle, this suffices to see a Hayes-compatible modem on /dev/rfcommZ on the host. This in fact works somehow, but using a terminal like minicom or kppp appears to be very slow and unreliable, and often enough, characters just disappear.
The problem is the already running bridge for /dev/ttyHSUSB0. That is, we now have two mappers running, both delivering the output of /dev/smd0 to their targets (/dev/ttyHSUSB0 and /dev/rfcommX, respectively). As my phone was attached to my host's USB as well (for adb-reasons) I could in fact see that the traffic arriving at the USB-port did not make it to /dev/rfcommZ, and vice versa..
The obvious action to take is to shutdown the running bridge, but that is not possible as it immediately gets respawned by init. That could be changed of course, but I wanted to be flexible, so I went another way, moved the binary /system/bin/port-bridge to /system/bin/port-bridge-orig and killed the process.
On the phone, I then ran
rfcomm watch
rfcomm watch X Y /system/bin/port-bridge-orig /dev/smd0 /dev/rfcommX &
Option watch tells rfcomm to restart listening when a connection is finished. As soon as the host connects (see above), rfcomm creates the device node /dev/rfcommX and invokes /system/bin/port-bridge-orig /dev/smd0 /dev/rfcommX.
I was testing this while the phone was still attached via USB, so as a final test, I unplugged the device, and the bluetooth connection could no more be restarted.
I don't have a source code of the bridge, so I started it with strace (yet another binary to compile using the SDK) and that clearly revealed the cause:
strace port-bridge
open("/sys/devices/platform/msm_hsusb_periphera/state", O_RDONLY|O_LARGEFILE) = 3
read(3, "USB_STATE_NOTATTACHE", 20) = 20
close(3) = 0
Setting the state manually with echo "USB_STATE_CONFIGURED" > /sys/devices/platform/msm_hsusb_periphera/state does not work, as the state is corrected immediately by the system.
The solution is to modify the binary with a hex-editor and to replace the location
/sys/devices/platform/msm_hsusb_periphera/state with a string of exactly the same length, I choosed /data/local/tmp/fake_sys_dev_platf_msmusb_state, saved the program as /data/local/bin/port-bridge-fake, and echoed the correct state (USB_STATE_CONFIGURED) into the file fake_sys_dev_platf_msmusb_state. The complete procedure is as follows, assuming that /system/bin/port-bridge has been copied to /system/bin/port-bridge-orig before (not moved, as above).
bt_modem_on
#!/system/bin/sh
/data/local/bin/dbus-send --system --type=method_call --print-reply --dest=org.bluez /org/bluez/hci0 org.bluez.Adapter.RemoveBonding string:<bt-address of headset>
mount -o remount,rw -t yaffs2 /dev/block/mtdblock1 /system
rm /system/bin/port-bridge
mount -o remount,ro -t yaffs2 /dev/block/mtdblock1 /system
killall -9 port-bridge
echo "USB_STATE_CONFIGURED" > /data/local/tmp/fake_sys_dev_platf_msmusb_state
/data/local/bin/rfcomm -A watch 0 17 /data/local/bin/port-bridge-fake /dev/smd0 /dev/rfcomm0 &
/data/local/bin/sdptool add --handle 0x10017 --channel 17 DUN
exit 0
A few more notes: The first line unpairs my headset (of course, dbus-send is not part of a stock or customized ROM, I compiled it as I did for the other binaries, like rfcomm, sdptool, etc.). If I don't unpair first, an incoming call will break both the headset's and the host's connection. If I unpair first and pair the headset again after the host and the phone are connected, everything works dandy. I think I know the reason for this, but have not yet found the time to investigate. The switch -A tells rfcomm to ask for authentification, which means that the PC and the phone get paired after both provide the same passkey.
Then I took 17 as the channel to communicate, hoping that it is ununsed by the system. It is, as can be seen using sdptool browse on the host and this in turn also means that we need to tell the phone's bt-subsystem to offer an appropriate service (last line).
Turn off:
bt_modem_off
#!/system/bin/sh
/data/local/bin/sdptool del 0x10017
killall -9 port-bridge-fake
killall -9 rfcomm
mount -o remount,rw -t yaffs2 /dev/block/mtdblock1 /system
cp -a /system/bin/port-bridge-orig /system/bin/port-bridge
mount -o remount,ro -t yaffs2 /dev/block/mtdblock1 /system
/system/bin/port-bridge /dev/smd0 /dev/ttyHSUSB0 &
exit 0
Dial-in on the host is then done as in the USB-case (see above), now using /dev/rfcomm0 instead of /dev/ttyUSB0.
A final comment: Data rate is very poor with BT. A dial-up provides an approximate
average of 40 KB/s (with rare peaks at 60 KB/s) downstream, where the USB-connection is 10 times faster (stable 2.5 Mbit/s). What makes it even worse, are parallel phone calls using a BT-headset. The voice-connection alone eats up to 35 KB/s, allowing the online-channel to download with not more than 5 KB/s. However, the connection stays stable and recovers after the headset-channel has been terminated. This setup works perfectly for Windows as well, of course (just setup a BT-modem).
I went the above way with Ubuntu 9.something and SuSE 11.1 (64 Bit). Be careful: 11.1's bluetooth is broken (not seriously, but broken), that is, something is wrong with either bluez4 or bluez3 … I don't know and I don't care.
The specific problem with SuSE 11.1 is that the small BT-icon in KDE's (and Gnome's) task bar does not do anything. Okay, that is better than what WinXP does, namely talking too much, but I need the icon for pairing. If I unpair the connection to my host, an attempt to go online will force the phone to ask for a PIN, and so is the host expected to do - which doesn't work.
Pairing is stressing my nerves anyway, whatever OS, so all I've ever admired was something scriptable; and there is. The name of the tool is simple agent, which is pure understatement. It can be found at git.kernel.org. Do this on the host:
rfcomm on the host
rfcomm bind 0 <bt-address-of-phone> 17 (see channel consids above)
pppd call gprs-bt
and in another shell just say
simple agent
simple_agent
and watch it asking for the PIN. Let's be smart and close our connection when done (i.e., after killing the above pppd):
terminate connection
rfcomm release 0
Btw.: When I say 'scriptable' then I am aware of that simple agent requires interaction. I use expect for full automation.
XIII. Eclipse and Android-SDK
In order to install applications, one needs a development-environment, and for Android, this is Eclipse with a plugin. This section is about setting it up.
Before using Eclipse for Android, one needs to set it up correctly. Start it, goto Window -> Preferences -> General -> Capabilities and enable CLassic Update.
We are now going to install the ADT-plugin, see also here. To setup the remote site, goto Help -> Software Updates -> Find and Install -> Search for new features to install and click on New Remote Site.... Enter a name (Android, say) and as URL https://dl-ssl.google.com/android/eclipse/. If that doesn't work, use http rather than https. Then click on Finish and restart Eclipse.
When starting Eclipse, it looks like this (in my case):
Go to Window -> Preferencies -> Android and provide the location of your local SDK:
You'll see this:
Connect your device via USB and got to Window -> Open Pespective -> Other.
Choose DDMS and watch your device being recognised. At this point, you can also take screenshots.
Unplug your device,
and choose File -> New -> Project:
choose Android Project and provide your details,
and you are here:
Watch your code,
and resolve problems like "R cannot be resolved". In this case, load the class from com.zarrabi.first after clicking on the red icon.
Now click on run, choose Android Application,
and a virtual device pops up and boots:
It is now ready,
and shows the installed applications, including the just deployed small app.
While the virtual device is open, watch again the DDMS-view to see that it now shows this phone instead of the real one before.
XIV. Ubuntu
Installing Ubuntu on the phone is very easy thanks to Paolo Sammicheli, because we are already running a Linux-Kernel, so all we do is to unpack an already compiled chroot-environment. Go here, download, unzip and start (instructions are given on the project's website).
I am not backing up Ubuntu with nandroid, as it wastes too much space on /sdcard/nandroid. Instead, the backup is stored on a host.
pack
tar cvf - ubuntu | /data/local/bin/ssh 192.168.1.2 -l zarrabi "gzip -9 > ubuntu.tgz"
unpack
/data/local/bin/ssh 192.168.1.2 -l zarrabi gunzip -c documents/pulse/card_backup/ubuntu.tgz | tar xvf -
Start TightVNC on the phone:
vncserver
export USER=root
vncserver -geometry 480x320
And watch on the client:
vncviewer
vncviewer 192.168.1.21:1
Beware, starting X exhausts the phone's capabilities in terms of performance.
XV. MoDaCo's Android 2.1 v6r1 leaked beta longstory ROM
Again: T-Mobile provides a 2.1-version (see above). The following has been written while only a leaked version was available, so the information is outdated. I will keep it for documentation reasons.
As of this writing, it's here. The forum discussing it is here, so you will better go to the second link first.
I started with a smoothly running Pulse, almost completely de-magentaized and tweaked slightly as described above (Bluetooth). I first backed up my existing nandroid-backups by saying the follwoing, and I also removed dalvik's cache:
preparation
tar cvf - BCDEMRS-20100510-1940 | /data/local/bin/ssh 192.168.1.2 -l zarrabi "gzip -9 > nandroid.tgz"
rm -rf /system/sd/dalvik-cache/*
One small side note here, although it's offtopic: Removing the Dalvik-cache is not only harmless, I strongly recommend to do so from time to time (reboots are a good opportunity). If you encounter problems with the market, for example, then go to the phone, remove all files in /system/sd/dalvik-cache/ and reboot. The cache will be rebuilt, of course, and you can install market-apps again.
I left sdcard's vfat partition unbackuped, pushed the ROM, and went into recovery mode:
preparation
adb push r6.1-2.1-pulse-a2sd+-signed.zip /sdcard
adb shell reboot recovery
There, I did a full nand and ext backup:
Then, I powered the device off, took out the card, inserted it into my card-reader and dd'd the content to my PC, just in case something goes wrong. And remember: I did not perform a backup of the vfat-partition.
dd
dd_rescue /dev/sdc ./new_card.img
Turned the card back into the phone, started it in recovery mode. There, I went to wipe, and choosed data/factory reset and ext2 wipe.
go to "Flash zip from sdcard" and choose r4-2.1-pulse-signed.zip", reboot afterwards and expect problems.
At this time, I was able to adb to the phone and saw it doing something (top, ps ) … but there was no locat and the device got stuck in android. The reason was unknown to me (because there was bo logcat to study), but a manual mount revealed that there was no /system/sd folder, so I created one saying
create mount-point for sdcard
mount -o remount,rw -t yaffs2 /dev/block/mtdblock1 /system
cd /system
mkdir sd
reboot
The boot-loop was away, the circular t-mobile-logo appeared, but still no logcat. The devices boots okay with only very few force closes. I found it quite stable. Device id changed to vendor=0x12d, product=0x1502 from vendor=0x12d1, product=0x1501 before, so needed to rescript sendsms etc.
Issues: No logcat, no vibration, no ddms (so no screenshots).
The logcat-issue could be resolved: Look at /sys/kernel/logger/log_main/enable. It returns 0, so set it to 1. Also look at /sys/kernel/logger/log_main/priority. It returns 0 as well, set it to 2. Now logcat works. The information provided in this blog is from here.
What also changed is that the green button goes to call log. All comments I saw relative to this complained about the behaviour, but I like it, as I got used to this by my old phone.
On tweaking APKs as above, I found that Contacts must not be compressed (replaces Community in 1.5).
Being at 2.1, I tried PDANET as it promises to do userspace NAT (see above). After pdanet has started, it offers a dial-up service on channel 3. So, on the host do
preparing a BT serial line for pdanet
rfcomm bind 0 <bt-address-of-phone> 3 (<- !)
and then do
invoking ppp
pppd call pdanet
where /etc/ppp/peers/pdanet is just like above for gprs (USB) with noccp uncommented (important!). The chat-script contains
/etc/ppp/dpanet-chat
''
ATD123
The results where pretty much the same as for minewt and vde (see above). Most of the packets are dropped and the longer I think about it, the more I am convinced that this is a problem of routing between the interfaces. Contrary to kernel-NAT, userspace-NAT does (probably, I don't know about pdanet's internals) have the disadvantage that the kernel is not aware of that incoming packets in response to a previously NATed packet are valid and therefore drops them. I will perhaps dig into this later.
The short investigations I took also showed that the port-bridge still exists and that I can go online as descried above. However, all theme-tweaking from above must be done again, as the icons have changed dramatically. I began to de-magenta this 2.1-version but decided to stay at 1.5 for now (for other reasons), so I stopped making the phone green.
And this is basically all I tested with 2.1. I found it quite fast and responsive, but when heavily loaded, using the graphical interface is a pain. Better not to use live wallpaper (hehe).
I went back to 1.5. Before, I initiated a nand backup of 2.1, and in fact, by just restoring it I can quickly switch to 2.1 again for testing purposes, but I am running 1.5 for now.
As an official 2.1 is out now, I frequently watch MoDaCo's forum and will definitely switch to it later, but that will then go into a separate posting.