1/*******************************************************************************
2 *      Copyright (C) 2012 Google Inc.
3 *      Licensed to The Android Open Source Project.
4 *
5 *      Licensed under the Apache License, Version 2.0 (the "License");
6 *      you may not use this file except in compliance with the License.
7 *      You may obtain a copy of the License at
8 *
9 *           http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *      Unless required by applicable law or agreed to in writing, software
12 *      distributed under the License is distributed on an "AS IS" BASIS,
13 *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *      See the License for the specific language governing permissions and
15 *      limitations under the License.
16 *******************************************************************************/
17
18package com.android.mail.ui;
19
20import com.android.mail.providers.Account;
21import com.android.mail.providers.Folder;
22import com.android.mail.providers.UIProvider;
23import com.android.mail.utils.LogTag;
24import com.android.mail.utils.LogUtils;
25import com.android.mail.ConversationListContext;
26
27import android.net.Uri;
28
29import android.content.BroadcastReceiver;
30import android.content.Context;
31import android.content.Intent;
32import android.content.IntentFilter;
33import android.content.IntentFilter.MalformedMimeTypeException;
34import android.text.TextUtils;
35
36
37/**
38 * A simple {@code BroadcastReceiver} which suppresses new e-mail notifications for a given folder.
39 */
40public class SuppressNotificationReceiver extends BroadcastReceiver {
41    private static final String LOG_TAG = LogTag.getLogTag();
42
43    private Context mContext;
44    private AbstractActivityController mController;
45    private String mMimeType;
46
47    /**
48     * Registers this receiver to suppress the new mail notifications for a given folder so
49     * that other {@code BroadcastReceiver}s don't receive them.
50     */
51    public boolean activate(Context context, AbstractActivityController controller) {
52        final Account account = controller.getCurrentAccount();
53
54        mContext = context;
55        mController = controller;
56
57        final IntentFilter filter = new IntentFilter(UIProvider.ACTION_UPDATE_NOTIFICATION);
58
59        // Note: the real notification receiver must have a lower (i.e. negative) priority
60        // than this receiver.
61        filter.setPriority(0);
62        if (account != null) {
63            mMimeType = account.mimeType;
64            try {
65                filter.addDataType(mMimeType);
66            } catch (MalformedMimeTypeException e) {
67                LogUtils.wtf(LOG_TAG, "Malformed mimetype: %s", mMimeType);
68            }
69        } else {
70            // If the current account is null, still register the receiver.  This allows the
71            // internal state of the receiver to match what the caller requested.
72            LogUtils.d(LOG_TAG, "Registering receiver with no mime type");
73        }
74        context.registerReceiver(this, filter);
75
76        return true;
77    }
78
79    /**
80     * Returns true if this suppressNotificationReceiver is activated
81     */
82    public boolean activated() {
83        return mContext != null;
84    }
85
86    /**
87     * Unregisters this receiver.
88     */
89    public void deactivate() {
90        try {
91            if (mContext != null) {
92                mContext.unregisterReceiver(this);
93                mContext = null;
94                mMimeType = null;
95            }
96        } catch (IllegalArgumentException e) {
97            // May throw if already unregistered. Ignore exception.
98        }
99    }
100
101    /**
102     * Returns a boolean indicating whether notifications are suppressed for the specified account.
103     */
104    public boolean notificationsDisabledForAccount(Account account) {
105        return mContext != null && TextUtils.equals(account.mimeType, mMimeType);
106    }
107
108    @Override
109    public void onReceive(Context context, Intent intent) {
110        final String action = intent.getAction();
111        if (!UIProvider.ACTION_UPDATE_NOTIFICATION.equals(action)) {
112            return;
113        }
114
115        if (!mController.isConversationListVisible()) {
116            // The conversation list is not visible, don't suppress notifications.
117            return;
118        }
119
120        final ConversationListContext listContext = mController.getCurrentListContext();
121        if (listContext == null) {
122            // A non-null list context was expected
123            LogUtils.e(LOG_TAG, "unexpected null context");
124            return;
125        }
126
127        if (ConversationListContext.isSearchResult(listContext)) {
128            // The user is looking at a search result, don't suppress notifications.
129            return;
130        }
131
132        final Account listContextAccount = listContext.account;
133        final Folder listContextFolder = listContext.folder;
134        // Guard against degenerate state in the controller
135        if (listContextAccount == null || listContextFolder == null) {
136            LogUtils.e(LOG_TAG, "SuppressNotificationReceiver.onReceive: account=%s, folder=%s",
137                    listContextAccount, listContextFolder);
138            return;
139        }
140
141        final Uri intentAccountUri =
142                (Uri)intent.getParcelableExtra(UIProvider.UpdateNotificationExtras.EXTRA_ACCOUNT);
143        if (!listContextAccount.uri.equals(intentAccountUri)) {
144            return;
145        }
146        final Uri intentFolderUri =
147                (Uri)intent.getParcelableExtra(UIProvider.UpdateNotificationExtras.EXTRA_FOLDER);
148
149        if (!listContextFolder.folderUri.equals(intentFolderUri)) {
150            return;
151        }
152        final int count = intent.getIntExtra(
153                UIProvider.UpdateNotificationExtras.EXTRA_UPDATED_UNREAD_COUNT, 0);
154        // If the count is zero we want to let the intent through so that the
155        // regular receiver can remove the notification.
156        // This will allow a server change, that modifies the unread count to 0, to be handled
157        // by the intended recpient to clear the notification.
158        if (count == 0) {
159            return;
160        }
161        LogUtils.i(LOG_TAG, "Aborting broadcast of intent %s, folder uri is %s",
162                intent, intentFolderUri);
163        abortBroadcast();
164    }
165}
166