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 19c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.appwidget.AppWidgetManager; 20c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.content.Context; 21c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.content.Intent; 22c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.content.res.Resources; 23c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.database.Cursor; 24c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.provider.Telephony.Threads; 25c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.text.Spannable; 26c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.text.SpannableStringBuilder; 27c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.text.style.ForegroundColorSpan; 28ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylorimport android.text.style.TextAppearanceSpan; 29c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.util.Log; 30c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.view.View; 31c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.widget.RemoteViews; 32c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport android.widget.RemoteViewsService; 33c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 34c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.LogTag; 35c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.R; 36c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.data.Contact; 37c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.data.Conversation; 38c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.ui.ConversationList; 39c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.ui.ConversationListItem; 40c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.ui.MessageUtils; 41c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorimport com.android.mms.util.SmileyParser; 42c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 43c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylorpublic class MmsWidgetService extends RemoteViewsService { 44c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private static final String TAG = "MmsWidgetService"; 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 } 186c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor synchronized (sWidgetLock) { 187c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return Math.min(mConversationCursor.getCount(), MAX_CONVERSATIONS_COUNT); 188c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 189c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 190c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 191c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor /* 192c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * Add color to a given text 193c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor */ 194c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private SpannableStringBuilder addColor(CharSequence text, int color) { 195c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor SpannableStringBuilder builder = new SpannableStringBuilder(text); 196c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (color != 0) { 197c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor builder.setSpan(new ForegroundColorSpan(color), 0, text.length(), 198c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 199c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 200c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return builder; 201c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 202c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 203c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor /** 204c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * @return the {@link RemoteViews} for a specific position in the list. 205c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor */ 206c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 207c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public RemoteViews getViewAt(int position) { 208c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 209c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "getViewAt position: " + position); 210c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 211c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor synchronized (sWidgetLock) { 212c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // "View more conversations" view. 213c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (mConversationCursor == null 214c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor || (mShouldShowViewMore && position >= getConversationCount())) { 215c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return getViewMoreConversationsView(); 216c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 217c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 218c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (!mConversationCursor.moveToPosition(position)) { 219c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // If we ever fail to move to a position, return the "View More conversations" 220c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // view. 221c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.w(TAG, "Failed to move to position: " + position); 222c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return getViewMoreConversationsView(); 223c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 224c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 225c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Conversation conv = Conversation.from(mContext, mConversationCursor); 226c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 227c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // Inflate and fill out the remote view 228c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor RemoteViews remoteViews = new RemoteViews( 229c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mContext.getPackageName(), R.layout.widget_conversation); 230c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 231c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (conv.hasUnreadMessages()) { 232c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setViewVisibility(R.id.widget_unread_background, View.VISIBLE); 233c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setViewVisibility(R.id.widget_read_background, View.GONE); 234c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } else { 235c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setViewVisibility(R.id.widget_unread_background, View.GONE); 236c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setViewVisibility(R.id.widget_read_background, View.VISIBLE); 237c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 238c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor boolean hasAttachment = conv.hasAttachment(); 239c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setViewVisibility(R.id.attachment, hasAttachment ? View.VISIBLE : 240c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor View.GONE); 241c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 242c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // Date 243c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setTextViewText(R.id.date, 244c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor addColor(MessageUtils.formatTimeStampString(mContext, conv.getDate()), 245c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor conv.hasUnreadMessages() ? SUBJECT_TEXT_COLOR_UNREAD : 246c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor SUBJECT_TEXT_COLOR_READ)); 247c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 248c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // From 249ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor int color = conv.hasUnreadMessages() ? SENDERS_TEXT_COLOR_UNREAD : 250ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor SENDERS_TEXT_COLOR_READ; 251c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor SpannableStringBuilder from = addColor(conv.getRecipients().formatNames(", "), 252ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor color); 253ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor 254ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor if (conv.hasDraft()) { 255ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor from.append(mContext.getResources().getString(R.string.draft_separator)); 256ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor int before = from.length(); 257ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor from.append(mContext.getResources().getString(R.string.has_draft)); 258ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor from.setSpan(new TextAppearanceSpan(mContext, 259ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor android.R.style.TextAppearance_Small, color), before, 260ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor from.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 261ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor from.setSpan(new ForegroundColorSpan( 262ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor mContext.getResources().getColor(R.drawable.text_color_red)), 263ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor before, from.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 264ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor } 265ee2749f9d077a6dfddd536b66694b4428c5df92cTom Taylor 266c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // Unread messages are shown in bold 267c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (conv.hasUnreadMessages()) { 268c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor from.setSpan(ConversationListItem.STYLE_BOLD, 0, from.length(), 269c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 270c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 271c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setTextViewText(R.id.from, from); 272c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 273c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // Subject 274c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // TODO: the SmileyParser inserts image spans but they don't seem to make it 275c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // into the remote view. 276c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor SmileyParser parser = SmileyParser.getInstance(); 277c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setTextViewText(R.id.subject, 278c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor addColor(parser.addSmileySpans(conv.getSnippet()), 279c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor conv.hasUnreadMessages() ? SUBJECT_TEXT_COLOR_UNREAD : 280c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor SUBJECT_TEXT_COLOR_READ)); 281c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 282c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor // On click intent. 283c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Intent clickIntent = new Intent(Intent.ACTION_VIEW); 284c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor clickIntent.setType("vnd.android-dir/mms-sms"); 285c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor clickIntent.putExtra("thread_id", conv.getThreadId()); 286c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 287c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setOnClickFillInIntent(R.id.widget_conversation, clickIntent); 288c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 289c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return remoteViews; 290c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 291c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 292c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 293c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor /** 294c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * @return the "View more conversations" view. When the user taps this item, they're 295c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor * taken to the messaging app's conversation list. 296c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor */ 297c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private RemoteViews getViewMoreConversationsView() { 298c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 299c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "getViewMoreConversationsView"); 300c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 301c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor RemoteViews view = new RemoteViews(mContext.getPackageName(), R.layout.widget_loading); 302c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor view.setTextViewText( 303c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor R.id.loading_text, mContext.getText(R.string.view_more_conversations)); 304c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor view.setOnClickFillInIntent(R.id.widget_loading, 305c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor new Intent(mContext, ConversationList.class)); 306c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return view; 307c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 308c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 309c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 310c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public RemoteViews getLoadingView() { 311c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor RemoteViews view = new RemoteViews(mContext.getPackageName(), R.layout.widget_loading); 312c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor view.setTextViewText( 313c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor R.id.loading_text, mContext.getText(R.string.loading_conversations)); 314c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return view; 315c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 316c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 317c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 318c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public int getViewTypeCount() { 3191e1be6fad69b0941e446576c20a6dfd79e8da629Tom Taylor return 2; 320c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 321c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 322c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 323c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public long getItemId(int position) { 324c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return position; 325c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 326c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 327c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor @Override 328c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public boolean hasStableIds() { 329c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor return true; 330c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 331c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 332c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor private void onLoadComplete() { 333c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 334c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "onLoadComplete"); 335c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 336c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor RemoteViews remoteViews = new RemoteViews(mContext.getPackageName(), R.layout.widget); 337c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 338c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setViewVisibility(R.id.widget_unread_count, mUnreadConvCount > 0 ? 339c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor View.VISIBLE : View.GONE); 340c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (mUnreadConvCount > 0) { 341c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor remoteViews.setTextViewText( 342c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor R.id.widget_unread_count, Integer.toString(mUnreadConvCount)); 343c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 344c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 345c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mAppWidgetManager.partiallyUpdateAppWidget(mAppWidgetId, remoteViews); 346c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 347c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 348c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor public void onUpdate(Contact updated) { 349c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) { 350c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor Log.v(TAG, "onUpdate from Contact: " + updated); 351c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 352c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor mAppWidgetManager.notifyAppWidgetViewDataChanged(mAppWidgetId, R.id.conversation_list); 353c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 354c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor 355c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor } 356c7aa632be8e7d3ebe71f236f534ea2f0af71e04aTom Taylor} 357