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; 18 19 import android.content.Context; 20 import android.database.sqlite.SQLiteDatabase; 21 import android.net.Uri; 22 import android.telephony.SubscriptionManager; 23 24 import com.android.messaging.datamodel.action.ActionService; 25 import com.android.messaging.datamodel.action.BackgroundWorker; 26 import com.android.messaging.datamodel.action.FixupMessageStatusOnStartupAction; 27 import com.android.messaging.datamodel.action.ProcessPendingMessagesAction; 28 import com.android.messaging.datamodel.data.BlockedParticipantsData; 29 import com.android.messaging.datamodel.data.BlockedParticipantsData.BlockedParticipantsDataListener; 30 import com.android.messaging.datamodel.data.ContactListItemData; 31 import com.android.messaging.datamodel.data.ContactPickerData; 32 import com.android.messaging.datamodel.data.ContactPickerData.ContactPickerDataListener; 33 import com.android.messaging.datamodel.data.ConversationData; 34 import com.android.messaging.datamodel.data.ConversationData.ConversationDataListener; 35 import com.android.messaging.datamodel.data.ConversationListData; 36 import com.android.messaging.datamodel.data.ConversationListData.ConversationListDataListener; 37 import com.android.messaging.datamodel.data.DraftMessageData; 38 import com.android.messaging.datamodel.data.GalleryGridItemData; 39 import com.android.messaging.datamodel.data.LaunchConversationData; 40 import com.android.messaging.datamodel.data.LaunchConversationData.LaunchConversationDataListener; 41 import com.android.messaging.datamodel.data.MediaPickerData; 42 import com.android.messaging.datamodel.data.MessagePartData; 43 import com.android.messaging.datamodel.data.ParticipantData; 44 import com.android.messaging.datamodel.data.ParticipantListItemData; 45 import com.android.messaging.datamodel.data.PeopleAndOptionsData; 46 import com.android.messaging.datamodel.data.PeopleAndOptionsData.PeopleAndOptionsDataListener; 47 import com.android.messaging.datamodel.data.PeopleOptionsItemData; 48 import com.android.messaging.datamodel.data.SettingsData; 49 import com.android.messaging.datamodel.data.SettingsData.SettingsDataListener; 50 import com.android.messaging.datamodel.data.SubscriptionListData; 51 import com.android.messaging.datamodel.data.VCardContactItemData; 52 import com.android.messaging.sms.MmsConfig; 53 import com.android.messaging.util.Assert; 54 import com.android.messaging.util.Assert.DoesNotRunOnMainThread; 55 import com.android.messaging.util.ConnectivityUtil; 56 import com.android.messaging.util.LogUtil; 57 import com.android.messaging.util.OsUtil; 58 import com.android.messaging.util.PhoneUtils; 59 60 import java.util.concurrent.ConcurrentHashMap; 61 62 public class DataModelImpl extends DataModel { 63 private final Context mContext; 64 private final ActionService mActionService; 65 private final BackgroundWorker mDataModelWorker; 66 private final DatabaseHelper mDatabaseHelper; 67 private final SyncManager mSyncManager; 68 69 // Cached ConnectivityUtil instance for Pre-N. 70 private static ConnectivityUtil sConnectivityUtilInstanceCachePreN = null; 71 // Cached ConnectivityUtil subId->instance for N and beyond 72 private static final ConcurrentHashMap<Integer, ConnectivityUtil> 73 sConnectivityUtilInstanceCacheN = new ConcurrentHashMap<>(); 74 DataModelImpl(final Context context)75 public DataModelImpl(final Context context) { 76 super(); 77 mContext = context; 78 mActionService = new ActionService(); 79 mDataModelWorker = new BackgroundWorker(); 80 mDatabaseHelper = DatabaseHelper.getInstance(context); 81 mSyncManager = new SyncManager(); 82 } 83 84 @Override createConversationListData(final Context context, final ConversationListDataListener listener, final boolean archivedMode)85 public ConversationListData createConversationListData(final Context context, 86 final ConversationListDataListener listener, final boolean archivedMode) { 87 return new ConversationListData(context, listener, archivedMode); 88 } 89 90 @Override createConversationData(final Context context, final ConversationDataListener listener, final String conversationId)91 public ConversationData createConversationData(final Context context, 92 final ConversationDataListener listener, final String conversationId) { 93 return new ConversationData(context, listener, conversationId); 94 } 95 96 @Override createContactListItemData()97 public ContactListItemData createContactListItemData() { 98 return new ContactListItemData(); 99 } 100 101 @Override createContactPickerData(final Context context, final ContactPickerDataListener listener)102 public ContactPickerData createContactPickerData(final Context context, 103 final ContactPickerDataListener listener) { 104 return new ContactPickerData(context, listener); 105 } 106 107 @Override createBlockedParticipantsData( final Context context, final BlockedParticipantsDataListener listener)108 public BlockedParticipantsData createBlockedParticipantsData( 109 final Context context, final BlockedParticipantsDataListener listener) { 110 return new BlockedParticipantsData(context, listener); 111 } 112 113 @Override createMediaPickerData(final Context context)114 public MediaPickerData createMediaPickerData(final Context context) { 115 return new MediaPickerData(context); 116 } 117 118 @Override createGalleryGridItemData()119 public GalleryGridItemData createGalleryGridItemData() { 120 return new GalleryGridItemData(); 121 } 122 123 @Override createLaunchConversationData( final LaunchConversationDataListener listener)124 public LaunchConversationData createLaunchConversationData( 125 final LaunchConversationDataListener listener) { 126 return new LaunchConversationData(listener); 127 } 128 129 @Override createPeopleOptionsItemData(final Context context)130 public PeopleOptionsItemData createPeopleOptionsItemData(final Context context) { 131 return new PeopleOptionsItemData(context); 132 } 133 134 @Override createPeopleAndOptionsData(final String conversationId, final Context context, final PeopleAndOptionsDataListener listener)135 public PeopleAndOptionsData createPeopleAndOptionsData(final String conversationId, 136 final Context context, final PeopleAndOptionsDataListener listener) { 137 return new PeopleAndOptionsData(conversationId, context, listener); 138 } 139 140 @Override createVCardContactItemData(final Context context, final MessagePartData data)141 public VCardContactItemData createVCardContactItemData(final Context context, 142 final MessagePartData data) { 143 return new VCardContactItemData(context, data); 144 } 145 146 @Override createVCardContactItemData(final Context context, final Uri vCardUri)147 public VCardContactItemData createVCardContactItemData(final Context context, 148 final Uri vCardUri) { 149 return new VCardContactItemData(context, vCardUri); 150 } 151 152 @Override createParticipantListItemData( final ParticipantData participant)153 public ParticipantListItemData createParticipantListItemData( 154 final ParticipantData participant) { 155 return new ParticipantListItemData(participant); 156 } 157 158 @Override createSubscriptonListData(Context context)159 public SubscriptionListData createSubscriptonListData(Context context) { 160 return new SubscriptionListData(context); 161 } 162 163 @Override createSettingsData(Context context, SettingsDataListener listener)164 public SettingsData createSettingsData(Context context, SettingsDataListener listener) { 165 return new SettingsData(context, listener); 166 } 167 168 @Override createDraftMessageData(String conversationId)169 public DraftMessageData createDraftMessageData(String conversationId) { 170 return new DraftMessageData(conversationId); 171 } 172 173 @Override getActionService()174 public ActionService getActionService() { 175 // We need to allow access to this on the UI thread since it's used to start actions. 176 return mActionService; 177 } 178 179 @Override getBackgroundWorkerForActionService()180 public BackgroundWorker getBackgroundWorkerForActionService() { 181 return mDataModelWorker; 182 } 183 184 @Override 185 @DoesNotRunOnMainThread getDatabase()186 public DatabaseWrapper getDatabase() { 187 // We prevent the main UI thread from accessing the database since we have to allow 188 // public access to this class to enable sub-packages to access data. 189 Assert.isNotMainThread(); 190 return mDatabaseHelper.getDatabase(); 191 } 192 193 @Override getSyncManager()194 public SyncManager getSyncManager() { 195 return mSyncManager; 196 } 197 198 @Override onCreateTables(final SQLiteDatabase db)199 void onCreateTables(final SQLiteDatabase db) { 200 LogUtil.w(LogUtil.BUGLE_TAG, "Rebuilt databases: reseting related state"); 201 // Clear other things that implicitly reference the DB 202 SyncManager.resetLastSyncTimestamps(); 203 } 204 205 @Override onActivityResume()206 public void onActivityResume() { 207 // Perform an incremental sync and register for changes if necessary 208 mSyncManager.updateSyncObserver(mContext); 209 210 // Trigger a participant refresh if needed, we should only need to refresh if there is 211 // contact change while the activity was paused. 212 ParticipantRefresh.refreshParticipantsIfNeeded(); 213 } 214 215 @Override onApplicationCreated()216 public void onApplicationCreated() { 217 if (OsUtil.isAtLeastN()) { 218 createConnectivityUtilForEachActiveSubscription(); 219 } else { 220 sConnectivityUtilInstanceCachePreN = new ConnectivityUtil(mContext); 221 } 222 223 FixupMessageStatusOnStartupAction.fixupMessageStatus(); 224 ProcessPendingMessagesAction.processFirstPendingMessage(); 225 SyncManager.immediateSync(); 226 227 if (OsUtil.isAtLeastL_MR1()) { 228 // Start listening for subscription change events for refreshing any data associated 229 // with subscriptions. 230 PhoneUtils.getDefault().toLMr1().registerOnSubscriptionsChangedListener( 231 new SubscriptionManager.OnSubscriptionsChangedListener() { 232 @Override 233 public void onSubscriptionsChanged() { 234 // TODO: This dynamically changes the mms config that app is 235 // currently using. It may cause inconsistency in some cases. We need 236 // to check the usage of mms config and handle the dynamic change 237 // gracefully 238 MmsConfig.loadAsync(); 239 ParticipantRefresh.refreshSelfParticipants(); 240 if (OsUtil.isAtLeastN()) { 241 createConnectivityUtilForEachActiveSubscription(); 242 } 243 } 244 }); 245 } 246 } 247 createConnectivityUtilForEachActiveSubscription()248 private void createConnectivityUtilForEachActiveSubscription() { 249 PhoneUtils.forEachActiveSubscription(new PhoneUtils.SubscriptionRunnable() { 250 @Override 251 public void runForSubscription(int subId) { 252 // Create the ConnectivityUtil instance for given subId if absent. 253 if (subId <= ParticipantData.DEFAULT_SELF_SUB_ID) { 254 subId = PhoneUtils.getDefault().getDefaultSmsSubscriptionId(); 255 } 256 if (!sConnectivityUtilInstanceCacheN.containsKey(subId)) { 257 sConnectivityUtilInstanceCacheN.put( 258 subId, new ConnectivityUtil(mContext, subId)); 259 } 260 } 261 }); 262 } 263 getConnectivityUtil(final int subId)264 public static ConnectivityUtil getConnectivityUtil(final int subId) { 265 if (OsUtil.isAtLeastN()) { 266 return sConnectivityUtilInstanceCacheN.get(subId); 267 } else { 268 return sConnectivityUtilInstanceCachePreN; 269 } 270 } 271 } 272