1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.messaging.datamodel.data;
18 
19 import android.app.LoaderManager;
20 import android.content.Context;
21 import android.content.Loader;
22 import android.database.Cursor;
23 import android.os.Bundle;
24 
25 import com.android.messaging.datamodel.BoundCursorLoader;
26 import com.android.messaging.datamodel.BugleNotifications;
27 import com.android.messaging.datamodel.DataModel;
28 import com.android.messaging.datamodel.DatabaseHelper.ParticipantColumns;
29 import com.android.messaging.datamodel.MessagingContentProvider;
30 import com.android.messaging.datamodel.SyncManager;
31 import com.android.messaging.datamodel.binding.BindableData;
32 import com.android.messaging.datamodel.binding.BindingBase;
33 import com.android.messaging.datamodel.data.ConversationListItemData.ConversationListViewColumns;
34 import com.android.messaging.receiver.SmsReceiver;
35 import com.android.messaging.util.Assert;
36 import com.android.messaging.util.LogUtil;
37 
38 import java.util.HashSet;
39 
40 public class ConversationListData extends BindableData
41         implements LoaderManager.LoaderCallbacks<Cursor> {
42 
43     private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
44     private static final String BINDING_ID = "bindingId";
45     public static final String SORT_ORDER =
46             ConversationListViewColumns.SORT_TIMESTAMP + " DESC";
47 
48     private static final String WHERE_ARCHIVED =
49             "(" + ConversationListViewColumns.ARCHIVE_STATUS + " = 1)";
50     public static final String WHERE_NOT_ARCHIVED =
51             "(" + ConversationListViewColumns.ARCHIVE_STATUS + " = 0)";
52 
53     public interface ConversationListDataListener {
onConversationListCursorUpdated(ConversationListData data, Cursor cursor)54         public void onConversationListCursorUpdated(ConversationListData data, Cursor cursor);
setBlockedParticipantsAvailable(boolean blockedAvailable)55         public void setBlockedParticipantsAvailable(boolean blockedAvailable);
56     }
57 
58     private ConversationListDataListener mListener;
59     private final Context mContext;
60     private final boolean mArchivedMode;
61     private LoaderManager mLoaderManager;
62 
ConversationListData(final Context context, final ConversationListDataListener listener, final boolean archivedMode)63     public ConversationListData(final Context context, final ConversationListDataListener listener,
64             final boolean archivedMode) {
65         mListener = listener;
66         mContext = context;
67         mArchivedMode = archivedMode;
68     }
69 
70     private static final int CONVERSATION_LIST_LOADER = 1;
71     private static final int BLOCKED_PARTICIPANTS_AVAILABLE_LOADER = 2;
72 
73     private static final String[] BLOCKED_PARTICIPANTS_PROJECTION = new String[] {
74             ParticipantColumns._ID,
75             ParticipantColumns.NORMALIZED_DESTINATION,
76     };
77     private static final int INDEX_BLOCKED_PARTICIPANTS_ID = 0;
78     private static final int INDEX_BLOCKED_PARTICIPANTS_NORMALIZED_DESTINATION = 1;
79 
80     // all blocked participants
81     private final HashSet<String> mBlockedParticipants = new HashSet<String>();
82 
83     @Override
onCreateLoader(final int id, final Bundle args)84     public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
85         final String bindingId = args.getString(BINDING_ID);
86         Loader<Cursor> loader = null;
87         // Check if data still bound to the requesting ui element
88         if (isBound(bindingId)) {
89             switch (id) {
90                 case BLOCKED_PARTICIPANTS_AVAILABLE_LOADER:
91                     loader = new BoundCursorLoader(bindingId, mContext,
92                             MessagingContentProvider.PARTICIPANTS_URI,
93                             BLOCKED_PARTICIPANTS_PROJECTION,
94                             ParticipantColumns.BLOCKED + "=1", null, null);
95                     break;
96                 case CONVERSATION_LIST_LOADER:
97                     loader = new BoundCursorLoader(bindingId, mContext,
98                             MessagingContentProvider.CONVERSATIONS_URI,
99                             ConversationListItemData.PROJECTION,
100                             mArchivedMode ? WHERE_ARCHIVED : WHERE_NOT_ARCHIVED,
101                             null,       // selection args
102                             SORT_ORDER);
103                     break;
104                 default:
105                     Assert.fail("Unknown loader id");
106                     break;
107             }
108         } else {
109             LogUtil.w(TAG, "Creating loader after unbinding list");
110         }
111         return loader;
112     }
113 
114     /**
115      * {@inheritDoc}
116      */
117     @Override
onLoadFinished(final Loader<Cursor> generic, final Cursor data)118     public void onLoadFinished(final Loader<Cursor> generic, final Cursor data) {
119         final BoundCursorLoader loader = (BoundCursorLoader) generic;
120         if (isBound(loader.getBindingId())) {
121             switch (loader.getId()) {
122                 case BLOCKED_PARTICIPANTS_AVAILABLE_LOADER:
123                     mBlockedParticipants.clear();
124                     for (int i = 0; i < data.getCount(); i++) {
125                         data.moveToPosition(i);
126                         mBlockedParticipants.add(data.getString(
127                                 INDEX_BLOCKED_PARTICIPANTS_NORMALIZED_DESTINATION));
128                     }
129                     mListener.setBlockedParticipantsAvailable(data != null && data.getCount() > 0);
130                     break;
131                 case CONVERSATION_LIST_LOADER:
132                     mListener.onConversationListCursorUpdated(this, data);
133                     break;
134                 default:
135                     Assert.fail("Unknown loader id");
136                     break;
137             }
138         } else {
139             LogUtil.w(TAG, "Loader finished after unbinding list");
140         }
141     }
142 
143     /**
144      * {@inheritDoc}
145      */
146     @Override
onLoaderReset(final Loader<Cursor> generic)147     public void onLoaderReset(final Loader<Cursor> generic) {
148         final BoundCursorLoader loader = (BoundCursorLoader) generic;
149         if (isBound(loader.getBindingId())) {
150             switch (loader.getId()) {
151                 case BLOCKED_PARTICIPANTS_AVAILABLE_LOADER:
152                     mListener.setBlockedParticipantsAvailable(false);
153                     break;
154                 case CONVERSATION_LIST_LOADER:
155                     mListener.onConversationListCursorUpdated(this, null);
156                     break;
157                 default:
158                     Assert.fail("Unknown loader id");
159                     break;
160             }
161         } else {
162             LogUtil.w(TAG, "Loader reset after unbinding list");
163         }
164     }
165 
166     private Bundle mArgs;
167 
init(final LoaderManager loaderManager, final BindingBase<ConversationListData> binding)168     public void init(final LoaderManager loaderManager,
169             final BindingBase<ConversationListData> binding) {
170         mArgs = new Bundle();
171         mArgs.putString(BINDING_ID, binding.getBindingId());
172         mLoaderManager = loaderManager;
173         mLoaderManager.initLoader(CONVERSATION_LIST_LOADER, mArgs, this);
174         mLoaderManager.initLoader(BLOCKED_PARTICIPANTS_AVAILABLE_LOADER, mArgs, this);
175     }
176 
handleMessagesSeen()177     public void handleMessagesSeen() {
178         BugleNotifications.markAllMessagesAsSeen();
179 
180         SmsReceiver.cancelSecondaryUserNotification();
181     }
182 
183     @Override
unregisterListeners()184     protected void unregisterListeners() {
185         mListener = null;
186 
187         // This could be null if we bind but the caller doesn't init the BindableData
188         if (mLoaderManager != null) {
189             mLoaderManager.destroyLoader(CONVERSATION_LIST_LOADER);
190             mLoaderManager.destroyLoader(BLOCKED_PARTICIPANTS_AVAILABLE_LOADER);
191             mLoaderManager = null;
192         }
193     }
194 
getHasFirstSyncCompleted()195     public boolean getHasFirstSyncCompleted() {
196         final SyncManager syncManager = DataModel.get().getSyncManager();
197         return syncManager.getHasFirstSyncCompleted();
198     }
199 
setScrolledToNewestConversation(boolean scrolledToNewestConversation)200     public void setScrolledToNewestConversation(boolean scrolledToNewestConversation) {
201         DataModel.get().setConversationListScrolledToNewestConversation(
202                 scrolledToNewestConversation);
203         if (scrolledToNewestConversation) {
204             handleMessagesSeen();
205         }
206     }
207 
getBlockedParticipants()208     public HashSet<String> getBlockedParticipants() {
209         return mBlockedParticipants;
210     }
211 }
212