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