MessagingNotification.java revision b0ef8fc2738b210a2bb0490e75eedc1e7b7b491f
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;
32c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.widget.MmsWidgetProvider;
3372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
34f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport com.google.android.mms.pdu.EncodedStringValue;
35f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport com.google.android.mms.pdu.PduHeaders;
36f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport com.google.android.mms.pdu.PduPersister;
37fd644551e8506266aad2b76463b51b44154ed62fTom Taylorimport android.database.sqlite.SqliteWrapper;
3872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
3972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.app.Notification;
4072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.app.NotificationManager;
4172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.app.PendingIntent;
421fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylorimport android.content.ComponentName;
4372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.ContentResolver;
4472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.Context;
4572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.Intent;
4672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.SharedPreferences;
4770f5af8fd89d66ae246a805d10a50540746319aaWei Huangimport android.content.BroadcastReceiver;
4870f5af8fd89d66ae246a805d10a50540746319aaWei Huangimport android.content.IntentFilter;
4972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.database.Cursor;
5072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.graphics.Typeface;
51006d49271549ed639ffcd70d94c7650bb3514796Jim Shumaimport android.media.AudioManager;
5272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.net.Uri;
53b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylorimport android.os.AsyncTask;
545a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylorimport android.os.Handler;
5572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.preference.PreferenceManager;
56f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.Mms;
57f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.Sms;
5872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.text.Spannable;
5972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.text.SpannableString;
6072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.text.TextUtils;
6172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.text.style.StyleSpan;
6272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.util.Log;
63800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERTimport android.widget.Toast;
6472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
6572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport java.util.Comparator;
66b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrickimport java.util.HashSet;
67b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrickimport java.util.Set;
6872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport java.util.SortedSet;
6972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport java.util.TreeSet;
7072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
7172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project/**
7272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * This class is used to update the notification indicator. It will check whether
7372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * there are unread messages. If yes, it would show the notification indicator,
7472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * otherwise, hide the indicator.
7572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project */
7672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectpublic class MessagingNotification {
77c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
78812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang    private static final String TAG = LogTag.APP;
7972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
8072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int NOTIFICATION_ID = 123;
8172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static final int MESSAGE_FAILED_NOTIFICATION_ID = 789;
8272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static final int DOWNLOAD_FAILED_NOTIFICATION_ID = 531;
83c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
84c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * This is the volume at which to play the in-conversation notification sound,
85c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * expressed as a fraction of the system notification volume.
86c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
87c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static final float IN_CONVERSATION_NOTIFICATION_VOLUME = 0.25f;
8872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
8972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // This must be consistent with the column constants below.
9072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String[] MMS_STATUS_PROJECTION = new String[] {
9172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Mms.THREAD_ID, Mms.DATE, Mms._ID, Mms.SUBJECT, Mms.SUBJECT_CHARSET };
9272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
9372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // This must be consistent with the column constants below.
9472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String[] SMS_STATUS_PROJECTION = new String[] {
9572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Sms.THREAD_ID, Sms.DATE, Sms.ADDRESS, Sms.SUBJECT, Sms.BODY };
9672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
9772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // These must be consistent with MMS_STATUS_PROJECTION and
9872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // SMS_STATUS_PROJECTION.
9972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_THREAD_ID   = 0;
10072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_DATE        = 1;
10172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_MMS_ID      = 2;
10272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SMS_ADDRESS = 2;
10372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SUBJECT     = 3;
10472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SUBJECT_CS  = 4;
10572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SMS_BODY    = 4;
10672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
107c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static final String[] SMS_THREAD_ID_PROJECTION = new String[] { Sms.THREAD_ID };
108c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static final String[] MMS_THREAD_ID_PROJECTION = new String[] { Mms.THREAD_ID };
109c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
11072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String NEW_INCOMING_SM_CONSTRAINT =
11172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            "(" + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_INBOX
112627007213deb59ef938c80353c8f3598b01478b3Wei Huang            + " AND " + Sms.SEEN + " = 0)";
11372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
114800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    private static final String NEW_DELIVERY_SM_CONSTRAINT =
115c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        "(" + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_SENT
116c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        + " AND " + Sms.STATUS + " = "+ Sms.STATUS_COMPLETE +")";
117800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
11872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String NEW_INCOMING_MM_CONSTRAINT =
11972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            "(" + Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_INBOX
120627007213deb59ef938c80353c8f3598b01478b3Wei Huang            + " AND " + Mms.SEEN + "=0"
12172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            + " AND (" + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_NOTIFICATION_IND
12272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            + " OR " + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_RETRIEVE_CONF + "))";
12372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
12472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final MmsSmsNotificationInfoComparator INFO_COMPARATOR =
12572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            new MmsSmsNotificationInfoComparator();
1265a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
12772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final Uri UNDELIVERED_URI = Uri.parse("content://mms-sms/undelivered");
12872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
12970f5af8fd89d66ae246a805d10a50540746319aaWei Huang
13070f5af8fd89d66ae246a805d10a50540746319aaWei Huang    private final static String NOTIFICATION_DELETED_ACTION =
13170f5af8fd89d66ae246a805d10a50540746319aaWei Huang            "com.android.mms.NOTIFICATION_DELETED_ACTION";
13270f5af8fd89d66ae246a805d10a50540746319aaWei Huang
13370f5af8fd89d66ae246a805d10a50540746319aaWei Huang    public static class OnDeletedReceiver extends BroadcastReceiver {
134c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        @Override
13570f5af8fd89d66ae246a805d10a50540746319aaWei Huang        public void onReceive(Context context, Intent intent) {
13670f5af8fd89d66ae246a805d10a50540746319aaWei Huang            if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
13770f5af8fd89d66ae246a805d10a50540746319aaWei Huang                Log.d(TAG, "[MessagingNotification] clear notification: mark all msgs seen");
13870f5af8fd89d66ae246a805d10a50540746319aaWei Huang            }
13970f5af8fd89d66ae246a805d10a50540746319aaWei Huang
14070f5af8fd89d66ae246a805d10a50540746319aaWei Huang            Conversation.markAllConversationsAsSeen(context);
14170f5af8fd89d66ae246a805d10a50540746319aaWei Huang        }
142c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
143c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
144c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static final long THREAD_ALL = -1;
145c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static final long THREAD_NONE = -2;
146c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
147c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Keeps track of the thread ID of the conversation that's currently displayed to the user
148c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
149c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static long sCurrentlyDisplayedThreadId;
150c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static final Object sCurrentlyDisplayedThreadLock = new Object();
151c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
15270f5af8fd89d66ae246a805d10a50540746319aaWei Huang    private static OnDeletedReceiver sNotificationDeletedReceiver = new OnDeletedReceiver();
15370f5af8fd89d66ae246a805d10a50540746319aaWei Huang    private static Intent sNotificationOnDeleteIntent;
1545a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor    private static Handler mToastHandler = new Handler();
15570f5af8fd89d66ae246a805d10a50540746319aaWei Huang
15672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private MessagingNotification() {
15772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
15872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
15970f5af8fd89d66ae246a805d10a50540746319aaWei Huang    public static void init(Context context) {
16070f5af8fd89d66ae246a805d10a50540746319aaWei Huang        // set up the intent filter for notification deleted action
16170f5af8fd89d66ae246a805d10a50540746319aaWei Huang        IntentFilter intentFilter = new IntentFilter();
16270f5af8fd89d66ae246a805d10a50540746319aaWei Huang        intentFilter.addAction(NOTIFICATION_DELETED_ACTION);
16370f5af8fd89d66ae246a805d10a50540746319aaWei Huang        context.registerReceiver(sNotificationDeletedReceiver, intentFilter);
16470f5af8fd89d66ae246a805d10a50540746319aaWei Huang
16570f5af8fd89d66ae246a805d10a50540746319aaWei Huang        // initialize the notification deleted action
16670f5af8fd89d66ae246a805d10a50540746319aaWei Huang        sNotificationOnDeleteIntent = new Intent(NOTIFICATION_DELETED_ACTION);
16770f5af8fd89d66ae246a805d10a50540746319aaWei Huang    }
16870f5af8fd89d66ae246a805d10a50540746319aaWei Huang
16972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    /**
170c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Specifies which message thread is currently being viewed by the user. New messages in that
171c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * thread will not generate a notification icon and will play the notification sound at a lower
172c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * volume. Make sure you set this to THREAD_NONE when the UI component that shows the thread is
173c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * no longer visible to the user (e.g. Activity.onPause(), etc.)
174c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param threadId The ID of the thread that the user is currently viewing. Pass THREAD_NONE
175c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     *  if the user is not viewing a thread, or THREAD_ALL if the user is viewing the conversation
176c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     *  list (note: that latter one has no effect as of this implementation)
177c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
178c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static void setCurrentlyDisplayedThreadId(long threadId) {
179c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        synchronized (sCurrentlyDisplayedThreadLock) {
180c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            sCurrentlyDisplayedThreadId = threadId;
181c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
182c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
183c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
184c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
185627007213deb59ef938c80353c8f3598b01478b3Wei Huang     * Checks to see if there are any "unseen" messages or delivery
18672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * reports.  Shows the most recent notification if there is one.
1873b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor     * Does its work and query in a worker thread.
18872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     *
18972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * @param context the context to use
19072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     */
1913b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor    public static void nonBlockingUpdateNewMessageIndicator(final Context context,
192c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            final long newMsgThreadId,
1933b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor            final boolean isStatusMessage) {
1943b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        new Thread(new Runnable() {
195c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            @Override
1963b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor            public void run() {
197c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                blockingUpdateNewMessageIndicator(context, newMsgThreadId, isStatusMessage);
1983b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor            }
199ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev        }, "MessagingNotification.nonBlockingUpdateNewMessageIndicator").start();
20072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
20172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
20272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    /**
203627007213deb59ef938c80353c8f3598b01478b3Wei Huang     * Checks to see if there are any "unseen" messages or delivery
20472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * reports.  Shows the most recent notification if there is one.
20572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     *
20672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * @param context the context to use
207c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param newMsgThreadId The thread ID of a new message that we're to notify about; if there's
208c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     *  no new message, use THREAD_NONE. If we should notify about multiple or unknown thread IDs,
209c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     *  use THREAD_ALL.
210c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param isStatusMessage
21172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     */
212c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static void blockingUpdateNewMessageIndicator(Context context, long newMsgThreadId,
213c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            boolean isStatusMessage) {
214c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        synchronized (sCurrentlyDisplayedThreadLock) {
215c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            if (newMsgThreadId > 0 && newMsgThreadId == sCurrentlyDisplayedThreadId) {
216c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                playInConversationNotificationSound(context);
217c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                return;
218c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            }
219c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
220c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
22172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        SortedSet<MmsSmsNotificationInfo> accumulator =
22272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                new TreeSet<MmsSmsNotificationInfo>(INFO_COMPARATOR);
223c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        MmsSmsDeliveryInfo delivery = null;
224b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        Set<Long> threads = new HashSet<Long>(4);
2255a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
22672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int count = 0;
22772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        count += accumulateNotificationInfo(
228b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                accumulator, getMmsNewMessageNotificationInfo(context, threads));
22972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        count += accumulateNotificationInfo(
230b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                accumulator, getSmsNewMessageNotificationInfo(context, threads));
23172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
23272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        cancelNotification(context, NOTIFICATION_ID);
23372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!accumulator.isEmpty()) {
234e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
235e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang                Log.d(TAG, "blockingUpdateNewMessageIndicator: count=" + count +
236c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                        ", newMsgThreadId=" + newMsgThreadId);
237e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            }
238c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            accumulator.first().deliver(context, newMsgThreadId != THREAD_NONE, count, threads.size());
23972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
2405a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
2413b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // And deals with delivery reports (which use Toasts). It's safe to call in a worker
2423b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // thread because the toast will eventually get posted to a handler.
243627007213deb59ef938c80353c8f3598b01478b3Wei Huang        delivery = getSmsNewDeliveryInfo(context);
244627007213deb59ef938c80353c8f3598b01478b3Wei Huang        if (delivery != null) {
245c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            delivery.deliver(context, isStatusMessage);
246627007213deb59ef938c80353c8f3598b01478b3Wei Huang        }
24772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
24872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
24972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    /**
250c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Play the in-conversation notification sound (it's the regular notification sound, but
251c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * played at half-volume
252c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
253c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static void playInConversationNotificationSound(Context context) {
254c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        final AudioManager audioManager =
255c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
256c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
257c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
258c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        String ringtoneStr = sp.getString(MessagingPreferenceActivity.NOTIFICATION_RINGTONE,
259c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                null);
260c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        if (TextUtils.isEmpty(ringtoneStr)) {
261c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            // Nothing to play
262c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            return;
263c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
264c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        Uri ringtoneUri = Uri.parse(ringtoneStr);
265c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        NotificationPlayer player = new NotificationPlayer(LogTag.APP);
266c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        player.play(context, ringtoneUri, false, AudioManager.STREAM_NOTIFICATION,
267c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                IN_CONVERSATION_NOTIFICATION_VOLUME);
268c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
269c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
270c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
27135a74a9e0ee7c171c6e17f0eda4b0df0253f8364Ficus Kirkpatrick     * Updates all pending notifications, clearing or updating them as
2723b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor     * necessary.
27335a74a9e0ee7c171c6e17f0eda4b0df0253f8364Ficus Kirkpatrick     */
274627007213deb59ef938c80353c8f3598b01478b3Wei Huang    public static void blockingUpdateAllNotifications(final Context context) {
275c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        nonBlockingUpdateNewMessageIndicator(context, THREAD_NONE, false);
276b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor        nonBlockingUpdateSendFailedNotification(context);
277627007213deb59ef938c80353c8f3598b01478b3Wei Huang        updateDownloadFailedNotification(context);
278c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor        MmsWidgetProvider.notifyDatasetChanged(context);
27935a74a9e0ee7c171c6e17f0eda4b0df0253f8364Ficus Kirkpatrick    }
2805a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
28172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int accumulateNotificationInfo(
282c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            SortedSet<MmsSmsNotificationInfo> set, MmsSmsNotificationInfo info) {
28372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (info != null) {
28472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            set.add(info);
28572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
28672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return info.mCount;
28772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
28872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
28972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return 0;
29072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
29172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
292800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    private static final class MmsSmsDeliveryInfo {
293c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public CharSequence mTicker;
294c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public long mTimeMillis;
295c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor
296c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public MmsSmsDeliveryInfo(CharSequence ticker, long timeMillis) {
297c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            mTicker = ticker;
298c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            mTimeMillis = timeMillis;
299c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        }
300c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor
301c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public void deliver(Context context, boolean isStatusMessage) {
302c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            updateDeliveryNotification(
303c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor                    context, isStatusMessage, mTicker, mTimeMillis);
304c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        }
305800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    }
306800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
30772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final class MmsSmsNotificationInfo {
308c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final Intent mClickIntent;
309c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final String mDescription;
310c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final int mIconResourceId;
311c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final CharSequence mTicker;
312c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final long mTimeMillis;
313c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final String mTitle;
314c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final int mCount;
31572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
31672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public MmsSmsNotificationInfo(
31772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Intent clickIntent, String description, int iconResourceId,
31872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                CharSequence ticker, long timeMillis, String title, int count) {
31972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mClickIntent = clickIntent;
32072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mDescription = description;
32172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mIconResourceId = iconResourceId;
32272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mTicker = ticker;
32372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mTimeMillis = timeMillis;
32472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mTitle = title;
32572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mCount = count;
32672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
32772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
328b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        public void deliver(Context context, boolean isNew, int count, int uniqueThreads) {
32972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            updateNotification(
3303c68b6852913222dd982dddd4e39b3e57613c37eWei Huang                    context, mClickIntent, mDescription, mIconResourceId, isNew,
3313c68b6852913222dd982dddd4e39b3e57613c37eWei Huang                    (isNew? mTicker : null), // only display the ticker if the message is new
3323c68b6852913222dd982dddd4e39b3e57613c37eWei Huang                    mTimeMillis, mTitle, count, uniqueThreads);
33372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
33472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
33572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public long getTime() {
33672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return mTimeMillis;
33772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
33872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
33972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
34072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final class MmsSmsNotificationInfoComparator
34172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            implements Comparator<MmsSmsNotificationInfo> {
342c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        @Override
34372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public int compare(
34472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                MmsSmsNotificationInfo info1, MmsSmsNotificationInfo info2) {
34572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return Long.signum(info2.getTime() - info1.getTime());
34672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
34772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
34872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
3493b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor    private static final MmsSmsNotificationInfo getMmsNewMessageNotificationInfo(
350b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            Context context, Set<Long> threads) {
35172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        ContentResolver resolver = context.getContentResolver();
3523b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor
3533b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // This query looks like this when logged:
3543b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // I/Database(  147): elapsedTime4Sql|/data/data/com.android.providers.telephony/databases/
3553b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // mmssms.db|0.362 ms|SELECT thread_id, date, _id, sub, sub_cs FROM pdu WHERE ((msg_box=1
3563b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // AND seen=0 AND (m_type=130 OR m_type=132))) ORDER BY date desc
3573b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor
35872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor cursor = SqliteWrapper.query(context, resolver, Mms.CONTENT_URI,
35972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            MMS_STATUS_PROJECTION, NEW_INCOMING_MM_CONSTRAINT,
36072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            null, Mms.DATE + " desc");
36172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
362b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        if (cursor == null) {
363b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            return null;
364b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
3655a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
366b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        try {
367b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            if (!cursor.moveToFirst()) {
368b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                return null;
36972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
370c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
371b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            long msgId = cursor.getLong(COLUMN_MMS_ID);
372b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            Uri msgUri = Mms.CONTENT_URI.buildUpon().appendPath(
373b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    Long.toString(msgId)).build();
374b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            String address = AddressUtils.getFrom(context, msgUri);
3751b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
3761b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor            Contact contact = Contact.get(address, false);
3771b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor            if (contact.getSendToVoicemail()) {
3781b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor                // don't notify
3791b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor                return null;
3801b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor            }
3811b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
382b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            String subject = getMmsSubject(
383b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    cursor.getString(COLUMN_SUBJECT), cursor.getInt(COLUMN_SUBJECT_CS));
384b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            long threadId = cursor.getLong(COLUMN_THREAD_ID);
385b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            long timeMillis = cursor.getLong(COLUMN_DATE) * 1000;
386b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
387e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
388e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang                Log.d(TAG, "getMmsNewMessageNotificationInfo: count=" + cursor.getCount() +
389e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang                        ", first addr = " + address + ", thread_id=" + threadId);
390e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            }
391e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang
392b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            MmsSmsNotificationInfo info = getNewMessageNotificationInfo(
393b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    address, subject, context,
394b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    R.drawable.stat_notify_mms, null, threadId,
395b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    timeMillis, cursor.getCount());
396b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
397b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            threads.add(threadId);
398b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            while (cursor.moveToNext()) {
399b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                threads.add(cursor.getLong(COLUMN_THREAD_ID));
400b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            }
401b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
402b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            return info;
403b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        } finally {
404b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            cursor.close();
40572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
40672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
40772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
4083b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor    private static final MmsSmsDeliveryInfo getSmsNewDeliveryInfo(Context context) {
409627007213deb59ef938c80353c8f3598b01478b3Wei Huang        ContentResolver resolver = context.getContentResolver();
410627007213deb59ef938c80353c8f3598b01478b3Wei Huang        Cursor cursor = SqliteWrapper.query(context, resolver, Sms.CONTENT_URI,
411627007213deb59ef938c80353c8f3598b01478b3Wei Huang                    SMS_STATUS_PROJECTION, NEW_DELIVERY_SM_CONSTRAINT,
4126a9c779f0c0dc6cf3ae942ff70fb6c806aa166dcBanavathu, Srinivas Naik                    null, Sms.DATE);
413800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
414ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom        if (cursor == null) {
415627007213deb59ef938c80353c8f3598b01478b3Wei Huang            return null;
416ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom        }
417800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
418627007213deb59ef938c80353c8f3598b01478b3Wei Huang        try {
419ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            if (!cursor.moveToLast()) {
420ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom                return null;
421ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            }
422800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
423627007213deb59ef938c80353c8f3598b01478b3Wei Huang            String address = cursor.getString(COLUMN_SMS_ADDRESS);
424627007213deb59ef938c80353c8f3598b01478b3Wei Huang            long timeMillis = 3000;
425800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
426ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            Contact contact = Contact.get(address, false);
427ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            String name = contact.getNameAndNumber();
428ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom
429ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            return new MmsSmsDeliveryInfo(context.getString(R.string.delivery_toast_body, name),
430627007213deb59ef938c80353c8f3598b01478b3Wei Huang                timeMillis);
431800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
432627007213deb59ef938c80353c8f3598b01478b3Wei Huang        } finally {
433627007213deb59ef938c80353c8f3598b01478b3Wei Huang            cursor.close();
434627007213deb59ef938c80353c8f3598b01478b3Wei Huang        }
435800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    }
436800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
4373b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor    private static final MmsSmsNotificationInfo getSmsNewMessageNotificationInfo(
438b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            Context context, Set<Long> threads) {
43972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        ContentResolver resolver = context.getContentResolver();
44072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor cursor = SqliteWrapper.query(context, resolver, Sms.CONTENT_URI,
44172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            SMS_STATUS_PROJECTION, NEW_INCOMING_SM_CONSTRAINT,
44272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            null, Sms.DATE + " desc");
44372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
444b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        if (cursor == null) {
445b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            return null;
446b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
4475a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
448b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        try {
449b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            if (!cursor.moveToFirst()) {
450b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                return null;
451b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            }
452b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
453b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            String address = cursor.getString(COLUMN_SMS_ADDRESS);
4541b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
4551b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor            Contact contact = Contact.get(address, false);
4561b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor            if (contact.getSendToVoicemail()) {
4571b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor                // don't notify
4581b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor                return null;
4591b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor            }
4601b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
461b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            String body = cursor.getString(COLUMN_SMS_BODY);
462b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            long threadId = cursor.getLong(COLUMN_THREAD_ID);
463b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            long timeMillis = cursor.getLong(COLUMN_DATE);
464b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
465d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor            if (Log.isLoggable(LogTag.APP, Log.VERBOSE))
466e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            {
467e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang                Log.d(TAG, "getSmsNewMessageNotificationInfo: count=" + cursor.getCount() +
468e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang                        ", first addr=" + address + ", thread_id=" + threadId);
469e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            }
470e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang
471b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            MmsSmsNotificationInfo info = getNewMessageNotificationInfo(
472b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    address, body, context, R.drawable.stat_notify_sms,
473b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    null, threadId, timeMillis, cursor.getCount());
474b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
475b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            threads.add(threadId);
476b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            while (cursor.moveToNext()) {
477b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                threads.add(cursor.getLong(COLUMN_THREAD_ID));
47872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
479b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
480b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            return info;
481b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        } finally {
482b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            cursor.close();
48372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
48472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
48572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
48672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final MmsSmsNotificationInfo getNewMessageNotificationInfo(
48772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String address,
48872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String body,
48972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Context context,
49072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            int iconResourceId,
49172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String subject,
49272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            long threadId,
49372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            long timeMillis,
49472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            int count) {
495812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang        Intent clickIntent = ComposeMessageActivity.createIntent(context, threadId);
496812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang        clickIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
497812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                | Intent.FLAG_ACTIVITY_SINGLE_TOP
498812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
49972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
50072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String senderInfo = buildTickerMessage(
50172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                context, address, null, null).toString();
50272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String senderInfoName = senderInfo.substring(
50372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                0, senderInfo.length() - 2);
50472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        CharSequence ticker = buildTickerMessage(
50572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                context, address, subject, body);
50672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
50772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return new MmsSmsNotificationInfo(
50872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                clickIntent, body, iconResourceId, ticker, timeMillis,
50972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                senderInfoName, count);
51072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
51172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
51272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void cancelNotification(Context context, int notificationId) {
51372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        NotificationManager nm = (NotificationManager) context.getSystemService(
51472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Context.NOTIFICATION_SERVICE);
51572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
51672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        nm.cancel(notificationId);
51772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
51872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
5195a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor    private static void updateDeliveryNotification(final Context context,
520c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor                                                   boolean isStatusMessage,
5215a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor                                                   final CharSequence message,
5225a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor                                                   final long timeMillis) {
523c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        if (!isStatusMessage) {
524c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            return;
525c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        }
526c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor
527800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
528d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor        if (!MessagingPreferenceActivity.getNotificationEnabled(context)) {
52970f5af8fd89d66ae246a805d10a50540746319aaWei Huang            return;
53070f5af8fd89d66ae246a805d10a50540746319aaWei Huang        }
531800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
532c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        mToastHandler.post(new Runnable() {
533c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            @Override
534c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            public void run() {
535c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor                Toast.makeText(context, message, (int)timeMillis).show();
536c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            }
537c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        });
538800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    }
539800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
54072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static void updateNotification(
54172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Context context,
54272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Intent clickIntent,
54372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String description,
54472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            int iconRes,
54572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            boolean isNew,
54672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            CharSequence ticker,
54772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            long timeMillis,
54872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String title,
549b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            int messageCount,
550b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            int uniqueThreadCount) {
551d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor        if (!MessagingPreferenceActivity.getNotificationEnabled(context)) {
55272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return;
55372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
55472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
555b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        Notification notification = new Notification(iconRes, ticker, timeMillis);
5561fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor        Intent[] intents;
557b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
558b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // If we have more than one unique thread, change the title (which would
559b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // normally be the contact who sent the message) to a generic one that
560b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // makes sense for multiple senders, and change the Intent to take the
561b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // user to the conversation list instead of the specific thread.
562b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        if (uniqueThreadCount > 1) {
563b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            title = context.getString(R.string.notification_multiple_title);
5641fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            Intent mainActivityIntent = new Intent(Intent.ACTION_MAIN);
565812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang
5661fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            mainActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
567812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                    | Intent.FLAG_ACTIVITY_SINGLE_TOP
568812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
569812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang
5701fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            mainActivityIntent.setType("vnd.android-dir/mms-sms");
5711fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            intents = new Intent[1];
5721fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            intents[0] = mainActivityIntent;
5731fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor        } else {
5741fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            // Build a stack of intents so when the user hits back from the ComposeMessageActivity
5751fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            // we're sending them to, they'll up on ConversationList.
5761fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            intents = new Intent[2];
5771fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor
5781fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            // First: root activity of the MessagingApp: ConversationList.
5791fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            // This is a convenient way to make the proper Intent to launch and
5801fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            // reset an application's task.
5811fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            intents[0] = Intent.makeRestartActivityTask(new ComponentName(context,
5821fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor                    ConversationList.class));
5831fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            intents[1] = clickIntent;
584b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
5855a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
586b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // If there is more than one message, change the description (which
587b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // would normally be a snippet of the individual message text) to
588627007213deb59ef938c80353c8f3598b01478b3Wei Huang        // a string indicating how many "unseen" messages there are.
589b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        if (messageCount > 1) {
590b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            description = context.getString(R.string.notification_multiple,
591b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                    Integer.toString(messageCount));
592b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
59372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
594b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // Make a startActivity() PendingIntent for the notification.
5951fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor        PendingIntent pendingIntent = PendingIntent.getActivities(context, 0, intents,
596810fae756f4d2db00b35d7c9dfead252737abdacTom Taylor                PendingIntent.FLAG_UPDATE_CURRENT);
59772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
598b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // Update the notification.
599b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        notification.setLatestEventInfo(context, title, description, pendingIntent);
60072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
60172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (isNew) {
602d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
603006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            String vibrateWhen;
604006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            if (sp.contains(MessagingPreferenceActivity.NOTIFICATION_VIBRATE_WHEN)) {
605006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                vibrateWhen =
606006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                    sp.getString(MessagingPreferenceActivity.NOTIFICATION_VIBRATE_WHEN, null);
607006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            } else if (sp.contains(MessagingPreferenceActivity.NOTIFICATION_VIBRATE)) {
608006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                vibrateWhen = sp.getBoolean(MessagingPreferenceActivity.NOTIFICATION_VIBRATE, false) ?
609006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                    context.getString(R.string.prefDefault_vibrate_true) :
610006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                    context.getString(R.string.prefDefault_vibrate_false);
611006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            } else {
612006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                vibrateWhen = context.getString(R.string.prefDefault_vibrateWhen);
613006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            }
614006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma
615006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            boolean vibrateAlways = vibrateWhen.equals("always");
616006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            boolean vibrateSilent = vibrateWhen.equals("silent");
617006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            AudioManager audioManager =
618006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
619006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            boolean nowSilent =
620006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
621006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma
622006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            if (vibrateAlways || vibrateSilent && nowSilent) {
62372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                notification.defaults |= Notification.DEFAULT_VIBRATE;
62472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
62572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
626627007213deb59ef938c80353c8f3598b01478b3Wei Huang            String ringtoneStr = sp.getString(MessagingPreferenceActivity.NOTIFICATION_RINGTONE,
627627007213deb59ef938c80353c8f3598b01478b3Wei Huang                    null);
62872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            notification.sound = TextUtils.isEmpty(ringtoneStr) ? null : Uri.parse(ringtoneStr);
62972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
63072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
63172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        notification.flags |= Notification.FLAG_SHOW_LIGHTS;
6325227290bbaefe2438cac9b3868a72a12a3339e83Mike Lockwood        notification.defaults |= Notification.DEFAULT_LIGHTS;
63372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
63470f5af8fd89d66ae246a805d10a50540746319aaWei Huang        // set up delete intent
63570f5af8fd89d66ae246a805d10a50540746319aaWei Huang        notification.deleteIntent = PendingIntent.getBroadcast(context, 0,
63670f5af8fd89d66ae246a805d10a50540746319aaWei Huang                sNotificationOnDeleteIntent, 0);
63770f5af8fd89d66ae246a805d10a50540746319aaWei Huang
63872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        NotificationManager nm = (NotificationManager)
63972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            context.getSystemService(Context.NOTIFICATION_SERVICE);
64072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
64172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        nm.notify(NOTIFICATION_ID, notification);
64272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
64372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
64472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    protected static CharSequence buildTickerMessage(
64572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Context context, String address, String subject, String body) {
64633a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrick        String displayAddress = Contact.get(address, true).getName();
6475a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
64872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        StringBuilder buf = new StringBuilder(
64972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                displayAddress == null
65072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                ? ""
65172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                : displayAddress.replace('\n', ' ').replace('\r', ' '));
65272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        buf.append(':').append(' ');
65372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
65472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int offset = buf.length();
65572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!TextUtils.isEmpty(subject)) {
65672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            subject = subject.replace('\n', ' ').replace('\r', ' ');
65772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            buf.append(subject);
65872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            buf.append(' ');
65972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
66072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
66172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!TextUtils.isEmpty(body)) {
66272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            body = body.replace('\n', ' ').replace('\r', ' ');
66372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            buf.append(body);
66472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
66572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
66672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        SpannableString spanText = new SpannableString(buf.toString());
66772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        spanText.setSpan(new StyleSpan(Typeface.BOLD), 0, offset,
66872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
66972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
67072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return spanText;
67172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
67272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
67372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static String getMmsSubject(String sub, int charset) {
67472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return TextUtils.isEmpty(sub) ? ""
67572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                : new EncodedStringValue(charset, PduPersister.getBytes(sub)).getString();
67672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
67772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
67872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void notifyDownloadFailed(Context context, long threadId) {
679b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        notifyFailed(context, true, threadId, false);
68072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
68172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
6825d2d0046ada7b53205e537d8675d32a8785e8d1dThe Android Open Source Project    public static void notifySendFailed(Context context) {
683b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        notifyFailed(context, false, 0, false);
68472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
68572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
686b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick    public static void notifySendFailed(Context context, boolean noisy) {
687b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        notifyFailed(context, false, 0, noisy);
688b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick    }
6895a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
690b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick    private static void notifyFailed(Context context, boolean isDownload, long threadId,
691b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick                                     boolean noisy) {
69272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // TODO factor out common code for creating notifications
693d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor        boolean enabled = MessagingPreferenceActivity.getNotificationEnabled(context);
69472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!enabled) {
69572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return;
69672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
69772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
69872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        NotificationManager nm = (NotificationManager)
69972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                context.getSystemService(Context.NOTIFICATION_SERVICE);
7005a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
70172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Strategy:
70272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // a. If there is a single failure notification, tapping on the notification goes
70372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        //    to the compose view.
7045a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor        // b. If there are two failure it stays in the thread view. Selecting one undelivered
70572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        //    thread will dismiss one undelivered notification but will still display the
70672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        //    notification.If you select the 2nd undelivered one it will dismiss the notification.
7075a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
7087015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        long[] msgThreadId = {0, 1};    // Dummy initial values, just to initialize the memory
70972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int totalFailedCount = getUndeliveredMessageCount(context, msgThreadId);
7107015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        if (totalFailedCount == 0 && !isDownload) {
7117015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev            return;
7127015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        }
7137015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // The getUndeliveredMessageCount method puts a non-zero value in msgThreadId[1] if all
7147015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // failures are from the same thread.
7157015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // If isDownload is true, we're dealing with 1 specific failure; therefore "all failed" are
7167015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // indeed in the same thread since there's only 1.
7177015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        boolean allFailedInSameThread = (msgThreadId[1] != 0) || isDownload;
7185a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
71972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Intent failedIntent;
72072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Notification notification = new Notification();
72172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String title;
72272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String description;
72372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (totalFailedCount > 1) {
72472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            description = context.getString(R.string.notification_failed_multiple,
72572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    Integer.toString(totalFailedCount));
72672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            title = context.getString(R.string.notification_failed_multiple_title);
72772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else {
72872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            title = isDownload ?
72972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        context.getString(R.string.message_download_failed_title) :
73072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        context.getString(R.string.message_send_failed_title);
7315a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
73272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            description = context.getString(R.string.message_failed_body);
7337015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        }
7347015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev
7357015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        if (allFailedInSameThread) {
736836945de572ac80fd6f6a7bf59036d4cce801410The Android Open Source Project            failedIntent = new Intent(context, ComposeMessageActivity.class);
73795817b166d415114bac89ca0946c3717ae229526Tom Taylor            if (isDownload) {
73895817b166d415114bac89ca0946c3717ae229526Tom Taylor                // When isDownload is true, the valid threadId is passed into this function.
73995817b166d415114bac89ca0946c3717ae229526Tom Taylor                failedIntent.putExtra("failed_download_flag", true);
74095817b166d415114bac89ca0946c3717ae229526Tom Taylor            } else {
7417015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev                threadId = msgThreadId[0];
74295817b166d415114bac89ca0946c3717ae229526Tom Taylor                failedIntent.putExtra("undelivered_flag", true);
7435a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor            }
7445a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor            failedIntent.putExtra("thread_id", threadId);
7457015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        } else {
7467015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev            failedIntent = new Intent(context, ConversationList.class);
74772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
74872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
749b92b26763e49fd9cc34d382dee4d764ef163bde5Ficus Kirkpatrick        failedIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
75072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        PendingIntent pendingIntent = PendingIntent.getActivity(
751810fae756f4d2db00b35d7c9dfead252737abdacTom Taylor                context, 0, failedIntent, PendingIntent.FLAG_UPDATE_CURRENT);
75272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
75372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        notification.icon = R.drawable.stat_notify_sms_failed;
75472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
75572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        notification.tickerText = title;
75672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
75772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        notification.setLatestEventInfo(context, title, description, pendingIntent);
75872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
759b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        if (noisy) {
760d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
761e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang            boolean vibrate = sp.getBoolean(MessagingPreferenceActivity.NOTIFICATION_VIBRATE,
762e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang                    false /* don't vibrate by default */);
763b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick            if (vibrate) {
764b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick                notification.defaults |= Notification.DEFAULT_VIBRATE;
765b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick            }
76672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
767e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang            String ringtoneStr = sp.getString(MessagingPreferenceActivity.NOTIFICATION_RINGTONE,
768e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang                    null);
769b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick            notification.sound = TextUtils.isEmpty(ringtoneStr) ? null : Uri.parse(ringtoneStr);
770b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        }
7715a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
77272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (isDownload) {
77372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            nm.notify(DOWNLOAD_FAILED_NOTIFICATION_ID, notification);
77472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else {
77572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            nm.notify(MESSAGE_FAILED_NOTIFICATION_ID, notification);
77672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
77772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
7785a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
7797015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev    /**
7807015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     * Query the DB and return the number of undelivered messages (total for both SMS and MMS)
7817015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     * @param context The context
7827015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     * @param threadIdResult A container to put the result in, according to the following rules:
7837015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  threadIdResult[0] contains the thread id of the first message.
7847015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  threadIdResult[1] is nonzero if the thread ids of all the messages are the same.
7857015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  You can pass in null for threadIdResult.
7867015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  You can pass in a threadIdResult of size 1 to avoid the comparison of each thread id.
7877015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     */
78872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static int getUndeliveredMessageCount(Context context, long[] threadIdResult) {
78972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor undeliveredCursor = SqliteWrapper.query(context, context.getContentResolver(),
790c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                UNDELIVERED_URI, MMS_THREAD_ID_PROJECTION, "read=0", null, null);
79172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (undeliveredCursor == null) {
79272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return 0;
79372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
79472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int count = undeliveredCursor.getCount();
79572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        try {
79672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (threadIdResult != null && undeliveredCursor.moveToFirst()) {
79772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                threadIdResult[0] = undeliveredCursor.getLong(0);
7985a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
7992f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                if (threadIdResult.length >= 2) {
8002f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    // Test to see if all the undelivered messages belong to the same thread.
8012f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    long firstId = threadIdResult[0];
8022f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    while (undeliveredCursor.moveToNext()) {
8032f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                        if (undeliveredCursor.getLong(0) != firstId) {
8042f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                            firstId = 0;
8052f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                            break;
8062f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                        }
8072f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    }
8082f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    threadIdResult[1] = firstId;    // non-zero if all ids are the same
8092f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                }
81072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
81172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } finally {
81272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            undeliveredCursor.close();
81372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
81472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return count;
81572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
81672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
817b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor    public static void nonBlockingUpdateSendFailedNotification(final Context context) {
818b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor        new AsyncTask<Void, Void, Integer>() {
819b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor            protected Integer doInBackground(Void... none) {
820b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                return getUndeliveredMessageCount(context, null);
821b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor            }
822b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor
823b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor            protected void onPostExecute(Integer result) {
824b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                if (result < 1) {
825b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                    cancelNotification(context, MESSAGE_FAILED_NOTIFICATION_ID);
826b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                } else {
827b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                    // rebuild and adjust the message count if necessary.
828b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                    notifySendFailed(context);
829b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                }
830b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor            }
831b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor        }.execute();
83272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
8335a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
8345a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor    /**
8352f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project     *  If all the undelivered messages belong to "threadId", cancel the notification.
8362f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project     */
8372f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project    public static void updateSendFailedNotificationForThread(Context context, long threadId) {
8382f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project        long[] msgThreadId = {0, 0};
8395a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor        if (getUndeliveredMessageCount(context, msgThreadId) > 0
8402f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                && msgThreadId[0] == threadId
8412f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                && msgThreadId[1] != 0) {
8422f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project            cancelNotification(context, MESSAGE_FAILED_NOTIFICATION_ID);
8432f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project        }
8442f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project    }
8455a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
84672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static int getDownloadFailedMessageCount(Context context) {
84772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Look for any messages in the MMS Inbox that are of the type
84872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // NOTIFICATION_IND (i.e. not already downloaded) and in the
84972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // permanent failure state.  If there are none, cancel any
85072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // failed download notification.
85172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor c = SqliteWrapper.query(context, context.getContentResolver(),
85272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Mms.Inbox.CONTENT_URI, null,
85372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Mms.MESSAGE_TYPE + "=" +
85472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    String.valueOf(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) +
85572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                " AND " + Mms.STATUS + "=" +
85672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    String.valueOf(DownloadManager.STATE_PERMANENT_FAILURE),
85772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                null, null);
85872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (c == null) {
85972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return 0;
86072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
86172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int count = c.getCount();
86272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        c.close();
86372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return count;
86472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
86572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
86672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void updateDownloadFailedNotification(Context context) {
86772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (getDownloadFailedMessageCount(context) < 1) {
86872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            cancelNotification(context, DOWNLOAD_FAILED_NOTIFICATION_ID);
86972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
87072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
8715a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
87295817b166d415114bac89ca0946c3717ae229526Tom Taylor    public static boolean isFailedToDeliver(Intent intent) {
87395817b166d415114bac89ca0946c3717ae229526Tom Taylor        return (intent != null) && intent.getBooleanExtra("undelivered_flag", false);
87495817b166d415114bac89ca0946c3717ae229526Tom Taylor    }
87595817b166d415114bac89ca0946c3717ae229526Tom Taylor
87695817b166d415114bac89ca0946c3717ae229526Tom Taylor    public static boolean isFailedToDownload(Intent intent) {
87795817b166d415114bac89ca0946c3717ae229526Tom Taylor        return (intent != null) && intent.getBooleanExtra("failed_download_flag", false);
87895817b166d415114bac89ca0946c3717ae229526Tom Taylor    }
879c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
880c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
881c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Get the thread ID of the SMS message with the given URI
882c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param context The context
883c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param uri The URI of the SMS message
884c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @return The thread ID, or THREAD_NONE if the URI contains no entries
885c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
886c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static long getSmsThreadId(Context context, Uri uri) {
887c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        Cursor cursor = SqliteWrapper.query(
888c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            context,
889c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            context.getContentResolver(),
890c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            uri,
891c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            SMS_THREAD_ID_PROJECTION,
892c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            null,
893c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            null,
894c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            null);
895c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
896c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        if (cursor == null) {
897c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            return THREAD_NONE;
898c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
899c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
900c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        try {
901c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            if (cursor.moveToFirst()) {
902c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                return cursor.getLong(cursor.getColumnIndex(Sms.THREAD_ID));
903c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            } else {
904c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                return THREAD_NONE;
905c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            }
906c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        } finally {
907c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            cursor.close();
908c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
909c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
910c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
911c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
912c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Get the thread ID of the MMS message with the given URI
913c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param context The context
914c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param uri The URI of the SMS message
915c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @return The thread ID, or THREAD_NONE if the URI contains no entries
916c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
917c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static long getThreadId(Context context, Uri uri) {
918c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        Cursor cursor = SqliteWrapper.query(
919c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                context,
920c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                context.getContentResolver(),
921c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                uri,
922c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                MMS_THREAD_ID_PROJECTION,
923c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                null,
924c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                null,
925c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                null);
926c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
927c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        if (cursor == null) {
928c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            return THREAD_NONE;
929c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
930c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
931c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        try {
932c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            if (cursor.moveToFirst()) {
933c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                return cursor.getLong(cursor.getColumnIndex(Mms.THREAD_ID));
934c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            } else {
935c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                return THREAD_NONE;
936c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            }
937c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        } finally {
938c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            cursor.close();
939c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
940c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
94172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project}
942