172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project/*
272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Copyright (C) 2008 Esmertec AG.
372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project *
572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * you may not use this file except in compliance with the License.
772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * You may obtain a copy of the License at
872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project *
972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
1072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project *
1172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * See the License for the specific language governing permissions and
1572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * limitations under the License.
1672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project */
1772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
1872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectpackage com.android.mms.transaction;
1972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
20f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND;
21f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF;
2272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
2372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport com.android.mms.R;
24812391ad832f3fdac054ad3a50af563da16e99b5Wei Huangimport com.android.mms.LogTag;
2533a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrickimport com.android.mms.data.Contact;
2670c73e05a792832aa28da751cdaf3fa83a7b8113Ficus Kirkpatrickimport com.android.mms.data.Conversation;
2772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport com.android.mms.ui.ComposeMessageActivity;
2872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport com.android.mms.ui.ConversationList;
2972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport com.android.mms.ui.MessagingPreferenceActivity;
3072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport com.android.mms.util.AddressUtils;
3172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport com.android.mms.util.DownloadManager;
3272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
33f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport com.google.android.mms.pdu.EncodedStringValue;
34f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport com.google.android.mms.pdu.PduHeaders;
35f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport com.google.android.mms.pdu.PduPersister;
36fd644551e8506266aad2b76463b51b44154ed62fTom Taylorimport android.database.sqlite.SqliteWrapper;
3772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
3872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.app.Notification;
3972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.app.NotificationManager;
4072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.app.PendingIntent;
4172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.ContentResolver;
4272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.Context;
4372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.Intent;
4472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.SharedPreferences;
4570f5af8fd89d66ae246a805d10a50540746319aaWei Huangimport android.content.BroadcastReceiver;
4670f5af8fd89d66ae246a805d10a50540746319aaWei Huangimport android.content.IntentFilter;
4772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.database.Cursor;
4872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.graphics.Typeface;
49006d49271549ed639ffcd70d94c7650bb3514796Jim Shumaimport android.media.AudioManager;
5072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.net.Uri;
515a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylorimport android.os.Handler;
5272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.preference.PreferenceManager;
53d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylorimport android.provider.Settings;
54f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.Mms;
55f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.Sms;
5672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.text.Spannable;
5772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.text.SpannableString;
5872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.text.TextUtils;
5972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.text.style.StyleSpan;
6072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.util.Log;
61800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERTimport android.widget.Toast;
6272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
6372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport java.util.Comparator;
64b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrickimport java.util.HashSet;
65b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrickimport java.util.Set;
6672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport java.util.SortedSet;
6772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport java.util.TreeSet;
6872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
6972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project/**
7072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * This class is used to update the notification indicator. It will check whether
7172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * there are unread messages. If yes, it would show the notification indicator,
7272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * otherwise, hide the indicator.
7372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project */
7472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectpublic class MessagingNotification {
75812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang    private static final String TAG = LogTag.APP;
7672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
7772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int NOTIFICATION_ID = 123;
7872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static final int MESSAGE_FAILED_NOTIFICATION_ID = 789;
7972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static final int DOWNLOAD_FAILED_NOTIFICATION_ID = 531;
8072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
8172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // This must be consistent with the column constants below.
8272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String[] MMS_STATUS_PROJECTION = new String[] {
8372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Mms.THREAD_ID, Mms.DATE, Mms._ID, Mms.SUBJECT, Mms.SUBJECT_CHARSET };
8472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
8572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // This must be consistent with the column constants below.
8672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String[] SMS_STATUS_PROJECTION = new String[] {
8772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Sms.THREAD_ID, Sms.DATE, Sms.ADDRESS, Sms.SUBJECT, Sms.BODY };
8872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
8972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // These must be consistent with MMS_STATUS_PROJECTION and
9072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // SMS_STATUS_PROJECTION.
9172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_THREAD_ID   = 0;
9272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_DATE        = 1;
9372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_MMS_ID      = 2;
9472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SMS_ADDRESS = 2;
9572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SUBJECT     = 3;
9672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SUBJECT_CS  = 4;
9772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SMS_BODY    = 4;
9872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
9972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String NEW_INCOMING_SM_CONSTRAINT =
10072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            "(" + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_INBOX
101627007213deb59ef938c80353c8f3598b01478b3Wei Huang            + " AND " + Sms.SEEN + " = 0)";
10272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
103800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    private static final String NEW_DELIVERY_SM_CONSTRAINT =
104c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        "(" + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_SENT
105c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        + " AND " + Sms.STATUS + " = "+ Sms.STATUS_COMPLETE +")";
106800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
10772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String NEW_INCOMING_MM_CONSTRAINT =
10872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            "(" + Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_INBOX
109627007213deb59ef938c80353c8f3598b01478b3Wei Huang            + " AND " + Mms.SEEN + "=0"
11072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            + " AND (" + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_NOTIFICATION_IND
11172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            + " OR " + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_RETRIEVE_CONF + "))";
11272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
11372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final MmsSmsNotificationInfoComparator INFO_COMPARATOR =
11472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            new MmsSmsNotificationInfoComparator();
1155a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
11672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final Uri UNDELIVERED_URI = Uri.parse("content://mms-sms/undelivered");
11772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
11870f5af8fd89d66ae246a805d10a50540746319aaWei Huang
11970f5af8fd89d66ae246a805d10a50540746319aaWei Huang    private final static String NOTIFICATION_DELETED_ACTION =
12070f5af8fd89d66ae246a805d10a50540746319aaWei Huang            "com.android.mms.NOTIFICATION_DELETED_ACTION";
12170f5af8fd89d66ae246a805d10a50540746319aaWei Huang
12270f5af8fd89d66ae246a805d10a50540746319aaWei Huang    public static class OnDeletedReceiver extends BroadcastReceiver {
12370f5af8fd89d66ae246a805d10a50540746319aaWei Huang        public void onReceive(Context context, Intent intent) {
12470f5af8fd89d66ae246a805d10a50540746319aaWei Huang            if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
12570f5af8fd89d66ae246a805d10a50540746319aaWei Huang                Log.d(TAG, "[MessagingNotification] clear notification: mark all msgs seen");
12670f5af8fd89d66ae246a805d10a50540746319aaWei Huang            }
12770f5af8fd89d66ae246a805d10a50540746319aaWei Huang
12870f5af8fd89d66ae246a805d10a50540746319aaWei Huang            Conversation.markAllConversationsAsSeen(context);
12970f5af8fd89d66ae246a805d10a50540746319aaWei Huang        }
13070f5af8fd89d66ae246a805d10a50540746319aaWei Huang    };
13170f5af8fd89d66ae246a805d10a50540746319aaWei Huang    private static OnDeletedReceiver sNotificationDeletedReceiver = new OnDeletedReceiver();
13270f5af8fd89d66ae246a805d10a50540746319aaWei Huang    private static Intent sNotificationOnDeleteIntent;
1335a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor    private static Handler mToastHandler = new Handler();
13470f5af8fd89d66ae246a805d10a50540746319aaWei Huang
13572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private MessagingNotification() {
13672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
13772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
13870f5af8fd89d66ae246a805d10a50540746319aaWei Huang    public static void init(Context context) {
13970f5af8fd89d66ae246a805d10a50540746319aaWei Huang        // set up the intent filter for notification deleted action
14070f5af8fd89d66ae246a805d10a50540746319aaWei Huang        IntentFilter intentFilter = new IntentFilter();
14170f5af8fd89d66ae246a805d10a50540746319aaWei Huang        intentFilter.addAction(NOTIFICATION_DELETED_ACTION);
14270f5af8fd89d66ae246a805d10a50540746319aaWei Huang        context.registerReceiver(sNotificationDeletedReceiver, intentFilter);
14370f5af8fd89d66ae246a805d10a50540746319aaWei Huang
14470f5af8fd89d66ae246a805d10a50540746319aaWei Huang        // initialize the notification deleted action
14570f5af8fd89d66ae246a805d10a50540746319aaWei Huang        sNotificationOnDeleteIntent = new Intent(NOTIFICATION_DELETED_ACTION);
14670f5af8fd89d66ae246a805d10a50540746319aaWei Huang    }
14770f5af8fd89d66ae246a805d10a50540746319aaWei Huang
14872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    /**
149627007213deb59ef938c80353c8f3598b01478b3Wei Huang     * Checks to see if there are any "unseen" messages or delivery
15072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * reports.  Shows the most recent notification if there is one.
1513b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor     * Does its work and query in a worker thread.
15272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     *
15372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * @param context the context to use
15472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     */
1553b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor    public static void nonBlockingUpdateNewMessageIndicator(final Context context,
1563b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor            final boolean isNew,
1573b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor            final boolean isStatusMessage) {
1583b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        new Thread(new Runnable() {
1593b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor            public void run() {
1603b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor                blockingUpdateNewMessageIndicator(context, isNew, isStatusMessage);
1613b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor            }
1623b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        }).start();
16372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
16472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
16572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    /**
166627007213deb59ef938c80353c8f3598b01478b3Wei Huang     * Checks to see if there are any "unseen" messages or delivery
16772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * reports.  Shows the most recent notification if there is one.
16872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     *
16972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * @param context the context to use
17072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * @param isNew if notify a new message comes, it should be true, otherwise, false.
17172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     */
1723b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor    public static void blockingUpdateNewMessageIndicator(Context context, boolean isNew,
173c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            boolean isStatusMessage) {
17472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        SortedSet<MmsSmsNotificationInfo> accumulator =
17572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                new TreeSet<MmsSmsNotificationInfo>(INFO_COMPARATOR);
176c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        MmsSmsDeliveryInfo delivery = null;
177b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        Set<Long> threads = new HashSet<Long>(4);
1785a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
17972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int count = 0;
18072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        count += accumulateNotificationInfo(
181b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                accumulator, getMmsNewMessageNotificationInfo(context, threads));
18272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        count += accumulateNotificationInfo(
183b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                accumulator, getSmsNewMessageNotificationInfo(context, threads));
18472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
18572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        cancelNotification(context, NOTIFICATION_ID);
18672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!accumulator.isEmpty()) {
187e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
188e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang                Log.d(TAG, "blockingUpdateNewMessageIndicator: count=" + count +
189e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang                        ", isNew=" + isNew);
190e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            }
191b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            accumulator.first().deliver(context, isNew, count, threads.size());
19272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
1935a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
1943b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // And deals with delivery reports (which use Toasts). It's safe to call in a worker
1953b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // thread because the toast will eventually get posted to a handler.
196627007213deb59ef938c80353c8f3598b01478b3Wei Huang        delivery = getSmsNewDeliveryInfo(context);
197627007213deb59ef938c80353c8f3598b01478b3Wei Huang        if (delivery != null) {
198c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            delivery.deliver(context, isStatusMessage);
199627007213deb59ef938c80353c8f3598b01478b3Wei Huang        }
20072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
20172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
20272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    /**
20335a74a9e0ee7c171c6e17f0eda4b0df0253f8364Ficus Kirkpatrick     * Updates all pending notifications, clearing or updating them as
2043b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor     * necessary.
20535a74a9e0ee7c171c6e17f0eda4b0df0253f8364Ficus Kirkpatrick     */
206627007213deb59ef938c80353c8f3598b01478b3Wei Huang    public static void blockingUpdateAllNotifications(final Context context) {
2073b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        nonBlockingUpdateNewMessageIndicator(context, false, false);
208627007213deb59ef938c80353c8f3598b01478b3Wei Huang        updateSendFailedNotification(context);
209627007213deb59ef938c80353c8f3598b01478b3Wei Huang        updateDownloadFailedNotification(context);
21035a74a9e0ee7c171c6e17f0eda4b0df0253f8364Ficus Kirkpatrick    }
2115a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
21272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int accumulateNotificationInfo(
21372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            SortedSet set, MmsSmsNotificationInfo info) {
21472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (info != null) {
21572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            set.add(info);
21672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
21772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return info.mCount;
21872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
21972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
22072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return 0;
22172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
22272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
223800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    private static final class MmsSmsDeliveryInfo {
224c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public CharSequence mTicker;
225c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public long mTimeMillis;
226c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor
227c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public MmsSmsDeliveryInfo(CharSequence ticker, long timeMillis) {
228c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            mTicker = ticker;
229c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            mTimeMillis = timeMillis;
230c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        }
231c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor
232c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public void deliver(Context context, boolean isStatusMessage) {
233c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            updateDeliveryNotification(
234c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor                    context, isStatusMessage, mTicker, mTimeMillis);
235c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        }
236800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    }
237800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
23872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final class MmsSmsNotificationInfo {
23972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public Intent mClickIntent;
24072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public String mDescription;
24172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public int mIconResourceId;
24272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public CharSequence mTicker;
24372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public long mTimeMillis;
24472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public String mTitle;
24572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public int mCount;
24672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
24772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public MmsSmsNotificationInfo(
24872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Intent clickIntent, String description, int iconResourceId,
24972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                CharSequence ticker, long timeMillis, String title, int count) {
25072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mClickIntent = clickIntent;
25172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mDescription = description;
25272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mIconResourceId = iconResourceId;
25372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mTicker = ticker;
25472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mTimeMillis = timeMillis;
25572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mTitle = title;
25672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mCount = count;
25772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
25872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
259b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        public void deliver(Context context, boolean isNew, int count, int uniqueThreads) {
26072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            updateNotification(
2613c68b6852913222dd982dddd4e39b3e57613c37eWei Huang                    context, mClickIntent, mDescription, mIconResourceId, isNew,
2623c68b6852913222dd982dddd4e39b3e57613c37eWei Huang                    (isNew? mTicker : null), // only display the ticker if the message is new
2633c68b6852913222dd982dddd4e39b3e57613c37eWei Huang                    mTimeMillis, mTitle, count, uniqueThreads);
26472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
26572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
26672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public long getTime() {
26772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return mTimeMillis;
26872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
26972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
27072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
27172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final class MmsSmsNotificationInfoComparator
27272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            implements Comparator<MmsSmsNotificationInfo> {
27372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public int compare(
27472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                MmsSmsNotificationInfo info1, MmsSmsNotificationInfo info2) {
27572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return Long.signum(info2.getTime() - info1.getTime());
27672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
27772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
27872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
2793b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor    private static final MmsSmsNotificationInfo getMmsNewMessageNotificationInfo(
280b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            Context context, Set<Long> threads) {
28172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        ContentResolver resolver = context.getContentResolver();
2823b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor
2833b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // This query looks like this when logged:
2843b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // I/Database(  147): elapsedTime4Sql|/data/data/com.android.providers.telephony/databases/
2853b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // mmssms.db|0.362 ms|SELECT thread_id, date, _id, sub, sub_cs FROM pdu WHERE ((msg_box=1
2863b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // AND seen=0 AND (m_type=130 OR m_type=132))) ORDER BY date desc
2873b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor
28872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor cursor = SqliteWrapper.query(context, resolver, Mms.CONTENT_URI,
28972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            MMS_STATUS_PROJECTION, NEW_INCOMING_MM_CONSTRAINT,
29072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            null, Mms.DATE + " desc");
29172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
292b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        if (cursor == null) {
293b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            return null;
294b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
2955a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
296b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        try {
297b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            if (!cursor.moveToFirst()) {
298b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                return null;
29972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
300b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            long msgId = cursor.getLong(COLUMN_MMS_ID);
301b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            Uri msgUri = Mms.CONTENT_URI.buildUpon().appendPath(
302b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    Long.toString(msgId)).build();
303b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            String address = AddressUtils.getFrom(context, msgUri);
3041b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
3051b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor            Contact contact = Contact.get(address, false);
3061b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor            if (contact.getSendToVoicemail()) {
3071b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor                // don't notify
3081b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor                return null;
3091b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor            }
3101b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
311b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            String subject = getMmsSubject(
312b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    cursor.getString(COLUMN_SUBJECT), cursor.getInt(COLUMN_SUBJECT_CS));
313b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            long threadId = cursor.getLong(COLUMN_THREAD_ID);
314b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            long timeMillis = cursor.getLong(COLUMN_DATE) * 1000;
315b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
316e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
317e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang                Log.d(TAG, "getMmsNewMessageNotificationInfo: count=" + cursor.getCount() +
318e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang                        ", first addr = " + address + ", thread_id=" + threadId);
319e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            }
320e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang
321b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            MmsSmsNotificationInfo info = getNewMessageNotificationInfo(
322b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    address, subject, context,
323b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    R.drawable.stat_notify_mms, null, threadId,
324b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    timeMillis, cursor.getCount());
325b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
326b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            threads.add(threadId);
327b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            while (cursor.moveToNext()) {
328b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                threads.add(cursor.getLong(COLUMN_THREAD_ID));
329b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            }
330b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
331b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            return info;
332b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        } finally {
333b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            cursor.close();
33472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
33572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
33672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
3373b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor    private static final MmsSmsDeliveryInfo getSmsNewDeliveryInfo(Context context) {
338627007213deb59ef938c80353c8f3598b01478b3Wei Huang        ContentResolver resolver = context.getContentResolver();
339627007213deb59ef938c80353c8f3598b01478b3Wei Huang        Cursor cursor = SqliteWrapper.query(context, resolver, Sms.CONTENT_URI,
340627007213deb59ef938c80353c8f3598b01478b3Wei Huang                    SMS_STATUS_PROJECTION, NEW_DELIVERY_SM_CONSTRAINT,
3416a9c779f0c0dc6cf3ae942ff70fb6c806aa166dcBanavathu, Srinivas Naik                    null, Sms.DATE);
342800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
343627007213deb59ef938c80353c8f3598b01478b3Wei Huang        if (cursor == null)
344627007213deb59ef938c80353c8f3598b01478b3Wei Huang            return null;
345800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
346627007213deb59ef938c80353c8f3598b01478b3Wei Huang        try {
3476a9c779f0c0dc6cf3ae942ff70fb6c806aa166dcBanavathu, Srinivas Naik            if (!cursor.moveToLast())
348627007213deb59ef938c80353c8f3598b01478b3Wei Huang            return null;
349800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
350627007213deb59ef938c80353c8f3598b01478b3Wei Huang            String address = cursor.getString(COLUMN_SMS_ADDRESS);
351627007213deb59ef938c80353c8f3598b01478b3Wei Huang            long timeMillis = 3000;
352800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
353627007213deb59ef938c80353c8f3598b01478b3Wei Huang            return new MmsSmsDeliveryInfo(String.format(
354627007213deb59ef938c80353c8f3598b01478b3Wei Huang                context.getString(R.string.delivery_toast_body), address),
355627007213deb59ef938c80353c8f3598b01478b3Wei Huang                timeMillis);
356800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
357627007213deb59ef938c80353c8f3598b01478b3Wei Huang        } finally {
358627007213deb59ef938c80353c8f3598b01478b3Wei Huang            cursor.close();
359627007213deb59ef938c80353c8f3598b01478b3Wei Huang        }
360800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    }
361800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
3623b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor    private static final MmsSmsNotificationInfo getSmsNewMessageNotificationInfo(
363b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            Context context, Set<Long> threads) {
36472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        ContentResolver resolver = context.getContentResolver();
36572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor cursor = SqliteWrapper.query(context, resolver, Sms.CONTENT_URI,
36672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            SMS_STATUS_PROJECTION, NEW_INCOMING_SM_CONSTRAINT,
36772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            null, Sms.DATE + " desc");
36872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
369b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        if (cursor == null) {
370b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            return null;
371b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
3725a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
373b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        try {
374b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            if (!cursor.moveToFirst()) {
375b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                return null;
376b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            }
377b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
378b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            String address = cursor.getString(COLUMN_SMS_ADDRESS);
3791b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
3801b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor            Contact contact = Contact.get(address, false);
3811b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor            if (contact.getSendToVoicemail()) {
3821b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor                // don't notify
3831b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor                return null;
3841b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor            }
3851b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
386b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            String body = cursor.getString(COLUMN_SMS_BODY);
387b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            long threadId = cursor.getLong(COLUMN_THREAD_ID);
388b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            long timeMillis = cursor.getLong(COLUMN_DATE);
389b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
390d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor            if (Log.isLoggable(LogTag.APP, Log.VERBOSE))
391e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            {
392e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang                Log.d(TAG, "getSmsNewMessageNotificationInfo: count=" + cursor.getCount() +
393e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang                        ", first addr=" + address + ", thread_id=" + threadId);
394e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            }
395e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang
396b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            MmsSmsNotificationInfo info = getNewMessageNotificationInfo(
397b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    address, body, context, R.drawable.stat_notify_sms,
398b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    null, threadId, timeMillis, cursor.getCount());
399b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
400b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            threads.add(threadId);
401b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            while (cursor.moveToNext()) {
402b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                threads.add(cursor.getLong(COLUMN_THREAD_ID));
40372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
404b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
405b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            return info;
406b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        } finally {
407b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            cursor.close();
40872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
40972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
41072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
41172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final MmsSmsNotificationInfo getNewMessageNotificationInfo(
41272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String address,
41372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String body,
41472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Context context,
41572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            int iconResourceId,
41672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String subject,
41772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            long threadId,
41872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            long timeMillis,
41972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            int count) {
420812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang        Intent clickIntent = ComposeMessageActivity.createIntent(context, threadId);
421812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang        clickIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
422812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                | Intent.FLAG_ACTIVITY_SINGLE_TOP
423812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
42472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
42572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String senderInfo = buildTickerMessage(
42672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                context, address, null, null).toString();
42772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String senderInfoName = senderInfo.substring(
42872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                0, senderInfo.length() - 2);
42972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        CharSequence ticker = buildTickerMessage(
43072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                context, address, subject, body);
43172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
43272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return new MmsSmsNotificationInfo(
43372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                clickIntent, body, iconResourceId, ticker, timeMillis,
43472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                senderInfoName, count);
43572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
43672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
43772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void cancelNotification(Context context, int notificationId) {
43872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        NotificationManager nm = (NotificationManager) context.getSystemService(
43972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Context.NOTIFICATION_SERVICE);
44072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
44172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        nm.cancel(notificationId);
44272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
44372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
4445a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor    private static void updateDeliveryNotification(final Context context,
445c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor                                                   boolean isStatusMessage,
4465a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor                                                   final CharSequence message,
4475a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor                                                   final long timeMillis) {
448c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        if (!isStatusMessage) {
449c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            return;
450c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        }
451c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor
452800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
453d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor        if (!MessagingPreferenceActivity.getNotificationEnabled(context)) {
45470f5af8fd89d66ae246a805d10a50540746319aaWei Huang            return;
45570f5af8fd89d66ae246a805d10a50540746319aaWei Huang        }
456800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
457c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        mToastHandler.post(new Runnable() {
458c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            public void run() {
459c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor                Toast.makeText(context, message, (int)timeMillis).show();
460c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            }
461c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        });
462800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    }
463800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
46472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static void updateNotification(
46572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Context context,
46672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Intent clickIntent,
46772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String description,
46872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            int iconRes,
46972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            boolean isNew,
47072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            CharSequence ticker,
47172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            long timeMillis,
47272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String title,
473b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            int messageCount,
474b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            int uniqueThreadCount) {
475d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor        if (!MessagingPreferenceActivity.getNotificationEnabled(context)) {
47672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return;
47772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
47872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
479b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        Notification notification = new Notification(iconRes, ticker, timeMillis);
480b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
481b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // If we have more than one unique thread, change the title (which would
482b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // normally be the contact who sent the message) to a generic one that
483b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // makes sense for multiple senders, and change the Intent to take the
484b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // user to the conversation list instead of the specific thread.
485b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        if (uniqueThreadCount > 1) {
486b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            title = context.getString(R.string.notification_multiple_title);
487812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang            clickIntent = new Intent(Intent.ACTION_MAIN);
488812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang
489812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang            clickIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
490812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                    | Intent.FLAG_ACTIVITY_SINGLE_TOP
491812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
492812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang
493b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            clickIntent.setType("vnd.android-dir/mms-sms");
494b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
4955a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
496b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // If there is more than one message, change the description (which
497b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // would normally be a snippet of the individual message text) to
498627007213deb59ef938c80353c8f3598b01478b3Wei Huang        // a string indicating how many "unseen" messages there are.
499b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        if (messageCount > 1) {
500b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            description = context.getString(R.string.notification_multiple,
501b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    Integer.toString(messageCount));
502b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
50372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
504b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // Make a startActivity() PendingIntent for the notification.
505810fae756f4d2db00b35d7c9dfead252737abdacTom Taylor        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, clickIntent,
506810fae756f4d2db00b35d7c9dfead252737abdacTom Taylor                PendingIntent.FLAG_UPDATE_CURRENT);
50772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
508b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // Update the notification.
509b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        notification.setLatestEventInfo(context, title, description, pendingIntent);
51072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
51172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (isNew) {
512d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
513006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            String vibrateWhen;
514006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            if (sp.contains(MessagingPreferenceActivity.NOTIFICATION_VIBRATE_WHEN)) {
515006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                vibrateWhen =
516006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                    sp.getString(MessagingPreferenceActivity.NOTIFICATION_VIBRATE_WHEN, null);
517006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            } else if (sp.contains(MessagingPreferenceActivity.NOTIFICATION_VIBRATE)) {
518006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                vibrateWhen = sp.getBoolean(MessagingPreferenceActivity.NOTIFICATION_VIBRATE, false) ?
519006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                    context.getString(R.string.prefDefault_vibrate_true) :
520006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                    context.getString(R.string.prefDefault_vibrate_false);
521006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            } else {
522006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                vibrateWhen = context.getString(R.string.prefDefault_vibrateWhen);
523006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            }
524006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma
525006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            boolean vibrateAlways = vibrateWhen.equals("always");
526006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            boolean vibrateSilent = vibrateWhen.equals("silent");
527006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            AudioManager audioManager =
528006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
529006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            boolean nowSilent =
530006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
531006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma
532006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            if (vibrateAlways || vibrateSilent && nowSilent) {
53372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                notification.defaults |= Notification.DEFAULT_VIBRATE;
53472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
53572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
536627007213deb59ef938c80353c8f3598b01478b3Wei Huang            String ringtoneStr = sp.getString(MessagingPreferenceActivity.NOTIFICATION_RINGTONE,
537627007213deb59ef938c80353c8f3598b01478b3Wei Huang                    null);
53872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            notification.sound = TextUtils.isEmpty(ringtoneStr) ? null : Uri.parse(ringtoneStr);
53972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
54072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
54172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        notification.flags |= Notification.FLAG_SHOW_LIGHTS;
5425227290bbaefe2438cac9b3868a72a12a3339e83Mike Lockwood        notification.defaults |= Notification.DEFAULT_LIGHTS;
54372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
54470f5af8fd89d66ae246a805d10a50540746319aaWei Huang        // set up delete intent
54570f5af8fd89d66ae246a805d10a50540746319aaWei Huang        notification.deleteIntent = PendingIntent.getBroadcast(context, 0,
54670f5af8fd89d66ae246a805d10a50540746319aaWei Huang                sNotificationOnDeleteIntent, 0);
54770f5af8fd89d66ae246a805d10a50540746319aaWei Huang
54872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        NotificationManager nm = (NotificationManager)
54972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            context.getSystemService(Context.NOTIFICATION_SERVICE);
55072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
55172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        nm.notify(NOTIFICATION_ID, notification);
55272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
55372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
55472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    protected static CharSequence buildTickerMessage(
55572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Context context, String address, String subject, String body) {
55633a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrick        String displayAddress = Contact.get(address, true).getName();
5575a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
55872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        StringBuilder buf = new StringBuilder(
55972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                displayAddress == null
56072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                ? ""
56172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                : displayAddress.replace('\n', ' ').replace('\r', ' '));
56272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        buf.append(':').append(' ');
56372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
56472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int offset = buf.length();
56572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!TextUtils.isEmpty(subject)) {
56672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            subject = subject.replace('\n', ' ').replace('\r', ' ');
56772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            buf.append(subject);
56872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            buf.append(' ');
56972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
57072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
57172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!TextUtils.isEmpty(body)) {
57272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            body = body.replace('\n', ' ').replace('\r', ' ');
57372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            buf.append(body);
57472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
57572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
57672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        SpannableString spanText = new SpannableString(buf.toString());
57772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        spanText.setSpan(new StyleSpan(Typeface.BOLD), 0, offset,
57872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
57972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
58072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return spanText;
58172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
58272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
58372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static String getMmsSubject(String sub, int charset) {
58472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return TextUtils.isEmpty(sub) ? ""
58572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                : new EncodedStringValue(charset, PduPersister.getBytes(sub)).getString();
58672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
58772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
58872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void notifyDownloadFailed(Context context, long threadId) {
589b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        notifyFailed(context, true, threadId, false);
59072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
59172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
5925d2d0046ada7b53205e537d8675d32a8785e8d1dThe Android Open Source Project    public static void notifySendFailed(Context context) {
593b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        notifyFailed(context, false, 0, false);
59472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
59572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
596b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick    public static void notifySendFailed(Context context, boolean noisy) {
597b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        notifyFailed(context, false, 0, noisy);
598b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick    }
5995a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
600b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick    private static void notifyFailed(Context context, boolean isDownload, long threadId,
601b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick                                     boolean noisy) {
60272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // TODO factor out common code for creating notifications
603d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor        boolean enabled = MessagingPreferenceActivity.getNotificationEnabled(context);
60472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!enabled) {
60572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return;
60672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
60772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
60872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        NotificationManager nm = (NotificationManager)
60972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                context.getSystemService(Context.NOTIFICATION_SERVICE);
6105a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
61172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Strategy:
61272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // a. If there is a single failure notification, tapping on the notification goes
61372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        //    to the compose view.
6145a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor        // b. If there are two failure it stays in the thread view. Selecting one undelivered
61572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        //    thread will dismiss one undelivered notification but will still display the
61672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        //    notification.If you select the 2nd undelivered one it will dismiss the notification.
6175a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
6187015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        long[] msgThreadId = {0, 1};    // Dummy initial values, just to initialize the memory
61972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int totalFailedCount = getUndeliveredMessageCount(context, msgThreadId);
6207015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        if (totalFailedCount == 0 && !isDownload) {
6217015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev            return;
6227015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        }
6237015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // The getUndeliveredMessageCount method puts a non-zero value in msgThreadId[1] if all
6247015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // failures are from the same thread.
6257015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // If isDownload is true, we're dealing with 1 specific failure; therefore "all failed" are
6267015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // indeed in the same thread since there's only 1.
6277015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        boolean allFailedInSameThread = (msgThreadId[1] != 0) || isDownload;
6285a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
62972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Intent failedIntent;
63072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Notification notification = new Notification();
63172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String title;
63272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String description;
63372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (totalFailedCount > 1) {
63472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            description = context.getString(R.string.notification_failed_multiple,
63572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    Integer.toString(totalFailedCount));
63672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            title = context.getString(R.string.notification_failed_multiple_title);
63772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else {
63872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            title = isDownload ?
63972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        context.getString(R.string.message_download_failed_title) :
64072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        context.getString(R.string.message_send_failed_title);
6415a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
64272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            description = context.getString(R.string.message_failed_body);
6437015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        }
6447015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev
6457015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        if (allFailedInSameThread) {
646836945de572ac80fd6f6a7bf59036d4cce801410The Android Open Source Project            failedIntent = new Intent(context, ComposeMessageActivity.class);
64795817b166d415114bac89ca0946c3717ae229526Tom Taylor            if (isDownload) {
64895817b166d415114bac89ca0946c3717ae229526Tom Taylor                // When isDownload is true, the valid threadId is passed into this function.
64995817b166d415114bac89ca0946c3717ae229526Tom Taylor                failedIntent.putExtra("failed_download_flag", true);
65095817b166d415114bac89ca0946c3717ae229526Tom Taylor            } else {
6517015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev                threadId = msgThreadId[0];
65295817b166d415114bac89ca0946c3717ae229526Tom Taylor                failedIntent.putExtra("undelivered_flag", true);
6535a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor            }
6545a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor            failedIntent.putExtra("thread_id", threadId);
6557015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        } else {
6567015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev            failedIntent = new Intent(context, ConversationList.class);
65772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
65872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
659b92b26763e49fd9cc34d382dee4d764ef163bde5Ficus Kirkpatrick        failedIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
66072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        PendingIntent pendingIntent = PendingIntent.getActivity(
661810fae756f4d2db00b35d7c9dfead252737abdacTom Taylor                context, 0, failedIntent, PendingIntent.FLAG_UPDATE_CURRENT);
66272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
66372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        notification.icon = R.drawable.stat_notify_sms_failed;
66472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
66572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        notification.tickerText = title;
66672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
66772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        notification.setLatestEventInfo(context, title, description, pendingIntent);
66872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
669b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        if (noisy) {
670d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
671e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang            boolean vibrate = sp.getBoolean(MessagingPreferenceActivity.NOTIFICATION_VIBRATE,
672e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang                    false /* don't vibrate by default */);
673b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick            if (vibrate) {
674b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick                notification.defaults |= Notification.DEFAULT_VIBRATE;
675b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick            }
67672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
677e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang            String ringtoneStr = sp.getString(MessagingPreferenceActivity.NOTIFICATION_RINGTONE,
678e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang                    null);
679b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick            notification.sound = TextUtils.isEmpty(ringtoneStr) ? null : Uri.parse(ringtoneStr);
680b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        }
6815a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
68272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (isDownload) {
68372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            nm.notify(DOWNLOAD_FAILED_NOTIFICATION_ID, notification);
68472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else {
68572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            nm.notify(MESSAGE_FAILED_NOTIFICATION_ID, notification);
68672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
68772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
6885a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
6897015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev    /**
6907015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     * Query the DB and return the number of undelivered messages (total for both SMS and MMS)
6917015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     * @param context The context
6927015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     * @param threadIdResult A container to put the result in, according to the following rules:
6937015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  threadIdResult[0] contains the thread id of the first message.
6947015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  threadIdResult[1] is nonzero if the thread ids of all the messages are the same.
6957015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  You can pass in null for threadIdResult.
6967015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  You can pass in a threadIdResult of size 1 to avoid the comparison of each thread id.
6977015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     */
69872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static int getUndeliveredMessageCount(Context context, long[] threadIdResult) {
69972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor undeliveredCursor = SqliteWrapper.query(context, context.getContentResolver(),
70035a74a9e0ee7c171c6e17f0eda4b0df0253f8364Ficus Kirkpatrick                UNDELIVERED_URI, new String[] { Mms.THREAD_ID }, "read=0", null, null);
70172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (undeliveredCursor == null) {
70272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return 0;
70372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
70472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int count = undeliveredCursor.getCount();
70572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        try {
70672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (threadIdResult != null && undeliveredCursor.moveToFirst()) {
70772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                threadIdResult[0] = undeliveredCursor.getLong(0);
7085a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
7092f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                if (threadIdResult.length >= 2) {
7102f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    // Test to see if all the undelivered messages belong to the same thread.
7112f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    long firstId = threadIdResult[0];
7122f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    while (undeliveredCursor.moveToNext()) {
7132f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                        if (undeliveredCursor.getLong(0) != firstId) {
7142f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                            firstId = 0;
7152f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                            break;
7162f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                        }
7172f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    }
7182f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    threadIdResult[1] = firstId;    // non-zero if all ids are the same
7192f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                }
72072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
72172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } finally {
72272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            undeliveredCursor.close();
72372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
72472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return count;
72572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
72672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
72772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void updateSendFailedNotification(Context context) {
72872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (getUndeliveredMessageCount(context, null) < 1) {
72972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            cancelNotification(context, MESSAGE_FAILED_NOTIFICATION_ID);
7305d2d0046ada7b53205e537d8675d32a8785e8d1dThe Android Open Source Project        } else {
7315d2d0046ada7b53205e537d8675d32a8785e8d1dThe Android Open Source Project            notifySendFailed(context);      // rebuild and adjust the message count if necessary.
73272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
73372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
7345a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
7355a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor    /**
7362f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project     *  If all the undelivered messages belong to "threadId", cancel the notification.
7372f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project     */
7382f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project    public static void updateSendFailedNotificationForThread(Context context, long threadId) {
7392f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project        long[] msgThreadId = {0, 0};
7405a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor        if (getUndeliveredMessageCount(context, msgThreadId) > 0
7412f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                && msgThreadId[0] == threadId
7422f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                && msgThreadId[1] != 0) {
7432f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project            cancelNotification(context, MESSAGE_FAILED_NOTIFICATION_ID);
7442f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project        }
7452f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project    }
7465a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
74772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static int getDownloadFailedMessageCount(Context context) {
74872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Look for any messages in the MMS Inbox that are of the type
74972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // NOTIFICATION_IND (i.e. not already downloaded) and in the
75072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // permanent failure state.  If there are none, cancel any
75172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // failed download notification.
75272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor c = SqliteWrapper.query(context, context.getContentResolver(),
75372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Mms.Inbox.CONTENT_URI, null,
75472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Mms.MESSAGE_TYPE + "=" +
75572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    String.valueOf(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) +
75672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                " AND " + Mms.STATUS + "=" +
75772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    String.valueOf(DownloadManager.STATE_PERMANENT_FAILURE),
75872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                null, null);
75972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (c == null) {
76072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return 0;
76172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
76272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int count = c.getCount();
76372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        c.close();
76472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return count;
76572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
76672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
76772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void updateDownloadFailedNotification(Context context) {
76872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (getDownloadFailedMessageCount(context) < 1) {
76972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            cancelNotification(context, DOWNLOAD_FAILED_NOTIFICATION_ID);
77072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
77172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
7725a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
77395817b166d415114bac89ca0946c3717ae229526Tom Taylor    public static boolean isFailedToDeliver(Intent intent) {
77495817b166d415114bac89ca0946c3717ae229526Tom Taylor        return (intent != null) && intent.getBooleanExtra("undelivered_flag", false);
77595817b166d415114bac89ca0946c3717ae229526Tom Taylor    }
77695817b166d415114bac89ca0946c3717ae229526Tom Taylor
77795817b166d415114bac89ca0946c3717ae229526Tom Taylor    public static boolean isFailedToDownload(Intent intent) {
77895817b166d415114bac89ca0946c3717ae229526Tom Taylor        return (intent != null) && intent.getBooleanExtra("failed_download_flag", false);
77995817b166d415114bac89ca0946c3717ae229526Tom Taylor    }
78072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project}
781