Tuesday, July 12, 2011

Insert, Update, Delete, View contacts in android 2.0

Starting from Android 2.0 (API Level 5), the Android platform provides an improved Contacts API for managing and integrating contacts from multiple accounts and from other data sources. To handle overlapping data from multiple sources, the contacts content provider aggregates similar contacts and presents them to users as a single entity. This article describes how to use the new API to manage (insert, update, delete, view) contacts.

The new Contacts API is defined in the android.provider.ContactsContract and related classes. The older API is still supported, although deprecated.

We need to understand the underlying structure of storage to better manipulate the contacts. We have three distinct types of tables – Contacts, Raw Contacts and Data.

All data related to a contact is stored in this generic data table with each row telling what is the data it stores through its MIME type. So we could have a Phone.CONTENT_ITEM_TYPE as the MIME type of the data row, it contains Phone data. Similarly, if we have Email.CONTENT_ITEM_TYPE as the row’s MIME type, then it stores email data. Like this lot of data rows are associated with a single Raw Contact.

Each Raw Contact refers to a specific contact’s data coming from one single source – say, you gmail account or your office Microsoft account.

The Contact is the topmost in the hierarchy which aggregates similar looking data from various sources into one single contact – a very handy feature when you have redundant data coming about the same contact from you various accounts – like a facebook account, orkut account, yahoo account and goggle account.  So the hierarchy looks like this:
So, when we want to insert a new contact, we always insert a Raw Contact. When we want to update an existing contact, we most often deal with the data tables which are accessible through a series of CommonDataKind classes. Because this would be to update particular types of data like phone or email.
Coming to the example:

I create an activity with four buttons to View, Add, Modify and Delete Contacts.

           Button view = (Button)findViewById(R.id.viewButton);
            Button add = (Button)findViewById(R.id.createButton);
            Button modify = (Button)findViewById(R.id.updateButton);
            Button delete = (Button)findViewById(R.id.deleteButton);
           
           
            view.setOnClickListener(new OnClickListener() {
                  public void onClick(View v){
                        displayContacts();
                        Log.i("NativeContentProvider""Completed Displaying Contact list");
                  }
            });

On the click of each of the buttons I invoke their respective methods: like displayContacts(),createContact(), updatecContact() and deleteContact(). We will now see each of these methods.

displayContacts() is pretty straightforward. Access to each of the tables mentioned above is through a content URI. I use the topmost level ‘Contacts’ URI to iterate through all the existing contacts and display their names and phone numbers (Toast them).

