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