MockUiProvider.java revision db5356a92ebc593e9eb564aaadad8dac8cd83554
1/** 2 * Copyright (c) 2011, Google Inc. 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 17package com.android.mail.providers.protos.mock; 18 19import android.content.ContentProvider; 20import android.content.ContentValues; 21import android.database.Cursor; 22import android.database.MatrixCursor; 23import android.net.Uri; 24import android.provider.BaseColumns; 25import android.text.Html; 26 27import com.android.mail.providers.ConversationInfo; 28import com.android.mail.providers.Folder; 29import com.android.mail.providers.FolderList; 30import com.android.mail.providers.MessageInfo; 31import com.android.mail.providers.ReplyFromAccount; 32import com.android.mail.providers.UIProvider; 33import com.android.mail.providers.UIProvider.AccountCapabilities; 34import com.android.mail.providers.UIProvider.AccountColumns; 35import com.android.mail.providers.UIProvider.AccountColumns.SettingsColumns; 36import com.android.mail.providers.UIProvider.AttachmentColumns; 37import com.android.mail.providers.UIProvider.ConversationColumns; 38import com.android.mail.providers.UIProvider.ConversationCursorCommand; 39import com.android.mail.providers.UIProvider.FolderCapabilities; 40import com.android.mail.providers.UIProvider.FolderColumns; 41import com.android.mail.providers.UIProvider.MessageColumns; 42import com.android.mail.utils.LogUtils; 43 44import com.google.common.annotations.VisibleForTesting; 45import com.google.common.collect.ImmutableList; 46import com.google.common.collect.ImmutableMap; 47import com.google.common.collect.Lists; 48import com.google.common.collect.Maps; 49 50import org.json.JSONArray; 51 52import java.util.ArrayList; 53import java.util.Date; 54import java.util.List; 55import java.util.Map; 56import java.util.Set; 57 58public final class MockUiProvider extends ContentProvider { 59 60 public static final String AUTHORITY = "com.android.mail.mockprovider"; 61 62 63 private static final Uri MOCK_ACCOUNTS_URI = Uri.parse("content://" + AUTHORITY + "/accounts"); 64 65 // A map of query result for uris 66 // TODO(pwestbro) read this map from an external file 67 private static Map<String, List<Map<String, Object>>> MOCK_QUERY_RESULTS = Maps.newHashMap(); 68 69 70 public static void initializeMockProvider() { 71 ImmutableMap.Builder<String, List<Map<String, Object>>> builder = ImmutableMap.builder(); 72 73 // Add results for account list 74 final List<Map<String, Object>> accountList = Lists.newArrayList(); 75 Map<String, Object> accountDetailsMap0; 76 Map<String, Object> folderDetailsMap0 = createFolderDetailsMap(0, "zero", true, 0, 2); 77 builder.put(folderDetailsMap0.get(FolderColumns.URI).toString(), 78 ImmutableList.of(folderDetailsMap0)); 79 Map<String, Object> folderDetailsMap2 = createFolderDetailsMap(2, "two", 2, 2); 80 // Account 0 81 accountDetailsMap0 = createAccountDetailsMap(0, 82 (String)folderDetailsMap0.get(FolderColumns.URI)); 83 84 accountList.add(accountDetailsMap0); 85 builder.put(((Uri) accountDetailsMap0.get(AccountColumns.URI)).toString(), 86 ImmutableList.of(accountDetailsMap0)); 87 88 // Account 1 89 Map<String, Object> accountDetailsMap1 = createAccountDetailsMap(1, 90 (String)folderDetailsMap2.get(FolderColumns.URI)); 91 accountList.add(accountDetailsMap1); 92 93 builder.put(((Uri) accountDetailsMap1.get(AccountColumns.URI)).toString(), 94 ImmutableList.of(accountDetailsMap1)); 95 96 // Account 2 97 98 Map<String, Object> accountDetailsMap2 = createAccountDetailsMap(2, 99 (String)folderDetailsMap0.get(FolderColumns.URI)); 100 accountList.add(accountDetailsMap2); 101 builder.put(((Uri) accountDetailsMap2.get(AccountColumns.URI)).toString(), 102 ImmutableList.of(accountDetailsMap2)); 103 104 // Account 3 105 Map<String, Object> accountDetailsMap3 = createAccountDetailsMap(3, 106 (String)folderDetailsMap2.get(FolderColumns.URI)); 107 accountList.add(accountDetailsMap3); 108 builder.put(((Uri) accountDetailsMap3.get(AccountColumns.URI)).toString(), 109 ImmutableList.of(accountDetailsMap3)); 110 111 // Add the account list to the builder 112 builder.put(getAccountsUri().toString(), accountList); 113 114 builder.put( 115 folderDetailsMap0.get(FolderColumns.CHILD_FOLDERS_LIST_URI).toString(), 116 ImmutableList.of(createFolderDetailsMap(10, "zeroChild0", 0, 0), 117 createFolderDetailsMap(11, "zeroChild1", 0, 0))); 118 119 120 ArrayList<Map<String, Object>> conversations = new ArrayList<Map<String, Object>>(); 121 for (int i = 0; i < 100; i++) { 122 String name = "zeroConv"+i; 123 conversations.add(createConversationDetailsMap(name.hashCode(), 124 name, 1, 5, 2)); 125 } 126 builder.put(folderDetailsMap0.get(FolderColumns.CONVERSATION_LIST_URI).toString(), 127 conversations); 128 129 Map<String, Object> message0 = createMessageDetailsMap("zeroConv0".hashCode(), "zeroConv0", 130 1, false); 131 builder.put(message0.get(MessageColumns.URI).toString(), ImmutableList.of(message0)); 132 builder.put(conversations.get(0).get(ConversationColumns.MESSAGE_LIST_URI).toString(), 133 ImmutableList.of(message0)); 134 builder.put(message0.get(MessageColumns.ATTACHMENT_LIST_URI).toString(), 135 ImmutableList.of(createAttachmentDetailsMap(0, "zero"))); 136 Map<String, Object> message1 = createMessageDetailsMap("zeroConv1".hashCode(), "zeroConv1", 137 1, false); 138 builder.put(message1.get(MessageColumns.URI).toString(), ImmutableList.of(message1)); 139 Map<String, Object> message1a = createMessageDetailsMap("zeroConv1a".hashCode(), "zeroConv1a", 140 2, false); 141 builder.put(message1a.get(MessageColumns.URI).toString(), ImmutableList.of(message1a)); 142 builder.put(conversations.get(1).get(ConversationColumns.MESSAGE_LIST_URI).toString(), 143 ImmutableList.of(message1, message1a)); 144 builder.put(message1.get(MessageColumns.ATTACHMENT_LIST_URI).toString(), 145 ImmutableList.of(createAttachmentDetailsMap(1, "one"))); 146 147 Map<String, Object> folderDetailsMap1 = createFolderDetailsMap(1, "one", 0, 0); 148 builder.put(folderDetailsMap1.get(FolderColumns.URI).toString(), 149 ImmutableList.of(folderDetailsMap1)); 150 builder.put(accountDetailsMap0.get(AccountColumns.FOLDER_LIST_URI).toString(), 151 ImmutableList.of(folderDetailsMap0, folderDetailsMap1)); 152 153 builder.put(folderDetailsMap2.get(FolderColumns.URI).toString(), 154 ImmutableList.of(folderDetailsMap2)); 155 Map<String, Object> folderDetailsMap3 = createFolderDetailsMap(3, "three", 0, 0); 156 builder.put(folderDetailsMap3.get(FolderColumns.URI).toString(), 157 ImmutableList.of(folderDetailsMap3)); 158 builder.put(accountDetailsMap1.get(AccountColumns.FOLDER_LIST_URI).toString(), 159 ImmutableList.of(folderDetailsMap2, folderDetailsMap3)); 160 161 builder.put(accountDetailsMap2.get(AccountColumns.FOLDER_LIST_URI).toString(), 162 ImmutableList.of(folderDetailsMap0, folderDetailsMap1)); 163 164 builder.put(accountDetailsMap3.get(AccountColumns.FOLDER_LIST_URI).toString(), 165 ImmutableList.of(folderDetailsMap0, folderDetailsMap1)); 166 167 Map<String, Object> conv3 = createConversationDetailsMap("zeroConv3".hashCode(), 168 "zeroConv3", 0, 1, 0); 169 builder.put(conv3.get(ConversationColumns.URI).toString(), 170 ImmutableList.of(conv3)); 171 Map<String, Object> conv4 = createConversationDetailsMap("zeroConv4".hashCode(), 172 "zeroConv4", 0, 1, 0); 173 builder.put(conv4.get(ConversationColumns.URI).toString(), 174 ImmutableList.of(conv4)); 175 builder.put(folderDetailsMap2.get(FolderColumns.CONVERSATION_LIST_URI).toString(), 176 ImmutableList.of(conv3, conv4)); 177 178 Map<String, Object> message2 = createMessageDetailsMap("zeroConv3".hashCode(), "zeroConv3", 179 0, true); 180 builder.put(message2.get(MessageColumns.URI).toString(), ImmutableList.of(message2)); 181 builder.put(conv3.get(ConversationColumns.MESSAGE_LIST_URI).toString(), 182 ImmutableList.of(message2)); 183 Map<String, Object> message3 = createMessageDetailsMap("zeroConv4".hashCode(), "zeroConv4", 184 0, true); 185 builder.put(message3.get(MessageColumns.URI).toString(), ImmutableList.of(message3)); 186 builder.put(conv4.get(ConversationColumns.MESSAGE_LIST_URI).toString(), 187 ImmutableList.of(message3)); 188 189 MOCK_QUERY_RESULTS = builder.build(); 190 } 191 192 private static Map<String, Object> createConversationDetailsMap(int conversationId, 193 String subject, int hasAttachments, int messageCount, int draftCount) { 194 final String conversationUri = "content://" + AUTHORITY + "/conversation/" + conversationId; 195 Map<String, Object> conversationMap = Maps.newHashMap(); 196 conversationMap.put(BaseColumns._ID, Long.valueOf(conversationId)); 197 conversationMap.put(ConversationColumns.URI, conversationUri); 198 conversationMap.put(ConversationColumns.MESSAGE_LIST_URI, conversationUri + "/getMessages"); 199 conversationMap.put(ConversationColumns.SUBJECT, "Conversation " + subject); 200 conversationMap.put(ConversationColumns.SNIPPET, "snippet"); 201 conversationMap.put(ConversationColumns.SENDER_INFO, 202 "account1@mock.com, account2@mock.com"); 203 conversationMap.put(ConversationColumns.DATE_RECEIVED_MS, new Date().getTime()); 204 conversationMap.put(ConversationColumns.HAS_ATTACHMENTS, hasAttachments); 205 conversationMap.put(ConversationColumns.NUM_MESSAGES, 1); 206 conversationMap.put(ConversationColumns.NUM_DRAFTS, 1); 207 conversationMap.put(ConversationColumns.SENDING_STATE, 1); 208 conversationMap.put(ConversationColumns.READ, 0); 209 conversationMap.put(ConversationColumns.SEEN, 0); 210 conversationMap.put(ConversationColumns.STARRED, 0); 211 conversationMap.put(ConversationColumns.CONVERSATION_INFO, 212 generateConversationInfo(messageCount, draftCount)); 213 final List<Folder> folders = new ArrayList<Folder>(3); 214 for (int i = 0; i < 3; i++) { 215 final Folder folder = Folder.newUnsafeInstance(); 216 folder.name = "folder" + i; 217 switch (i) { 218 case 0: 219 folder.bgColor = "#fff000"; 220 break; 221 case 1: 222 folder.bgColor = "#0000FF"; 223 break; 224 case 2: 225 folder.bgColor = "#FFFF00"; 226 break; 227 default: 228 folder.bgColor = null; 229 break; 230 } 231 232 folders.add(folder); 233 } 234 final FolderList folderList = FolderList.copyOf(folders); 235 conversationMap.put( 236 MockRespondMatrixCursor.MOCK_RESPOND_PREFIX + 237 ConversationCursorCommand.COMMAND_GET_RAW_FOLDERS, folderList); 238 return conversationMap; 239 } 240 241 private static byte[] generateConversationInfo(int messageCount, int draftCount) { 242 ConversationInfo info = new ConversationInfo(messageCount, draftCount, "first", 243 "firstUnread", "last"); 244 for (int i = 0; i < messageCount; i++) { 245 if (i % 2 == 0) { 246 info.addMessage(new MessageInfo(false, false, 247 i + "Test <testsender@test.com>", -1, "testsender@test.com")); 248 } else if (i % 3 == 0) { 249 info.addMessage(new MessageInfo(true, false, i + "sender@test.com", -1, 250 "sender@test.com")); 251 } else { 252 info.addMessage(new MessageInfo(false, false, MessageInfo.SENDER_LIST_TOKEN_ELIDED, 253 -1, null)); 254 } 255 } 256 return info.toBlob(); 257 } 258 259 private static Map<String, Object> createMessageDetailsMap(int messageId, String subject, 260 int hasAttachments, boolean addReplyTo) { 261 final String messageUri = "content://" + AUTHORITY + "/message/" + messageId; 262 Map<String, Object> messageMap = Maps.newHashMap(); 263 messageMap.put(BaseColumns._ID, Long.valueOf(messageId)); 264 messageMap.put(MessageColumns.URI, messageUri); 265 messageMap.put(MessageColumns.SUBJECT, "Message " + subject); 266 messageMap.put(MessageColumns.SNIPPET, "SNIPPET"); 267 String html = "<html><body><b><i>This is some html!!!</i></b></body></html>"; 268 messageMap.put(MessageColumns.BODY_HTML, html); 269 messageMap.put(MessageColumns.BODY_TEXT, Html.fromHtml(html)); 270 messageMap.put(MessageColumns.HAS_ATTACHMENTS, hasAttachments); 271 messageMap.put(MessageColumns.DATE_RECEIVED_MS, new Date().getTime()); 272 messageMap.put(MessageColumns.ATTACHMENT_LIST_URI, messageUri + "/getAttachments"); 273 messageMap.put(MessageColumns.TO, "account1@mock.com, account2@mock.com"); 274 messageMap.put(MessageColumns.FROM, "fromaccount1@mock.com"); 275 return messageMap; 276 } 277 278 private static Map<String, Object> createAttachmentDetailsMap(int attachmentId, String name) { 279 Map<String, Object> attachmentMap = Maps.newHashMap(); 280 attachmentMap.put(BaseColumns._ID, Long.valueOf(attachmentId)); 281 attachmentMap.put(AttachmentColumns.NAME, "Attachment " + name); 282 attachmentMap.put(AttachmentColumns.URI, 283 "attachmentUri/" + attachmentMap.get(AttachmentColumns.NAME)); 284 return attachmentMap; 285 } 286 287 private static Map<String, Object> createFolderDetailsMap(int folderId, String name, 288 int unread, int total) { 289 return createFolderDetailsMap(folderId, name, false, unread, total); 290 } 291 292 private static Map<String, Object> createFolderDetailsMap(int folderId, String name, 293 boolean hasChildren, int unread, int total) { 294 final String folderUri = "content://" + AUTHORITY + "/folder/" + folderId; 295 Map<String, Object> folderMap = Maps.newHashMap(); 296 folderMap.put(BaseColumns._ID, Long.valueOf(folderId)); 297 folderMap.put(FolderColumns.URI, folderUri); 298 folderMap.put(FolderColumns.NAME, "Folder " + name); 299 folderMap.put(FolderColumns.HAS_CHILDREN, new Integer(hasChildren ? 1 : 0)); 300 folderMap.put(FolderColumns.CONVERSATION_LIST_URI, folderUri + "/getConversations"); 301 folderMap.put(FolderColumns.CHILD_FOLDERS_LIST_URI, folderUri + "/getChildFolders"); 302 folderMap.put(FolderColumns.CAPABILITIES, 303 Long.valueOf( 304 FolderCapabilities.SYNCABLE | 305 FolderCapabilities.PARENT | 306 FolderCapabilities.CAN_HOLD_MAIL | 307 FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES)); 308 folderMap.put(FolderColumns.UNREAD_COUNT, unread); 309 folderMap.put(FolderColumns.TOTAL_COUNT, total); 310 folderMap.put(FolderColumns.SYNC_STATUS, 0); 311 folderMap.put(FolderColumns.LAST_SYNC_RESULT, 0); 312 return folderMap; 313 } 314 315 // Temporarily made this public to allow the Gmail accounts to use the mock ui provider uris 316 public static Map<String, Object> createAccountDetailsMap(int accountId,String defaultInbox) { 317 final String accountUri = getMockAccountUri(accountId); 318 Map<String, Object> accountMap = Maps.newHashMap(); 319 accountMap.put(BaseColumns._ID, Long.valueOf(accountId)); 320 accountMap.put(AccountColumns.NAME, "account" + accountId + "@mockuiprovider.com"); 321 accountMap.put(AccountColumns.TYPE, "com.android.mail.providers.protos.mock"); 322 accountMap.put(AccountColumns.PROVIDER_VERSION, Long.valueOf(1)); 323 accountMap.put(AccountColumns.URI, Uri.parse(accountUri)); 324 accountMap.put(AccountColumns.CAPABILITIES, 325 Integer.valueOf( 326 AccountCapabilities.SYNCABLE_FOLDERS | 327 AccountCapabilities.REPORT_SPAM | 328 AccountCapabilities.ARCHIVE | 329 AccountCapabilities.MUTE | 330 AccountCapabilities.SERVER_SEARCH | 331 AccountCapabilities.FOLDER_SERVER_SEARCH | 332 AccountCapabilities.SANITIZED_HTML | 333 AccountCapabilities.DRAFT_SYNCHRONIZATION | 334 AccountCapabilities.MULTIPLE_FROM_ADDRESSES | 335 AccountCapabilities.SMART_REPLY | 336 AccountCapabilities.LOCAL_SEARCH | 337 AccountCapabilities.THREADED_CONVERSATIONS | 338 AccountCapabilities.MULTIPLE_FOLDERS_PER_CONV)); 339 JSONArray replyFroms = new JSONArray(); 340 ArrayList<ReplyFromAccount> list = new ArrayList<ReplyFromAccount>(); 341 list.add(new ReplyFromAccount(null, Uri.parse(accountUri), "customAddress1@custom.com", 342 "customAddress2@custom.com", "Custom1", false, true)); 343 list.add(new ReplyFromAccount(null, Uri.parse(accountUri), "customAddress2@custom.com", 344 "customAddress2@custom.com", "Custom2", false, true)); 345 for (ReplyFromAccount a : list) { 346 replyFroms.put(a.serialize()); 347 } 348 accountMap.put(AccountColumns.ACCOUNT_FROM_ADDRESSES, replyFroms.toString()); 349 accountMap.put(AccountColumns.FOLDER_LIST_URI, Uri.parse(accountUri + "/folders")); 350 accountMap.put(AccountColumns.FULL_FOLDER_LIST_URI, Uri.parse(accountUri + "/folders")); 351 accountMap.put(AccountColumns.SEARCH_URI, Uri.parse(accountUri + "/search")); 352 accountMap.put(AccountColumns.EXPUNGE_MESSAGE_URI, 353 Uri.parse(accountUri + "/expungeMessage")); 354 accountMap.put(AccountColumns.UNDO_URI, Uri.parse(accountUri + "/undo")); 355 accountMap.put(AccountColumns.SETTINGS_INTENT_URI, Uri.EMPTY); 356 accountMap.put(AccountColumns.HELP_INTENT_URI, Uri.EMPTY); 357 accountMap.put(AccountColumns.SEND_FEEDBACK_INTENT_URI, Uri.EMPTY); 358 accountMap.put(AccountColumns.REAUTHENTICATION_INTENT_URI, Uri.EMPTY); 359 accountMap.put(AccountColumns.SYNC_STATUS, 0); 360 accountMap.put(AccountColumns.COMPOSE_URI, Uri.parse(accountUri + "/compose")); 361 accountMap.put(AccountColumns.RECENT_FOLDER_LIST_URI, 362 Uri.parse(accountUri + "/recentFolderListUri")); 363 accountMap.put(AccountColumns.MIME_TYPE, "account/mock"); 364 accountMap.put(AccountColumns.COLOR, 0); 365 accountMap.put(AccountColumns.RECENT_FOLDER_LIST_URI, Uri.EMPTY); 366 accountMap.put(AccountColumns.DEFAULT_RECENT_FOLDER_LIST_URI, Uri.EMPTY); 367 accountMap.put(AccountColumns.MANUAL_SYNC_URI, Uri.EMPTY); 368 accountMap.put(AccountColumns.VIEW_INTENT_PROXY_URI, Uri.EMPTY); 369 accountMap.put(AccountColumns.ACCOUNT_COOKIE_QUERY_URI, Uri.EMPTY); 370 accountMap.put(AccountColumns.UPDATE_SETTINGS_URI, Uri.EMPTY); 371 accountMap.put(AccountColumns.ENABLE_MESSAGE_TRANSFORMS, 1); 372 373 374 // Add settings columns 375 accountMap.put(SettingsColumns.SIGNATURE, ""); 376 accountMap.put(SettingsColumns.AUTO_ADVANCE, 1); 377 accountMap.put(SettingsColumns.MESSAGE_TEXT_SIZE, 1); 378 accountMap.put(SettingsColumns.SNAP_HEADERS, 1); 379 accountMap.put(SettingsColumns.REPLY_BEHAVIOR, 1); 380 accountMap.put(SettingsColumns.CONV_LIST_ICON, 1); 381 accountMap.put(SettingsColumns.CONFIRM_DELETE, 1); 382 accountMap.put(SettingsColumns.CONFIRM_ARCHIVE, 1); 383 accountMap.put(SettingsColumns.CONFIRM_SEND, 1); 384 accountMap.put(SettingsColumns.DEFAULT_INBOX, defaultInbox); 385 accountMap.put(SettingsColumns.DEFAULT_INBOX_NAME, "Inbox"); 386 accountMap.put(SettingsColumns.FORCE_REPLY_FROM_DEFAULT, 1); 387 accountMap.put(SettingsColumns.MAX_ATTACHMENT_SIZE, 25 * 1024 * 1024); 388 accountMap.put(SettingsColumns.SWIPE, 1); 389 accountMap.put(SettingsColumns.PRIORITY_ARROWS_ENABLED, 1); 390 accountMap.put(SettingsColumns.SETUP_INTENT_URI, Uri.EMPTY); 391 accountMap.put(SettingsColumns.CONVERSATION_VIEW_MODE, 1); 392 accountMap.put(SettingsColumns.VEILED_ADDRESS_PATTERN, null); 393 accountMap.put(SettingsColumns.MOVE_TO_INBOX, Uri.EMPTY); 394 return accountMap; 395 } 396 397 public static String getMockAccountUri(int accountId) { 398 return "content://" + AUTHORITY + "/account/" + accountId; 399 } 400 401 @Override 402 public boolean onCreate() { 403 MockUiProvider.initializeMockProvider(); 404 return true; 405 } 406 407 @Override 408 public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, 409 String sortOrder) { 410 411 final List<Map<String, Object>> queryResults = MOCK_QUERY_RESULTS.get(url.toString()); 412 413 if (queryResults != null && queryResults.size() > 0) { 414 // Get the projection. If there are rows in the result set, pick the first item to 415 // generate the projection 416 // TODO (pwestbro): handle the case where we want to return an empty result.\ 417 if (projection == null) { 418 Set<String> keys = queryResults.get(0).keySet(); 419 projection = keys.toArray(new String[keys.size()]); 420 } 421 final MatrixCursor matrixCursor = 422 new MockRespondMatrixCursor(projection, queryResults.size(), queryResults); 423 424 for (Map<String, Object> queryResult : queryResults) { 425 MatrixCursor.RowBuilder rowBuilder = matrixCursor.newRow(); 426 427 for (String key : projection) { 428 rowBuilder.add(queryResult.get(key)); 429 } 430 } 431 return matrixCursor; 432 } 433 434 return null; 435 } 436 437 @Override 438 public Uri insert(Uri url, ContentValues values) { 439 return url; 440 } 441 442 @Override 443 public int update(Uri url, ContentValues values, String selection, 444 String[] selectionArgs) { 445 return 0; 446 } 447 448 @Override 449 public int delete(Uri url, String selection, String[] selectionArgs) { 450 return 0; 451 } 452 453 @Override 454 public String getType(Uri uri) { 455 return null; 456 } 457 458 @VisibleForTesting 459 static Uri getAccountsUri() { 460 return MOCK_ACCOUNTS_URI; 461 } 462} 463 464