1/*
2 * Copyright (C) 2012 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 */
16package com.android.mail;
17
18import android.app.IntentService;
19import android.content.Context;
20import android.content.Intent;
21import android.net.Uri;
22
23import com.android.mail.analytics.Analytics;
24import com.android.mail.photo.ContactFetcher;
25import com.android.mail.providers.Account;
26import com.android.mail.providers.Folder;
27import com.android.mail.utils.FolderUri;
28import com.android.mail.utils.LogTag;
29import com.android.mail.utils.LogUtils;
30import com.android.mail.utils.NotificationUtils;
31import com.android.mail.utils.StorageLowState;
32import com.android.mail.utils.Utils;
33
34/**
35 * A service to handle various intents asynchronously.
36 */
37public class MailIntentService extends IntentService {
38    private static final String LOG_TAG = LogTag.getLogTag();
39
40    public static final String ACTION_RESEND_NOTIFICATIONS =
41            "com.android.mail.action.RESEND_NOTIFICATIONS";
42    public static final String ACTION_CLEAR_NEW_MAIL_NOTIFICATIONS =
43            "com.android.mail.action.CLEAR_NEW_MAIL_NOTIFICATIONS";
44
45    /**
46     * After user replies an email from Wear, it marks the conversation as read and resend
47     * notifications.
48     */
49    public static final String ACTION_RESEND_NOTIFICATIONS_WEAR =
50            "com.android.mail.action.RESEND_NOTIFICATIONS_WEAR";
51
52    public static final String ACTION_BACKUP_DATA_CHANGED =
53            "com.android.mail.action.BACKUP_DATA_CHANGED";
54    public static final String ACTION_SEND_SET_NEW_EMAIL_INDICATOR =
55            "com.android.mail.action.SEND_SET_NEW_EMAIL_INDICATOR";
56
57    public static final String CONVERSATION_EXTRA = "conversation";
58
59    public MailIntentService() {
60        super("MailIntentService");
61    }
62
63    protected MailIntentService(final String name) {
64        super(name);
65    }
66
67    @Override
68    protected void onHandleIntent(final Intent intent) {
69        // UnifiedEmail does not handle all Intents
70
71        LogUtils.v(LOG_TAG, "Handling intent %s", intent);
72
73        final String action = intent.getAction();
74
75        if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
76            NotificationUtils.cancelAndResendNotificationsOnLocaleChange(
77                    this, getContactFetcher());
78        } else if (ACTION_CLEAR_NEW_MAIL_NOTIFICATIONS.equals(action)) {
79            final Account account = intent.getParcelableExtra(Utils.EXTRA_ACCOUNT);
80            final Folder folder = intent.getParcelableExtra(Utils.EXTRA_FOLDER);
81
82            NotificationUtils.clearFolderNotification(this, account, folder, true /* markSeen */);
83            Analytics.getInstance().sendEvent("notification_dismiss", folder.getTypeDescription(),
84                    null, 0);
85        } else if (ACTION_RESEND_NOTIFICATIONS.equals(action)) {
86            final Uri accountUri = intent.getParcelableExtra(Utils.EXTRA_ACCOUNT_URI);
87
88            final Uri extraFolderUri = intent.getParcelableExtra(Utils.EXTRA_FOLDER_URI);
89            final FolderUri folderUri =
90                    extraFolderUri == null ? null : new FolderUri(extraFolderUri);
91
92            NotificationUtils.resendNotifications(
93                    this, false, accountUri, folderUri, getContactFetcher());
94        } else if (ACTION_RESEND_NOTIFICATIONS_WEAR.equals(action)) {
95            final Account account = intent.getParcelableExtra(Utils.EXTRA_ACCOUNT);
96            final Folder folder = intent.getParcelableExtra(Utils.EXTRA_FOLDER);
97            final Uri conversationUri = intent.getParcelableExtra(Utils.EXTRA_CONVERSATION);
98
99            // Mark the conversation as read and refresh the notifications.  This happens
100            // when user replies to a conversation remotely from a Wear device.
101            NotificationUtils.markConversationAsReadAndSeen(this, conversationUri);
102            NotificationUtils.resendNotifications(this, false, account.uri,
103                    folder.folderUri, getContactFetcher());
104        } else if (ACTION_SEND_SET_NEW_EMAIL_INDICATOR.equals(action)) {
105            final int unreadCount = intent.getIntExtra(NotificationUtils.EXTRA_UNREAD_COUNT, 0);
106            final int unseenCount = intent.getIntExtra(NotificationUtils.EXTRA_UNSEEN_COUNT, 0);
107            final Account account = intent.getParcelableExtra(Utils.EXTRA_ACCOUNT);
108            final Folder folder = intent.getParcelableExtra(Utils.EXTRA_FOLDER);
109            final boolean getAttention =
110                    intent.getBooleanExtra(NotificationUtils.EXTRA_GET_ATTENTION, false);
111
112            NotificationUtils.setNewEmailIndicator(this, unreadCount, unseenCount,
113                    account, folder, getAttention, getContactFetcher());
114        } else if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
115            // The storage_low state is recorded centrally even though
116            // no handler might be present to change application state
117            // based on state changes.
118            StorageLowState.setIsStorageLow(true);
119        } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
120            StorageLowState.setIsStorageLow(false);
121        }
122    }
123
124    public static void broadcastBackupDataChanged(final Context context) {
125        final Intent intent = new Intent(ACTION_BACKUP_DATA_CHANGED);
126        intent.setPackage(context.getPackageName());
127        context.startService(intent);
128    }
129
130    /**
131     * Derived classes should override this method if they wish to provide their own contact loading
132     * behavior separate from the ContactProvider-based default. The default behavior of this method
133     * returns null.
134     */
135    public ContactFetcher getContactFetcher() {
136        return null;
137    }
138}
139