MockUiProvider.java revision 27e85f244604c8de53b76b135e0dd6f2bf3cad96
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.os.Parcel;
25import android.provider.BaseColumns;
26import android.text.Html;
27
28import com.android.mail.providers.AccountCacheProvider;
29import com.android.mail.providers.Account;
30import com.android.mail.providers.UIProvider.AccountCapabilities;
31import com.android.mail.providers.UIProvider.AccountColumns;
32import com.android.mail.providers.UIProvider.AttachmentColumns;
33import com.android.mail.providers.UIProvider.ConversationColumns;
34import com.android.mail.providers.UIProvider.FolderCapabilities;
35import com.android.mail.providers.UIProvider.FolderColumns;
36import com.android.mail.providers.UIProvider.MessageColumns;
37import com.android.mail.providers.UIProvider.SettingsColumns;
38
39import com.google.common.annotations.VisibleForTesting;
40import com.google.common.collect.ImmutableList;
41import com.google.common.collect.ImmutableMap;
42import com.google.common.collect.Lists;
43import com.google.common.collect.Maps;
44
45import java.util.Date;
46import java.util.List;
47import java.util.Map;
48import java.util.Set;
49
50public final class MockUiProvider extends ContentProvider {
51
52    public static final String AUTHORITY = "com.android.mail.mockprovider";
53
54
55    static final String BASE_URI_STRING = "content://" + AUTHORITY;
56
57    public static final int NUM_MOCK_ACCOUNTS = 2;
58
59    // A map of query result for uris
60    // TODO(pwestbro) read this map from an external
61    private static Map<String, List<Map<String, Object>>> MOCK_QUERY_RESULTS = Maps.newHashMap();
62
63
64    public static void initializeMockProvider() {
65        ImmutableMap.Builder<String, List<Map<String, Object>>> builder = ImmutableMap.builder();
66
67        // Add results for account list
68        final List<Map<String, Object>> accountList = Lists.newArrayList();
69        Map<String, Object> accountDetailsMap0;
70
71        // Account 1
72        accountDetailsMap0 = createAccountDetailsMap(0, true);
73
74        accountList.add(accountDetailsMap0);
75        Uri accountUri1 = (Uri) accountDetailsMap0.get(AccountColumns.URI);
76        builder.put(accountUri1.toString(), ImmutableList.of(accountDetailsMap0));
77
78        // Account 2
79        Map<String, Object> accountDetailsMap1 = createAccountDetailsMap(1, true);
80        accountList.add(accountDetailsMap1);
81
82        Uri accountUri2 = (Uri) accountDetailsMap1.get(AccountColumns.URI);
83        builder.put(accountUri2.toString(), ImmutableList.of(accountDetailsMap1));
84
85        // Add the account list to the builder
86        builder.put(getAccountsUri().toString(), accountList);
87
88        Map<String, Object> folderDetailsMap0 = createFolderDetailsMap(0, "zero", true, 0, 2);
89        builder.put(folderDetailsMap0.get(FolderColumns.URI).toString(),
90                ImmutableList.of(folderDetailsMap0));
91        builder.put(
92                folderDetailsMap0.get(FolderColumns.CHILD_FOLDERS_LIST_URI).toString(),
93                ImmutableList.of(createFolderDetailsMap(10, "zeroChild0", 0, 0),
94                        createFolderDetailsMap(11, "zeroChild1", 0, 0)));
95
96        Map<String, Object> conv0 = createConversationDetailsMap("zeroConv0".hashCode(),
97                "zeroConv0", 1);
98        builder.put(conv0.get(ConversationColumns.URI).toString(),
99                ImmutableList.of(conv0));
100        Map<String, Object> conv1 = createConversationDetailsMap("zeroConv1".hashCode(),
101                "zeroConv1", 1);
102        builder.put(conv1.get(ConversationColumns.URI).toString(),
103                ImmutableList.of(conv1));
104        builder.put(folderDetailsMap0.get(FolderColumns.CONVERSATION_LIST_URI).toString(),
105                ImmutableList.of(conv0, conv1));
106
107        Map<String, Object> message0 = createMessageDetailsMap("zeroConv0".hashCode(), "zeroConv0",
108                1, false);
109        builder.put(message0.get(MessageColumns.URI).toString(), ImmutableList.of(message0));
110        builder.put(conv0.get(ConversationColumns.MESSAGE_LIST_URI).toString(),
111                ImmutableList.of(message0));
112        builder.put(message0.get(MessageColumns.ATTACHMENT_LIST_URI).toString(),
113                ImmutableList.of(createAttachmentDetailsMap(0, "zero")));
114        Map<String, Object> message1 = createMessageDetailsMap("zeroConv1".hashCode(), "zeroConv1",
115                1, false);
116        builder.put(message1.get(MessageColumns.URI).toString(), ImmutableList.of(message1));
117        Map<String, Object> message1a = createMessageDetailsMap("zeroConv1a".hashCode(), "zeroConv1a",
118                2, false);
119        builder.put(message1a.get(MessageColumns.URI).toString(), ImmutableList.of(message1a));
120        builder.put(conv1.get(ConversationColumns.MESSAGE_LIST_URI).toString(),
121                ImmutableList.of(message1, message1a));
122        builder.put(message1.get(MessageColumns.ATTACHMENT_LIST_URI).toString(),
123                ImmutableList.of(createAttachmentDetailsMap(1, "one")));
124
125        Map<String, Object> folderDetailsMap1 = createFolderDetailsMap(1, "one", 0, 0);
126        builder.put(folderDetailsMap1.get(FolderColumns.URI).toString(),
127                ImmutableList.of(folderDetailsMap1));
128        builder.put(accountDetailsMap0.get(AccountColumns.FOLDER_LIST_URI).toString(),
129                ImmutableList.of(folderDetailsMap0, folderDetailsMap1));
130        Map<String, Object> settings0 = createSettingsDetailsMap(folderDetailsMap0.get(
131                FolderColumns.URI).toString());
132        builder.put(accountDetailsMap0.get(AccountColumns.SETTINGS_QUERY_URI).toString(),
133                ImmutableList.of(settings0));
134
135        Map<String, Object> folderDetailsMap2 = createFolderDetailsMap(2, "two", 2, 2);
136        builder.put(folderDetailsMap2.get(FolderColumns.URI).toString(),
137                ImmutableList.of(folderDetailsMap2));
138        Map<String, Object> folderDetailsMap3 = createFolderDetailsMap(3, "three", 0, 0);
139        builder.put(folderDetailsMap3.get(FolderColumns.URI).toString(),
140                ImmutableList.of(folderDetailsMap3));
141        builder.put(accountDetailsMap1.get(AccountColumns.FOLDER_LIST_URI).toString(),
142                ImmutableList.of(folderDetailsMap2, folderDetailsMap3));
143        Map<String, Object> settings1 = createSettingsDetailsMap(folderDetailsMap2.get(
144                FolderColumns.URI).toString());
145        builder.put(accountDetailsMap1.get(AccountColumns.SETTINGS_QUERY_URI).toString(),
146                ImmutableList.of(settings1));
147
148        Map<String, Object> conv2 = createConversationDetailsMap("zeroConv2".hashCode(),
149                "zeroConv2", 0);
150        builder.put(conv2.get(ConversationColumns.URI).toString(),
151                ImmutableList.of(conv2));
152        Map<String, Object> conv3 = createConversationDetailsMap("zeroConv3".hashCode(),
153                "zeroConv3", 0);
154        builder.put(conv3.get(ConversationColumns.URI).toString(),
155                ImmutableList.of(conv3));
156        builder.put(folderDetailsMap2.get(FolderColumns.CONVERSATION_LIST_URI).toString(),
157                ImmutableList.of(conv2, conv3));
158
159        Map<String, Object> message2 = createMessageDetailsMap("zeroConv2".hashCode(), "zeroConv2",
160                0, true);
161        builder.put(message2.get(MessageColumns.URI).toString(), ImmutableList.of(message2));
162        builder.put(conv2.get(ConversationColumns.MESSAGE_LIST_URI).toString(),
163                ImmutableList.of(message2));
164        Map<String, Object> message3 = createMessageDetailsMap("zeroConv3".hashCode(), "zeroConv3",
165                0, true);
166        builder.put(message3.get(MessageColumns.URI).toString(), ImmutableList.of(message3));
167        builder.put(conv3.get(ConversationColumns.MESSAGE_LIST_URI).toString(),
168                ImmutableList.of(message3));
169
170        MOCK_QUERY_RESULTS = builder.build();
171    }
172
173    private static Map<String, Object> createSettingsDetailsMap(String uri) {
174        Map<String, Object> settingsMap = Maps.newHashMap();
175        settingsMap.put(SettingsColumns.DEFAULT_INBOX, uri);
176        return settingsMap;
177    }
178
179    private static Map<String, Object> createConversationDetailsMap(int conversationId,
180            String subject, int hasAttachments) {
181        final String conversationUri = "content://" + AUTHORITY + "/conversation/" + conversationId;
182        Map<String, Object> conversationMap = Maps.newHashMap();
183        conversationMap.put(BaseColumns._ID, Long.valueOf(conversationId));
184        conversationMap.put(ConversationColumns.URI, conversationUri);
185        conversationMap.put(ConversationColumns.MESSAGE_LIST_URI, conversationUri + "/getMessages");
186        conversationMap.put(ConversationColumns.SUBJECT, "Conversation " + subject);
187        conversationMap.put(ConversationColumns.SNIPPET, "snippet");
188        conversationMap.put(ConversationColumns.SENDER_INFO,
189                "account1@mock.com, account2@mock.com");
190        conversationMap.put(ConversationColumns.DATE_RECEIVED_MS, new Date().getTime());
191        conversationMap.put(ConversationColumns.HAS_ATTACHMENTS, hasAttachments);
192        conversationMap.put(ConversationColumns.NUM_MESSAGES, 1);
193        conversationMap.put(ConversationColumns.NUM_DRAFTS, 1);
194        conversationMap.put(ConversationColumns.SENDING_STATE, 1);
195        conversationMap.put(ConversationColumns.READ, 0);
196        conversationMap.put(ConversationColumns.STARRED, 0);
197        return conversationMap;
198    }
199
200    private static Map<String, Object> createMessageDetailsMap(int messageId, String subject,
201            int hasAttachments, boolean addReplyTo) {
202        final String messageUri = "content://" + AUTHORITY + "/message/" + messageId;
203        Map<String, Object> messageMap = Maps.newHashMap();
204        messageMap.put(BaseColumns._ID, Long.valueOf(messageId));
205        messageMap.put(MessageColumns.URI, messageUri);
206        messageMap.put(MessageColumns.SUBJECT, "Message " + subject);
207        messageMap.put(MessageColumns.SNIPPET, "SNIPPET");
208        String html = "<html><body><b><i>This is some html!!!</i></b></body></html>";
209        messageMap.put(MessageColumns.BODY_HTML, html);
210        messageMap.put(MessageColumns.BODY_TEXT, Html.fromHtml(html));
211        messageMap.put(MessageColumns.HAS_ATTACHMENTS, hasAttachments);
212        messageMap.put(MessageColumns.DATE_RECEIVED_MS, new Date().getTime());
213        messageMap.put(MessageColumns.ATTACHMENT_LIST_URI, messageUri + "/getAttachments");
214        messageMap.put(MessageColumns.TO, "account1@mock.com, account2@mock.com");
215        messageMap.put(MessageColumns.FROM, "fromaccount1@mock.com");
216        if (addReplyTo) {
217            messageMap.put(MessageColumns.REPLY_TO, "replytofromaccount1@mock.com");
218        }
219        return messageMap;
220    }
221
222    private static Map<String, Object> createAttachmentDetailsMap(int attachmentId, String name) {
223        Map<String, Object> attachmentMap = Maps.newHashMap();
224        attachmentMap.put(BaseColumns._ID, Long.valueOf(attachmentId));
225        attachmentMap.put(AttachmentColumns.NAME, "Attachment " + name);
226        attachmentMap.put(AttachmentColumns.URI,
227                "attachmentUri/" + attachmentMap.get(AttachmentColumns.NAME));
228        return attachmentMap;
229    }
230
231    private static Map<String, Object> createFolderDetailsMap(int folderId, String name,
232            int unread, int total) {
233        return createFolderDetailsMap(folderId, name, false, unread, total);
234    }
235
236    private static Map<String, Object> createFolderDetailsMap(int folderId, String name,
237            boolean hasChildren, int unread, int total) {
238        final String folderUri = "content://" + AUTHORITY + "/folder/" + folderId;
239        Map<String, Object> folderMap = Maps.newHashMap();
240        folderMap.put(BaseColumns._ID, Long.valueOf(folderId));
241        folderMap.put(FolderColumns.URI, folderUri);
242        folderMap.put(FolderColumns.NAME, "Folder " + name);
243        folderMap.put(FolderColumns.HAS_CHILDREN, new Integer(hasChildren ? 1 : 0));
244        folderMap.put(FolderColumns.CONVERSATION_LIST_URI, folderUri + "/getConversations");
245        folderMap.put(FolderColumns.CHILD_FOLDERS_LIST_URI, folderUri + "/getChildFolders");
246        folderMap.put(FolderColumns.CAPABILITIES,
247                Long.valueOf(
248                        FolderCapabilities.SYNCABLE |
249                        FolderCapabilities.PARENT |
250                        FolderCapabilities.CAN_HOLD_MAIL |
251                        FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES));
252        folderMap.put(FolderColumns.UNREAD_COUNT, unread);
253        folderMap.put(FolderColumns.TOTAL_COUNT, total);
254        folderMap.put(FolderColumns.SYNC_STATUS, 0);
255        folderMap.put(FolderColumns.LAST_SYNC_RESULT, 0);
256        return folderMap;
257    }
258
259    // Temporarily made this public to allow the Gmail accounts to use the mock ui provider uris
260    public static Map<String, Object> createAccountDetailsMap(int accountId, boolean cacheMap) {
261        final String accountUri = getMockAccountUri(accountId);
262        Map<String, Object> accountMap = Maps.newHashMap();
263        accountMap.put(BaseColumns._ID, Long.valueOf(accountId));
264        accountMap.put(AccountColumns.NAME, "account" + accountId + "@mockuiprovider.com");
265        accountMap.put(AccountColumns.PROVIDER_VERSION, Long.valueOf(1));
266        accountMap.put(AccountColumns.URI, Uri.parse(accountUri));
267        accountMap.put(AccountColumns.CAPABILITIES,
268                Integer.valueOf(
269                        AccountCapabilities.SYNCABLE_FOLDERS |
270                        AccountCapabilities.REPORT_SPAM |
271                        AccountCapabilities.ARCHIVE |
272                        AccountCapabilities.MUTE |
273                        AccountCapabilities.SERVER_SEARCH |
274                        AccountCapabilities.FOLDER_SERVER_SEARCH |
275                        AccountCapabilities.SANITIZED_HTML |
276                        AccountCapabilities.DRAFT_SYNCHRONIZATION |
277                        AccountCapabilities.MULTIPLE_FROM_ADDRESSES |
278                        AccountCapabilities.SMART_REPLY |
279                        AccountCapabilities.LOCAL_SEARCH |
280                        AccountCapabilities.THREADED_CONVERSATIONS |
281                        AccountCapabilities.MULTIPLE_FOLDERS_PER_CONV));
282        accountMap.put(AccountColumns.FOLDER_LIST_URI, Uri.parse(accountUri + "/folders"));
283        accountMap.put(AccountColumns.SEARCH_URI, Uri.parse(accountUri + "/search"));
284        accountMap.put(AccountColumns.ACCOUNT_FROM_ADDRESSES_URI,
285                Uri.parse(accountUri + "/fromAddresses"));
286        accountMap.put(AccountColumns.SAVE_DRAFT_URI, Uri.parse(accountUri + "/saveDraft"));
287        accountMap.put(AccountColumns.SEND_MAIL_URI, Uri.parse(accountUri + "/sendMail"));
288        accountMap.put(AccountColumns.EXPUNGE_MESSAGE_URI,
289                Uri.parse(accountUri + "/expungeMessage"));
290        accountMap.put(AccountColumns.UNDO_URI, Uri.parse(accountUri + "/undo"));
291        accountMap.put(AccountColumns.SETTINGS_INTENT_URI, Uri.parse("http://www.google.com"));
292        accountMap.put(AccountColumns.SETTINGS_QUERY_URI, Uri.parse(accountUri + "/settings"));
293        accountMap.put(AccountColumns.HELP_INTENT_URI, Uri.parse("http://www.google.com"));
294        accountMap.put(AccountColumns.SYNC_STATUS, 0);
295        accountMap.put(AccountColumns.COMPOSE_URI, Uri.parse(accountUri + "/compose"));
296        accountMap.put(AccountColumns.RECENT_FOLDER_LIST_URI,
297                Uri.parse(accountUri + "/recentFolderListUri"));
298        if (cacheMap) {
299            addAccountInfoToAccountCache(accountMap);
300        }
301        return accountMap;
302    }
303
304    public static String getMockAccountUri(int accountId) {
305        return "content://" + AUTHORITY + "/account/" + accountId;
306    }
307
308    @Override
309    public boolean onCreate() {
310        return true;
311    }
312
313    @Override
314    public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
315            String sortOrder) {
316
317        // TODO (pwestbro): respect the projection that is specified by the caller
318
319        final List<Map<String, Object>> queryResults =
320                MOCK_QUERY_RESULTS.get(url.toString());
321
322        if (queryResults != null && queryResults.size() > 0) {
323            // Get the projection.  If there are rows in the result set, pick the first item to
324            // generate the projection
325            // TODO (pwestbro): handle the case where we want to return an empty result.\
326            if (projection == null) {
327                Set<String> keys = queryResults.get(0).keySet();
328                projection = keys.toArray(new String[keys.size()]);
329            }
330            MatrixCursor matrixCursor = new MatrixCursor(projection, queryResults.size());
331
332            for (Map<String, Object> queryResult : queryResults) {
333                MatrixCursor.RowBuilder rowBuilder = matrixCursor.newRow();
334
335                for (String key : projection) {
336                    rowBuilder.add(queryResult.get(key));
337                }
338            }
339            return matrixCursor;
340        }
341
342        return null;
343    }
344
345    @Override
346    public Uri insert(Uri url, ContentValues values) {
347        return url;
348    }
349
350    @Override
351    public int update(Uri url, ContentValues values, String selection,
352            String[] selectionArgs) {
353        return 0;
354    }
355
356    @Override
357    public int delete(Uri url, String selection, String[] selectionArgs) {
358        return 0;
359    }
360
361    @Override
362    public String getType(Uri uri) {
363        return null;
364    }
365
366    @VisibleForTesting
367    static Uri getAccountsUri() {
368        // TODO: this should probably return a different specific to the mock account list
369        return Uri.parse(BASE_URI_STRING + "/");
370    }
371
372    private static void addAccountInfoToAccountCache(Map<String, Object> accountInfo) {
373        final Parcel dest = Parcel.obtain();
374
375        dest.writeString((String) accountInfo.get(AccountColumns.NAME));
376        dest.writeString("mock");
377        dest.writeInt(0);
378        dest.writeParcelable((Uri) accountInfo.get(AccountColumns.URI), 0);
379        dest.writeInt((Integer) accountInfo.get(AccountColumns.CAPABILITIES));
380        dest.writeParcelable((Uri) accountInfo.get(AccountColumns.FOLDER_LIST_URI), 0);
381        dest.writeParcelable((Uri) accountInfo.get(AccountColumns.SEARCH_URI), 0);
382        dest.writeParcelable((Uri) accountInfo.get(AccountColumns.ACCOUNT_FROM_ADDRESSES_URI), 0);
383        dest.writeParcelable((Uri) accountInfo.get(AccountColumns.SAVE_DRAFT_URI), 0);
384        dest.writeParcelable((Uri) accountInfo.get(AccountColumns.SEND_MAIL_URI), 0);
385        dest.writeParcelable((Uri) accountInfo.get(AccountColumns.EXPUNGE_MESSAGE_URI), 0);
386        dest.writeParcelable((Uri) accountInfo.get(AccountColumns.UNDO_URI), 0);
387        dest.writeParcelable((Uri) accountInfo.get(AccountColumns.SETTINGS_INTENT_URI), 0);
388        dest.writeParcelable((Uri)accountInfo.get(AccountColumns.SETTINGS_QUERY_URI), 0);
389        dest.writeParcelable((Uri) accountInfo.get(AccountColumns.HELP_INTENT_URI), 0);
390        dest.writeInt((Integer) accountInfo.get(AccountColumns.SYNC_STATUS));
391        dest.writeParcelable((Uri) accountInfo.get(AccountColumns.COMPOSE_URI), 0);
392        dest.writeString((String) accountInfo.get(AccountColumns.MIME_TYPE));
393        dest.writeParcelable((Uri) accountInfo.get(AccountColumns.RECENT_FOLDER_LIST_URI), 0);
394        dest.setDataPosition(0);
395        final Account account = new Account(dest);
396        AccountCacheProvider.addAccount(account);
397    }
398}
399
400