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