1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.businesscard; 18 19 import android.content.ContentResolver; 20 import android.content.Intent; 21 import android.net.Uri; 22 import android.os.Build; 23 24 /** 25 * This abstract class defines SDK-independent API for communication with 26 * Contacts Provider. The actual implementation used by the application depends 27 * on the level of API available on the device. If the API level is Cupcake or 28 * Donut, we want to use the {@link ContactAccessorSdk3_4} class. If it is 29 * Eclair or higher, we want to use {@link ContactAccessorSdk5}. 30 */ 31 public abstract class ContactAccessor { 32 33 /** 34 * Static singleton instance of {@link ContactAccessor} holding the 35 * SDK-specific implementation of the class. 36 */ 37 private static ContactAccessor sInstance; 38 getInstance()39 public static ContactAccessor getInstance() { 40 if (sInstance == null) { 41 String className; 42 43 /* 44 * Check the version of the SDK we are running on. Choose an 45 * implementation class designed for that version of the SDK. 46 * 47 * Unfortunately we have to use strings to represent the class 48 * names. If we used the conventional ContactAccessorSdk5.class.getName() 49 * syntax, we would get a ClassNotFoundException at runtime on pre-Eclair SDKs. 50 * Using the above syntax would force Dalvik to load the class and try to 51 * resolve references to all other classes it uses. Since the pre-Eclair 52 * does not have those classes, the loading of ContactAccessorSdk5 would fail. 53 */ 54 @SuppressWarnings("deprecation") 55 int sdkVersion = Integer.parseInt(Build.VERSION.SDK); // Cupcake style 56 if (sdkVersion < Build.VERSION_CODES.ECLAIR) { 57 className = "com.example.android.businesscard.ContactAccessorSdk3_4"; 58 } else { 59 className = "com.example.android.businesscard.ContactAccessorSdk5"; 60 } 61 62 /* 63 * Find the required class by name and instantiate it. 64 */ 65 try { 66 Class<? extends ContactAccessor> clazz = 67 Class.forName(className).asSubclass(ContactAccessor.class); 68 sInstance = clazz.newInstance(); 69 } catch (Exception e) { 70 throw new IllegalStateException(e); 71 } 72 } 73 74 return sInstance; 75 } 76 77 /** 78 * Returns the {@link Intent#ACTION_PICK} intent configured for the right authority: legacy 79 * or current. 80 */ getPickContactIntent()81 public abstract Intent getPickContactIntent(); 82 83 /** 84 * Loads contact data for the supplied URI. The actual queries will differ for different APIs 85 * used, but the result is the same: the {@link #mDisplayName} and {@link #mPhoneNumber} 86 * fields are populated with correct data. 87 */ loadContact(ContentResolver contentResolver, Uri contactUri)88 public abstract ContactInfo loadContact(ContentResolver contentResolver, Uri contactUri); 89 } 90