Search This Blog

27 June 2010

Manually installed FroYo

Ok, I got impatient.  I have been checking my System Updates window a few times a day, and still no sign of the update...  so I decided to do it manually using these instructions (recapped here):

*Note: These instructions are apparently for the unlocked TMobile version of the NexusOne (which I happen to be using on the AT&T network).

  1. Verify that you are on build ERE27 (under Settings | About Phone)
  2. Download this file as '' in the root of your microSD (which I did via the USB connection)
  3. Not sure if it is necessary, but I unplugged the USB for the next few steps
  4. Power off your phone
  5. Hold down the trackball and press/release the power button
  6. When the white screen with skateboarding robots show up, make sure Bootloader is selected (should be already) and hit the power button.
  7. If you try to scroll down (using Volume buttons) the screen may flash to another message for a moment. When it comes back, scroll down to Recovery and hit the power button.
  8. After it reboots, you'll see the exclamation screen.
  9. Press the power and volume up buttons.  I found PressPower->Press/Release Volume->Release Power seemed to work
  10. Using the trackball, scroll down and select Apply
  11. It will take awhile, then reboots... then it takes a really long while. Go make a sandwich.
  12. Once it is booted again, verify that FRF50 is installed.
  13. In my case, it immediately started doing a synchronization.  If it does, I'd recommend waiting until it finishes.
  14. Delete from the microSD
  15. Put this file as '' in the root of your microSD.
  16. Repeat steps #3 through #10.
  17. This time, after applying the update, you'll have to select the reboot option.
  18. It's going to take awhile.  Go check your email.
  19. Once it boots up, verify that FRF83 is installed.
  20. Delete from the microSD.
  21. Enjoy

18 June 2010

Phone ID and Other Useful Tidbits

Let's start with a basic project:

F:\work> mvn archetype:generate -DarchetypeCatalog=
2: -> galatea-archetype (null)
artifactId: PhoneIDTest
version: 1.0-SNAPSHOT

F:\work> cd PhoneIDTest
F:\work\PhoneIDTest> mvn clean install

Add this to your AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

Add this convenience method to your PhoneIDTestActivity:
    private void showMessage(String msg)
        Toast.makeText(this, msg, Toast.LENGTH_LONG).show();

Insert this into the end of your onCreate method:
        TelephonyManager mgr = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
            case TelephonyManager.PHONE_TYPE_CDMA:
            case TelephonyManager.PHONE_TYPE_GSM:
            case TelephonyManager.PHONE_TYPE_NONE:
                showMessage("Unknown phone type");

        showMessage("Device ID: " + mgr.getDeviceId());
        showMessage("Version: " + mgr.getDeviceSoftwareVersion());
        showMessage("Number: " + mgr.getLine1Number());
        showMessage("Country: " + mgr.getNetworkOperatorName());
        showMessage("Sim Serial#: " + mgr.getSimSerialNumber());
        showMessage("Subscriber ID: " + mgr.getSubscriberId());
        showMessage("Operator: " + mgr.getSimOperatorName());
Redeploy (mvn clean install) and run the app.

11 June 2010

Accessing call logs

Start with a basic project:

F:\work> mvn archetype:generate -DarchetypeCatalog=
2: -> galatea-archetype (null)
artifactId: CallLogs
version: 1.0-SNAPSHOT

F:\work> cd CallLogs
F:\work\CallLogs> mvn clean install

Add the READ_CONTACTS permission to your AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_CONTACTS" />

Add this to the end of your onCreate() in CallLogsActivity:
        Uri allCalls = Uri.parse("content://call_log/calls");
        Cursor c = managedQuery(allCalls, null, null, null, null);
        for(String colName : c.getColumnNames())
            Log.v(TAG, "Column Name: " + colName);

        if (c.moveToFirst())
               String id = c.getString(c.getColumnIndex(CallLog.Calls._ID));
               String num = c.getString(c.getColumnIndex(CallLog.Calls.NUMBER));
               int type = Integer.parseInt(c.getString(c.getColumnIndex(CallLog.Calls.TYPE)));

                switch (type)
                    case 1: Log.v(TAG, id + ", " +num + ": INCOMING") ; break;
                    case 2: Log.v(TAG, id + ", " +num + ": OUTGOING") ;break;
                    case 3: Log.v(TAG, id + ", " +num + ": MISSED") ; break;
           } while (c.moveToNext());

Redeploy (mvn clean install).  If you watch the logs (adb logcat) while running the app on the emulator, you will see the column names listed -- but not any call logs... How do we fix that?
V/CallLogs(  870): Column Name: numbertype
V/CallLogs(  870): Column Name: new
V/CallLogs(  870): Column Name: duration
V/CallLogs(  870): Column Name: _id
V/CallLogs(  870): Column Name: numberlabel
V/CallLogs(  870): Column Name: name
V/CallLogs(  870): Column Name: number
V/CallLogs(  870): Column Name: type
V/CallLogs(  870): Column Name: date

The easy answer is that you can dial a number on the emulator (even though it won't connect) and then re-run your CallLogs app to see the number you just dialed listed as an OUTGOING call.

What about incoming and missed?  Create another AVD and launch a secondary emulator.  In the titlebar and taskbar icon name, you can see some number associated with each emulator instance (like: 5554).  From one emulator, you can "dial" the number of the other. So, for instance, in emulator 5556 open the dialer and dial 5554.  Dial from one to the other; answer some not others; Dial the other direction, etc.

Run your app again.  In my case, the emulator seemed to not log MISSED calls. 

At some point, you are bound to wonder what those nulls are in the managed query....  from the API:
public final Cursor managedQuery(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

A few brief examples of what you can do (per this tutorial):

uri: Who to get data from?
    Uri allCalls = Uri.parse("content://call_log/calls");

projection: What columns to return?
    String[] projection = new String[]{Calls._ID, Calls.NUMBER, Calls.TYPE};
selection: SQL WHERE clause
    String selection = "Calls.NUMBER LIKE '65%'"; //---retrieve numbers beginning with 65---
    String[] selectionArgs = null;
selectionArgs: (to populate the selection clause)

sortOrder: SQL ORDER BY clause
    String sortOrder = "Calls.TYPE DESC"; //---sort result by call TYPE descending---
So, for example,
Cursor c = managedQuery(
    new String[]{Calls._ID, Calls.NUMBER, Calls.TYPE},
    "Calls.NUMBER LIKE '65%'",
    "Calls.TYPE DESC"
would return the _id, number, type columns from numbers that started with 65 in descending order....