1c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor/* 2c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * Copyright (C) 2012 The Android Open Source Project 3c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * 4c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * Licensed under the Apache License, Version 2.0 (the "License"); 5c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * you may not use this file except in compliance with the License. 6c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * You may obtain a copy of the License at 7c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * 8c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * http://www.apache.org/licenses/LICENSE-2.0 9c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * 10c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * Unless required by applicable law or agreed to in writing, software 11c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * distributed under the License is distributed on an "AS IS" BASIS, 12c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * See the License for the specific language governing permissions and 14c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * limitations under the License. 15c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor */ 16c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 17c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorpackage com.android.mms.widget; 18c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 191c5596602dcc0ccbf04782333d0d61dbb090784cRoger Chenimport android.app.PendingIntent; 20c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.appwidget.AppWidgetManager; 21c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.content.Context; 22c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.content.Intent; 23c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.content.res.Resources; 24c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.database.Cursor; 25c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.provider.Telephony.Threads; 26c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.text.Spannable; 27c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.text.SpannableStringBuilder; 28c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.text.style.ForegroundColorSpan; 29ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylorimport android.text.style.TextAppearanceSpan; 30c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.util.Log; 31c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.view.View; 32c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.widget.RemoteViews; 33c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.widget.RemoteViewsService; 34c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 35c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.LogTag; 36c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.R; 37c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.data.Contact; 38c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.data.Conversation; 39c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.ui.ConversationList; 40c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.ui.ConversationListItem; 41c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.ui.MessageUtils; 42c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 43c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorpublic class MmsWidgetService extends RemoteViewsService { 44ab845dee6565a8dfc384186bc8f2e801a2b087e1Ye Wen private static final String TAG = LogTag.TAG; 45c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 46c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor /** 47c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * Lock to avoid race condition between widgets. 48c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor */ 49c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private static final Object sWidgetLock = new Object(); 50c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 51c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 52c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public RemoteViewsFactory onGetViewFactory(Intent intent) { 53c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 54c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "onGetViewFactory intent: " + intent); 55c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 56c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return new MmsFactory(getApplicationContext(), intent); 57c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 58c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 59c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor /** 60c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * Remote Views Factory for Mms Widget. 61c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor */ 62c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private static class MmsFactory 63c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor implements RemoteViewsService.RemoteViewsFactory, Contact.UpdateListener { 64c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private static final int MAX_CONVERSATIONS_COUNT = 25; 65c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private final Context mContext; 66c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private final int mAppWidgetId; 67c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private boolean mShouldShowViewMore; 68c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private Cursor mConversationCursor; 69c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private int mUnreadConvCount; 70c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private final AppWidgetManager mAppWidgetManager; 71c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 72c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // Static colors 73c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private static int SUBJECT_TEXT_COLOR_READ; 74c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private static int SUBJECT_TEXT_COLOR_UNREAD; 75c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private static int SENDERS_TEXT_COLOR_READ; 76c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private static int SENDERS_TEXT_COLOR_UNREAD; 77c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 78c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public MmsFactory(Context context, Intent intent) { 79c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mContext = context; 80c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mAppWidgetId = intent.getIntExtra( 81c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); 82c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mAppWidgetManager = AppWidgetManager.getInstance(context); 83c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 84c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "MmsFactory intent: " + intent + "widget id: " + mAppWidgetId); 85c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 86c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // Initialize colors 87c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Resources res = context.getResources(); 88c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor SENDERS_TEXT_COLOR_READ = res.getColor(R.color.widget_sender_text_color_read); 89c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor SENDERS_TEXT_COLOR_UNREAD = res.getColor(R.color.widget_sender_text_color_unread); 90c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor SUBJECT_TEXT_COLOR_READ = res.getColor(R.color.widget_subject_text_color_read); 91c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor SUBJECT_TEXT_COLOR_UNREAD = res.getColor(R.color.widget_subject_text_color_unread); 92c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 93c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 94c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 95c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public void onCreate() { 96c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 97c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "onCreate"); 98c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 99c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Contact.addListener(this); 100c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 101c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 102c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 103c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public void onDestroy() { 104c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 105c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "onDestroy"); 106c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 107c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor synchronized (sWidgetLock) { 108c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (mConversationCursor != null && !mConversationCursor.isClosed()) { 109c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mConversationCursor.close(); 110c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mConversationCursor = null; 111c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 112c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Contact.removeListener(this); 113c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 114c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 115c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 116c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 117c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public void onDataSetChanged() { 118c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 119c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "onDataSetChanged"); 120c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 121c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor synchronized (sWidgetLock) { 122c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (mConversationCursor != null) { 123c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mConversationCursor.close(); 124c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mConversationCursor = null; 125c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 126c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mConversationCursor = queryAllConversations(); 127c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mUnreadConvCount = queryUnreadCount(); 128c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor onLoadComplete(); 129c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 130c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 131c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 132c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private Cursor queryAllConversations() { 133c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return mContext.getContentResolver().query( 134c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Conversation.sAllThreadsUri, Conversation.ALL_THREADS_PROJECTION, 135c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor null, null, null); 136c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 137c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 138c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private int queryUnreadCount() { 139c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Cursor cursor = null; 140c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor int unreadCount = 0; 141c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor try { 142c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor cursor = mContext.getContentResolver().query( 143c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Conversation.sAllThreadsUri, Conversation.ALL_THREADS_PROJECTION, 144c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Threads.READ + "=0", null, null); 145c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (cursor != null) { 146c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor unreadCount = cursor.getCount(); 147c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 148c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } finally { 149c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (cursor != null) { 150c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor cursor.close(); 151c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 152c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 153c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return unreadCount; 154c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 155c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 156c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor /** 157c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * Returns the number of items should be shown in the widget list. This method also updates 158c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * the boolean that indicates whether the "show more" item should be shown. 159c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * @return the number of items to be displayed in the list. 160c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor */ 161c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 162c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public int getCount() { 163c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 164c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "getCount"); 165c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 166c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor synchronized (sWidgetLock) { 167c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (mConversationCursor == null) { 168c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return 0; 169c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 170c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor final int count = getConversationCount(); 171c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mShouldShowViewMore = count < mConversationCursor.getCount(); 172c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return count + (mShouldShowViewMore ? 1 : 0); 173c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 174c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 175c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 176c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor /** 177c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * Returns the number of conversations that should be shown in the widget. This method 178c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * doesn't update the boolean that indicates that the "show more" item should be included 179c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * in the list. 180c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * @return 181c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor */ 182c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private int getConversationCount() { 183c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 184c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "getConversationCount"); 185c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 1861c5596602dcc0ccbf04782333d0d61dbb090784cRoger Chen 1871c5596602dcc0ccbf04782333d0d61dbb090784cRoger Chen return Math.min(mConversationCursor.getCount(), MAX_CONVERSATIONS_COUNT); 188c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 189c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 190c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor /* 191c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * Add color to a given text 192c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor */ 193c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private SpannableStringBuilder addColor(CharSequence text, int color) { 194c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor SpannableStringBuilder builder = new SpannableStringBuilder(text); 195c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (color != 0) { 196c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor builder.setSpan(new ForegroundColorSpan(color), 0, text.length(), 197c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 198c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 199c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return builder; 200c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 201c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 202c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor /** 203c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * @return the {@link RemoteViews} for a specific position in the list. 204c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor */ 205c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 206c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public RemoteViews getViewAt(int position) { 207c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 208c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "getViewAt position: " + position); 209c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 210c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor synchronized (sWidgetLock) { 211c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // "View more conversations" view. 212c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (mConversationCursor == null 213c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor || (mShouldShowViewMore && position >= getConversationCount())) { 214c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return getViewMoreConversationsView(); 215c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 216c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 217c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (!mConversationCursor.moveToPosition(position)) { 218c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // If we ever fail to move to a position, return the "View More conversations" 219c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // view. 220c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.w(TAG, "Failed to move to position: " + position); 221c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return getViewMoreConversationsView(); 222c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 223c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 224c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Conversation conv = Conversation.from(mContext, mConversationCursor); 225c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 226c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // Inflate and fill out the remote view 227c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor RemoteViews remoteViews = new RemoteViews( 228c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mContext.getPackageName(), R.layout.widget_conversation); 229c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 230c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (conv.hasUnreadMessages()) { 231c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setViewVisibility(R.id.widget_unread_background, View.VISIBLE); 232c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setViewVisibility(R.id.widget_read_background, View.GONE); 233c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } else { 234c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setViewVisibility(R.id.widget_unread_background, View.GONE); 235c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setViewVisibility(R.id.widget_read_background, View.VISIBLE); 236c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 237c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor boolean hasAttachment = conv.hasAttachment(); 238c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setViewVisibility(R.id.attachment, hasAttachment ? View.VISIBLE : 239c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor View.GONE); 240c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 241c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // Date 242c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setTextViewText(R.id.date, 243c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor addColor(MessageUtils.formatTimeStampString(mContext, conv.getDate()), 244c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor conv.hasUnreadMessages() ? SUBJECT_TEXT_COLOR_UNREAD : 245c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor SUBJECT_TEXT_COLOR_READ)); 246c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 247c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // From 248ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor int color = conv.hasUnreadMessages() ? SENDERS_TEXT_COLOR_UNREAD : 249ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor SENDERS_TEXT_COLOR_READ; 250c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor SpannableStringBuilder from = addColor(conv.getRecipients().formatNames(", "), 251ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor color); 252ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor 253ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor if (conv.hasDraft()) { 254ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor from.append(mContext.getResources().getString(R.string.draft_separator)); 255ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor int before = from.length(); 256ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor from.append(mContext.getResources().getString(R.string.has_draft)); 257ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor from.setSpan(new TextAppearanceSpan(mContext, 258ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor android.R.style.TextAppearance_Small, color), before, 259ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor from.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 260ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor from.setSpan(new ForegroundColorSpan( 261ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor mContext.getResources().getColor(R.drawable.text_color_red)), 262ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor before, from.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 263ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor } 264ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor 265c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // Unread messages are shown in bold 266c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (conv.hasUnreadMessages()) { 267c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor from.setSpan(ConversationListItem.STYLE_BOLD, 0, from.length(), 268c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 269c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 270c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setTextViewText(R.id.from, from); 271c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 272c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // Subject 273c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setTextViewText(R.id.subject, 274c7c68dba4f3440f234f65eef579f9aaa82682f8cTom Taylor addColor(conv.getSnippet(), 275c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor conv.hasUnreadMessages() ? SUBJECT_TEXT_COLOR_UNREAD : 276c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor SUBJECT_TEXT_COLOR_READ)); 277c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 278c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // On click intent. 279c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Intent clickIntent = new Intent(Intent.ACTION_VIEW); 280c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor clickIntent.setType("vnd.android-dir/mms-sms"); 281c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor clickIntent.putExtra("thread_id", conv.getThreadId()); 282c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 283c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setOnClickFillInIntent(R.id.widget_conversation, clickIntent); 284c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 285c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return remoteViews; 286c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 287c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 288c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 289c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor /** 290c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * @return the "View more conversations" view. When the user taps this item, they're 291c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * taken to the messaging app's conversation list. 292c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor */ 293c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private RemoteViews getViewMoreConversationsView() { 294c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 295c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "getViewMoreConversationsView"); 296c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 297c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor RemoteViews view = new RemoteViews(mContext.getPackageName(), R.layout.widget_loading); 298c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor view.setTextViewText( 299c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor R.id.loading_text, mContext.getText(R.string.view_more_conversations)); 3001c5596602dcc0ccbf04782333d0d61dbb090784cRoger Chen PendingIntent pendingIntent = 3011c5596602dcc0ccbf04782333d0d61dbb090784cRoger Chen PendingIntent.getActivity(mContext, 0, new Intent(mContext, 3021c5596602dcc0ccbf04782333d0d61dbb090784cRoger Chen ConversationList.class), 3031c5596602dcc0ccbf04782333d0d61dbb090784cRoger Chen PendingIntent.FLAG_UPDATE_CURRENT); 3041c5596602dcc0ccbf04782333d0d61dbb090784cRoger Chen view.setOnClickPendingIntent(R.id.widget_loading, pendingIntent); 305c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return view; 306c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 307c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 308c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 309c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public RemoteViews getLoadingView() { 310c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor RemoteViews view = new RemoteViews(mContext.getPackageName(), R.layout.widget_loading); 311c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor view.setTextViewText( 312c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor R.id.loading_text, mContext.getText(R.string.loading_conversations)); 313c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return view; 314c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 315c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 316c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 317c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public int getViewTypeCount() { 3181e1be6fad69b0941e446576c20a6dfd79e8da629Tom Taylor return 2; 319c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 320c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 321c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 322c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public long getItemId(int position) { 323c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return position; 324c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 325c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 326c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 327c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public boolean hasStableIds() { 328c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return true; 329c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 330c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 331c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private void onLoadComplete() { 332c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 333c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "onLoadComplete"); 334c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 335c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor RemoteViews remoteViews = new RemoteViews(mContext.getPackageName(), R.layout.widget); 336c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 337c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setViewVisibility(R.id.widget_unread_count, mUnreadConvCount > 0 ? 338c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor View.VISIBLE : View.GONE); 339c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (mUnreadConvCount > 0) { 340c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setTextViewText( 341c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor R.id.widget_unread_count, Integer.toString(mUnreadConvCount)); 342c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 343c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 344c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mAppWidgetManager.partiallyUpdateAppWidget(mAppWidgetId, remoteViews); 345c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 346c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 347c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public void onUpdate(Contact updated) { 348c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 349c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "onUpdate from Contact: " + updated); 350c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 351c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mAppWidgetManager.notifyAppWidgetViewDataChanged(mAppWidgetId, R.id.conversation_list); 352c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 353c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 354c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 355c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor} 356