1 /* 2 * Copyright (C) 2016 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 android.provider.cts.contacts; 18 19 import android.content.ContentProvider; 20 import android.content.ContentValues; 21 import android.content.UriMatcher; 22 import android.database.Cursor; 23 import android.database.MatrixCursor; 24 import android.net.Uri; 25 import android.provider.ContactsContract; 26 import android.provider.ContactsContract.Contacts; 27 import android.provider.ContactsContract.Directory; 28 import android.provider.ContactsContract.RawContacts; 29 import android.provider.cts.contacts.account.StaticAccountAuthenticator; 30 import android.text.TextUtils; 31 import android.util.Log; 32 33 import org.json.JSONException; 34 import org.json.JSONObject; 35 36 /** 37 * GAL provider for CTS. 38 */ 39 public class DummyGalProvider extends ContentProvider { 40 private static final String TAG = "DummyGalProvider"; 41 42 public static final String AUTHORITY = "android.provider.cts.contacts.dgp"; 43 44 public static final String ACCOUNT_NAME = "dummygal"; 45 public static final String ACCOUNT_TYPE = StaticAccountAuthenticator.TYPE; 46 47 public static final String DISPLAY_NAME = "dummy-gal"; 48 49 public static final String ERROR_MESSAGE_KEY = "error"; 50 public static final String QUERY_KEY = "query"; 51 public static final String CALLER_PACKAGE_NAME_KEY = "package_name"; 52 public static final String LIMIT_KEY = "limit"; 53 54 55 private static final int GAL_DIRECTORIES = 0; 56 private static final int GAL_FILTER = 1; 57 private static final int GAL_CONTACT = 2; 58 private static final int GAL_CONTACT_WITH_ID = 3; 59 private static final int GAL_EMAIL_FILTER = 4; 60 private static final int GAL_PHONE_FILTER = 5; 61 private static final int GAL_PHONE_LOOKUP = 6; 62 63 private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); 64 65 static { 66 sURIMatcher.addURI(AUTHORITY, "directories", GAL_DIRECTORIES); 67 sURIMatcher.addURI(AUTHORITY, "contacts/filter/*", GAL_FILTER); 68 // The following URIs are not supported by this class. 69 // sURIMatcher.addURI(AUTHORITY, "contacts/lookup/*/entities", GAL_CONTACT); 70 // sURIMatcher.addURI(AUTHORITY, "contacts/lookup/*/#/entities", GAL_CONTACT_WITH_ID); 71 // sURIMatcher.addURI(AUTHORITY, "data/emails/filter/*", GAL_EMAIL_FILTER); 72 // sURIMatcher.addURI(AUTHORITY, "data/phones/filter/*", GAL_PHONE_FILTER); 73 // sURIMatcher.addURI(AUTHORITY, "phone_lookup/*", GAL_PHONE_LOOKUP); 74 } 75 76 @Override 77 public boolean onCreate() { 78 return true; 79 } 80 81 @Override 82 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 83 String sortOrder) { 84 Log.d(TAG, "uri: " + uri); 85 final int match = sURIMatcher.match(uri); 86 87 switch (match) { 88 case GAL_DIRECTORIES: { 89 return handleDirectories(projection); 90 } 91 case GAL_FILTER: { 92 try { 93 return handleFilter(uri, projection); 94 } catch (JSONException e) { 95 Log.e(TAG, "Caught exception", e); 96 return null; 97 } 98 } 99 } 100 return null; 101 } 102 103 @Override 104 public String getType(Uri uri) { 105 return null; 106 } 107 108 @Override 109 public Uri insert(Uri uri, ContentValues values) { 110 return null; 111 } 112 113 @Override 114 public int delete(Uri uri, String selection, String[] selectionArgs) { 115 return 0; 116 } 117 118 @Override 119 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 120 return 0; 121 } 122 123 /** 124 * Build a cursor containing the directory information. 125 * 126 * See com.android.providers.contacts.ContactDirectoryManager. 127 */ 128 private Cursor handleDirectories(String[] projection) { 129 MatrixCursor cursor; 130 Object[] row; 131 cursor = new MatrixCursor(projection); 132 133 row = new Object[projection.length]; 134 135 for (int i = 0; i < projection.length; i++) { 136 String column = projection[i]; 137 if (column.equals(Directory.ACCOUNT_NAME)) { 138 row[i] = ACCOUNT_NAME; 139 } else if (column.equals(Directory.ACCOUNT_TYPE)) { 140 row[i] = ACCOUNT_TYPE; 141 } else if (column.equals(Directory.TYPE_RESOURCE_ID)) { 142 row[i] = ""; 143 } else if (column.equals(Directory.DISPLAY_NAME)) { 144 row[i] = DISPLAY_NAME; 145 } else if (column.equals(Directory.EXPORT_SUPPORT)) { 146 row[i] = Directory.EXPORT_SUPPORT_NONE; 147 } else if (column.equals(Directory.SHORTCUT_SUPPORT)) { 148 row[i] = Directory.SHORTCUT_SUPPORT_NONE; 149 } else if (column.equals(Directory.PHOTO_SUPPORT)) { 150 row[i] = Directory.PHOTO_SUPPORT_NONE; 151 } 152 } 153 cursor.addRow(row); 154 return cursor; 155 } 156 157 /** 158 * Build a cursor to return from the {@link #GAL_FILTER} URI, which returns the following 159 * information in the display_name column as json. 160 * 161 * - It checks whether the incoming account name/type match the values returned by {@link 162 * #handleDirectories(String[])}, and if not, set a error message to the result. 163 * - If above check succeeds, then sets the query parameters in the result. The caller 164 * checks the returned values. 165 */ 166 private Cursor handleFilter(Uri uri, String[] projection) throws JSONException { 167 final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME); 168 final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE); 169 final String limit = uri.getQueryParameter(ContactsContract.LIMIT_PARAM_KEY); 170 final String callerPackage = uri.getQueryParameter(Directory.CALLER_PACKAGE_PARAM_KEY); 171 172 final JSONObject result = new JSONObject(); 173 174 final StringBuilder error = new StringBuilder(); 175 if (!ACCOUNT_NAME.equals(accountName)) { 176 error.append(String.format("Account name expected=%s but was %s\n", 177 ACCOUNT_NAME, accountName)); 178 } 179 if (!ACCOUNT_TYPE.equals(accountType)) { 180 error.append(String.format("Account type expected=%s but was %s\n", 181 ACCOUNT_TYPE, accountType)); 182 } 183 184 if (error.length() > 0) { 185 result.put(ERROR_MESSAGE_KEY, error.toString()); 186 } else { 187 if (!TextUtils.isEmpty(limit)) { 188 result.put(LIMIT_KEY, limit); 189 } 190 if (!TextUtils.isEmpty(callerPackage)) { 191 result.put(CALLER_PACKAGE_NAME_KEY, callerPackage); 192 } 193 result.put(QUERY_KEY, uri.getLastPathSegment()); 194 } 195 if (projection == null) { 196 projection = new String[]{Contacts.DISPLAY_NAME}; 197 } 198 199 final MatrixCursor c = new MatrixCursor(projection); 200 201 Object[] row = new Object[projection.length]; 202 for (int i = 0; i < projection.length; i++) { 203 String column = projection[i]; 204 if (Contacts.DISPLAY_NAME.equals(column)) { 205 row[i] = result.toString(); 206 continue; 207 } 208 // All other fields are null. 209 } 210 211 c.addRow(row); 212 return c; 213 } 214 } 215