We know Contacts is a ContentProvider and hence we need to query through aContentResolver which returns all the data of the contacts.

   private void displayContacts() {
     
      ContentResolver cr = getContentResolver();
        Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
                nullnullnullnull);
        if (cur.getCount() > 0) {
            while (cur.moveToNext()) {
                  String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
                  String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                  if (Integer.parseInt(cur.getString(
                        cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
                     Cursor pCur = cr.query(
                               ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                               null,
                               ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
                               new String[]{id}, null);
                     while (pCur.moveToNext()) {
                         String phoneNo = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                         Toast.makeText(NativeContentProvider.this"Name: " + name + ", Phone No: " + phoneNo, Toast.LENGTH_SHORT).show();
                     }
                    pCur.close();
                }
            }
        }
    }

I will try to briefly explain the above method.  Line 1 gets a handle to the ContentResolver. Line 2 queries the Contacts URI (ContactsContract.Contacts.CONTENT_URI ) without any mention of the specific columns or “where” clause of an SQL query. Notice all the 4 parameters are null. This means that we are not making any conditional query into the contacts table and hence all data is returned into the cursor.

Next, I check that the cursor is not empty and iterate through the cursor data. I retrieve the _ID andDISPLAY_NAME from the Contacts and then, I check for the flag if the contact has a phone number. This information is available in contacts table itself. But the Phone number details are in the data tables. Hence after checking for the flag, I query the CommonDataKings.Phone.CONTENT_URI for the phone data of that specific ID. From this new cursor named pCur, I retrieve the Phone Number. If there are multiple phone number for one contact, all of them will be retrieved and toasted one after another.
Now, let us see how to create or insert a new contact.

In the createContact() method which is called when you click on the “Add Contact” button, I first query to see if the hardcoded name “Sample Name” already exists. If so, I toast a message stating the same. If not, then I get into actually inserting the name along with a phone number. The first part of the check you can view in the complete source code available for download. Only the second part of inserting a contact is explained here. For this, we need to use a ContentResolver always.

ContentResolverprovides an applyBatch(…) method which takes an array ofContentProviderOperation classes as a parameter. All the data built into theContentProviderOperations are committed or inserted into the ContentProvider that we are working on. IN this case, the ContentProvider we are working on are Contacts and the authority associated with the same is ContactsContract.AUTHORITY

Here is the code for the same:

        ArrayList<ContentProviderOperation> ops = newArrayList<ContentProviderOperation>();
        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE,"accountname@gmail.com")
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME"com.google")
                .build());
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name)
                .build());
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_HOME)
                .build());

       
        try {
                  cr.applyBatch(ContactsContract.AUTHORITY, ops);
….

In the first element in the ops array, I am setting the details of the account to which I want to add the contact. In this case the gmail account type is accontname@gmail.com and the account name is“com.google”. The latter has to be unique and hence it is recommended to use the internet URLs of the source of data.

In the second element, I am adding the name of the contact and in the third the phone data. You notice that I use .withValueBackReference(..) as we still have not created the Raw contact and hence we do not have the Id. The first row creates the id and hands over the id to the next rows of data. 
This array ops is passed into the ContentResolver and thus the data is inserted.

For updating the phone number of an existing contact, I again use the ContentResolver with theContentProviderOperation array. However, now, I pass the where clause and the parameters of the where clause – specifically indicating that only the phone number of the “Sample Name” contact has to be updated.
            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
                    .withSelection(where, params)
                    .withValue(ContactsContract.CommonDataKinds.Phone.DATA, phone)
                    .build());

Notice the .withSelection(where, params). The where and params look like this:

        String where = ContactsContract.Data.DISPLAY_NAME + " = ? AND " +
                        ContactsContract.Data.MIMETYPE + " = ? AND " +
                        String.valueOf(ContactsContract.CommonDataKinds.Phone.TYPE) + " = ? ";
       
String[] params = new String[] {name,
                  ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
                  String.valueOf(ContactsContract.CommonDataKinds.Phone.TYPE_HOME)};

