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;
6480528ea3bf0b480ad85da602da1b07cd0f5f98b1Tom Taylorimport com.android.mms.MmsConfig;
65d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.R;
66d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.data.Contact;
67d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.data.Conversation;
68d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.data.WorkingMessage;
69d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.model.SlideModel;
70d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.model.SlideshowModel;
71d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.ui.ComposeMessageActivity;
72d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.ui.ConversationList;
733c307cabb5bd96ed174930ebf17f533bf2a79de7Tom Taylorimport com.android.mms.ui.MessageUtils;
74d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.ui.MessagingPreferenceActivity;
75d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.util.AddressUtils;
76d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.util.DownloadManager;
77d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.widget.MmsWidgetProvider;
7880528ea3bf0b480ad85da602da1b07cd0f5f98b1Tom Taylor
79d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.MmsException;
80d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.EncodedStringValue;
81d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.GenericPdu;
82d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.MultimediaMessagePdu;
83d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.PduHeaders;
84d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.PduPersister;
8572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
8672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project/**
8772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * This class is used to update the notification indicator. It will check whether
8872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * there are unread messages. If yes, it would show the notification indicator,
8972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * otherwise, hide the indicator.
9072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project */
9172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectpublic class MessagingNotification {
92c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
93812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang    private static final String TAG = LogTag.APP;
9481b3875142eb12aca44ef95522c1d04e337488cbTom Taylor    private static final boolean DEBUG = false;
9572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
9672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int NOTIFICATION_ID = 123;
9772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static final int MESSAGE_FAILED_NOTIFICATION_ID = 789;
9872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static final int DOWNLOAD_FAILED_NOTIFICATION_ID = 531;
99c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
100c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * This is the volume at which to play the in-conversation notification sound,
101c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * expressed as a fraction of the system notification volume.
102c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
103c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static final float IN_CONVERSATION_NOTIFICATION_VOLUME = 0.25f;
10472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
10572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // This must be consistent with the column constants below.
10672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String[] MMS_STATUS_PROJECTION = new String[] {
10772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Mms.THREAD_ID, Mms.DATE, Mms._ID, Mms.SUBJECT, Mms.SUBJECT_CHARSET };
10872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
10972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // This must be consistent with the column constants below.
11072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String[] SMS_STATUS_PROJECTION = new String[] {
11172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Sms.THREAD_ID, Sms.DATE, Sms.ADDRESS, Sms.SUBJECT, Sms.BODY };
11272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
11372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // These must be consistent with MMS_STATUS_PROJECTION and
11472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    // SMS_STATUS_PROJECTION.
11572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_THREAD_ID   = 0;
11672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_DATE        = 1;
11772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_MMS_ID      = 2;
11872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SMS_ADDRESS = 2;
11972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SUBJECT     = 3;
12072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SUBJECT_CS  = 4;
12172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int COLUMN_SMS_BODY    = 4;
12272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
123c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static final String[] SMS_THREAD_ID_PROJECTION = new String[] { Sms.THREAD_ID };
124c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static final String[] MMS_THREAD_ID_PROJECTION = new String[] { Mms.THREAD_ID };
125c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
12672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String NEW_INCOMING_SM_CONSTRAINT =
12772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            "(" + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_INBOX
128627007213deb59ef938c80353c8f3598b01478b3Wei Huang            + " AND " + Sms.SEEN + " = 0)";
12972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
130800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    private static final String NEW_DELIVERY_SM_CONSTRAINT =
131c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        "(" + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_SENT
132c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        + " AND " + Sms.STATUS + " = "+ Sms.STATUS_COMPLETE +")";
133800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
13472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final String NEW_INCOMING_MM_CONSTRAINT =
13572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            "(" + Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_INBOX
136627007213deb59ef938c80353c8f3598b01478b3Wei Huang            + " AND " + Mms.SEEN + "=0"
13772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            + " AND (" + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_NOTIFICATION_IND
13872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            + " OR " + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_RETRIEVE_CONF + "))";
13972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
140429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final NotificationInfoComparator INFO_COMPARATOR =
141429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            new NotificationInfoComparator();
1425a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
14372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final Uri UNDELIVERED_URI = Uri.parse("content://mms-sms/undelivered");
14472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
14570f5af8fd89d66ae246a805d10a50540746319aaWei Huang
14670f5af8fd89d66ae246a805d10a50540746319aaWei Huang    private final static String NOTIFICATION_DELETED_ACTION =
14770f5af8fd89d66ae246a805d10a50540746319aaWei Huang            "com.android.mms.NOTIFICATION_DELETED_ACTION";
14870f5af8fd89d66ae246a805d10a50540746319aaWei Huang
14970f5af8fd89d66ae246a805d10a50540746319aaWei Huang    public static class OnDeletedReceiver extends BroadcastReceiver {
150c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        @Override
15170f5af8fd89d66ae246a805d10a50540746319aaWei Huang        public void onReceive(Context context, Intent intent) {
15270f5af8fd89d66ae246a805d10a50540746319aaWei Huang            if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
15370f5af8fd89d66ae246a805d10a50540746319aaWei Huang                Log.d(TAG, "[MessagingNotification] clear notification: mark all msgs seen");
15470f5af8fd89d66ae246a805d10a50540746319aaWei Huang            }
15570f5af8fd89d66ae246a805d10a50540746319aaWei Huang
15670f5af8fd89d66ae246a805d10a50540746319aaWei Huang            Conversation.markAllConversationsAsSeen(context);
15770f5af8fd89d66ae246a805d10a50540746319aaWei Huang        }
158c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
159c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
160c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static final long THREAD_ALL = -1;
161c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static final long THREAD_NONE = -2;
162c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
163c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Keeps track of the thread ID of the conversation that's currently displayed to the user
164c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
165c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static long sCurrentlyDisplayedThreadId;
166c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static final Object sCurrentlyDisplayedThreadLock = new Object();
167c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
16870f5af8fd89d66ae246a805d10a50540746319aaWei Huang    private static OnDeletedReceiver sNotificationDeletedReceiver = new OnDeletedReceiver();
16970f5af8fd89d66ae246a805d10a50540746319aaWei Huang    private static Intent sNotificationOnDeleteIntent;
1704ce94b2f607a93ed1a75dad7a8cbde88391a499eTom Taylor    private static Handler sHandler = new Handler();
171429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static PduPersister sPduPersister;
172429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final int MAX_BITMAP_DIMEN_DP = 360;
173429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static float sScreenDensity;
174429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
175ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    private static final int MAX_MESSAGES_TO_SHOW = 8;  // the maximum number of new messages to
176429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                                                        // show in a single notification.
177429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
17870f5af8fd89d66ae246a805d10a50540746319aaWei Huang
17972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private MessagingNotification() {
18072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
18172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
18270f5af8fd89d66ae246a805d10a50540746319aaWei Huang    public static void init(Context context) {
18370f5af8fd89d66ae246a805d10a50540746319aaWei Huang        // set up the intent filter for notification deleted action
18470f5af8fd89d66ae246a805d10a50540746319aaWei Huang        IntentFilter intentFilter = new IntentFilter();
18570f5af8fd89d66ae246a805d10a50540746319aaWei Huang        intentFilter.addAction(NOTIFICATION_DELETED_ACTION);
186429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
187429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        // TODO: should we unregister when the app gets killed?
18870f5af8fd89d66ae246a805d10a50540746319aaWei Huang        context.registerReceiver(sNotificationDeletedReceiver, intentFilter);
189429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        sPduPersister = PduPersister.getPduPersister(context);
19070f5af8fd89d66ae246a805d10a50540746319aaWei Huang
19170f5af8fd89d66ae246a805d10a50540746319aaWei Huang        // initialize the notification deleted action
19270f5af8fd89d66ae246a805d10a50540746319aaWei Huang        sNotificationOnDeleteIntent = new Intent(NOTIFICATION_DELETED_ACTION);
193429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
194429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        sScreenDensity = context.getResources().getDisplayMetrics().density;
19570f5af8fd89d66ae246a805d10a50540746319aaWei Huang    }
19670f5af8fd89d66ae246a805d10a50540746319aaWei Huang
19772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    /**
198c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Specifies which message thread is currently being viewed by the user. New messages in that
199c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * thread will not generate a notification icon and will play the notification sound at a lower
200c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * volume. Make sure you set this to THREAD_NONE when the UI component that shows the thread is
201c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * no longer visible to the user (e.g. Activity.onPause(), etc.)
202c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param threadId The ID of the thread that the user is currently viewing. Pass THREAD_NONE
203c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     *  if the user is not viewing a thread, or THREAD_ALL if the user is viewing the conversation
204c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     *  list (note: that latter one has no effect as of this implementation)
205c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
206c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static void setCurrentlyDisplayedThreadId(long threadId) {
207c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        synchronized (sCurrentlyDisplayedThreadLock) {
208c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            sCurrentlyDisplayedThreadId = threadId;
2092d65e7eb956e60c058de876ddbfff504620ce7a3Tom Taylor            if (DEBUG) {
2102d65e7eb956e60c058de876ddbfff504620ce7a3Tom Taylor                Log.d(TAG, "setCurrentlyDisplayedThreadId: " + sCurrentlyDisplayedThreadId);
2112d65e7eb956e60c058de876ddbfff504620ce7a3Tom Taylor            }
212c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
213c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
214c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
215c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
216627007213deb59ef938c80353c8f3598b01478b3Wei Huang     * Checks to see if there are any "unseen" messages or delivery
21772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * reports.  Shows the most recent notification if there is one.
2183b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor     * Does its work and query in a worker thread.
21972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     *
22072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * @param context the context to use
22172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     */
2223b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor    public static void nonBlockingUpdateNewMessageIndicator(final Context context,
223c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            final long newMsgThreadId,
2243b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor            final boolean isStatusMessage) {
225bc7f97ae7d3661a44211d404fe4e187c35afadceTom Taylor        if (DEBUG) {
226bc7f97ae7d3661a44211d404fe4e187c35afadceTom Taylor            Log.d(TAG, "nonBlockingUpdateNewMessageIndicator: newMsgThreadId: " +
227bc7f97ae7d3661a44211d404fe4e187c35afadceTom Taylor                    newMsgThreadId +
228bc7f97ae7d3661a44211d404fe4e187c35afadceTom Taylor                    " sCurrentlyDisplayedThreadId: " + sCurrentlyDisplayedThreadId);
229bc7f97ae7d3661a44211d404fe4e187c35afadceTom Taylor        }
2303b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        new Thread(new Runnable() {
231c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            @Override
2323b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor            public void run() {
233c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                blockingUpdateNewMessageIndicator(context, newMsgThreadId, isStatusMessage);
2343b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor            }
235ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev        }, "MessagingNotification.nonBlockingUpdateNewMessageIndicator").start();
23672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
23772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
23872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    /**
239627007213deb59ef938c80353c8f3598b01478b3Wei Huang     * Checks to see if there are any "unseen" messages or delivery
240429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * reports and builds a sorted (by delivery date) list of unread notifications.
24172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     *
24272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     * @param context the context to use
243c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param newMsgThreadId The thread ID of a new message that we're to notify about; if there's
244c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     *  no new message, use THREAD_NONE. If we should notify about multiple or unknown thread IDs,
245c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     *  use THREAD_ALL.
246c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param isStatusMessage
24772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project     */
248c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static void blockingUpdateNewMessageIndicator(Context context, long newMsgThreadId,
249c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            boolean isStatusMessage) {
250d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor        if (DEBUG) {
251d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor            Contact.logWithTrace(TAG, "blockingUpdateNewMessageIndicator: newMsgThreadId: " +
252d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                    newMsgThreadId);
253d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor        }
25480528ea3bf0b480ad85da602da1b07cd0f5f98b1Tom Taylor        final boolean isDefaultSmsApp = MmsConfig.isSmsEnabled(context);
25580528ea3bf0b480ad85da602da1b07cd0f5f98b1Tom Taylor        if (!isDefaultSmsApp) {
25680528ea3bf0b480ad85da602da1b07cd0f5f98b1Tom Taylor            cancelNotification(context, NOTIFICATION_ID);
25780528ea3bf0b480ad85da602da1b07cd0f5f98b1Tom Taylor            if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
25880528ea3bf0b480ad85da602da1b07cd0f5f98b1Tom Taylor                Log.d(TAG, "blockingUpdateNewMessageIndicator: not the default sms app - skipping "
25980528ea3bf0b480ad85da602da1b07cd0f5f98b1Tom Taylor                        + "notification");
26080528ea3bf0b480ad85da602da1b07cd0f5f98b1Tom Taylor            }
26180528ea3bf0b480ad85da602da1b07cd0f5f98b1Tom Taylor            return;
26280528ea3bf0b480ad85da602da1b07cd0f5f98b1Tom Taylor        }
26380528ea3bf0b480ad85da602da1b07cd0f5f98b1Tom Taylor
2644c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        // notificationSet is kept sorted by the incoming message delivery time, with the
2654c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        // most recent message first.
2664c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        SortedSet<NotificationInfo> notificationSet =
2674c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                new TreeSet<NotificationInfo>(INFO_COMPARATOR);
268c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
269b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        Set<Long> threads = new HashSet<Long>(4);
2705a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
2714c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        addMmsNotificationInfos(context, threads, notificationSet);
2724c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        addSmsNotificationInfos(context, threads, notificationSet);
27372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
274b98c3af3e015c6e63476f152a7af1a1310cd0e9dTom Taylor        if (notificationSet.isEmpty()) {
275b98c3af3e015c6e63476f152a7af1a1310cd0e9dTom Taylor            if (DEBUG) {
276b98c3af3e015c6e63476f152a7af1a1310cd0e9dTom Taylor                Log.d(TAG, "blockingUpdateNewMessageIndicator: notificationSet is empty, " +
277b98c3af3e015c6e63476f152a7af1a1310cd0e9dTom Taylor                        "canceling existing notifications");
278b98c3af3e015c6e63476f152a7af1a1310cd0e9dTom Taylor            }
279b98c3af3e015c6e63476f152a7af1a1310cd0e9dTom Taylor            cancelNotification(context, NOTIFICATION_ID);
280b98c3af3e015c6e63476f152a7af1a1310cd0e9dTom Taylor        } else {
2816d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor            if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
2826d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor                Log.d(TAG, "blockingUpdateNewMessageIndicator: count=" + notificationSet.size() +
283c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                        ", newMsgThreadId=" + newMsgThreadId);
284e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang            }
285c6be7e1a81769764ce0b51ce03406ad96944d8e5Tom Taylor            synchronized (sCurrentlyDisplayedThreadLock) {
286d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                if (newMsgThreadId > 0 && newMsgThreadId == sCurrentlyDisplayedThreadId &&
287d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                        threads.contains(newMsgThreadId)) {
288c6be7e1a81769764ce0b51ce03406ad96944d8e5Tom Taylor                    if (DEBUG) {
289c6be7e1a81769764ce0b51ce03406ad96944d8e5Tom Taylor                        Log.d(TAG, "blockingUpdateNewMessageIndicator: newMsgThreadId == " +
290c6be7e1a81769764ce0b51ce03406ad96944d8e5Tom Taylor                                "sCurrentlyDisplayedThreadId so NOT showing notification," +
291c6be7e1a81769764ce0b51ce03406ad96944d8e5Tom Taylor                                " but playing soft sound. threadId: " + newMsgThreadId);
292c6be7e1a81769764ce0b51ce03406ad96944d8e5Tom Taylor                    }
293c6be7e1a81769764ce0b51ce03406ad96944d8e5Tom Taylor                    playInConversationNotificationSound(context);
294c6be7e1a81769764ce0b51ce03406ad96944d8e5Tom Taylor                    return;
295c6be7e1a81769764ce0b51ce03406ad96944d8e5Tom Taylor                }
296c6be7e1a81769764ce0b51ce03406ad96944d8e5Tom Taylor            }
2974c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor            updateNotification(context, newMsgThreadId != THREAD_NONE, threads.size(),
2984c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                    notificationSet);
29972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
3005a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
3013b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // And deals with delivery reports (which use Toasts). It's safe to call in a worker
3023b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // thread because the toast will eventually get posted to a handler.
3034c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        MmsSmsDeliveryInfo delivery = getSmsNewDeliveryInfo(context);
304627007213deb59ef938c80353c8f3598b01478b3Wei Huang        if (delivery != null) {
305c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            delivery.deliver(context, isStatusMessage);
306627007213deb59ef938c80353c8f3598b01478b3Wei Huang        }
3076db678ea4fb26fcffb06daa30ad7ef64d902b3d2Roger Chen
3086db678ea4fb26fcffb06daa30ad7ef64d902b3d2Roger Chen        notificationSet.clear();
3096db678ea4fb26fcffb06daa30ad7ef64d902b3d2Roger Chen        threads.clear();
31072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
31172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
31272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    /**
313c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Play the in-conversation notification sound (it's the regular notification sound, but
314c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * played at half-volume
315c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
316c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    private static void playInConversationNotificationSound(Context context) {
317c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
318c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        String ringtoneStr = sp.getString(MessagingPreferenceActivity.NOTIFICATION_RINGTONE,
319c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                null);
320c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        if (TextUtils.isEmpty(ringtoneStr)) {
321c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            // Nothing to play
322c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            return;
323c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
324c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        Uri ringtoneUri = Uri.parse(ringtoneStr);
3254ce94b2f607a93ed1a75dad7a8cbde88391a499eTom Taylor        final NotificationPlayer player = new NotificationPlayer(LogTag.APP);
326c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        player.play(context, ringtoneUri, false, AudioManager.STREAM_NOTIFICATION,
327c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                IN_CONVERSATION_NOTIFICATION_VOLUME);
3284ce94b2f607a93ed1a75dad7a8cbde88391a499eTom Taylor
3294ce94b2f607a93ed1a75dad7a8cbde88391a499eTom Taylor        // Stop the sound after five seconds to handle continuous ringtones
3304ce94b2f607a93ed1a75dad7a8cbde88391a499eTom Taylor        sHandler.postDelayed(new Runnable() {
3314ce94b2f607a93ed1a75dad7a8cbde88391a499eTom Taylor            @Override
3324ce94b2f607a93ed1a75dad7a8cbde88391a499eTom Taylor            public void run() {
3334ce94b2f607a93ed1a75dad7a8cbde88391a499eTom Taylor                player.stop();
3344ce94b2f607a93ed1a75dad7a8cbde88391a499eTom Taylor            }
3354ce94b2f607a93ed1a75dad7a8cbde88391a499eTom Taylor        }, 5000);
336c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
337c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
338c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
33935a74a9e0ee7c171c6e17f0eda4b0df0253f8364Ficus Kirkpatrick     * Updates all pending notifications, clearing or updating them as
3403b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor     * necessary.
34135a74a9e0ee7c171c6e17f0eda4b0df0253f8364Ficus Kirkpatrick     */
342bc7f97ae7d3661a44211d404fe4e187c35afadceTom Taylor    public static void blockingUpdateAllNotifications(final Context context, long threadId) {
343d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor        if (DEBUG) {
344d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor            Contact.logWithTrace(TAG, "blockingUpdateAllNotifications: newMsgThreadId: " +
345d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                    threadId);
346d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor        }
347bc7f97ae7d3661a44211d404fe4e187c35afadceTom Taylor        nonBlockingUpdateNewMessageIndicator(context, threadId, false);
348b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor        nonBlockingUpdateSendFailedNotification(context);
349627007213deb59ef938c80353c8f3598b01478b3Wei Huang        updateDownloadFailedNotification(context);
350c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor        MmsWidgetProvider.notifyDatasetChanged(context);
35135a74a9e0ee7c171c6e17f0eda4b0df0253f8364Ficus Kirkpatrick    }
3525a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
353800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    private static final class MmsSmsDeliveryInfo {
354c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public CharSequence mTicker;
355c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public long mTimeMillis;
356c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor
357c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public MmsSmsDeliveryInfo(CharSequence ticker, long timeMillis) {
358c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            mTicker = ticker;
359c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            mTimeMillis = timeMillis;
360c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        }
361c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor
362c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        public void deliver(Context context, boolean isStatusMessage) {
363c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            updateDeliveryNotification(
364c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor                    context, isStatusMessage, mTicker, mTimeMillis);
365c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        }
366800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    }
367800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
368429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final class NotificationInfo {
369c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final Intent mClickIntent;
370ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public final String mMessage;
371c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final CharSequence mTicker;
372c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final long mTimeMillis;
373c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        public final String mTitle;
374429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        public final Bitmap mAttachmentBitmap;
375429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        public final Contact mSender;
376429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        public final boolean mIsSms;
377ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public final int mAttachmentType;
378ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public final String mSubject;
379ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public final long mThreadId;
380429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
381429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        /**
382429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * @param isSms true if sms, false if mms
383429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * @param clickIntent where to go when the user taps the notification
384ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor         * @param message for a single message, this is the message text
385ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor         * @param subject text of mms subject
386429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * @param ticker text displayed ticker-style across the notification, typically formatted
387429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * as sender: message
388429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * @param timeMillis date the message was received
389429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * @param title for a single message, this is the sender
390429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         * @param attachmentBitmap a bitmap of an attachment, such as a picture or video
391ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor         * @param sender contact of the sender
392ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor         * @param attachmentType of the mms attachment
393ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor         * @param threadId thread this message belongs to
394429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor         */
395429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        public NotificationInfo(boolean isSms,
396ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                Intent clickIntent, String message, String subject,
397429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                CharSequence ticker, long timeMillis, String title,
398ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                Bitmap attachmentBitmap, Contact sender,
399ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                int attachmentType, long threadId) {
400429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            mIsSms = isSms;
40172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mClickIntent = clickIntent;
402ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            mMessage = message;
403ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            mSubject = subject;
40472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mTicker = ticker;
40572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mTimeMillis = timeMillis;
40672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mTitle = title;
407429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            mAttachmentBitmap = attachmentBitmap;
408429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            mSender = sender;
409ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            mAttachmentType = attachmentType;
410ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            mThreadId = threadId;
41172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
41272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
41372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public long getTime() {
41472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return mTimeMillis;
41572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
416ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
417ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        // This is the message string used in bigText and bigPicture notifications.
418ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public CharSequence formatBigMessage(Context context) {
419ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            final TextAppearanceSpan notificationSubjectSpan = new TextAppearanceSpan(
420ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    context, R.style.NotificationPrimaryText);
421ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
422ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            // Change multiple newlines (with potential white space between), into a single new line
423ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            final String message =
424ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    !TextUtils.isEmpty(mMessage) ? mMessage.replaceAll("\\n\\s+", "\n") : "";
425ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
426ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
427ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (!TextUtils.isEmpty(mSubject)) {
428ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.append(mSubject);
429ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.setSpan(notificationSubjectSpan, 0, mSubject.length(), 0);
430ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
431ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (mAttachmentType > WorkingMessage.TEXT) {
432ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                if (spannableStringBuilder.length() > 0) {
433ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    spannableStringBuilder.append('\n');
434ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                }
435ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.append(getAttachmentTypeString(context, mAttachmentType));
436ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
437ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (mMessage != null) {
438ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                if (spannableStringBuilder.length() > 0) {
439ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    spannableStringBuilder.append('\n');
440ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                }
441ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.append(mMessage);
442ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
443ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            return spannableStringBuilder;
444ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
445ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
446ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        // This is the message string used in each line of an inboxStyle notification.
447ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public CharSequence formatInboxMessage(Context context) {
448ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          final TextAppearanceSpan notificationSenderSpan = new TextAppearanceSpan(
449ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  context, R.style.NotificationPrimaryText);
450ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
451ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          final TextAppearanceSpan notificationSubjectSpan = new TextAppearanceSpan(
452ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  context, R.style.NotificationSubjectText);
453ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
454ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          // Change multiple newlines (with potential white space between), into a single new line
455ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          final String message =
456ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  !TextUtils.isEmpty(mMessage) ? mMessage.replaceAll("\\n\\s+", "\n") : "";
457ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
458ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
459ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          final String sender = mSender.getName();
460ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          if (!TextUtils.isEmpty(sender)) {
461ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              spannableStringBuilder.append(sender);
462ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              spannableStringBuilder.setSpan(notificationSenderSpan, 0, sender.length(), 0);
463ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          }
464ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          String separator = context.getString(R.string.notification_separator);
465ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          if (!mIsSms) {
466ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              if (!TextUtils.isEmpty(mSubject)) {
467ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  if (spannableStringBuilder.length() > 0) {
468ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                      spannableStringBuilder.append(separator);
469ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  }
470ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  int start = spannableStringBuilder.length();
471ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  spannableStringBuilder.append(mSubject);
472ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  spannableStringBuilder.setSpan(notificationSubjectSpan, start,
473ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                          start + mSubject.length(), 0);
474ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              }
475ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              if (mAttachmentType > WorkingMessage.TEXT) {
476ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  if (spannableStringBuilder.length() > 0) {
477ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                      spannableStringBuilder.append(separator);
478ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  }
479ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  spannableStringBuilder.append(getAttachmentTypeString(context, mAttachmentType));
480ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              }
481ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          }
482ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          if (message.length() > 0) {
483ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              if (spannableStringBuilder.length() > 0) {
484ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                  spannableStringBuilder.append(separator);
485ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              }
486ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              int start = spannableStringBuilder.length();
487ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              spannableStringBuilder.append(message);
488ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor              spannableStringBuilder.setSpan(notificationSubjectSpan, start,
489ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                      start + message.length(), 0);
490ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          }
491ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor          return spannableStringBuilder;
492ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
493ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
494ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        // This is the summary string used in bigPicture notifications.
495ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        public CharSequence formatPictureMessage(Context context) {
496ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            final TextAppearanceSpan notificationSubjectSpan = new TextAppearanceSpan(
497ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    context, R.style.NotificationPrimaryText);
498ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
499ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            // Change multiple newlines (with potential white space between), into a single new line
500ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            final String message =
501ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    !TextUtils.isEmpty(mMessage) ? mMessage.replaceAll("\\n\\s+", "\n") : "";
502ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
503ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            // Show the subject or the message (if no subject)
504ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
505ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (!TextUtils.isEmpty(mSubject)) {
506ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.append(mSubject);
507ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.setSpan(notificationSubjectSpan, 0, mSubject.length(), 0);
508ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
509ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (message.length() > 0 && spannableStringBuilder.length() == 0) {
510ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.append(message);
511ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.setSpan(notificationSubjectSpan, 0, message.length(), 0);
512ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
513ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            return spannableStringBuilder;
514ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
51572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
51672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
517ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    // Return a formatted string with all the sender names separated by commas.
518ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    private static CharSequence formatSenders(Context context,
519ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            ArrayList<NotificationInfo> senders) {
520ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        final TextAppearanceSpan notificationSenderSpan = new TextAppearanceSpan(
521ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                context, R.style.NotificationPrimaryText);
522ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
523ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        String separator = context.getString(R.string.enumeration_comma);   // ", "
524ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
525ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        int len = senders.size();
526ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        for (int i = 0; i < len; i++) {
527ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (i > 0) {
528ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.append(separator);
529ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
530ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            spannableStringBuilder.append(senders.get(i).mSender.getName());
531ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
532ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        spannableStringBuilder.setSpan(notificationSenderSpan, 0,
533ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                spannableStringBuilder.length(), 0);
534ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        return spannableStringBuilder;
535ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    }
536ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
537ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    // Return a formatted string with the attachmentType spelled out as a string. For
538ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    // no attachment (or just text), return null.
539ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    private static CharSequence getAttachmentTypeString(Context context, int attachmentType) {
540ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        final TextAppearanceSpan notificationAttachmentSpan = new TextAppearanceSpan(
541ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                context, R.style.NotificationSecondaryText);
542ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        int id = 0;
543ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        switch (attachmentType) {
544ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            case WorkingMessage.AUDIO: id = R.string.attachment_audio; break;
545ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            case WorkingMessage.VIDEO: id = R.string.attachment_video; break;
546ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            case WorkingMessage.SLIDESHOW: id = R.string.attachment_slideshow; break;
547ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            case WorkingMessage.IMAGE: id = R.string.attachment_picture; break;
548ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
549ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        if (id > 0) {
550ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            final SpannableString spannableString = new SpannableString(context.getString(id));
551ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            spannableString.setSpan(notificationAttachmentSpan,
552ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    0, spannableString.length(), 0);
553ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            return spannableString;
554ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
555ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        return null;
556ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor     }
557ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
558429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    /**
559429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     *
560429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * Sorts by the time a notification was received in descending order -- newer first.
561429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     *
562429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     */
563429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final class NotificationInfoComparator
564429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            implements Comparator<NotificationInfo> {
565c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        @Override
56672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public int compare(
567429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                NotificationInfo info1, NotificationInfo info2) {
56872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return Long.signum(info2.getTime() - info1.getTime());
56972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
57072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
57172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
572429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final void addMmsNotificationInfos(
5734c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor            Context context, Set<Long> threads, SortedSet<NotificationInfo> notificationSet) {
57472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        ContentResolver resolver = context.getContentResolver();
5753b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor
5763b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // This query looks like this when logged:
5773b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // I/Database(  147): elapsedTime4Sql|/data/data/com.android.providers.telephony/databases/
5783b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // mmssms.db|0.362 ms|SELECT thread_id, date, _id, sub, sub_cs FROM pdu WHERE ((msg_box=1
5793b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor        // AND seen=0 AND (m_type=130 OR m_type=132))) ORDER BY date desc
5803b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor
58172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor cursor = SqliteWrapper.query(context, resolver, Mms.CONTENT_URI,
58272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            MMS_STATUS_PROJECTION, NEW_INCOMING_MM_CONSTRAINT,
58372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            null, Mms.DATE + " desc");
58472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
585b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        if (cursor == null) {
586429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            return;
587b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
5885a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
589b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        try {
590429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            while (cursor.moveToNext()) {
591c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
592429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                long msgId = cursor.getLong(COLUMN_MMS_ID);
593429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                Uri msgUri = Mms.CONTENT_URI.buildUpon().appendPath(
594429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        Long.toString(msgId)).build();
595429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                String address = AddressUtils.getFrom(context, msgUri);
5961b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
597429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                Contact contact = Contact.get(address, false);
598429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                if (contact.getSendToVoicemail()) {
599429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    // don't notify, skip this one
600429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    continue;
601429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                }
6021b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
603429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                String subject = getMmsSubject(
604429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        cursor.getString(COLUMN_SUBJECT), cursor.getInt(COLUMN_SUBJECT_CS));
6053c307cabb5bd96ed174930ebf17f533bf2a79de7Tom Taylor                subject = MessageUtils.cleanseMmsSubject(context, subject);
6063c307cabb5bd96ed174930ebf17f533bf2a79de7Tom Taylor
607429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                long threadId = cursor.getLong(COLUMN_THREAD_ID);
608429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                long timeMillis = cursor.getLong(COLUMN_DATE) * 1000;
609b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
610429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
611429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    Log.d(TAG, "addMmsNotificationInfos: count=" + cursor.getCount() +
612429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                            ", addr = " + address + ", thread_id=" + threadId);
613429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                }
614e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang
615429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                // Extract the message and/or an attached picture from the first slide
616429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                Bitmap attachedPicture = null;
617429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                String messageBody = null;
618ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                int attachmentType = WorkingMessage.TEXT;
619429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                try {
620429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    GenericPdu pdu = sPduPersister.load(msgUri);
621f677c24f07befa52ae977461c56fedeb0ad3eb47Tom Taylor                    if (pdu != null && pdu instanceof MultimediaMessagePdu) {
622429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        SlideshowModel slideshow = SlideshowModel.createFromPduBody(context,
623429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                                ((MultimediaMessagePdu)pdu).getBody());
624ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        attachmentType = getAttachmentType(slideshow);
625429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        SlideModel firstSlide = slideshow.get(0);
626429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        if (firstSlide != null) {
627429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                            if (firstSlide.hasImage()) {
628429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                                int maxDim = dp2Pixels(MAX_BITMAP_DIMEN_DP);
629429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                                attachedPicture = firstSlide.getImage().getBitmap(maxDim, maxDim);
630429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                            }
631429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                            if (firstSlide.hasText()) {
632429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                                messageBody = firstSlide.getText().getText();
633429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                            }
634429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        }
635429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    }
636429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                } catch (final MmsException e) {
637429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    Log.e(TAG, "MmsException loading uri: " + msgUri, e);
638bc7f97ae7d3661a44211d404fe4e187c35afadceTom Taylor                    continue;   // skip this bad boy -- don't generate an empty notification
639429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                }
640b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
641ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                NotificationInfo info = getNewMessageNotificationInfo(context,
642ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        false /* isSms */,
643429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                        address,
644ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        messageBody, subject,
645ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        threadId,
646ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        timeMillis,
647ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        attachedPicture,
648ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        contact,
649ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        attachmentType);
650429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
6514c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                notificationSet.add(info);
652b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
653429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                threads.add(threadId);
654429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            }
655b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        } finally {
656b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            cursor.close();
65772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
65872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
65972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
660ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    // Look at the passed in slideshow and determine what type of attachment it is.
661ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    private static int getAttachmentType(SlideshowModel slideshow) {
662ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        int slideCount = slideshow.size();
663ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
664ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        if (slideCount == 0) {
665ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            return WorkingMessage.TEXT;
666ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        } else if (slideCount > 1) {
667ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            return WorkingMessage.SLIDESHOW;
668ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        } else {
669ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            SlideModel slide = slideshow.get(0);
670ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (slide.hasImage()) {
671ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                return WorkingMessage.IMAGE;
672ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            } else if (slide.hasVideo()) {
673ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                return WorkingMessage.VIDEO;
674ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            } else if (slide.hasAudio()) {
675ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                return WorkingMessage.AUDIO;
676ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
677ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        }
678ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        return WorkingMessage.TEXT;
679ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor    }
680ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
681429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final int dp2Pixels(int dip) {
682429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        return (int) (dip * sScreenDensity + 0.5f);
683429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    }
684429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
6853b21f6ab04db5936d73e9f53032f1587389380ffTom Taylor    private static final MmsSmsDeliveryInfo getSmsNewDeliveryInfo(Context context) {
686627007213deb59ef938c80353c8f3598b01478b3Wei Huang        ContentResolver resolver = context.getContentResolver();
687627007213deb59ef938c80353c8f3598b01478b3Wei Huang        Cursor cursor = SqliteWrapper.query(context, resolver, Sms.CONTENT_URI,
688627007213deb59ef938c80353c8f3598b01478b3Wei Huang                    SMS_STATUS_PROJECTION, NEW_DELIVERY_SM_CONSTRAINT,
6896a9c779f0c0dc6cf3ae942ff70fb6c806aa166dcBanavathu, Srinivas Naik                    null, Sms.DATE);
690800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
691ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom        if (cursor == null) {
692627007213deb59ef938c80353c8f3598b01478b3Wei Huang            return null;
693ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom        }
694800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
695627007213deb59ef938c80353c8f3598b01478b3Wei Huang        try {
696ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            if (!cursor.moveToLast()) {
697ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom                return null;
698ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            }
699800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
700627007213deb59ef938c80353c8f3598b01478b3Wei Huang            String address = cursor.getString(COLUMN_SMS_ADDRESS);
701627007213deb59ef938c80353c8f3598b01478b3Wei Huang            long timeMillis = 3000;
702800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
703ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            Contact contact = Contact.get(address, false);
704ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            String name = contact.getNameAndNumber();
705ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom
706ac9a5e52dc349faae2a7d8a990ff2b674c61f027Alexander Blom            return new MmsSmsDeliveryInfo(context.getString(R.string.delivery_toast_body, name),
707627007213deb59ef938c80353c8f3598b01478b3Wei Huang                timeMillis);
708800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
709627007213deb59ef938c80353c8f3598b01478b3Wei Huang        } finally {
710627007213deb59ef938c80353c8f3598b01478b3Wei Huang            cursor.close();
711627007213deb59ef938c80353c8f3598b01478b3Wei Huang        }
712800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    }
713800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
714429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final void addSmsNotificationInfos(
7154c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor            Context context, Set<Long> threads, SortedSet<NotificationInfo> notificationSet) {
71672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        ContentResolver resolver = context.getContentResolver();
71772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor cursor = SqliteWrapper.query(context, resolver, Sms.CONTENT_URI,
71872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            SMS_STATUS_PROJECTION, NEW_INCOMING_SM_CONSTRAINT,
71972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            null, Sms.DATE + " desc");
72072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
721b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        if (cursor == null) {
722429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            return;
723b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
7245a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
725b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        try {
726429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            while (cursor.moveToNext()) {
727429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                String address = cursor.getString(COLUMN_SMS_ADDRESS);
728b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
729429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                Contact contact = Contact.get(address, false);
730429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                if (contact.getSendToVoicemail()) {
731429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    // don't notify, skip this one
732429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    continue;
733429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                }
7341b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
735ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                String message = cursor.getString(COLUMN_SMS_BODY);
736429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                long threadId = cursor.getLong(COLUMN_THREAD_ID);
737429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                long timeMillis = cursor.getLong(COLUMN_DATE);
7381b8df494e49bf934fe160baea54ab5afc2ff3100Tom Taylor
739429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                if (Log.isLoggable(LogTag.APP, Log.VERBOSE))
740429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                {
741429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    Log.d(TAG, "addSmsNotificationInfos: count=" + cursor.getCount() +
742429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                            ", addr=" + address + ", thread_id=" + threadId);
743429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                }
744b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
745e14b79584cca1bf7ba60c53bd7e3d6386adbfc59Wei Huang
746ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                NotificationInfo info = getNewMessageNotificationInfo(context, true /* isSms */,
747ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        address, message, null /* subject */,
748ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        threadId, timeMillis, null /* attachmentBitmap */,
749ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        contact, WorkingMessage.TEXT);
750b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
7514c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                notificationSet.add(info);
752429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
753429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                threads.add(threadId);
754b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick                threads.add(cursor.getLong(COLUMN_THREAD_ID));
75572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
756b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        } finally {
757b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick            cursor.close();
75872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
75972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
76072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
761429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    private static final NotificationInfo getNewMessageNotificationInfo(
762ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            Context context,
763429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            boolean isSms,
76472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String address,
765ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            String message,
76672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            String subject,
76772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            long threadId,
76872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            long timeMillis,
769429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            Bitmap attachmentBitmap,
770ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            Contact contact,
771ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            int attachmentType) {
772812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang        Intent clickIntent = ComposeMessageActivity.createIntent(context, threadId);
773812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang        clickIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
774812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                | Intent.FLAG_ACTIVITY_SINGLE_TOP
775812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
77672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
77772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String senderInfo = buildTickerMessage(
77872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                context, address, null, null).toString();
77972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String senderInfoName = senderInfo.substring(
78072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                0, senderInfo.length() - 2);
78172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        CharSequence ticker = buildTickerMessage(
782ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                context, address, subject, message);
78372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
784429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        return new NotificationInfo(isSms,
785ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                clickIntent, message, subject, ticker, timeMillis,
786ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                senderInfoName, attachmentBitmap, contact, attachmentType, threadId);
78772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
78872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
78972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void cancelNotification(Context context, int notificationId) {
79072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        NotificationManager nm = (NotificationManager) context.getSystemService(
79172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Context.NOTIFICATION_SERVICE);
79272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
793d2f67cfca13a6e415636dc253c371fb76974f5faTom Taylor        Log.d(TAG, "cancelNotification");
79472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        nm.cancel(notificationId);
79572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
79672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
7975a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor    private static void updateDeliveryNotification(final Context context,
798c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor                                                   boolean isStatusMessage,
7995a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor                                                   final CharSequence message,
8005a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor                                                   final long timeMillis) {
801c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        if (!isStatusMessage) {
802c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            return;
803c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        }
804c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor
805800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
806d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor        if (!MessagingPreferenceActivity.getNotificationEnabled(context)) {
80770f5af8fd89d66ae246a805d10a50540746319aaWei Huang            return;
80870f5af8fd89d66ae246a805d10a50540746319aaWei Huang        }
809800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
8104ce94b2f607a93ed1a75dad7a8cbde88391a499eTom Taylor        sHandler.post(new Runnable() {
811c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            @Override
812c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            public void run() {
813c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor                Toast.makeText(context, message, (int)timeMillis).show();
814c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor            }
815c36deab7d27940a07554cc424114d9c9ddd36552Tom Taylor        });
816800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT    }
817800f2ac17e15b24e93158574649e821a334c491eAlexis ROBERT
818429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor    /**
819429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * updateNotification is *the* main function for building the actual notification handed to
820429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * the NotificationManager
821429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * @param context
822429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * @param isNew if we've got a new message, show the ticker
823429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     * @param uniqueThreadCount
8244c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor     * @param notificationSet the set of notifications to display
825429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor     */
82672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static void updateNotification(
82772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Context context,
82872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            boolean isNew,
8294c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor            int uniqueThreadCount,
8304c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor            SortedSet<NotificationInfo> notificationSet) {
831429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        // If the user has turned off notifications in settings, don't do any notifying.
832d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor        if (!MessagingPreferenceActivity.getNotificationEnabled(context)) {
8339ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor            if (DEBUG) {
8349ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor                Log.d(TAG, "updateNotification: notifications turned off in prefs, bailing");
8359ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor            }
83672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return;
83772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
83872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
839429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        // Figure out what we've got -- whether all sms's, mms's, or a mixture of both.
8404c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        final int messageCount = notificationSet.size();
8414c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor        NotificationInfo mostRecentNotification = notificationSet.first();
842429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
843674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        final Notification.Builder noti = new Notification.Builder(context)
844429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                .setWhen(mostRecentNotification.mTimeMillis);
845674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler
846429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        if (isNew) {
847ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            noti.setTicker(mostRecentNotification.mTicker);
848429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        }
849fb7068020e74e431acc9511212d2a6d17258ab9eAdam Powell        TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context);
850b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick
851b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // If we have more than one unique thread, change the title (which would
852b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // normally be the contact who sent the message) to a generic one that
853b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // makes sense for multiple senders, and change the Intent to take the
854b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // user to the conversation list instead of the specific thread.
855674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler
856429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        // Cases:
857429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        //   1) single message from single thread - intent goes to ComposeMessageActivity
858429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        //   2) multiple messages from single thread - intent goes to ComposeMessageActivity
859429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        //   3) messages from multiple threads - intent goes to ConversationList
860429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
861ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        final Resources res = context.getResources();
862429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        String title = null;
86364fefc1c9b26bd6778c318e83cec696abb389c22Daniel Sandler        Bitmap avatar = null;
864429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        if (uniqueThreadCount > 1) {    // messages from multiple threads
8651fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            Intent mainActivityIntent = new Intent(Intent.ACTION_MAIN);
866812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang
8671fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            mainActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
868812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                    | Intent.FLAG_ACTIVITY_SINGLE_TOP
869812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
870812391ad832f3fdac054ad3a50af563da16e99b5Wei Huang
8711fdc24a996e1c2d6a1add1f40260c5e0380f3112Tom Taylor            mainActivityIntent.setType("vnd.android-dir/mms-sms");
8726cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor            taskStackBuilder.addNextIntent(mainActivityIntent);
873ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            title = context.getString(R.string.message_count_notification, messageCount);
874429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        } else {    // same thread, single or multiple messages
875ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            title = mostRecentNotification.mTitle;
876429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            BitmapDrawable contactDrawable = (BitmapDrawable)mostRecentNotification.mSender
877429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                    .getAvatar(context, null);
878ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (contactDrawable != null) {
879ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // Show the sender's avatar as the big icon. Contact bitmaps are 96x96 so we
880ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // have to scale 'em up to 128x128 to fill the whole notification large icon.
88164fefc1c9b26bd6778c318e83cec696abb389c22Daniel Sandler                avatar = contactDrawable.getBitmap();
882ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                if (avatar != null) {
883ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    final int idealIconHeight =
884ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        res.getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
885ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    final int idealIconWidth =
886ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                         res.getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
887ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    if (avatar.getHeight() < idealIconHeight) {
888ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        // Scale this image to fit the intended size
889ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        avatar = Bitmap.createScaledBitmap(
890ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                                avatar, idealIconWidth, idealIconHeight, true);
891ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    }
892ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    if (avatar != null) {
893ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        noti.setLargeIcon(avatar);
894ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    }
895ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                }
896ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
897429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
8986cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor            taskStackBuilder.addParentStack(ComposeMessageActivity.class);
8996cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor            taskStackBuilder.addNextIntent(mostRecentNotification.mClickIntent);
900b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        }
901ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        // Always have to set the small icon or the notification is ignored
902ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        noti.setSmallIcon(R.drawable.stat_notify_sms);
903ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
904429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        NotificationManager nm = (NotificationManager)
905429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                context.getSystemService(Context.NOTIFICATION_SERVICE);
90672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
907b11a5086727c4b67c72ca605771fb37e12dcf803Ficus Kirkpatrick        // Update the notification.
908674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        noti.setContentTitle(title)
9096cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor            .setContentIntent(
9106cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor                    taskStackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT))
911e858f1252faf8c9a228d834d94c43fa6fefd73f3John Spurlock            .setCategory(Notification.CATEGORY_MESSAGE)
912ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            .setPriority(Notification.PRIORITY_DEFAULT);     // TODO: set based on contact coming
913ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                                                             // from a favorite.
914429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
9154c99d70732d5bf20d34da3ce76753e00c7ae7c39Christoph Studer        // Tag notification with all senders.
9164c99d70732d5bf20d34da3ce76753e00c7ae7c39Christoph Studer        for (NotificationInfo info : notificationSet) {
9174c99d70732d5bf20d34da3ce76753e00c7ae7c39Christoph Studer            Uri peopleReferenceUri = info.mSender.getPeopleReferenceUri();
9184c99d70732d5bf20d34da3ce76753e00c7ae7c39Christoph Studer            if (peopleReferenceUri != null) {
9194c99d70732d5bf20d34da3ce76753e00c7ae7c39Christoph Studer                noti.addPerson(peopleReferenceUri.toString());
9204c99d70732d5bf20d34da3ce76753e00c7ae7c39Christoph Studer            }
9214c99d70732d5bf20d34da3ce76753e00c7ae7c39Christoph Studer        }
9224c99d70732d5bf20d34da3ce76753e00c7ae7c39Christoph Studer
923674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        int defaults = 0;
92472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
92572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (isNew) {
926d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
927006d49271549ed639ffcd70d94c7650bb3514796Jim Shuma
92890e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor            boolean vibrate = false;
92990e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor            if (sp.contains(MessagingPreferenceActivity.NOTIFICATION_VIBRATE)) {
93090e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor                // The most recent change to the vibrate preference is to store a boolean
93190e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor                // value in NOTIFICATION_VIBRATE. If prefs contain that preference, use that
93290e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor                // first.
93390e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor                vibrate = sp.getBoolean(MessagingPreferenceActivity.NOTIFICATION_VIBRATE,
93490e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor                        false);
93590e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor            } else if (sp.contains(MessagingPreferenceActivity.NOTIFICATION_VIBRATE_WHEN)) {
93690e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor                // This is to support the pre-JellyBean MR1.1 version of vibrate preferences
93790e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor                // when vibrate was a tri-state setting. As soon as the user opens the Messaging
93890e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor                // app's settings, it will migrate this setting from NOTIFICATION_VIBRATE_WHEN
93990e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor                // to the boolean value stored in NOTIFICATION_VIBRATE.
94090e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor                String vibrateWhen =
94190e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor                        sp.getString(MessagingPreferenceActivity.NOTIFICATION_VIBRATE_WHEN, null);
94290e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor                vibrate = "always".equals(vibrateWhen);
94390e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor            }
94490e32e59610d4a395716b1cfa9c8b041b45e3d4eTom Taylor            if (vibrate) {
945674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler                defaults |= Notification.DEFAULT_VIBRATE;
94672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
94772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
948627007213deb59ef938c80353c8f3598b01478b3Wei Huang            String ringtoneStr = sp.getString(MessagingPreferenceActivity.NOTIFICATION_RINGTONE,
949627007213deb59ef938c80353c8f3598b01478b3Wei Huang                    null);
950674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler            noti.setSound(TextUtils.isEmpty(ringtoneStr) ? null : Uri.parse(ringtoneStr));
951d2f67cfca13a6e415636dc253c371fb76974f5faTom Taylor            Log.d(TAG, "updateNotification: new message, adding sound to the notification");
95272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
95372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
954674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        defaults |= Notification.DEFAULT_LIGHTS;
955674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler
956674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        noti.setDefaults(defaults);
95772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
95870f5af8fd89d66ae246a805d10a50540746319aaWei Huang        // set up delete intent
959674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        noti.setDeleteIntent(PendingIntent.getBroadcast(context, 0,
960674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler                sNotificationOnDeleteIntent, 0));
96170f5af8fd89d66ae246a805d10a50540746319aaWei Huang
962674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        final Notification notification;
963429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
964ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        if (messageCount == 1) {
965ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            // We've got a single message
966ca7b54a002b5bc627171d1b275cb016bf1105da2Daniel Sandler
967ca7b54a002b5bc627171d1b275cb016bf1105da2Daniel Sandler            // This sets the text for the collapsed form:
968ca7b54a002b5bc627171d1b275cb016bf1105da2Daniel Sandler            noti.setContentText(mostRecentNotification.formatBigMessage(context));
969ca7b54a002b5bc627171d1b275cb016bf1105da2Daniel Sandler
970ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (mostRecentNotification.mAttachmentBitmap != null) {
971ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // The message has a picture, show that
972ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
973ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                notification = new Notification.BigPictureStyle(noti)
974ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .bigPicture(mostRecentNotification.mAttachmentBitmap)
975ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    // This sets the text for the expanded picture form:
976ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .setSummaryText(mostRecentNotification.formatPictureMessage(context))
977ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .build();
978ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            } else {
979ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // Show a single notification -- big style with the text of the whole message
980ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                notification = new Notification.BigTextStyle(noti)
981ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .bigText(mostRecentNotification.formatBigMessage(context))
982ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .build();
983ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            }
9846d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor            if (DEBUG) {
9856d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor                Log.d(TAG, "updateNotification: single message notification");
9866d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor            }
987ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor        } else {
988ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            // We've got multiple messages
989ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            if (uniqueThreadCount == 1) {
990ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // We've got multiple messages for the same thread.
991ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // Starting with the oldest new message, display the full text of each message.
992ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // Begin a line for each subsequent message.
993429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                SpannableStringBuilder buf = new SpannableStringBuilder();
994ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                NotificationInfo infos[] =
9954c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                        notificationSet.toArray(new NotificationInfo[messageCount]);
996ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                int len = infos.length;
997ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                for (int i = len - 1; i >= 0; i--) {
998ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    NotificationInfo info = infos[i];
999ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
1000ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    buf.append(info.formatBigMessage(context));
1001429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
1002ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    if (i != 0) {
1003ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        buf.append('\n');
1004ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    }
1005ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                }
1006ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
1007ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                noti.setContentText(context.getString(R.string.message_count_notification,
1008ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        messageCount));
1009ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
1010ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // Show a single notification -- big style with the text of all the messages
1011ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                notification = new Notification.BigTextStyle(noti)
1012ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .bigText(buf)
10134c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                    // Forcibly show the last line, with the app's smallIcon in it, if we
101464fefc1c9b26bd6778c318e83cec696abb389c22Daniel Sandler                    // kicked the smallIcon out with an avatar bitmap
101564fefc1c9b26bd6778c318e83cec696abb389c22Daniel Sandler                    .setSummaryText((avatar == null) ? null : " ")
1016ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    .build();
10176d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor                if (DEBUG) {
10186d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor                    Log.d(TAG, "updateNotification: multi messages for single thread");
10196d2ba55a4bd1937bbec101ab2a4c005b566b43f8Tom Taylor                }
1020ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor            } else {
1021ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // Build a set of the most recent notification per threadId.
10224c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                HashSet<Long> uniqueThreads = new HashSet<Long>(messageCount);
1023ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                ArrayList<NotificationInfo> mostRecentNotifPerThread =
1024ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        new ArrayList<NotificationInfo>();
10254c6c7c65a1033d5cc0d87cc8b0e07a69db1842e8Tom Taylor                Iterator<NotificationInfo> notifications = notificationSet.iterator();
1026ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                while (notifications.hasNext()) {
1027ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    NotificationInfo notificationInfo = notifications.next();
1028ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    if (!uniqueThreads.contains(notificationInfo.mThreadId)) {
1029ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        uniqueThreads.add(notificationInfo.mThreadId);
1030ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                        mostRecentNotifPerThread.add(notificationInfo);
1031ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    }
1032ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                }
1033ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // When collapsed, show all the senders like this:
1034ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                //     Fred Flinstone, Barry Manilow, Pete...
1035ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                noti.setContentText(formatSenders(context, mostRecentNotifPerThread));
1036ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                Notification.InboxStyle inboxStyle = new Notification.InboxStyle(noti);
1037ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
1038ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // We have to set the summary text to non-empty so the content text doesn't show
1039ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // up when expanded.
1040ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                inboxStyle.setSummaryText(" ");
1041ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
1042ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // At this point we've got multiple messages in multiple threads. We only
1043ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // want to show the most recent message per thread, which are in
1044ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                // mostRecentNotifPerThread.
1045ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                int uniqueThreadMessageCount = mostRecentNotifPerThread.size();
1046ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                int maxMessages = Math.min(MAX_MESSAGES_TO_SHOW, uniqueThreadMessageCount);
1047ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor
1048ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                for (int i = 0; i < maxMessages; i++) {
1049ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    NotificationInfo info = mostRecentNotifPerThread.get(i);
1050ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    inboxStyle.addLine(info.formatInboxMessage(context));
1051ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                }
1052ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                notification = inboxStyle.build();
10536db678ea4fb26fcffb06daa30ad7ef64d902b3d2Roger Chen
10546db678ea4fb26fcffb06daa30ad7ef64d902b3d2Roger Chen                uniqueThreads.clear();
10556db678ea4fb26fcffb06daa30ad7ef64d902b3d2Roger Chen                mostRecentNotifPerThread.clear();
10566db678ea4fb26fcffb06daa30ad7ef64d902b3d2Roger Chen
1057ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                if (DEBUG) {
1058ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                    Log.d(TAG, "updateNotification: multi messages," +
1059ee0f8ea8d8739358387443b4fe7d1d9edf44f601Tom Taylor                            " showing inboxStyle notification");
1060429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                }
10619ab4d755b862392724b7dbb12e636235a05cb3bdTom Taylor            }
1062674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler        }
1063674b5045f39aedf85e6a7e38237860d000f46de0Daniel Sandler
106472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        nm.notify(NOTIFICATION_ID, notification);
106572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
106672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
106772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    protected static CharSequence buildTickerMessage(
106872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Context context, String address, String subject, String body) {
106933a87f96f8c625aa10131a77a3968c97c4ec5a62Ficus Kirkpatrick        String displayAddress = Contact.get(address, true).getName();
10705a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
107172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        StringBuilder buf = new StringBuilder(
107272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                displayAddress == null
107372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                ? ""
107472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                : displayAddress.replace('\n', ' ').replace('\r', ' '));
107572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        buf.append(':').append(' ');
107672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
107772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int offset = buf.length();
107872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!TextUtils.isEmpty(subject)) {
107972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            subject = subject.replace('\n', ' ').replace('\r', ' ');
108072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            buf.append(subject);
108172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            buf.append(' ');
108272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
108372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
108472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!TextUtils.isEmpty(body)) {
108572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            body = body.replace('\n', ' ').replace('\r', ' ');
108672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            buf.append(body);
108772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
108872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
108972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        SpannableString spanText = new SpannableString(buf.toString());
109072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        spanText.setSpan(new StyleSpan(Typeface.BOLD), 0, offset,
109172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
109272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
109372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return spanText;
109472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
109572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
109672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static String getMmsSubject(String sub, int charset) {
109772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return TextUtils.isEmpty(sub) ? ""
109872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                : new EncodedStringValue(charset, PduPersister.getBytes(sub)).getString();
109972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
110072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
110172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void notifyDownloadFailed(Context context, long threadId) {
1102b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        notifyFailed(context, true, threadId, false);
110372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
110472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
11055d2d0046ada7b53205e537d8675d32a8785e8d1dThe Android Open Source Project    public static void notifySendFailed(Context context) {
1106b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        notifyFailed(context, false, 0, false);
110772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
110872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
1109b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick    public static void notifySendFailed(Context context, boolean noisy) {
1110b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        notifyFailed(context, false, 0, noisy);
1111b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick    }
11125a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
1113b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick    private static void notifyFailed(Context context, boolean isDownload, long threadId,
1114b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick                                     boolean noisy) {
111572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // TODO factor out common code for creating notifications
1116d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor        boolean enabled = MessagingPreferenceActivity.getNotificationEnabled(context);
111772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!enabled) {
111872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return;
111972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
112072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
112172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Strategy:
112272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // a. If there is a single failure notification, tapping on the notification goes
112372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        //    to the compose view.
11245a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor        // b. If there are two failure it stays in the thread view. Selecting one undelivered
112572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        //    thread will dismiss one undelivered notification but will still display the
112672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        //    notification.If you select the 2nd undelivered one it will dismiss the notification.
11275a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
11287015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        long[] msgThreadId = {0, 1};    // Dummy initial values, just to initialize the memory
112972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int totalFailedCount = getUndeliveredMessageCount(context, msgThreadId);
11307015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        if (totalFailedCount == 0 && !isDownload) {
11317015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev            return;
11327015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        }
11337015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // The getUndeliveredMessageCount method puts a non-zero value in msgThreadId[1] if all
11347015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // failures are from the same thread.
11357015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // If isDownload is true, we're dealing with 1 specific failure; therefore "all failed" are
11367015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        // indeed in the same thread since there's only 1.
11377015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        boolean allFailedInSameThread = (msgThreadId[1] != 0) || isDownload;
11385a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
113972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Intent failedIntent;
114072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Notification notification = new Notification();
114172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String title;
114272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        String description;
114372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (totalFailedCount > 1) {
114472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            description = context.getString(R.string.notification_failed_multiple,
114572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    Integer.toString(totalFailedCount));
114672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            title = context.getString(R.string.notification_failed_multiple_title);
114772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else {
114872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            title = isDownload ?
114972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        context.getString(R.string.message_download_failed_title) :
115072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        context.getString(R.string.message_send_failed_title);
11515a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
115272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            description = context.getString(R.string.message_failed_body);
11537015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        }
11547015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev
1155fb7068020e74e431acc9511212d2a6d17258ab9eAdam Powell        TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context);
11567015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        if (allFailedInSameThread) {
1157836945de572ac80fd6f6a7bf59036d4cce801410The Android Open Source Project            failedIntent = new Intent(context, ComposeMessageActivity.class);
115895817b166d415114bac89ca0946c3717ae229526Tom Taylor            if (isDownload) {
115995817b166d415114bac89ca0946c3717ae229526Tom Taylor                // When isDownload is true, the valid threadId is passed into this function.
116095817b166d415114bac89ca0946c3717ae229526Tom Taylor                failedIntent.putExtra("failed_download_flag", true);
116195817b166d415114bac89ca0946c3717ae229526Tom Taylor            } else {
11627015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev                threadId = msgThreadId[0];
116395817b166d415114bac89ca0946c3717ae229526Tom Taylor                failedIntent.putExtra("undelivered_flag", true);
11645a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor            }
11655a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor            failedIntent.putExtra("thread_id", threadId);
11666cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor            taskStackBuilder.addParentStack(ComposeMessageActivity.class);
11677015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev        } else {
11687015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev            failedIntent = new Intent(context, ConversationList.class);
116972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
11706cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor        taskStackBuilder.addNextIntent(failedIntent);
117172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
117272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        notification.icon = R.drawable.stat_notify_sms_failed;
117372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
117472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        notification.tickerText = title;
117572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
11766cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor        notification.setLatestEventInfo(context, title, description,
11776cc254afc74dee97c7ef356612ae9ec7bc8b77ceTom Taylor                taskStackBuilder.getPendingIntent(0,  PendingIntent.FLAG_UPDATE_CURRENT));
117872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
1179b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        if (noisy) {
1180d83675687b1ef742c33bffe8195d7b1852c2c01dTom Taylor            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
1181e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang            boolean vibrate = sp.getBoolean(MessagingPreferenceActivity.NOTIFICATION_VIBRATE,
1182e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang                    false /* don't vibrate by default */);
1183b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick            if (vibrate) {
1184b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick                notification.defaults |= Notification.DEFAULT_VIBRATE;
1185b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick            }
118672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
1187e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang            String ringtoneStr = sp.getString(MessagingPreferenceActivity.NOTIFICATION_RINGTONE,
1188e3baaa51cd25b52c7a24e381319926b9da00abdfWei Huang                    null);
1189b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick            notification.sound = TextUtils.isEmpty(ringtoneStr) ? null : Uri.parse(ringtoneStr);
1190b3cb9bbf929f70cb4855f03e4bfbed749022cf1bFicus Kirkpatrick        }
11915a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
1192429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor        NotificationManager notificationMgr = (NotificationManager)
1193429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor                context.getSystemService(Context.NOTIFICATION_SERVICE);
1194429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor
119572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (isDownload) {
1196429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            notificationMgr.notify(DOWNLOAD_FAILED_NOTIFICATION_ID, notification);
119772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else {
1198429f4c0b2a6ada384e30af31644f1edba0284b4dTom Taylor            notificationMgr.notify(MESSAGE_FAILED_NOTIFICATION_ID, notification);
119972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
120072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
12015a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
12027015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev    /**
12037015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     * Query the DB and return the number of undelivered messages (total for both SMS and MMS)
12047015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     * @param context The context
12057015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     * @param threadIdResult A container to put the result in, according to the following rules:
12067015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  threadIdResult[0] contains the thread id of the first message.
12077015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  threadIdResult[1] is nonzero if the thread ids of all the messages are the same.
12087015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  You can pass in null for threadIdResult.
12097015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     *  You can pass in a threadIdResult of size 1 to avoid the comparison of each thread id.
12107015fa3f96383fa8a34d6b9e28f61d228e234d7eTodor Kalaydjiev     */
121172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static int getUndeliveredMessageCount(Context context, long[] threadIdResult) {
121272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor undeliveredCursor = SqliteWrapper.query(context, context.getContentResolver(),
1213c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                UNDELIVERED_URI, MMS_THREAD_ID_PROJECTION, "read=0", null, null);
121472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (undeliveredCursor == null) {
121572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return 0;
121672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
121772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int count = undeliveredCursor.getCount();
121872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        try {
121972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (threadIdResult != null && undeliveredCursor.moveToFirst()) {
122072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                threadIdResult[0] = undeliveredCursor.getLong(0);
12215a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
12222f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                if (threadIdResult.length >= 2) {
12232f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    // Test to see if all the undelivered messages belong to the same thread.
12242f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    long firstId = threadIdResult[0];
12252f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    while (undeliveredCursor.moveToNext()) {
12262f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                        if (undeliveredCursor.getLong(0) != firstId) {
12272f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                            firstId = 0;
12282f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                            break;
12292f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                        }
12302f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    }
12312f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                    threadIdResult[1] = firstId;    // non-zero if all ids are the same
12322f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                }
123372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
123472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } finally {
123572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            undeliveredCursor.close();
123672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
123772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return count;
123872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
123972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
1240b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor    public static void nonBlockingUpdateSendFailedNotification(final Context context) {
1241b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor        new AsyncTask<Void, Void, Integer>() {
1242b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor            protected Integer doInBackground(Void... none) {
1243b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                return getUndeliveredMessageCount(context, null);
1244b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor            }
1245b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor
1246b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor            protected void onPostExecute(Integer result) {
1247b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                if (result < 1) {
1248b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                    cancelNotification(context, MESSAGE_FAILED_NOTIFICATION_ID);
1249b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                } else {
1250b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                    // rebuild and adjust the message count if necessary.
1251b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                    notifySendFailed(context);
1252b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor                }
1253b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor            }
1254b0ef8fc2738b210a2bb0490e75eedc1e7b7b491fTom Taylor        }.execute();
125572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
12565a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
12575a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor    /**
12582f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project     *  If all the undelivered messages belong to "threadId", cancel the notification.
12592f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project     */
12602f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project    public static void updateSendFailedNotificationForThread(Context context, long threadId) {
12612f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project        long[] msgThreadId = {0, 0};
12625a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor        if (getUndeliveredMessageCount(context, msgThreadId) > 0
12632f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                && msgThreadId[0] == threadId
12642f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project                && msgThreadId[1] != 0) {
12652f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project            cancelNotification(context, MESSAGE_FAILED_NOTIFICATION_ID);
12662f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project        }
12672f56791329cefc49ce79663b8d3aff50594cc1f3The Android Open Source Project    }
12685a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
126972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static int getDownloadFailedMessageCount(Context context) {
127072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Look for any messages in the MMS Inbox that are of the type
127172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // NOTIFICATION_IND (i.e. not already downloaded) and in the
127272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // permanent failure state.  If there are none, cancel any
127372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // failed download notification.
127472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Cursor c = SqliteWrapper.query(context, context.getContentResolver(),
127572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Mms.Inbox.CONTENT_URI, null,
127672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Mms.MESSAGE_TYPE + "=" +
127772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    String.valueOf(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) +
127872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                " AND " + Mms.STATUS + "=" +
127972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    String.valueOf(DownloadManager.STATE_PERMANENT_FAILURE),
128072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                null, null);
128172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (c == null) {
128272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return 0;
128372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
128472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int count = c.getCount();
128572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        c.close();
128672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return count;
128772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
128872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
128972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static void updateDownloadFailedNotification(Context context) {
129072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (getDownloadFailedMessageCount(context) < 1) {
129172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            cancelNotification(context, DOWNLOAD_FAILED_NOTIFICATION_ID);
129272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
129372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
12945a73318ac906b37eb5634a6975a8a26ef5ed36efTom Taylor
129595817b166d415114bac89ca0946c3717ae229526Tom Taylor    public static boolean isFailedToDeliver(Intent intent) {
129695817b166d415114bac89ca0946c3717ae229526Tom Taylor        return (intent != null) && intent.getBooleanExtra("undelivered_flag", false);
129795817b166d415114bac89ca0946c3717ae229526Tom Taylor    }
129895817b166d415114bac89ca0946c3717ae229526Tom Taylor
129995817b166d415114bac89ca0946c3717ae229526Tom Taylor    public static boolean isFailedToDownload(Intent intent) {
130095817b166d415114bac89ca0946c3717ae229526Tom Taylor        return (intent != null) && intent.getBooleanExtra("failed_download_flag", false);
130195817b166d415114bac89ca0946c3717ae229526Tom Taylor    }
1302c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
1303c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
1304c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Get the thread ID of the SMS message with the given URI
1305c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param context The context
1306c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param uri The URI of the SMS message
1307c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @return The thread ID, or THREAD_NONE if the URI contains no entries
1308c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
1309c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static long getSmsThreadId(Context context, Uri uri) {
1310c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        Cursor cursor = SqliteWrapper.query(
1311c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            context,
1312c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            context.getContentResolver(),
1313c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            uri,
1314c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            SMS_THREAD_ID_PROJECTION,
1315c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            null,
1316c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            null,
1317c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            null);
1318c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
1319c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        if (cursor == null) {
1320d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor            if (DEBUG) {
1321d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                Log.d(TAG, "getSmsThreadId uri: " + uri + " NULL cursor! returning THREAD_NONE");
1322d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor            }
1323c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            return THREAD_NONE;
1324c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
1325c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
1326c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        try {
1327c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            if (cursor.moveToFirst()) {
13287ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                int columnIndex = cursor.getColumnIndex(Sms.THREAD_ID);
13297ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                if (columnIndex < 0) {
13307ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                    if (DEBUG) {
13317ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                        Log.d(TAG, "getSmsThreadId uri: " + uri +
13327ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                                " Couldn't read row 0, col -1! returning THREAD_NONE");
13337ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                    }
13347ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                    return THREAD_NONE;
13357ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                }
13367ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                long threadId = cursor.getLong(columnIndex);
1337d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                if (DEBUG) {
1338d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                    Log.d(TAG, "getSmsThreadId uri: " + uri +
1339d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                            " returning threadId: " + threadId);
1340d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                }
1341d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                return threadId;
1342c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            } else {
1343d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                if (DEBUG) {
1344d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                    Log.d(TAG, "getSmsThreadId uri: " + uri +
1345d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                            " NULL cursor! returning THREAD_NONE");
1346d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                }
1347c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                return THREAD_NONE;
1348c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            }
1349c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        } finally {
1350c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            cursor.close();
1351c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
1352c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
1353c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
1354c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    /**
1355c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * Get the thread ID of the MMS message with the given URI
1356c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param context The context
1357c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @param uri The URI of the SMS message
1358c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     * @return The thread ID, or THREAD_NONE if the URI contains no entries
1359c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev     */
1360c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    public static long getThreadId(Context context, Uri uri) {
1361c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        Cursor cursor = SqliteWrapper.query(
1362c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                context,
1363c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                context.getContentResolver(),
1364c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                uri,
1365c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                MMS_THREAD_ID_PROJECTION,
1366c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                null,
1367c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                null,
1368c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                null);
1369c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
1370c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        if (cursor == null) {
1371d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor            if (DEBUG) {
1372d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                Log.d(TAG, "getThreadId uri: " + uri + " NULL cursor! returning THREAD_NONE");
1373d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor            }
1374c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            return THREAD_NONE;
1375c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
1376c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev
1377c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        try {
1378c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            if (cursor.moveToFirst()) {
13797ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                int columnIndex = cursor.getColumnIndex(Mms.THREAD_ID);
13807ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                if (columnIndex < 0) {
13817ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                    if (DEBUG) {
13827ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                        Log.d(TAG, "getThreadId uri: " + uri +
13837ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                                " Couldn't read row 0, col -1! returning THREAD_NONE");
13847ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                    }
13857ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                    return THREAD_NONE;
13867ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                }
13877ecebc423d3fb8e9d8b5703780582f5a486aa742yoohyun.choi                long threadId = cursor.getLong(columnIndex);
1388d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                if (DEBUG) {
1389d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                    Log.d(TAG, "getThreadId uri: " + uri +
1390d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                            " returning threadId: " + threadId);
1391d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                }
1392d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                return threadId;
1393c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            } else {
1394d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                if (DEBUG) {
1395d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                    Log.d(TAG, "getThreadId uri: " + uri +
1396d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                            " NULL cursor! returning THREAD_NONE");
1397d645c8b53ae904bc059ee1ca7232916637c223e5Tom Taylor                }
1398c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev                return THREAD_NONE;
1399c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            }
1400c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        } finally {
1401c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev            cursor.close();
1402c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev        }
1403c8d727902ff6976c45285a12aab176545a7848bbTodor Kalaydjiev    }
140472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project}
1405