The world of programming
A friend of mine sent me this picture which shows who did what in the field of computing. He found the picture on Smash magazine's website (don't know where). But here it is:
Setting up your Android environment
I have seen quite a few posts on some lists asking about how to set up a programming environment for Android. While it is very straight forward, the documentation is all over the place. So, I decided to write this tutorial
.
In this tutorial, we will install Android SDK in eclipse (Galileo), we will add an SD Card to your emulator and put some pictures in it. I have written this tutorial with Windows users in mind but the process should not be very different for other platforms.
I have written this tutorial assuming that you already have JDK installed. If you don't have it already installed then please install it before reading this. You can find a tutorial on how to install here.
Installing the SDK
- Download the latest eclipse IDE from
http://www.eclipse.org/downloads/.You can also download Galileo directly from here.
- Create a folder in your c:\ drive and name it android. The file you just downloaded (at least from the direct link I provided above) is a zip file which contains a folder called eclipse. Extract the zip file and place the folder in, c:\android. Now, you have eclipse installed in c:\android. Go into the eclipse folder. You will see an executable called eclipse. Double click it to run eclipse.
- Now, download the android SDK 1.6 (the latest as of this writing) for windows from the link below:http://developer.android.com/sdk/download.html?v=android-sdk-windows-1.6_r1.zipTo download the SDK for other platforms, go here :http://developer.android.com/sdk/1.6_r1/index.html
- Extract the contents of the zip file in c:\android\. Now, you will have 2 folders in c:\android\. One is eclipse and the other is android-sdk-windows-xxx.android-sdk-windows-xxx folder contains another folder called tools. We need to add this folder to the system's PATH variable. To do that, Click on Start, then right click on "My Computer" and click on "Properties" in the menu that pops up.
The "System Properties" dialog will pop up. Click on the "Advanced" tab and then click on "Environment variables". Another dialog will appear.
Run eclipse. Click on Help -> Install New Software.
An install dialog will appear. Click on "Add", another dialog will appear. Type in Android for name and put in https://dl-ssl.google.com/android/eclipse for Location. Then click OK. Click on next, check both the checkboxes and click next. Eclipse will start downloading the plugin and install it. You will be asked to restart eclipse after the installation is done. Click on "Yes" when it asks you to restart. Eclipse will restart and you can, now, create Android projects!
Now that the basic installation is done. Let's setup the SC Card.
Setting up the SD Card
Creating the SD card is very easy.
- Click on Start -> Run. The run dialog will appear
- Type "cmd" (without the quotes) and hit enter or click the OK button. A commant prompt window will appear.
- Type "android list targets" in it and hit enter. It will show you a list of targets. Get the id for Android 1.6. It will most probably be 2
- Type the command "android create avd -n testavd -t <target_id> -c 128M" (without the quotes) and hit enter. Make sure to subsitute the <target_id> with the actual ID you got from "android list targets" command. Since it will most probably be 2, the command will look like this "android create avd -n testavd -t 2 -c 128M (again without quotes).
- Press enter 1 more time
Viola! you have created your SD Card for the emulator. The next time you start the emulator, you will be able to access it. Below is an illustration to make things easy.
When I created my SD card, I needed to get some pictures on it. So, I used an external program called winimage to do that.
Working with your SD card
- Download winimage from http://www.winimage.com/download.htm. You can either get the zip file or the exe file. I downloaded the zip file, extracted it and use that.
- Run winimage.exe and make sure your emulator is not running.
- Click on Open image icon. Browse to c:\android\sd_card\ folder. Select sdcard and click OK button. Winimage will open the sdcard image. Now, you can browse the file structure and add files, delete files, etc. After you are done, make sure to close winimage or you won't be able to access the SD card from the emulator.
As always here's an illustration:
Now, we have an the SD Card image open. Let's create a folder called "media" and put some pictures in it. When you take pictures with your phone's camera they are stored in the media folder in your SD Card.
To create the media folder, click on Image, then on Create Folder. A dialog box will appear. Type "MEDIA" in it. and Click OK. After the folder is created, you can drag and drop pictures from your computer to the media folder just like you would normally do it when copying files from one location on your computer to another.
PHP and Sabre
What is Sabre?
Sabre is a company that has data of all flight schedules, etc. And, using their system, you can book flights, hotels, rent cars, etc.
Getting PHP to talk with Sabre
I tried PHP Soap and nuSoap. They both didn't work for me because of their limitations. So I ended up writing a small script of my own that talks with Sabre for me after I realized that the headers being sent by all the SOAP libraries I tried, were not compatible with Sabre's web services.
Sabre checks the "Content-Type" header in your request. If that is not "text/xml", you will always get an error, even if your xml is correct.
Here's a little piece of code that should help with the transport part. I will leave the generation of XML to you.
/** * Sabre class (for connecting to Sabre web services) * @author Moazzam Khan <moazzam at moazzam-khan dot com> * @version $Id$ */ class Sabre { public $host; public $port; public $timeout; public function Sabre() { $this->timeout = 30; } public function makeRequest($body) { $header = "POST /websvc HTTP/1.1\r\n" . "Host: {$this->host}:{$this->port} Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Content-Type: text/xml Content-Length: ".strlen($body)." Pragma: no-cache Cache-Control: no-cache"; $fp = fsockopen("ssl://".$this->host, $this->port, $errno, $errstr, $this->timeout); if(!$fp){ print "SOCKET ERROR $errstr ($errno)\n"; } else { //send the request fputs($fp, $header."\r\n\r\n".$body, strlen($header."\r\n\r\n".$body)); stream_set_timeout($fp, 30); stream_set_blocking ($fp, 1); while (!feof($fp)) { $line = fread($fp, 2048); if (trim(strlen($line)) < 10) continue; $output .= $line; } fclose($fp); } $ret = explode("\r\n\r\n", $output); $ret = explode("\r\n", $ret[1]); for ($i=0; $i<count($ret); ++$i) if (strlen($ret[$i]) < 5) $ret[$i] = ''; return implode('', $ret); } }
Android HttpRequest class (version 2.1)
Version of of this class had some bugs so I corrected them and here is the latest version
Enjoy!
package moz.http; import java.net.*; import java.io.*; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import org.apache.http.client.HttpClient; import org.apache.commons.*; import android.util.Log; /** * HTTP Request class * * You can use this class and distribute it as long as you give proper credit * and place and leave this notice intact :). Check my blog for updated * version(s) of this class (http://moazzam-khan.com) * * Usage Examples: * * Get Request * -------------------------------- * HttpData data = HttpRequest.get("http://example.com/index.php?user=hello"); * System.out.println(data.content); * * Post Request * -------------------------------- * HttpData data = HttpRequest.post("http://xyz.com", "var1=val&var2=val2"); * System.out.println(data.content); * Enumeration<String> keys = dat.cookies.keys(); // cookies * while (keys.hasMoreElements()) { * System.out.println(keys.nextElement() + " = " + * data.cookies.get(keys.nextElement() + "rn"); * } * Enumeration<String> keys = dat.headers.keys(); // headers * while (keys.hasMoreElements()) { * System.out.println(keys.nextElement() + " = " + * data.headers.get(keys.nextElement() + "rn"); * } * * Upload a file * -------------------------------- * ArrayList<File> files = new ArrayList(); * files.add(new File("/etc/someFile")); * files.add(new File("/home/user/anotherFile")); * * Hashtable<String, String> ht = new Hashtable<String, String>(); * ht.put("var1", "val1"); * * HttpData data = HttpRequest.post("http://xyz.com", ht, files); * System.out.println(data.content); * * @author Moazzam Khan */ public class HttpRequest { /** * HttpGet request * * @param sUrl * @return */ public static HttpData get(String sUrl) { HttpData ret = new HttpData(); String str; StringBuffer buff = new StringBuffer(); try { URL url = new URL(sUrl); URLConnection con = url.openConnection(); BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); while ((str = in.readLine()) != null) { buff.append(str); } ret.content = buff.toString(); //get headers Map<String, List<String>> headers = con.getHeaderFields(); Set<Entry<String, List<String>>> hKeys = headers.entrySet(); for (Iterator<Entry<String, List<String>>> i = hKeys.iterator(); i.hasNext();) { Entry<String, List<String>> m = i.next(); Log.w("HEADER_KEY", m.getKey() + ""); ret.headers.put(m.getKey(), m.getValue().toString()); if (m.getKey().equals("set-cookie")) ret.cookies.put(m.getKey(), m.getValue().toString()); } } catch (Exception e) { Log.e("HttpRequest", e.toString()); } return ret; } /** * HTTP post request * * @param sUrl * @param ht * @return * @throws Exception */ public static HttpData post(String sUrl, Hashtable<String, String> ht) throws Exception { String key; StringBuffer data = new StringBuffer(); Enumeration<String> keys = ht.keys(); while (keys.hasMoreElements()) { key = keys.nextElement(); data.append(URLEncoder.encode(key, "UTF-8")); data.append("="); data.append(URLEncoder.encode(ht.get(key), "UTF-8")); data.append("&"); } return HttpRequest.post(sUrl, data.toString()); } /** * HTTP post request * * @param sUrl * @param data * @return */ public static HttpData post(String sUrl, String data) { StringBuffer ret = new StringBuffer(); HttpData dat = new HttpData(); String header; try { // Send data URL url = new URL(sUrl); URLConnection conn = url.openConnection(); conn.setDoOutput(true); OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); wr.write(data); wr.flush(); // Get the response Map<String, List<String>> headers = conn.getHeaderFields(); Set<Entry<String, List<String>>> hKeys = headers.entrySet(); for (Iterator<Entry<String, List<String>>> i = hKeys.iterator(); i.hasNext();) { Entry<String, List<String>> m = i.next(); Log.w("HEADER_KEY", m.getKey() + ""); dat.headers.put(m.getKey(), m.getValue().toString()); if (m.getKey().equals("set-cookie")) dat.cookies.put(m.getKey(), m.getValue().toString()); } BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while ((line = rd.readLine()) != null) { ret.append(line); } Log.e("ERROR", line); wr.close(); rd.close(); } catch (Exception e) { Log.e("ERROR", "ERROR IN CODE:"+e.getMessage()); } dat.content = ret.toString(); return dat; } /** * Post request (upload files) * @param sUrl * @param files * @return HttpData */ public static HttpData post(String sUrl, ArrayList<File> files) { Hashtable<String, String> ht = new Hashtable<String, String>(); return HttpRequest.post(sUrl, ht, files); } /** * Post request (upload files) * @param sUrl * @param params Form data * @param files * @return */ public static HttpData post(String sUrl, Hashtable<String, String> params, ArrayList<File> files) { HttpData ret = new HttpData(); try { String boundary = "*****************************************"; String newLine = "rn"; int bytesAvailable; int bufferSize; int maxBufferSize = 4096; int bytesRead; URL url = new URL(sUrl); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setDoInput(true); con.setDoOutput(true); con.setUseCaches(false); con.setRequestMethod("POST"); con.setRequestProperty("Connection", "Keep-Alive"); con.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary); DataOutputStream dos = new DataOutputStream(con.getOutputStream()); //dos.writeChars(params); //upload files for (int i=0; i<files.size(); i++) { Log.i("HREQ", i+""); FileInputStream fis = new FileInputStream(files.get(i)); dos.writeBytes("--" + boundary + newLine); dos.writeBytes("Content-Disposition: form-data; " + "name="file_"+i+"";filename="" + files.get(i).getPath() +""" + newLine + newLine); bytesAvailable = fis.available(); bufferSize = Math.min(bytesAvailable, maxBufferSize); byte[] buffer = new byte[bufferSize]; bytesRead = fis.read(buffer, 0, bufferSize); while (bytesRead > 0) { dos.write(buffer, 0, bufferSize); bytesAvailable = fis.available(); bufferSize = Math.min(bytesAvailable, maxBufferSize); bytesRead = fis.read(buffer, 0, bufferSize); } dos.writeBytes(newLine); dos.writeBytes("--" + boundary + "--" + newLine); fis.close(); } // Now write the data Enumeration keys = params.keys(); String key, val; while (keys.hasMoreElements()) { key = keys.nextElement().toString(); val = params.get(key); dos.writeBytes("--" + boundary + newLine); dos.writeBytes("Content-Disposition: form-data;name="" + key+""" + newLine + newLine + val); dos.writeBytes(newLine); dos.writeBytes("--" + boundary + "--" + newLine); } dos.flush(); BufferedReader rd = new BufferedReader( new InputStreamReader(con.getInputStream())); String line; while ((line = rd.readLine()) != null) { ret.content += line + "rn"; } //get headers Map<String, List<String>> headers = con.getHeaderFields(); Set<Entry<String, List<String>>> hKeys = headers.entrySet(); for (Iterator<Entry<String, List<String>>> i = hKeys.iterator(); i.hasNext();) { Entry<String, List<String>> m = i.next(); Log.w("HEADER_KEY", m.getKey() + ""); ret.headers.put(m.getKey(), m.getValue().toString()); if (m.getKey().equals("set-cookie")) ret.cookies.put(m.getKey(), m.getValue().toString()); } dos.close(); rd.close(); } catch (MalformedURLException me) { } catch (IOException ie) { } catch (Exception e) { Log.e("HREQ", "Exception: "+e.toString()); } return ret; } }
You will also need the class below:
package moz.http; import java.util.Hashtable; public class HttpData { public String content; public Hashtable cookies = new Hashtable(); public Hashtable headers = new Hashtable(); }
HTTP Request class for Android (version 2)
Hi Everyone,
After some people pointed out the problems they had with version 2 of this class, I took it all out. Please go to: http://moazzam-khan.com/blog/?p=490 for version 2.1
Removing mywebsearch as the default search engine from Firefox
If you have accidentally installed myWebSearch as the default search engine for firefox, and want to remove it then do the following :
- Close Firefox
- Go to C:\program files\mozilla firefox\chrome\
- Delete the files m3ffxtbr.jar and m3ffxtbr.manifest
- Go to c:\program files\ and delete the mywebsearch folder, if it is there.
HTTP Request class for Android
Here is a class that can be used to make HTTP get and HTTP post requests. I haven't commented everything but the usage should be pretty clear from the method signatures.
Note: This is for Android 1.5.
[java]
import java.net.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import org.apache.http.client.HttpClient;
import org.apache.commons.*;
import android.util.Log;
public class HttpRequest {
/**
* HttpGet - doesn't read cookies
*
* @param sUrl
* @return
*/
public static HttpData get(String sUrl) {
HttpData ret = new HttpData();
String str;
StringBuffer buff = new StringBuffer();
try {
URL url = new URL(sUrl);
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
while ((str = in.readLine()) != null) {
buff.append(str);
}
ret.content = buff.toString();
} catch (Exception e) {
Log.e("HttpRequest", e.toString());
}
return ret;
}
/**
* HTTP post request
*
* @param sUrl
* @param ht
* @return
* @throws Exception
*/
public static HttpData post(String sUrl, Hashtable
StringBuffer data = new StringBuffer();
Enumeration
while (keys.hasMoreElements()) {
data.append(URLEncoder.encode(keys.nextElement(), "UTF-8"));
data.append("=");
data.append(URLEncoder.encode(ht.get(keys.nextElement()), "UTF-8"));
data.append("&");
}
return HttpRequest.post(sUrl, data.toString());
}
/**
* HTTP post request
*
* @param sUrl
* @param data
* @return
*/
public static HttpData post(String sUrl, String data) {
StringBuffer ret = new StringBuffer();
HttpData dat = new HttpData();
String header;
try {
// Send data
URL url = new URL(sUrl);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(data);
wr.flush();
// Get the response
Map
Set
for (Iterator
Entry
Log.w("HEADER_KEY", m.getKey() + "");
dat.headers.put(m.getKey(), m.getValue().toString());
if (m.getKey().equals("set-cookie"))
dat.cookies.put(m.getKey(), m.getValue().toString());
}
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
ret.append(line);
}
wr.close();
rd.close();
} catch (Exception e) {
Log.e("ERROR", "ERROR IN CODE:"+e.toString());
}
dat.content = ret.toString();
return dat;
}
}
[/java]
You will also need this class along with it.
[java]
import java.util.Hashtable;
public class HttpData {
public String content;
public Hashtable
public Hashtable
}
[/java]
Google Voice Review
I had signed up for Google Voice a week or so ago and I got an email today saying that I was invited to test it out. So, here is a somewhat detailed review of it. Keep in mind that it is still in testing phase
.
How does it work?
Google lets you choose a phone number for your Google Voice account. It will, then, ask you for your phone number. You can give it a number of your mobile/cell phone or your home phone. Whenever someone calls your Google voice phone number, you home phone or cell phone will ring (depending on what phone number you gave Google when signing up).
You can have more than one phone ring when your Google Voice number is called. And, you have filter calls. For example, you can have your cell phone ring if your business clients call and have your home phone ring if your friends call. This can be used to prioritize your phone calls.
How do you place calls you ask? You can login to your Google Voice account from your browser and click on place call button. It will ask you for the phone number you wish to call and which phone it should ring (your home phone or any other phones you have added). It will, then, call you on the phone you specify, then it will call the other person and connect you both.
If you wish to access it from your phone (make phone calls, send SMS, etc), Google has made mobile apps for Android and Blackberry. They also made an app for iPhone but Apple rejected it. Google also has a mobile version of Google voice website, so you can always login to your account through your web browser.
[screenshots]
The features:
- ListenIn - You can listen to your friends leaving your a voicemail. You don't have to wait will they are done recording it.
- Record calls - This, I think, is a great feature. You can record your calls whenever you want. It can be at the start of a conversation or in the middle. Press 4 to start recording and press 4 again to stop recording.
- Switch phones - If you are talking on your mobile phone and the voice quality is bad, you can hit * on your mobile phone and all other phones you added to your voice account will start ringing. You can, then, pick up the phone with best reception and start talking again without anyone noticing
.
You can also make international calls. And, Google has very cheap rates. It would have been good to have unlimited international calls for a flat rate (like MetroPCS does) but it still is better than most international calling plans out there.
It sounds too good to be true
Depending upon how important your privacy is to you, it might be. I read Google's privacy policy. It states that even after you have terminated your account, your phone calls, voicemails, SMS, etc will remain on Google's backup systems. I don't know if other phone carriers that (I should probably read their privacy policy and find out - it's good to know) but yeah. They don't say whether your voicemails, etc will be deleted permanently if you were to delete them.
This shouldn't come as a surprise, though. Gmail does the same thing. Your emails are never physically deleted from their servers. They are just marked as deleted so you don't see them anymore.
Visit these links for more information:
http://www.google.com/support/voice/bin/answer.py?hl=en&answer=115037
http://www.google.com/googlevoice/legal-notices.html
http://www.google.com/googlevoice/privacy-policy.html
http://www.google.com/support/voice/bin/answer.py?hl=en&answer=154724
Cheap cell phone plans
Almost a century ago (when my grandparents were young) land lines were considered to be very advanced technology. Dial tone phones came out when I was a kid. In just a few decades, phones have become so common and mobile that they have become a part of almost everyone's daily life. Cell phones (or mobile phones) are now so common that everyone and their mother has one. We all know where there is a need, there is someone taking advantage of that need. So, we have carriers like Tmobile, Sprint, Bell, etc. charging their customers based on the minutes used.
The cell phone industry underwent another change (in USA) about a year ago. What was the change? Flat rate plans for cell phones! What was its cause? An unknown company - Metro PCS - that came out of nowhere and took over a chunk of cell phone users with its cheap prices. Their lowest plan goes for $30. It doesn't have voicemail or anything else. However, you can make as many calls as you want and you can receive them. For about $15 more, you can get voicemail, etc. And, unlimited data, unlimited texts, unlimited calls and unlimited international calls.
Even land lines don't offer international calls for that price! Metro PCS successfully grabbed customers from various national service providers *cough* like Sprint and Tmobile *cough* .
What did this cause?
This made cell phone carriers (at least some of them) rethink their plans too. Sprint is not offering a $50 plan with unlimited calls, unlimited texts and unlimited data. Tmobile is offering a $50 ($89 for families) plan for unlimited calls to already existing customers. You have to get text and data separately.
What's the catch?
Metro PCS has great service is metro cities like New York City, Seattle, etc. It's reception is bad in other areas. However, they are working on increasing their coverage. And, they don't have a very wide selection of phones. In fact, they have only one smart phone. Since Metro PCS operates on CDMA network, you cannot use their service with your current phone (assuming you have a GSM phone like me).
Sprint did the same thing. For their $50 unlimited everything plan, they have a custom set of phones which are regular phones and they don't offer this service with smart phones. This means if you want to browse the net, you are stuck with the phone keypad and a small screen which means you won't be using that unlimited data a lot. I have seen a lot of people text like crazy on regular flip phones so I think people will use that regardless of their phone.
Tmobile' service is $50 for only calls. If you want unlimited text, it is additional $5 and unlimited internet is $20. The good thing, however, is that it works on a GSM network so you can use it with any GSM phone. The bad thing? Tmobile drops calls very frequently. If your friends text you today, you might get that text tomorrow. Sometimes even voicemail is delayed. The data, on the other hand, is good.
ATT seems to be doing its own thing with iPhones. As far as I know, they charge over a $100 for 400 minutes. However, a lot of people are willing to pay that because of their iPhones.
For more information, visit the links below:
Google voice
Yes, people. It's out. At least for the test phase Google didn't really keep it a secret that it wants to get into the telecom industry. And, we all know that when Google does something, it changes everything!
Google voice is an application that runs on your phone and PC. Google will assign you a phone number. If anyone calls that number, your phone receives the call. You can check your voicemail on the phone or your PC. You can even read transcripts of your voicemail (speech to text). Another great thing about Google voice is that it lets you select which phone should ring when someone calls. For now, you have to get an invite to be able to use Google voice (please send me an invite if you have any left
). However, that will hopefully change in the future.
What does it mean for us as consumers? Hopefully a change in the way telecom industry operates and cheaper prices (a big shout out to MetroPCS for cheap cell phone service). There is one concern, though. Google owns an email service, a video service, online albums, and now phones. Can this lead to the "big brother" concept where "they" watch everything we do? Gmail scans through your email to show you relevant ads. Google states that no human being goes through them but how can we be sure? I know the whole privacy thing is an issue of its own. I would like to hear your (the reader's) thoughts on this. Please leave comments and let me know what you think








