MessagingNotification.java revision 2d65e7eb956e60c058de876ddbfff504620ce7a3
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
23d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport java.util.ArrayList;
24d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport java.util.Comparator;
25d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport java.util.HashSet;
26d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport java.util.Iterator;
27d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport java.util.Set;
28d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport java.util.SortedSet;
29d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport java.util.TreeSet;
3072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
3172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.app.Notification;
3272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.app.NotificationManager;
3372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.app.PendingIntent;
346cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylorimport android.app.TaskStackBuilder;
35d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport android.content.BroadcastReceiver;
3672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.ContentResolver;
3772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.Context;
3872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.Intent;
3970f5af8fd89d66ae246a805d10a50540746319aaWei Huangimport android.content.IntentFilter;
40d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport android.content.SharedPreferences;
41ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylorimport android.content.res.Resources;
4272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.database.Cursor;
43d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport android.database.sqlite.SqliteWrapper;
44429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylorimport android.graphics.Bitmap;
4572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.graphics.Typeface;
46429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylorimport android.graphics.drawable.BitmapDrawable;
47006d49271549ed639ffcd70d94c7650bb3514796Jim Shumaimport android.media.AudioManager;
4872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.net.Uri;
49b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylorimport android.os.AsyncTask;
505a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylorimport android.os.Handler;
5172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.preference.PreferenceManager;
52f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.Mms;
53f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.Sms;
5472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.text.Spannable;
5572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.text.SpannableString;
56429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylorimport android.text.SpannableStringBuilder;
5772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.text.TextUtils;
5872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.text.style.StyleSpan;
59ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylorimport android.text.style.TextAppearanceSpan;
6072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.util.Log;
61800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERTimport android.widget.Toast;
6272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
63d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.LogTag;
64d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.R;
65d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.data.Contact;
66d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.data.Conversation;
67d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.data.WorkingMessage;
68d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.model.SlideModel;
69d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.model.SlideshowModel;
70d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.ui.ComposeMessageActivity;
71d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.ui.ConversationList;
723c307cabb5bd96ed174930ebf17f533bf2a79de7Tom Taylorimport com.android.mms.ui.MessageUtils;
73d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.ui.MessagingPreferenceActivity;
74d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.util.AddressUtils;
75d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.util.DownloadManager;
76d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.widget.MmsWidgetProvider;
77d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.MmsException;
78d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.EncodedStringValue;
79d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.GenericPdu;
80d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.MultimediaMessagePdu;
81d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.PduHeaders;
82d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.PduPersister;
8372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
8472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project/**
8572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * This class is used to update the notification indicator. It will check whether
8672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * there are unread messages. If yes, it would show the notification indicator,
8772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * otherwise, hide the indicator.
8872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project */
8972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectpublic class MessagingNotification {
90c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
91812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang    private static final String TAG = LogTag.APP;
926d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor    private static final boolean DEBUG = true;  // TODO turn off before ship
9372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
9472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int NOTIFICATION_ID = 123;
9572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static final int MESSAGE_FAILED_NOTIFICATION_ID = 789;
9672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static final int DOWNLOAD_FAILED_NOTIFICATION_ID = 531;
97c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
98c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * This is the volume at which to play the in-conversation notification sound,
99c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * expressed as a fraction of the system notification volume.
100c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
101c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static final float IN_CONVERSATION_NOTIFICATION_VOLUME = 0.25f;
10272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
10372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // This must be consistent with the column constants below.
10472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String[] MMS_STATUS_PROJECTION = new String[] {
10572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Mms.THREAD_ID, Mms.DATE, Mms._ID, Mms.SUBJECT, Mms.SUBJECT_CHARSET };
10672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
10772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // This must be consistent with the column constants below.
10872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String[] SMS_STATUS_PROJECTION = new String[] {
10972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Sms.THREAD_ID, Sms.DATE, Sms.ADDRESS, Sms.SUBJECT, Sms.BODY };
11072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
11172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // These must be consistent with MMS_STATUS_PROJECTION and
11272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // SMS_STATUS_PROJECTION.
11372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_THREAD_ID   = 0;
11472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_DATE        = 1;
11572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_MMS_ID      = 2;
11672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SMS_ADDRESS = 2;
11772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SUBJECT     = 3;
11872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SUBJECT_CS  = 4;
11972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SMS_BODY    = 4;
12072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
121c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static final String[] SMS_THREAD_ID_PROJECTION = new String[] { Sms.THREAD_ID };
122c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static final String[] MMS_THREAD_ID_PROJECTION = new String[] { Mms.THREAD_ID };
123c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
12472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String NEW_INCOMING_SM_CONSTRAINT =
12572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            "(" + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_INBOX
126627007213deb59ef938c80353c8f3598b01478b3Wei Huang            + " AND " + Sms.SEEN + " = 0)";
12772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
128800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    private static final String NEW_DELIVERY_SM_CONSTRAINT =
129c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        "(" + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_SENT
130c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        + " AND " + Sms.STATUS + " = "+ Sms.STATUS_COMPLETE +")";
131800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
13272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String NEW_INCOMING_MM_CONSTRAINT =
13372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            "(" + Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_INBOX
134627007213deb59ef938c80353c8f3598b01478b3Wei Huang            + " AND " + Mms.SEEN + "=0"
13572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            + " AND (" + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_NOTIFICATION_IND
13672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            + " OR " + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_RETRIEVE_CONF + "))";
13772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
138429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final NotificationInfoComparator INFO_COMPARATOR =
139429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            new NotificationInfoComparator();
1405a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
14172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final Uri UNDELIVERED_URI = Uri.parse("content://mms-sms/undelivered");
14272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
14370f5af8fd89d66ae246a805d10a50540746319aaWei Huang
14470f5af8fd89d66ae246a805d10a50540746319aaWei Huang    private final static String NOTIFICATION_DELETED_ACTION =
14570f5af8fd89d66ae246a805d10a50540746319aaWei Huang            "com.android.mms.NOTIFICATION_DELETED_ACTION";
14670f5af8fd89d66ae246a805d10a50540746319aaWei Huang
14770f5af8fd89d66ae246a805d10a50540746319aaWei Huang    public static class OnDeletedReceiver extends BroadcastReceiver {
148c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        @Override
14970f5af8fd89d66ae246a805d10a50540746319aaWei Huang        public void onReceive(Context context, Intent intent) {
15070f5af8fd89d66ae246a805d10a50540746319aaWei Huang            if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
15170f5af8fd89d66ae246a805d10a50540746319aaWei Huang                Log.d(TAG, "[MessagingNotification] clear notification: mark all msgs seen");
15270f5af8fd89d66ae246a805d10a50540746319aaWei Huang            }
15370f5af8fd89d66ae246a805d10a50540746319aaWei Huang
15470f5af8fd89d66ae246a805d10a50540746319aaWei Huang            Conversation.markAllConversationsAsSeen(context);
15570f5af8fd89d66ae246a805d10a50540746319aaWei Huang        }
156c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
157c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
158c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static final long THREAD_ALL = -1;
159c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static final long THREAD_NONE = -2;
160c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
161c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Keeps track of the thread ID of the conversation that's currently displayed to the user
162c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
163c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static long sCurrentlyDisplayedThreadId;
164c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static final Object sCurrentlyDisplayedThreadLock = new Object();
165c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
16670f5af8fd89d66ae246a805d10a50540746319aaWei Huang    private static OnDeletedReceiver sNotificationDeletedReceiver = new OnDeletedReceiver();
16770f5af8fd89d66ae246a805d10a50540746319aaWei Huang    private static Intent sNotificationOnDeleteIntent;
168429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static Handler sToastHandler = new Handler();
169429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static PduPersister sPduPersister;
170429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final int MAX_BITMAP_DIMEN_DP = 360;
171429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static float sScreenDensity;
172429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
173ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    private static final int MAX_MESSAGES_TO_SHOW = 8;  // the maximum number of new messages to
174429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                                                        // show in a single notification.
175429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
17670f5af8fd89d66ae246a805d10a50540746319aaWei Huang
17772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private MessagingNotification() {
17872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
17972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
18070f5af8fd89d66ae246a805d10a50540746319aaWei Huang    public static void init(Context context) {
18170f5af8fd89d66ae246a805d10a50540746319aaWei Huang        // set up the intent filter for notification deleted action
18270f5af8fd89d66ae246a805d10a50540746319aaWei Huang        IntentFilter intentFilter = new IntentFilter();
18370f5af8fd89d66ae246a805d10a50540746319aaWei Huang        intentFilter.addAction(NOTIFICATION_DELETED_ACTION);
184429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
185429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        // TODO: should we unregister when the app gets killed?
18670f5af8fd89d66ae246a805d10a50540746319aaWei Huang        context.registerReceiver(sNotificationDeletedReceiver, intentFilter);
187429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        sPduPersister = PduPersister.getPduPersister(context);
18870f5af8fd89d66ae246a805d10a50540746319aaWei Huang
18970f5af8fd89d66ae246a805d10a50540746319aaWei Huang        // initialize the notification deleted action
19070f5af8fd89d66ae246a805d10a50540746319aaWei Huang        sNotificationOnDeleteIntent = new Intent(NOTIFICATION_DELETED_ACTION);
191429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
192429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        sScreenDensity = context.getResources().getDisplayMetrics().density;
19370f5af8fd89d66ae246a805d10a50540746319aaWei Huang    }
19470f5af8fd89d66ae246a805d10a50540746319aaWei Huang
19572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    /**
196c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Specifies which message thread is currently being viewed by the user. New messages in that
197c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * thread will not generate a notification icon and will play the notification sound at a lower
198c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * volume. Make sure you set this to THREAD_NONE when the UI component that shows the thread is
199c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * no longer visible to the user (e.g. Activity.onPause(), etc.)
200c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param threadId The ID of the thread that the user is currently viewing. Pass THREAD_NONE
201c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     *  if the user is not viewing a thread, or THREAD_ALL if the user is viewing the conversation
202c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     *  list (note: that latter one has no effect as of this implementation)
203c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
204c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static void setCurrentlyDisplayedThreadId(long threadId) {
205c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        synchronized (sCurrentlyDisplayedThreadLock) {
206c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            sCurrentlyDisplayedThreadId = threadId;
2072d65e7eb956e60c058de876ddbfff504620ce7a3Tom Taylor            if (DEBUG) {
2082d65e7eb956e60c058de876ddbfff504620ce7a3Tom Taylor                Log.d(TAG, "setCurrentlyDisplayedThreadId: " + sCurrentlyDisplayedThreadId);
2092d65e7eb956e60c058de876ddbfff504620ce7a3Tom Taylor            }
210c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
211c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
212c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
213c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
214627007213deb59ef938c80353c8f3598b01478b3Wei Huang     * Checks to see if there are any "unseen" messages or delivery
21572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * reports.  Shows the most recent notification if there is one.
2163b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor     * Does its work and query in a worker thread.
21772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     *
21872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * @param context the context to use
21972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     */
2203b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor    public static void nonBlockingUpdateNewMessageIndicator(final Context context,
221c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            final long newMsgThreadId,
2223b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor            final boolean isStatusMessage) {
2233b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        new Thread(new Runnable() {
224c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            @Override
2253b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor            public void run() {
226c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                blockingUpdateNewMessageIndicator(context, newMsgThreadId, isStatusMessage);
2273b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor            }
228ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev        }, "MessagingNotification.nonBlockingUpdateNewMessageIndicator").start();
22972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
23072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
23172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    /**
232627007213deb59ef938c80353c8f3598b01478b3Wei Huang     * Checks to see if there are any "unseen" messages or delivery
233429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * reports and builds a sorted (by delivery date) list of unread notifications.
23472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     *
23572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * @param context the context to use
236c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param newMsgThreadId The thread ID of a new message that we're to notify about; if there's
237c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     *  no new message, use THREAD_NONE. If we should notify about multiple or unknown thread IDs,
238c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     *  use THREAD_ALL.
239c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param isStatusMessage
24072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     */
241c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static void blockingUpdateNewMessageIndicator(Context context, long newMsgThreadId,
242c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            boolean isStatusMessage) {
243c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        synchronized (sCurrentlyDisplayedThreadLock) {
244c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            if (newMsgThreadId > 0 && newMsgThreadId == sCurrentlyDisplayedThreadId) {
2459ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor                if (DEBUG) {
2469ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor                    Log.d(TAG, "blockingUpdateNewMessageIndicator: newMsgThreadId == " +
2479ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor                            "sCurrentlyDisplayedThreadId so NOT showing notification," +
2489ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor                            " but playing soft sound. threadId: " + newMsgThreadId);
2499ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor                }
250c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                playInConversationNotificationSound(context);
251c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                return;
252c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            }
253c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
2544c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        // notificationSet is kept sorted by the incoming message delivery time, with the
2554c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        // most recent message first.
2564c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        SortedSet<NotificationInfo> notificationSet =
2574c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                new TreeSet<NotificationInfo>(INFO_COMPARATOR);
258c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
259b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        Set<Long> threads = new HashSet<Long>(4);
2605a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
2614c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        addMmsNotificationInfos(context, threads, notificationSet);
2624c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        addSmsNotificationInfos(context, threads, notificationSet);
26372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
26472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        cancelNotification(context, NOTIFICATION_ID);
2654c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        if (!notificationSet.isEmpty()) {
2666d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor            if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
2676d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor                Log.d(TAG, "blockingUpdateNewMessageIndicator: count=" + notificationSet.size() +
268c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                        ", newMsgThreadId=" + newMsgThreadId);
269e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            }
2704c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor            updateNotification(context, newMsgThreadId != THREAD_NONE, threads.size(),
2714c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                    notificationSet);
27272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
2735a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
2743b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // And deals with delivery reports (which use Toasts). It's safe to call in a worker
2753b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // thread because the toast will eventually get posted to a handler.
2764c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        MmsSmsDeliveryInfo delivery = getSmsNewDeliveryInfo(context);
277627007213deb59ef938c80353c8f3598b01478b3Wei Huang        if (delivery != null) {
278c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            delivery.deliver(context, isStatusMessage);
279627007213deb59ef938c80353c8f3598b01478b3Wei Huang        }
28072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
28172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
28272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    /**
283c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Play the in-conversation notification sound (it's the regular notification sound, but
284c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * played at half-volume
285c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
286c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static void playInConversationNotificationSound(Context context) {
287c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
288c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        String ringtoneStr = sp.getString(MessagingPreferenceActivity.NOTIFICATION_RINGTONE,
289c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                null);
290c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        if (TextUtils.isEmpty(ringtoneStr)) {
291c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            // Nothing to play
292c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            return;
293c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
294c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        Uri ringtoneUri = Uri.parse(ringtoneStr);
295c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        NotificationPlayer player = new NotificationPlayer(LogTag.APP);
296c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        player.play(context, ringtoneUri, false, AudioManager.STREAM_NOTIFICATION,
297c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                IN_CONVERSATION_NOTIFICATION_VOLUME);
298c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
299c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
300c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
30135a74a9e0ee7c171c6e17f0eda4b0df0253f8364Ficus Kirkpatrick     * Updates all pending notifications, clearing or updating them as
3023b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor     * necessary.
30335a74a9e0ee7c171c6e17f0eda4b0df0253f8364Ficus Kirkpatrick     */
304627007213deb59ef938c80353c8f3598b01478b3Wei Huang    public static void blockingUpdateAllNotifications(final Context context) {
305c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        nonBlockingUpdateNewMessageIndicator(context, THREAD_NONE, false);
306b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor        nonBlockingUpdateSendFailedNotification(context);
307627007213deb59ef938c80353c8f3598b01478b3Wei Huang        updateDownloadFailedNotification(context);
308c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor        MmsWidgetProvider.notifyDatasetChanged(context);
30935a74a9e0ee7c171c6e17f0eda4b0df0253f8364Ficus Kirkpatrick    }
3105a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
311800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    private static final class MmsSmsDeliveryInfo {
312c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public CharSequence mTicker;
313c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public long mTimeMillis;
314c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor
315c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public MmsSmsDeliveryInfo(CharSequence ticker, long timeMillis) {
316c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            mTicker = ticker;
317c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            mTimeMillis = timeMillis;
318c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        }
319c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor
320c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public void deliver(Context context, boolean isStatusMessage) {
321c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            updateDeliveryNotification(
322c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor                    context, isStatusMessage, mTicker, mTimeMillis);
323c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        }
324800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    }
325800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
326429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final class NotificationInfo {
327c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final Intent mClickIntent;
328ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public final String mMessage;
329c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final CharSequence mTicker;
330c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final long mTimeMillis;
331c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final String mTitle;
332429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        public final Bitmap mAttachmentBitmap;
333429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        public final Contact mSender;
334429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        public final boolean mIsSms;
335ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public final int mAttachmentType;
336ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public final String mSubject;
337ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public final long mThreadId;
338429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
339429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        /**
340429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * @param isSms true if sms, false if mms
341429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * @param clickIntent where to go when the user taps the notification
342ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor         * @param message for a single message, this is the message text
343ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor         * @param subject text of mms subject
344429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * @param ticker text displayed ticker-style across the notification, typically formatted
345429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * as sender: message
346429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * @param timeMillis date the message was received
347429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * @param title for a single message, this is the sender
348429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * @param attachmentBitmap a bitmap of an attachment, such as a picture or video
349ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor         * @param sender contact of the sender
350ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor         * @param attachmentType of the mms attachment
351ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor         * @param threadId thread this message belongs to
352429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         */
353429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        public NotificationInfo(boolean isSms,
354ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                Intent clickIntent, String message, String subject,
355429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                CharSequence ticker, long timeMillis, String title,
356ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                Bitmap attachmentBitmap, Contact sender,
357ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                int attachmentType, long threadId) {
358429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            mIsSms = isSms;
35972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mClickIntent = clickIntent;
360ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            mMessage = message;
361ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            mSubject = subject;
36272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mTicker = ticker;
36372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mTimeMillis = timeMillis;
36472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mTitle = title;
365429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            mAttachmentBitmap = attachmentBitmap;
366429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            mSender = sender;
367ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            mAttachmentType = attachmentType;
368ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            mThreadId = threadId;
36972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
37072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
37172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public long getTime() {
37272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return mTimeMillis;
37372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
374ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
375ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        // This is the message string used in bigText and bigPicture notifications.
376ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public CharSequence formatBigMessage(Context context) {
377ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            final TextAppearanceSpan notificationSubjectSpan = new TextAppearanceSpan(
378ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    context, R.style.NotificationPrimaryText);
379ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
380ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            // Change multiple newlines (with potential white space between), into a single new line
381ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            final String message =
382ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    !TextUtils.isEmpty(mMessage) ? mMessage.replaceAll("\\n\\s+", "\n") : "";
383ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
384ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
385ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (!TextUtils.isEmpty(mSubject)) {
386ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.append(mSubject);
387ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.setSpan(notificationSubjectSpan, 0, mSubject.length(), 0);
388ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
389ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (mAttachmentType > WorkingMessage.TEXT) {
390ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                if (spannableStringBuilder.length() > 0) {
391ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    spannableStringBuilder.append('\n');
392ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                }
393ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.append(getAttachmentTypeString(context, mAttachmentType));
394ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
395ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (mMessage != null) {
396ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                if (spannableStringBuilder.length() > 0) {
397ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    spannableStringBuilder.append('\n');
398ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                }
399ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.append(mMessage);
400ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
401ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            return spannableStringBuilder;
402ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
403ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
404ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        // This is the message string used in each line of an inboxStyle notification.
405ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public CharSequence formatInboxMessage(Context context) {
406ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          final TextAppearanceSpan notificationSenderSpan = new TextAppearanceSpan(
407ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  context, R.style.NotificationPrimaryText);
408ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
409ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          final TextAppearanceSpan notificationSubjectSpan = new TextAppearanceSpan(
410ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  context, R.style.NotificationSubjectText);
411ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
412ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          // Change multiple newlines (with potential white space between), into a single new line
413ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          final String message =
414ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  !TextUtils.isEmpty(mMessage) ? mMessage.replaceAll("\\n\\s+", "\n") : "";
415ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
416ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
417ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          final String sender = mSender.getName();
418ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          if (!TextUtils.isEmpty(sender)) {
419ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              spannableStringBuilder.append(sender);
420ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              spannableStringBuilder.setSpan(notificationSenderSpan, 0, sender.length(), 0);
421ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          }
422ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          String separator = context.getString(R.string.notification_separator);
423ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          if (!mIsSms) {
424ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              if (!TextUtils.isEmpty(mSubject)) {
425ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  if (spannableStringBuilder.length() > 0) {
426ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                      spannableStringBuilder.append(separator);
427ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  }
428ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  int start = spannableStringBuilder.length();
429ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  spannableStringBuilder.append(mSubject);
430ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  spannableStringBuilder.setSpan(notificationSubjectSpan, start,
431ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                          start + mSubject.length(), 0);
432ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              }
433ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              if (mAttachmentType > WorkingMessage.TEXT) {
434ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  if (spannableStringBuilder.length() > 0) {
435ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                      spannableStringBuilder.append(separator);
436ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  }
437ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  spannableStringBuilder.append(getAttachmentTypeString(context, mAttachmentType));
438ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              }
439ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          }
440ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          if (message.length() > 0) {
441ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              if (spannableStringBuilder.length() > 0) {
442ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  spannableStringBuilder.append(separator);
443ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              }
444ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              int start = spannableStringBuilder.length();
445ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              spannableStringBuilder.append(message);
446ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              spannableStringBuilder.setSpan(notificationSubjectSpan, start,
447ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                      start + message.length(), 0);
448ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          }
449ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          return spannableStringBuilder;
450ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
451ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
452ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        // This is the summary string used in bigPicture notifications.
453ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public CharSequence formatPictureMessage(Context context) {
454ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            final TextAppearanceSpan notificationSubjectSpan = new TextAppearanceSpan(
455ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    context, R.style.NotificationPrimaryText);
456ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
457ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            // Change multiple newlines (with potential white space between), into a single new line
458ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            final String message =
459ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    !TextUtils.isEmpty(mMessage) ? mMessage.replaceAll("\\n\\s+", "\n") : "";
460ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
461ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            // Show the subject or the message (if no subject)
462ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
463ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (!TextUtils.isEmpty(mSubject)) {
464ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.append(mSubject);
465ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.setSpan(notificationSubjectSpan, 0, mSubject.length(), 0);
466ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
467ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (message.length() > 0 && spannableStringBuilder.length() == 0) {
468ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.append(message);
469ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.setSpan(notificationSubjectSpan, 0, message.length(), 0);
470ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
471ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            return spannableStringBuilder;
472ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
47372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
47472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
475ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    // Return a formatted string with all the sender names separated by commas.
476ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    private static CharSequence formatSenders(Context context,
477ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            ArrayList<NotificationInfo> senders) {
478ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        final TextAppearanceSpan notificationSenderSpan = new TextAppearanceSpan(
479ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                context, R.style.NotificationPrimaryText);
480ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
481ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        String separator = context.getString(R.string.enumeration_comma);   // ", "
482ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
483ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        int len = senders.size();
484ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        for (int i = 0; i < len; i++) {
485ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (i > 0) {
486ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.append(separator);
487ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
488ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            spannableStringBuilder.append(senders.get(i).mSender.getName());
489ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
490ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        spannableStringBuilder.setSpan(notificationSenderSpan, 0,
491ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.length(), 0);
492ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        return spannableStringBuilder;
493ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    }
494ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
495ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    // Return a formatted string with the attachmentType spelled out as a string. For
496ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    // no attachment (or just text), return null.
497ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    private static CharSequence getAttachmentTypeString(Context context, int attachmentType) {
498ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        final TextAppearanceSpan notificationAttachmentSpan = new TextAppearanceSpan(
499ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                context, R.style.NotificationSecondaryText);
500ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        int id = 0;
501ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        switch (attachmentType) {
502ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            case WorkingMessage.AUDIO: id = R.string.attachment_audio; break;
503ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            case WorkingMessage.VIDEO: id = R.string.attachment_video; break;
504ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            case WorkingMessage.SLIDESHOW: id = R.string.attachment_slideshow; break;
505ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            case WorkingMessage.IMAGE: id = R.string.attachment_picture; break;
506ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
507ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        if (id > 0) {
508ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            final SpannableString spannableString = new SpannableString(context.getString(id));
509ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            spannableString.setSpan(notificationAttachmentSpan,
510ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    0, spannableString.length(), 0);
511ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            return spannableString;
512ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
513ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        return null;
514ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor     }
515ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
516429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    /**
517429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     *
518429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * Sorts by the time a notification was received in descending order -- newer first.
519429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     *
520429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     */
521429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final class NotificationInfoComparator
522429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            implements Comparator<NotificationInfo> {
523c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        @Override
52472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public int compare(
525429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                NotificationInfo info1, NotificationInfo info2) {
52672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return Long.signum(info2.getTime() - info1.getTime());
52772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
52872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
52972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
530429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final void addMmsNotificationInfos(
5314c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor            Context context, Set<Long> threads, SortedSet<NotificationInfo> notificationSet) {
53272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        ContentResolver resolver = context.getContentResolver();
5333b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor
5343b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // This query looks like this when logged:
5353b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // I/Database(  147): elapsedTime4Sql|/data/data/com.android.providers.telephony/databases/
5363b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // mmssms.db|0.362 ms|SELECT thread_id, date, _id, sub, sub_cs FROM pdu WHERE ((msg_box=1
5373b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // AND seen=0 AND (m_type=130 OR m_type=132))) ORDER BY date desc
5383b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor
53972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor cursor = SqliteWrapper.query(context, resolver, Mms.CONTENT_URI,
54072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            MMS_STATUS_PROJECTION, NEW_INCOMING_MM_CONSTRAINT,
54172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            null, Mms.DATE + " desc");
54272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
543b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        if (cursor == null) {
544429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            return;
545b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
5465a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
547b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        try {
548429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            while (cursor.moveToNext()) {
549c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
550429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                long msgId = cursor.getLong(COLUMN_MMS_ID);
551429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                Uri msgUri = Mms.CONTENT_URI.buildUpon().appendPath(
552429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        Long.toString(msgId)).build();
553429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                String address = AddressUtils.getFrom(context, msgUri);
5541b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
555429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                Contact contact = Contact.get(address, false);
556429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                if (contact.getSendToVoicemail()) {
557429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    // don't notify, skip this one
558429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    continue;
559429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                }
5601b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
561429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                String subject = getMmsSubject(
562429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        cursor.getString(COLUMN_SUBJECT), cursor.getInt(COLUMN_SUBJECT_CS));
5633c307cabb5bd96ed174930ebf17f533bf2a79de7Tom Taylor                subject = MessageUtils.cleanseMmsSubject(context, subject);
5643c307cabb5bd96ed174930ebf17f533bf2a79de7Tom Taylor
565429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                long threadId = cursor.getLong(COLUMN_THREAD_ID);
566429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                long timeMillis = cursor.getLong(COLUMN_DATE) * 1000;
567b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
568429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
569429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    Log.d(TAG, "addMmsNotificationInfos: count=" + cursor.getCount() +
570429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                            ", addr = " + address + ", thread_id=" + threadId);
571429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                }
572e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang
573429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                // Extract the message and/or an attached picture from the first slide
574429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                Bitmap attachedPicture = null;
575429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                String messageBody = null;
576ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                int attachmentType = WorkingMessage.TEXT;
577429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                try {
578429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    GenericPdu pdu = sPduPersister.load(msgUri);
579f677c24f07befa52ae977461c56fedeb0ad3eb47Tom Taylor                    if (pdu != null && pdu instanceof MultimediaMessagePdu) {
580429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        SlideshowModel slideshow = SlideshowModel.createFromPduBody(context,
581429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                                ((MultimediaMessagePdu)pdu).getBody());
582ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        attachmentType = getAttachmentType(slideshow);
583429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        SlideModel firstSlide = slideshow.get(0);
584429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        if (firstSlide != null) {
585429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                            if (firstSlide.hasImage()) {
586429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                                int maxDim = dp2Pixels(MAX_BITMAP_DIMEN_DP);
587429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                                attachedPicture = firstSlide.getImage().getBitmap(maxDim, maxDim);
588429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                            }
589429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                            if (firstSlide.hasText()) {
590429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                                messageBody = firstSlide.getText().getText();
591429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                            }
592429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        }
593429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    }
594429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                } catch (final MmsException e) {
595429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    Log.e(TAG, "MmsException loading uri: " + msgUri, e);
596429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                }
597b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
598ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                NotificationInfo info = getNewMessageNotificationInfo(context,
599ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        false /* isSms */,
600429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        address,
601ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        messageBody, subject,
602ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        threadId,
603ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        timeMillis,
604ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        attachedPicture,
605ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        contact,
606ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        attachmentType);
607429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
6084c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                notificationSet.add(info);
609b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
610429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                threads.add(threadId);
611429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            }
612b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        } finally {
613b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            cursor.close();
61472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
61572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
61672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
617ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    // Look at the passed in slideshow and determine what type of attachment it is.
618ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    private static int getAttachmentType(SlideshowModel slideshow) {
619ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        int slideCount = slideshow.size();
620ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
621ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        if (slideCount == 0) {
622ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            return WorkingMessage.TEXT;
623ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        } else if (slideCount > 1) {
624ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            return WorkingMessage.SLIDESHOW;
625ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        } else {
626ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            SlideModel slide = slideshow.get(0);
627ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (slide.hasImage()) {
628ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                return WorkingMessage.IMAGE;
629ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            } else if (slide.hasVideo()) {
630ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                return WorkingMessage.VIDEO;
631ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            } else if (slide.hasAudio()) {
632ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                return WorkingMessage.AUDIO;
633ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
634ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
635ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        return WorkingMessage.TEXT;
636ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    }
637ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
638429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final int dp2Pixels(int dip) {
639429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        return (int) (dip * sScreenDensity + 0.5f);
640429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    }
641429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
6423b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor    private static final MmsSmsDeliveryInfo getSmsNewDeliveryInfo(Context context) {
643627007213deb59ef938c80353c8f3598b01478b3Wei Huang        ContentResolver resolver = context.getContentResolver();
644627007213deb59ef938c80353c8f3598b01478b3Wei Huang        Cursor cursor = SqliteWrapper.query(context, resolver, Sms.CONTENT_URI,
645627007213deb59ef938c80353c8f3598b01478b3Wei Huang                    SMS_STATUS_PROJECTION, NEW_DELIVERY_SM_CONSTRAINT,
6466a9c779f0c0dc6cf3ae942ff70fb6c806aa166dcBanavathu, Srinivas Naik                    null, Sms.DATE);
647800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
648ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom        if (cursor == null) {
649627007213deb59ef938c80353c8f3598b01478b3Wei Huang            return null;
650ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom        }
651800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
652627007213deb59ef938c80353c8f3598b01478b3Wei Huang        try {
653ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            if (!cursor.moveToLast()) {
654ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom                return null;
655ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            }
656800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
657627007213deb59ef938c80353c8f3598b01478b3Wei Huang            String address = cursor.getString(COLUMN_SMS_ADDRESS);
658627007213deb59ef938c80353c8f3598b01478b3Wei Huang            long timeMillis = 3000;
659800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
660ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            Contact contact = Contact.get(address, false);
661ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            String name = contact.getNameAndNumber();
662ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom
663ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            return new MmsSmsDeliveryInfo(context.getString(R.string.delivery_toast_body, name),
664627007213deb59ef938c80353c8f3598b01478b3Wei Huang                timeMillis);
665800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
666627007213deb59ef938c80353c8f3598b01478b3Wei Huang        } finally {
667627007213deb59ef938c80353c8f3598b01478b3Wei Huang            cursor.close();
668627007213deb59ef938c80353c8f3598b01478b3Wei Huang        }
669800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    }
670800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
671429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final void addSmsNotificationInfos(
6724c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor            Context context, Set<Long> threads, SortedSet<NotificationInfo> notificationSet) {
67372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        ContentResolver resolver = context.getContentResolver();
67472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor cursor = SqliteWrapper.query(context, resolver, Sms.CONTENT_URI,
67572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            SMS_STATUS_PROJECTION, NEW_INCOMING_SM_CONSTRAINT,
67672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            null, Sms.DATE + " desc");
67772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
678b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        if (cursor == null) {
679429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            return;
680b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
6815a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
682b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        try {
683429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            while (cursor.moveToNext()) {
684429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                String address = cursor.getString(COLUMN_SMS_ADDRESS);
685b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
686429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                Contact contact = Contact.get(address, false);
687429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                if (contact.getSendToVoicemail()) {
688429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    // don't notify, skip this one
689429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    continue;
690429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                }
6911b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
692ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                String message = cursor.getString(COLUMN_SMS_BODY);
693429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                long threadId = cursor.getLong(COLUMN_THREAD_ID);
694429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                long timeMillis = cursor.getLong(COLUMN_DATE);
6951b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
696429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                if (Log.isLoggable(LogTag.APP, Log.VERBOSE))
697429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                {
698429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    Log.d(TAG, "addSmsNotificationInfos: count=" + cursor.getCount() +
699429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                            ", addr=" + address + ", thread_id=" + threadId);
700429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                }
701b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
702e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang
703ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                NotificationInfo info = getNewMessageNotificationInfo(context, true /* isSms */,
704ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        address, message, null /* subject */,
705ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        threadId, timeMillis, null /* attachmentBitmap */,
706ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        contact, WorkingMessage.TEXT);
707b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
7084c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                notificationSet.add(info);
709429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
710429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                threads.add(threadId);
711b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                threads.add(cursor.getLong(COLUMN_THREAD_ID));
71272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
713b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        } finally {
714b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            cursor.close();
71572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
71672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
71772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
718429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final NotificationInfo getNewMessageNotificationInfo(
719ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            Context context,
720429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            boolean isSms,
72172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String address,
722ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            String message,
72372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String subject,
72472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            long threadId,
72572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            long timeMillis,
726429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            Bitmap attachmentBitmap,
727ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            Contact contact,
728ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            int attachmentType) {
729812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang        Intent clickIntent = ComposeMessageActivity.createIntent(context, threadId);
730812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang        clickIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
731812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                | Intent.FLAG_ACTIVITY_SINGLE_TOP
732812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
73372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
73472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String senderInfo = buildTickerMessage(
73572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                context, address, null, null).toString();
73672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String senderInfoName = senderInfo.substring(
73772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                0, senderInfo.length() - 2);
73872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        CharSequence ticker = buildTickerMessage(
739ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                context, address, subject, message);
74072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
741429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        return new NotificationInfo(isSms,
742ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                clickIntent, message, subject, ticker, timeMillis,
743ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                senderInfoName, attachmentBitmap, contact, attachmentType, threadId);
74472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
74572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
74672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void cancelNotification(Context context, int notificationId) {
74772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        NotificationManager nm = (NotificationManager) context.getSystemService(
74872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Context.NOTIFICATION_SERVICE);
74972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
75072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        nm.cancel(notificationId);
75172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
75272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
7535a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor    private static void updateDeliveryNotification(final Context context,
754c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor                                                   boolean isStatusMessage,
7555a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor                                                   final CharSequence message,
7565a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor                                                   final long timeMillis) {
757c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        if (!isStatusMessage) {
758c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            return;
759c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        }
760c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor
761800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
762d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor        if (!MessagingPreferenceActivity.getNotificationEnabled(context)) {
76370f5af8fd89d66ae246a805d10a50540746319aaWei Huang            return;
76470f5af8fd89d66ae246a805d10a50540746319aaWei Huang        }
765800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
766429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        sToastHandler.post(new Runnable() {
767c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            @Override
768c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            public void run() {
769c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor                Toast.makeText(context, message, (int)timeMillis).show();
770c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            }
771c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        });
772800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    }
773800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
774429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    /**
775429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * updateNotification is *the* main function for building the actual notification handed to
776429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * the NotificationManager
777429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * @param context
778429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * @param isNew if we've got a new message, show the ticker
779429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * @param uniqueThreadCount
7804c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor     * @param notificationSet the set of notifications to display
781429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     */
78272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static void updateNotification(
78372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Context context,
78472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            boolean isNew,
7854c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor            int uniqueThreadCount,
7864c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor            SortedSet<NotificationInfo> notificationSet) {
787429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        // If the user has turned off notifications in settings, don't do any notifying.
788d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor        if (!MessagingPreferenceActivity.getNotificationEnabled(context)) {
7899ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor            if (DEBUG) {
7909ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor                Log.d(TAG, "updateNotification: notifications turned off in prefs, bailing");
7919ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor            }
79272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return;
79372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
79472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
795429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        // Figure out what we've got -- whether all sms's, mms's, or a mixture of both.
7964c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        final int messageCount = notificationSet.size();
7974c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        NotificationInfo mostRecentNotification = notificationSet.first();
798429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
799674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        final Notification.Builder noti = new Notification.Builder(context)
800429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                .setWhen(mostRecentNotification.mTimeMillis);
801674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler
802429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        if (isNew) {
803ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            noti.setTicker(mostRecentNotification.mTicker);
804429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        }
805fb7068020e74e431acc9511212d2a6d17258ab9eAdam Powell        TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context);
806b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
807b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // If we have more than one unique thread, change the title (which would
808b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // normally be the contact who sent the message) to a generic one that
809b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // makes sense for multiple senders, and change the Intent to take the
810b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // user to the conversation list instead of the specific thread.
811674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler
812429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        // Cases:
813429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        //   1) single message from single thread - intent goes to ComposeMessageActivity
814429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        //   2) multiple messages from single thread - intent goes to ComposeMessageActivity
815429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        //   3) messages from multiple threads - intent goes to ConversationList
816429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
817ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        final Resources res = context.getResources();
818429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        String title = null;
81964fefc1c9b26bd6778c318e83cec696abb389c22Daniel Sandler        Bitmap avatar = null;
820429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        if (uniqueThreadCount > 1) {    // messages from multiple threads
8211fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            Intent mainActivityIntent = new Intent(Intent.ACTION_MAIN);
822812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang
8231fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            mainActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
824812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                    | Intent.FLAG_ACTIVITY_SINGLE_TOP
825812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
826812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang
8271fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            mainActivityIntent.setType("vnd.android-dir/mms-sms");
8286cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor            taskStackBuilder.addNextIntent(mainActivityIntent);
829ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            title = context.getString(R.string.message_count_notification, messageCount);
830429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        } else {    // same thread, single or multiple messages
831ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            title = mostRecentNotification.mTitle;
832429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            BitmapDrawable contactDrawable = (BitmapDrawable)mostRecentNotification.mSender
833429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    .getAvatar(context, null);
834ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (contactDrawable != null) {
835ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // Show the sender's avatar as the big icon. Contact bitmaps are 96x96 so we
836ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // have to scale 'em up to 128x128 to fill the whole notification large icon.
83764fefc1c9b26bd6778c318e83cec696abb389c22Daniel Sandler                avatar = contactDrawable.getBitmap();
838ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                if (avatar != null) {
839ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    final int idealIconHeight =
840ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        res.getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
841ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    final int idealIconWidth =
842ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                         res.getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
843ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    if (avatar.getHeight() < idealIconHeight) {
844ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        // Scale this image to fit the intended size
845ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        avatar = Bitmap.createScaledBitmap(
846ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                                avatar, idealIconWidth, idealIconHeight, true);
847ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    }
848ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    if (avatar != null) {
849ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        noti.setLargeIcon(avatar);
850ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    }
851ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                }
852ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
853429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
8546cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor            taskStackBuilder.addParentStack(ComposeMessageActivity.class);
8556cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor            taskStackBuilder.addNextIntent(mostRecentNotification.mClickIntent);
856b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
857ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        // Always have to set the small icon or the notification is ignored
858ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        noti.setSmallIcon(R.drawable.stat_notify_sms);
859ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
860429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        NotificationManager nm = (NotificationManager)
861429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                context.getSystemService(Context.NOTIFICATION_SERVICE);
86272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
863b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // Update the notification.
864674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        noti.setContentTitle(title)
8656cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor            .setContentIntent(
8666cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor                    taskStackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT))
867429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            .addKind(Notification.KIND_MESSAGE)
868ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            .setPriority(Notification.PRIORITY_DEFAULT);     // TODO: set based on contact coming
869ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                                                             // from a favorite.
870429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
871674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        int defaults = 0;
87272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
87372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (isNew) {
874d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
875006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            String vibrateWhen;
876006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            if (sp.contains(MessagingPreferenceActivity.NOTIFICATION_VIBRATE_WHEN)) {
877006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                vibrateWhen =
878006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                    sp.getString(MessagingPreferenceActivity.NOTIFICATION_VIBRATE_WHEN, null);
879006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            } else if (sp.contains(MessagingPreferenceActivity.NOTIFICATION_VIBRATE)) {
880429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                vibrateWhen =
881429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        sp.getBoolean(MessagingPreferenceActivity.NOTIFICATION_VIBRATE, false) ?
882006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                    context.getString(R.string.prefDefault_vibrate_true) :
883006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                    context.getString(R.string.prefDefault_vibrate_false);
884006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            } else {
885006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                vibrateWhen = context.getString(R.string.prefDefault_vibrateWhen);
886006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            }
887006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma
888006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            boolean vibrateAlways = vibrateWhen.equals("always");
889006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            boolean vibrateSilent = vibrateWhen.equals("silent");
890006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            AudioManager audioManager =
891006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
892006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            boolean nowSilent =
893006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma                audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
894006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma
895006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma            if (vibrateAlways || vibrateSilent && nowSilent) {
896674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler                defaults |= Notification.DEFAULT_VIBRATE;
89772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
89872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
899627007213deb59ef938c80353c8f3598b01478b3Wei Huang            String ringtoneStr = sp.getString(MessagingPreferenceActivity.NOTIFICATION_RINGTONE,
900627007213deb59ef938c80353c8f3598b01478b3Wei Huang                    null);
901674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler            noti.setSound(TextUtils.isEmpty(ringtoneStr) ? null : Uri.parse(ringtoneStr));
9029ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor            if (DEBUG) {
9039ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor                Log.d(TAG, "updateNotification: new message, adding sound to the notification");
9049ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor            }
90572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
90672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
907674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        defaults |= Notification.DEFAULT_LIGHTS;
908674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler
909674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        noti.setDefaults(defaults);
91072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
91170f5af8fd89d66ae246a805d10a50540746319aaWei Huang        // set up delete intent
912674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        noti.setDeleteIntent(PendingIntent.getBroadcast(context, 0,
913674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler                sNotificationOnDeleteIntent, 0));
91470f5af8fd89d66ae246a805d10a50540746319aaWei Huang
915674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        final Notification notification;
916429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
917ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        if (messageCount == 1) {
918ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            // We've got a single message
919ca7b54a002b5bc627171d1b275cb016bf1105da2Daniel Sandler
920ca7b54a002b5bc627171d1b275cb016bf1105da2Daniel Sandler            // This sets the text for the collapsed form:
921ca7b54a002b5bc627171d1b275cb016bf1105da2Daniel Sandler            noti.setContentText(mostRecentNotification.formatBigMessage(context));
922ca7b54a002b5bc627171d1b275cb016bf1105da2Daniel Sandler
923ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (mostRecentNotification.mAttachmentBitmap != null) {
924ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // The message has a picture, show that
925ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
926ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                notification = new Notification.BigPictureStyle(noti)
927ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .bigPicture(mostRecentNotification.mAttachmentBitmap)
928ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    // This sets the text for the expanded picture form:
929ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .setSummaryText(mostRecentNotification.formatPictureMessage(context))
930ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .build();
931ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            } else {
932ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // Show a single notification -- big style with the text of the whole message
933ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                notification = new Notification.BigTextStyle(noti)
934ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .bigText(mostRecentNotification.formatBigMessage(context))
935ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .build();
936ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
9376d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor            if (DEBUG) {
9386d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor                Log.d(TAG, "updateNotification: single message notification");
9396d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor            }
940ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        } else {
941ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            // We've got multiple messages
942ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (uniqueThreadCount == 1) {
943ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // We've got multiple messages for the same thread.
944ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // Starting with the oldest new message, display the full text of each message.
945ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // Begin a line for each subsequent message.
946429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                SpannableStringBuilder buf = new SpannableStringBuilder();
947ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                NotificationInfo infos[] =
9484c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                        notificationSet.toArray(new NotificationInfo[messageCount]);
949ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                int len = infos.length;
950ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                for (int i = len - 1; i >= 0; i--) {
951ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    NotificationInfo info = infos[i];
952ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
953ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    buf.append(info.formatBigMessage(context));
954429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
955ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    if (i != 0) {
956ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        buf.append('\n');
957ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    }
958ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                }
959ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
960ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                noti.setContentText(context.getString(R.string.message_count_notification,
961ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        messageCount));
962ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
963ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // Show a single notification -- big style with the text of all the messages
964ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                notification = new Notification.BigTextStyle(noti)
965ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .bigText(buf)
9664c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                    // Forcibly show the last line, with the app's smallIcon in it, if we
96764fefc1c9b26bd6778c318e83cec696abb389c22Daniel Sandler                    // kicked the smallIcon out with an avatar bitmap
96864fefc1c9b26bd6778c318e83cec696abb389c22Daniel Sandler                    .setSummaryText((avatar == null) ? null : " ")
969ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .build();
9706d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor                if (DEBUG) {
9716d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor                    Log.d(TAG, "updateNotification: multi messages for single thread");
9726d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor                }
973ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            } else {
974ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // Build a set of the most recent notification per threadId.
9754c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                HashSet<Long> uniqueThreads = new HashSet<Long>(messageCount);
976ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                ArrayList<NotificationInfo> mostRecentNotifPerThread =
977ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        new ArrayList<NotificationInfo>();
9784c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                Iterator<NotificationInfo> notifications = notificationSet.iterator();
979ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                while (notifications.hasNext()) {
980ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    NotificationInfo notificationInfo = notifications.next();
981ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    if (!uniqueThreads.contains(notificationInfo.mThreadId)) {
982ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        uniqueThreads.add(notificationInfo.mThreadId);
983ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        mostRecentNotifPerThread.add(notificationInfo);
984ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    }
985ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                }
986ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // When collapsed, show all the senders like this:
987ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                //     Fred Flinstone, Barry Manilow, Pete...
988ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                noti.setContentText(formatSenders(context, mostRecentNotifPerThread));
989ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                Notification.InboxStyle inboxStyle = new Notification.InboxStyle(noti);
990ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
991ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // We have to set the summary text to non-empty so the content text doesn't show
992ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // up when expanded.
993ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                inboxStyle.setSummaryText(" ");
994ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
995ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // At this point we've got multiple messages in multiple threads. We only
996ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // want to show the most recent message per thread, which are in
997ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // mostRecentNotifPerThread.
998ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                int uniqueThreadMessageCount = mostRecentNotifPerThread.size();
999ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                int maxMessages = Math.min(MAX_MESSAGES_TO_SHOW, uniqueThreadMessageCount);
1000ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
1001ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                for (int i = 0; i < maxMessages; i++) {
1002ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    NotificationInfo info = mostRecentNotifPerThread.get(i);
1003ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    inboxStyle.addLine(info.formatInboxMessage(context));
1004ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                }
1005ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                notification = inboxStyle.build();
1006ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                if (DEBUG) {
1007ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    Log.d(TAG, "updateNotification: multi messages," +
1008ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                            " showing inboxStyle notification");
1009429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                }
10109ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor            }
1011674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        }
1012674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler
101372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        nm.notify(NOTIFICATION_ID, notification);
101472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
101572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
101672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    protected static CharSequence buildTickerMessage(
101772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Context context, String address, String subject, String body) {
101833a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrick        String displayAddress = Contact.get(address, true).getName();
10195a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
102072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        StringBuilder buf = new StringBuilder(
102172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                displayAddress == null
102272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                ? ""
102372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                : displayAddress.replace('\n', ' ').replace('\r', ' '));
102472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        buf.append(':').append(' ');
102572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
102672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int offset = buf.length();
102772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!TextUtils.isEmpty(subject)) {
102872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            subject = subject.replace('\n', ' ').replace('\r', ' ');
102972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            buf.append(subject);
103072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            buf.append(' ');
103172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
103272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
103372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!TextUtils.isEmpty(body)) {
103472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            body = body.replace('\n', ' ').replace('\r', ' ');
103572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            buf.append(body);
103672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
103772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
103872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        SpannableString spanText = new SpannableString(buf.toString());
103972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        spanText.setSpan(new StyleSpan(Typeface.BOLD), 0, offset,
104072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
104172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
104272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return spanText;
104372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
104472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
104572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static String getMmsSubject(String sub, int charset) {
104672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return TextUtils.isEmpty(sub) ? ""
104772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                : new EncodedStringValue(charset, PduPersister.getBytes(sub)).getString();
104872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
104972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
105072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void notifyDownloadFailed(Context context, long threadId) {
1051b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        notifyFailed(context, true, threadId, false);
105272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
105372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
10545d2d0046ada7b53205e537d8675d32a8785e8d1dThe Android Open Source Project    public static void notifySendFailed(Context context) {
1055b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        notifyFailed(context, false, 0, false);
105672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
105772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
1058b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick    public static void notifySendFailed(Context context, boolean noisy) {
1059b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        notifyFailed(context, false, 0, noisy);
1060b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick    }
10615a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
1062b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick    private static void notifyFailed(Context context, boolean isDownload, long threadId,
1063b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick                                     boolean noisy) {
106472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // TODO factor out common code for creating notifications
1065d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor        boolean enabled = MessagingPreferenceActivity.getNotificationEnabled(context);
106672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!enabled) {
106772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return;
106872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
106972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
107072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Strategy:
107172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // a. If there is a single failure notification, tapping on the notification goes
107272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        //    to the compose view.
10735a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor        // b. If there are two failure it stays in the thread view. Selecting one undelivered
107472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        //    thread will dismiss one undelivered notification but will still display the
107572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        //    notification.If you select the 2nd undelivered one it will dismiss the notification.
10765a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
10777015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        long[] msgThreadId = {0, 1};    // Dummy initial values, just to initialize the memory
107872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int totalFailedCount = getUndeliveredMessageCount(context, msgThreadId);
10797015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        if (totalFailedCount == 0 && !isDownload) {
10807015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev            return;
10817015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        }
10827015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // The getUndeliveredMessageCount method puts a non-zero value in msgThreadId[1] if all
10837015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // failures are from the same thread.
10847015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // If isDownload is true, we're dealing with 1 specific failure; therefore "all failed" are
10857015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // indeed in the same thread since there's only 1.
10867015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        boolean allFailedInSameThread = (msgThreadId[1] != 0) || isDownload;
10875a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
108872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Intent failedIntent;
108972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Notification notification = new Notification();
109072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String title;
109172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String description;
109272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (totalFailedCount > 1) {
109372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            description = context.getString(R.string.notification_failed_multiple,
109472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    Integer.toString(totalFailedCount));
109572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            title = context.getString(R.string.notification_failed_multiple_title);
109672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else {
109772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            title = isDownload ?
109872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        context.getString(R.string.message_download_failed_title) :
109972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        context.getString(R.string.message_send_failed_title);
11005a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
110172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            description = context.getString(R.string.message_failed_body);
11027015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        }
11037015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev
1104fb7068020e74e431acc9511212d2a6d17258ab9eAdam Powell        TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context);
11057015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        if (allFailedInSameThread) {
1106836945de572ac80fd6f6a7bf59036d4cce801410The Android Open Source Project            failedIntent = new Intent(context, ComposeMessageActivity.class);
110795817b166d415114bac89ca0946c3717ae229526Tom Taylor            if (isDownload) {
110895817b166d415114bac89ca0946c3717ae229526Tom Taylor                // When isDownload is true, the valid threadId is passed into this function.
110995817b166d415114bac89ca0946c3717ae229526Tom Taylor                failedIntent.putExtra("failed_download_flag", true);
111095817b166d415114bac89ca0946c3717ae229526Tom Taylor            } else {
11117015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev                threadId = msgThreadId[0];
111295817b166d415114bac89ca0946c3717ae229526Tom Taylor                failedIntent.putExtra("undelivered_flag", true);
11135a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor            }
11145a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor            failedIntent.putExtra("thread_id", threadId);
11156cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor            taskStackBuilder.addParentStack(ComposeMessageActivity.class);
11167015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        } else {
11177015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev            failedIntent = new Intent(context, ConversationList.class);
111872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
11196cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor        taskStackBuilder.addNextIntent(failedIntent);
112072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
112172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        notification.icon = R.drawable.stat_notify_sms_failed;
112272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
112372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        notification.tickerText = title;
112472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
11256cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor        notification.setLatestEventInfo(context, title, description,
11266cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor                taskStackBuilder.getPendingIntent(0,  PendingIntent.FLAG_UPDATE_CURRENT));
112772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
1128b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        if (noisy) {
1129d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
1130e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang            boolean vibrate = sp.getBoolean(MessagingPreferenceActivity.NOTIFICATION_VIBRATE,
1131e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang                    false /* don't vibrate by default */);
1132b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick            if (vibrate) {
1133b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick                notification.defaults |= Notification.DEFAULT_VIBRATE;
1134b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick            }
113572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
1136e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang            String ringtoneStr = sp.getString(MessagingPreferenceActivity.NOTIFICATION_RINGTONE,
1137e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang                    null);
1138b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick            notification.sound = TextUtils.isEmpty(ringtoneStr) ? null : Uri.parse(ringtoneStr);
1139b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        }
11405a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
1141429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        NotificationManager notificationMgr = (NotificationManager)
1142429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                context.getSystemService(Context.NOTIFICATION_SERVICE);
1143429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
114472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (isDownload) {
1145429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            notificationMgr.notify(DOWNLOAD_FAILED_NOTIFICATION_ID, notification);
114672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else {
1147429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            notificationMgr.notify(MESSAGE_FAILED_NOTIFICATION_ID, notification);
114872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
114972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
11505a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
11517015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev    /**
11527015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     * Query the DB and return the number of undelivered messages (total for both SMS and MMS)
11537015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     * @param context The context
11547015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     * @param threadIdResult A container to put the result in, according to the following rules:
11557015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  threadIdResult[0] contains the thread id of the first message.
11567015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  threadIdResult[1] is nonzero if the thread ids of all the messages are the same.
11577015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  You can pass in null for threadIdResult.
11587015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  You can pass in a threadIdResult of size 1 to avoid the comparison of each thread id.
11597015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     */
116072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static int getUndeliveredMessageCount(Context context, long[] threadIdResult) {
116172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor undeliveredCursor = SqliteWrapper.query(context, context.getContentResolver(),
1162c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                UNDELIVERED_URI, MMS_THREAD_ID_PROJECTION, "read=0", null, null);
116372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (undeliveredCursor == null) {
116472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return 0;
116572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
116672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int count = undeliveredCursor.getCount();
116772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        try {
116872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (threadIdResult != null && undeliveredCursor.moveToFirst()) {
116972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                threadIdResult[0] = undeliveredCursor.getLong(0);
11705a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
11712f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                if (threadIdResult.length >= 2) {
11722f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    // Test to see if all the undelivered messages belong to the same thread.
11732f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    long firstId = threadIdResult[0];
11742f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    while (undeliveredCursor.moveToNext()) {
11752f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                        if (undeliveredCursor.getLong(0) != firstId) {
11762f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                            firstId = 0;
11772f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                            break;
11782f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                        }
11792f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    }
11802f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    threadIdResult[1] = firstId;    // non-zero if all ids are the same
11812f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                }
118272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
118372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } finally {
118472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            undeliveredCursor.close();
118572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
118672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return count;
118772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
118872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
1189b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor    public static void nonBlockingUpdateSendFailedNotification(final Context context) {
1190b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor        new AsyncTask<Void, Void, Integer>() {
1191b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor            protected Integer doInBackground(Void... none) {
1192b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                return getUndeliveredMessageCount(context, null);
1193b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor            }
1194b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor
1195b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor            protected void onPostExecute(Integer result) {
1196b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                if (result < 1) {
1197b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                    cancelNotification(context, MESSAGE_FAILED_NOTIFICATION_ID);
1198b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                } else {
1199b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                    // rebuild and adjust the message count if necessary.
1200b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                    notifySendFailed(context);
1201b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                }
1202b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor            }
1203b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor        }.execute();
120472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
12055a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
12065a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor    /**
12072f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project     *  If all the undelivered messages belong to "threadId", cancel the notification.
12082f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project     */
12092f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project    public static void updateSendFailedNotificationForThread(Context context, long threadId) {
12102f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project        long[] msgThreadId = {0, 0};
12115a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor        if (getUndeliveredMessageCount(context, msgThreadId) > 0
12122f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                && msgThreadId[0] == threadId
12132f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                && msgThreadId[1] != 0) {
12142f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project            cancelNotification(context, MESSAGE_FAILED_NOTIFICATION_ID);
12152f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project        }
12162f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project    }
12175a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
121872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static int getDownloadFailedMessageCount(Context context) {
121972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Look for any messages in the MMS Inbox that are of the type
122072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // NOTIFICATION_IND (i.e. not already downloaded) and in the
122172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // permanent failure state.  If there are none, cancel any
122272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // failed download notification.
122372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor c = SqliteWrapper.query(context, context.getContentResolver(),
122472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Mms.Inbox.CONTENT_URI, null,
122572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Mms.MESSAGE_TYPE + "=" +
122672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    String.valueOf(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) +
122772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                " AND " + Mms.STATUS + "=" +
122872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    String.valueOf(DownloadManager.STATE_PERMANENT_FAILURE),
122972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                null, null);
123072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (c == null) {
123172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return 0;
123272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
123372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int count = c.getCount();
123472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        c.close();
123572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return count;
123672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
123772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
123872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void updateDownloadFailedNotification(Context context) {
123972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (getDownloadFailedMessageCount(context) < 1) {
124072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            cancelNotification(context, DOWNLOAD_FAILED_NOTIFICATION_ID);
124172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
124272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
12435a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
124495817b166d415114bac89ca0946c3717ae229526Tom Taylor    public static boolean isFailedToDeliver(Intent intent) {
124595817b166d415114bac89ca0946c3717ae229526Tom Taylor        return (intent != null) && intent.getBooleanExtra("undelivered_flag", false);
124695817b166d415114bac89ca0946c3717ae229526Tom Taylor    }
124795817b166d415114bac89ca0946c3717ae229526Tom Taylor
124895817b166d415114bac89ca0946c3717ae229526Tom Taylor    public static boolean isFailedToDownload(Intent intent) {
124995817b166d415114bac89ca0946c3717ae229526Tom Taylor        return (intent != null) && intent.getBooleanExtra("failed_download_flag", false);
125095817b166d415114bac89ca0946c3717ae229526Tom Taylor    }
1251c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
1252c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
1253c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Get the thread ID of the SMS message with the given URI
1254c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param context The context
1255c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param uri The URI of the SMS message
1256c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @return The thread ID, or THREAD_NONE if the URI contains no entries
1257c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
1258c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static long getSmsThreadId(Context context, Uri uri) {
1259c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        Cursor cursor = SqliteWrapper.query(
1260c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            context,
1261c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            context.getContentResolver(),
1262c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            uri,
1263c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            SMS_THREAD_ID_PROJECTION,
1264c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            null,
1265c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            null,
1266c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            null);
1267c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
1268c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        if (cursor == null) {
1269c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            return THREAD_NONE;
1270c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
1271c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
1272c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        try {
1273c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            if (cursor.moveToFirst()) {
1274c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                return cursor.getLong(cursor.getColumnIndex(Sms.THREAD_ID));
1275c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            } else {
1276c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                return THREAD_NONE;
1277c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            }
1278c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        } finally {
1279c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            cursor.close();
1280c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
1281c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
1282c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
1283c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
1284c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Get the thread ID of the MMS message with the given URI
1285c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param context The context
1286c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param uri The URI of the SMS message
1287c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @return The thread ID, or THREAD_NONE if the URI contains no entries
1288c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
1289c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static long getThreadId(Context context, Uri uri) {
1290c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        Cursor cursor = SqliteWrapper.query(
1291c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                context,
1292c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                context.getContentResolver(),
1293c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                uri,
1294c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                MMS_THREAD_ID_PROJECTION,
1295c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                null,
1296c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                null,
1297c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                null);
1298c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
1299c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        if (cursor == null) {
1300c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            return THREAD_NONE;
1301c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
1302c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
1303c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        try {
1304c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            if (cursor.moveToFirst()) {
1305c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                return cursor.getLong(cursor.getColumnIndex(Mms.THREAD_ID));
1306c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            } else {
1307c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                return THREAD_NONE;
1308c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            }
1309c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        } finally {
1310c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            cursor.close();
1311c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
1312c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
131372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project}
1314