Delete too is done in a very similar manner with no values but only the selection criteria is provided for which contact to be deleted.

      ContentResolver cr = getContentResolver();
      String where = ContactsContract.Data.DISPLAY_NAME + " = ? ";
      String[] params = new String[] {name};
   
        ArrayList<ContentProviderOperation> ops = newArrayList<ContentProviderOperation>();
       ops.add(ContentProviderOperation.newDelete(ContactsContract.RawContacts.CONTENT_URI)
              .withSelection(where, params)
              .build());
        try {
                  cr.applyBatch(ContactsContract.AUTHORITYops);
            } catch (RemoteException e) {
….


I really scouted the internet a lot to find a comprehensive tutorial on the new Contacts Content Provider API but could not find anything that easily. Hope this helps all who of you who are looking for the same.

Friday, July 8, 2011

Designer’s Guide to Supporting Multiple Android Device Screens

Introduction

For designers, Android is the elephant in the room when it comes to app design. As much as designers would like to think it’s an iOS world in which all anyones cares about are iPhones, iPads and the App Store, nobody can ignore that Android currently has the majority of smartphone market share and that it is being used on everything from tablets to e-readers. In short, the Google Android platform is quickly becoming ubiquitous, and brands are starting to notice.

But let’s face it. Android’s multiple devices and form factors make it feel like designing for it is an uphill battle. And its cryptic documentation is hardly a starting point for designing and producing great apps. Surf the Web for resources on Android design and you’ll find little there to guide you.

If all this feels discouraging (and if it’s the reason you’re not designing apps for Android), you’re not alone. Fortunately, Android is beginning to address the issues with multiple devices and screen sizes, and device makers are slowly arriving at standards that will eventually reduce complexity.

This article will help designers become familiar with what they need to know to get started with Android and to deliver the right assets to the development team. The topics we’ll cover are:
  • Demystifying Android screen densities,
  • Learning the fundamentals of Android design via design patterns,
  • Design assets your developer needs,
  • How to get screenshots,
  • What Android 3 is about, and what’s on the horizon.


Android Smartphones And Display Sizes

When starting any digital design project, understanding the hardware first is a good idea. For iOS apps, that would be the iPhone and iPod Touch. Android, meanwhile, spans dozens of devices and makers. Where to begin?

The baseline for screens supported by Android smartphone devices is the T-Mobile G1, the first commercially available Android-powered device, which has an HVGA screen measuring 320 × 480 pixels.

HVGA stands for “half-size video graphics array” (or half-size VGA) and is the standard display size for today’s smartphones. The iPhone 3GS, 3G and 2G use the same configuration.

android10_android_design_patterns_01
T-Mobile G1, the first commercially available Android device and the baseline for Android screen specifications.

To keep things simple, Android breaks down physical screen sizes (measured as the screen’s diagonal length from the top-left corner to bottom-right corner) into four general sizes: small, normal, large and xlarge.

android10_android_design_patterns_02

Two common Android screen sizes. (Image from Google I/O 2010)

320 × 480 is considered a “normal” screen size by Android. As for “xlarge,” think tablets. However, the most popular Android smartphones today have WVGA (i.e. wide VGA) 800+ × 480-pixel HD displays. So, what’s “normal” is quickly changing.

android10_android_design_patterns_03

Diagram of various screen configurations available from emulator skins in the Android SDK. (Image: Android Developers website)

For testing, I use a Motorola Droid X, which has a WVGA screen. Again, this is considered “large” by Android’s standards.

The variety of display sizes can be challenging for designers who are trying to create one-size-fits-all layouts. I’ve found that the best approach is to design one set of layouts for 320 × 480 (your baseline) and another set for 320 × 533 (which would be considered a “large” physical screen size).

While this creates more work for both the designer and developer, the larger physical screen size on bigger devices such as the Motorola Droid and HTC Evo might require changes to the baseline layouts that make better use of the extra real estate.

What You Need to Know About Screen Densities

Screen sizes are only half the picture! Developers don’t refer to a screen’s resolution, but rather its density. Here’s how Android defines the terms in its Developers Guide:
  • Resolution: The total number of physical pixels on a screen.
  • Screen density: The quantity of pixels within a physical area of the screen, usually referred to as DPI (dots per inch).
  • Density-independent pixel (DP): This is a virtual pixel unit that you would use when defining a layout’s UI in order to express the layout’s dimensions or position in a density-independent way. The density-independent pixel is equivalent to one physical pixel on a 160 DPI screen, which is the baseline density assumed by the system of a “medium”-density screen. At runtime, the system transparently handles any scaling of the DP units as necessary, based on the actual density of the screen in use. The conversion of DP units to screen pixels is simple: pixels = DP * (DPI / 160). For example, on a 240 DPI screen, 1 DP equals 1.5 physical pixels. Always use DP units when defining your application’s UI to ensure that the UI displays properly on screens with different densities.
It’s a bit confusing, but here’s what you need to know. As with screen sizes, Android breaks down screen densities into four basic densities: lDPI (low), mDPI (medium), hDPI (high), and xhDPI (extra high). This is important because you’ll need to deliver all graphical assets (i.e. the bitmaps) in sets of lDPI, mDPI and hDPI densities. For now, let’s assume that xhDPI is for tablets only.

What this means is that all non-drawable graphics (i.e. graphics that can’t be scaled automatically by Android at runtime) need to be scaled from your “medium” (i.e. 320 × 480) baseline screen layouts.

The bitmap requirement is similar to preparing graphics for print vs. the Web. If you have any experience with print production, you’ll know that a 72 PPI image will look very pixelated and blurry when scaled up and printed. Instead, you would need to redo the image as a vector image or use a high-resolution photo and then set the file’s resolution at around 300 PPI in order to print it without any loss of image quality. Screen density for Android works similar, except that we’re not changing the file’s resolution, only the image’s size (i.e. standard 72 PPI is fine).

Let’s say you took a bitmap icon measuring 100 × 100 pixels from one of the screens of your baseline designs (remember the “baseline” is a layout set at 320 × 480). Placing this same 100 × 100 icon on a device with an lDPI screen would make the icon appear big and blurry. Likewise, placing it on a device with an hDPI screen would make it appear too small (due to the device having more dots per inch than the mDPI screen).

android10_android_design_patterns_04
An application without density support. (Image: Android Developers website)

To adjust for the different device screen densities, we need to follow a 3:4:6:8 scaling ratio between the four density sizes. (For the iPhone, it’s easy: it’s just a 2:1 ratio between the iPhone 4 and 3GS.) Using our ratios and some simple math, we can create four different versions of our bitmap to hand off to our developer for production:
  • 75 × 75 for low-density screens (i.e. ×0.75);
  • 100 × 100 for medium-density screens (our baseline);
  • 150 × 150 for high-density screens (×1.5);
  • 200 × 200 for extra high-density screens (×2.0). (We’re concerned with only lDPI, mDPI and hDPI for Android smartphone apps.)
android10_android_design_patterns_05

The final graphic assets would appear like this using the four different screen densities.

After you’ve produced all of your graphics, you could organize your graphics library as follows:

android10_android_design_patterns_06

The suggested organization and labeling of asset folders and files. In preparing our star graphic, all file prefixes could be preceded by the name ic_star, without changing the names of the respective densities.

You might be confused about what PPI (pixels per inch) to set your deliverables at. Just leave them at the standard 72 PPI, and scale the images accordingly.



Using Android Design Patterns

Clients often ask whether they can use their iPhone app design for Android. If you’re looking for shortcuts, building an app for mobile Web browsers using something like Webkit and HTML5 is perhaps a better choice. But to produce a native Android app, the answer is no. Why? Because Android’s UI conventions are different from iPhone’s.

The big difference is the “Back” key, for navigating to previous pages. The Back key on Android devices is fixed and always available to the user, regardless of the app. It’s either a physical part of the device or digitally fixed to the bottom of the screen, independent of any app, as in the recently released Android 3.0 for tablets (more on this later).

android10_android_design_patterns_07

The hard “Back” key on a smartphone running Android 2.0.

The presence of a Back key outside of the app itself leaves space for other elements at the top of the screen, such as a logo, title or menu. While this navigational convention differs greatly from that of iOS, there are still other differentiators that Android calls “design patterns.” According to Android, a design pattern is a “general solution to a recurring problem.” Below are the main Android design patterns that were introduced with version 2.0.

Dashboard

This pattern solves the problem of having to navigate to several layers within an app. It provides a launch pad solution for rich apps such as Facebook, LinkedIn and Evernote.

android10_android_design_patterns_08

The dashboard design pattern, as used by Facebook and LinkedIn.

Action Bar

The action bar is one of Android’s most important design patterns and differentiators. It works very similar to a conventional website’s banner, with the logo or title typically on the left and the navigation items on the right. The action bar’s design is flexible and allows for hovering menus and expanding search boxes. It’s generally used as a global feature rather than a contextual one.

android10_android_design_patterns_09

The action bar design pattern as used by Twitter.

Search Bar

This gives the user a simple way to search by category, and it provides search suggestions.

android10_android_design_patterns_10

The search bar design pattern as used in the Google Search app.


Quick Actions

This design pattern is similar to iOS’ pop-up behavior that gives the user additional contextual actions. For example, tapping a photo in an app might trigger a quick action bar that allows the user to share the photo.

android10_android_design_patterns_11

The quick action design pattern as used by Twitter.

Companion Widget

Widgets allow an app to display notifications on the user’s launch screen. Unlike push notifications in iOS, which behave as temporary modal dialogs, companion widgets remain on the launch screen. (Tip: to select a widget for your Android device, simply tap and hold any empty space on one of the launch screens.)

android10_android_design_patterns_12

The companion widget by Engadget, New York Times and Pandora.

Using established design patterns is important for keeping the experience intuitive and familiar for your users. Users don’t want an iPhone experience on their Android device any more than a Mac user wants a Microsoft experience in their Mac OS environment. Understanding design patterns is the first step to learning to speak Android and designing an optimal experience for its users. Your developers will also thank you!



Android Design Deliverables

OK, so you’ve designed your Android app and are ready to make it a reality. What do you need to hand off to the developer? Here’s a quick list of deliverables:
  • Annotated wireframes of the user experience based on the baseline “medium” size of 320 × 480 DPI. Include additional screens for instances when a “large” screen size requires a modified layout or when a landscape version is required.
  • Two sets of visual design mock-ups of key screens for both medium-sized HVGA 320 × 480 screens and large-sized 320 × 533 screens (based on a WVGA 800 × 480 hDPI physical pixel screen size).
  • Specifications for spacing, font sizes and colors, and an indication of any bitmaps.
  • A graphics library with lDPI, mDPI and hDPI versions of all bitmaps saved as transparent PNG files. If you’re planning on developing one version of your app for smaller devices and another version for larger devices, then you’ll need lDPI and mDPI sets for your “medium” baseline design and one hDPI set for your “large” version.
  • Density-specific app icons, including the app’s launch icon, as transparent PNG files. Android already provides excellent tips for designers on this topic, along with some downloads, including graphic PSD templates.


How To Take Screenshots

Your product manager has just asked for screenshots of the developer’s build. The developer is busy and can’t get them to you until tomorrow. What do you do?! As of this writing, Android has no built-in way to take screenshots (bummer, I know). The only way is to just deal with it, and that means pretending to be a developer for a while and downloading some really scary software. Let’s get started!

The following software must be downloaded in a Windows environment (I use Windows via Parallels Desktop on my Mac).
  1. All USB drivers for your Android device,
  2. Android software development kit (SDK),
  3. Java SE SDK
Then, on your computer:
  1. Extract the USB drivers to a folder on your desktop,
  2. Extract the Android SDK to a folder on your desktop,
  3. Install the Java SE SDK.
On your Android device:
  1. Open “Settings” (you’ll find it in the apps menu),
  2. Tap on “Applications,”
  3. Tap on “Development,”
  4. Check the box for “USB debugging.”
android10_android_design_patterns_13

Now, for the fun part:
  1. Connect your Android device to your computer via USB, and allow Windows to install all drivers. One of the drivers may not be found and will require you to go to the Window’s Device Manager in the Control Panel. There, locate the device (the one with the yellow warning icon beside it), and right-click on it.
  2. Choose to “update/install” the driver for your device.
  3. Go to your desktop. Open the Android SDK folder and select SDK Setup.exe.
  4. Allow it to automatically refresh its list of the operating system SDKs that are available, and select to install all packages.
  5. Once finished, exit the application.
  6. Go back to the opened Android SDK folder on your desktop, and open the “Tools” folder.
  7. Click on the file ddms to open the Dalvik Debug Monitor.
  8. Select your device from the “Name” pane.
  9. In the application’s top menu, open the “Device” menu, and choose “Screen capture…” A Device Screen Capture window will open, and you should see the launch screen of your Android device.
android10_android_design_patterns_14

The Dalvik Debut Monitor.

To navigate:
  • Grab your Android device and navigate to any page. Go back to your computer and select “Refresh” in the Device Screen Capture window. The current screen from your Android device should appear.
  • If you’re on a Mac, you can just do the old Shift + Command + 4 trick to take a screenshot. In Windows, you can copy and paste it into one of the Windows media applications.