/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.messaging.datamodel; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.telephony.SubscriptionManager; import com.android.messaging.datamodel.action.ActionService; import com.android.messaging.datamodel.action.BackgroundWorker; import com.android.messaging.datamodel.action.FixupMessageStatusOnStartupAction; import com.android.messaging.datamodel.action.ProcessPendingMessagesAction; import com.android.messaging.datamodel.data.BlockedParticipantsData; import com.android.messaging.datamodel.data.BlockedParticipantsData.BlockedParticipantsDataListener; import com.android.messaging.datamodel.data.ContactListItemData; import com.android.messaging.datamodel.data.ContactPickerData; import com.android.messaging.datamodel.data.ContactPickerData.ContactPickerDataListener; import com.android.messaging.datamodel.data.ConversationData; import com.android.messaging.datamodel.data.ConversationData.ConversationDataListener; import com.android.messaging.datamodel.data.ConversationListData; import com.android.messaging.datamodel.data.ConversationListData.ConversationListDataListener; import com.android.messaging.datamodel.data.DraftMessageData; import com.android.messaging.datamodel.data.GalleryGridItemData; import com.android.messaging.datamodel.data.LaunchConversationData; import com.android.messaging.datamodel.data.LaunchConversationData.LaunchConversationDataListener; import com.android.messaging.datamodel.data.MediaPickerData; import com.android.messaging.datamodel.data.MessagePartData; import com.android.messaging.datamodel.data.ParticipantData; import com.android.messaging.datamodel.data.ParticipantListItemData; import com.android.messaging.datamodel.data.PeopleAndOptionsData; import com.android.messaging.datamodel.data.PeopleAndOptionsData.PeopleAndOptionsDataListener; import com.android.messaging.datamodel.data.PeopleOptionsItemData; import com.android.messaging.datamodel.data.SettingsData; import com.android.messaging.datamodel.data.SettingsData.SettingsDataListener; import com.android.messaging.datamodel.data.SubscriptionListData; import com.android.messaging.datamodel.data.VCardContactItemData; import com.android.messaging.sms.MmsConfig; import com.android.messaging.util.Assert; import com.android.messaging.util.Assert.DoesNotRunOnMainThread; import com.android.messaging.util.ConnectivityUtil; import com.android.messaging.util.LogUtil; import com.android.messaging.util.OsUtil; import com.android.messaging.util.PhoneUtils; import java.util.concurrent.ConcurrentHashMap; public class DataModelImpl extends DataModel { private final Context mContext; private final ActionService mActionService; private final BackgroundWorker mDataModelWorker; private final DatabaseHelper mDatabaseHelper; private final SyncManager mSyncManager; // Cached ConnectivityUtil instance for Pre-N. private static ConnectivityUtil sConnectivityUtilInstanceCachePreN = null; // Cached ConnectivityUtil subId->instance for N and beyond private static final ConcurrentHashMap sConnectivityUtilInstanceCacheN = new ConcurrentHashMap<>(); public DataModelImpl(final Context context) { super(); mContext = context; mActionService = new ActionService(); mDataModelWorker = new BackgroundWorker(); mDatabaseHelper = DatabaseHelper.getInstance(context); mSyncManager = new SyncManager(); } @Override public ConversationListData createConversationListData(final Context context, final ConversationListDataListener listener, final boolean archivedMode) { return new ConversationListData(context, listener, archivedMode); } @Override public ConversationData createConversationData(final Context context, final ConversationDataListener listener, final String conversationId) { return new ConversationData(context, listener, conversationId); } @Override public ContactListItemData createContactListItemData() { return new ContactListItemData(); } @Override public ContactPickerData createContactPickerData(final Context context, final ContactPickerDataListener listener) { return new ContactPickerData(context, listener); } @Override public BlockedParticipantsData createBlockedParticipantsData( final Context context, final BlockedParticipantsDataListener listener) { return new BlockedParticipantsData(context, listener); } @Override public MediaPickerData createMediaPickerData(final Context context) { return new MediaPickerData(context); } @Override public GalleryGridItemData createGalleryGridItemData() { return new GalleryGridItemData(); } @Override public LaunchConversationData createLaunchConversationData( final LaunchConversationDataListener listener) { return new LaunchConversationData(listener); } @Override public PeopleOptionsItemData createPeopleOptionsItemData(final Context context) { return new PeopleOptionsItemData(context); } @Override public PeopleAndOptionsData createPeopleAndOptionsData(final String conversationId, final Context context, final PeopleAndOptionsDataListener listener) { return new PeopleAndOptionsData(conversationId, context, listener); } @Override public VCardContactItemData createVCardContactItemData(final Context context, final MessagePartData data) { return new VCardContactItemData(context, data); } @Override public VCardContactItemData createVCardContactItemData(final Context context, final Uri vCardUri) { return new VCardContactItemData(context, vCardUri); } @Override public ParticipantListItemData createParticipantListItemData( final ParticipantData participant) { return new ParticipantListItemData(participant); } @Override public SubscriptionListData createSubscriptonListData(Context context) { return new SubscriptionListData(context); } @Override public SettingsData createSettingsData(Context context, SettingsDataListener listener) { return new SettingsData(context, listener); } @Override public DraftMessageData createDraftMessageData(String conversationId) { return new DraftMessageData(conversationId); } @Override public ActionService getActionService() { // We need to allow access to this on the UI thread since it's used to start actions. return mActionService; } @Override public BackgroundWorker getBackgroundWorkerForActionService() { return mDataModelWorker; } @Override @DoesNotRunOnMainThread public DatabaseWrapper getDatabase() { // We prevent the main UI thread from accessing the database since we have to allow // public access to this class to enable sub-packages to access data. Assert.isNotMainThread(); return mDatabaseHelper.getDatabase(); } @Override public SyncManager getSyncManager() { return mSyncManager; } @Override void onCreateTables(final SQLiteDatabase db) { LogUtil.w(LogUtil.BUGLE_TAG, "Rebuilt databases: reseting related state"); // Clear other things that implicitly reference the DB SyncManager.resetLastSyncTimestamps(); } @Override public void onActivityResume() { // Perform an incremental sync and register for changes if necessary mSyncManager.updateSyncObserver(mContext); // Trigger a participant refresh if needed, we should only need to refresh if there is // contact change while the activity was paused. ParticipantRefresh.refreshParticipantsIfNeeded(); } @Override public void onApplicationCreated() { if (OsUtil.isAtLeastN()) { createConnectivityUtilForEachActiveSubscription(); } else { sConnectivityUtilInstanceCachePreN = new ConnectivityUtil(mContext); } FixupMessageStatusOnStartupAction.fixupMessageStatus(); ProcessPendingMessagesAction.processFirstPendingMessage(); SyncManager.immediateSync(); if (OsUtil.isAtLeastL_MR1()) { // Start listening for subscription change events for refreshing any data associated // with subscriptions. PhoneUtils.getDefault().toLMr1().registerOnSubscriptionsChangedListener( new SubscriptionManager.OnSubscriptionsChangedListener() { @Override public void onSubscriptionsChanged() { // TODO: This dynamically changes the mms config that app is // currently using. It may cause inconsistency in some cases. We need // to check the usage of mms config and handle the dynamic change // gracefully MmsConfig.loadAsync(); ParticipantRefresh.refreshSelfParticipants(); if (OsUtil.isAtLeastN()) { createConnectivityUtilForEachActiveSubscription(); } } }); } } private void createConnectivityUtilForEachActiveSubscription() { PhoneUtils.forEachActiveSubscription(new PhoneUtils.SubscriptionRunnable() { @Override public void runForSubscription(int subId) { // Create the ConnectivityUtil instance for given subId if absent. if (subId <= ParticipantData.DEFAULT_SELF_SUB_ID) { subId = PhoneUtils.getDefault().getDefaultSmsSubscriptionId(); } if (!sConnectivityUtilInstanceCacheN.containsKey(subId)) { sConnectivityUtilInstanceCacheN.put( subId, new ConnectivityUtil(mContext, subId)); } } }); } public static ConnectivityUtil getConnectivityUtil(final int subId) { if (OsUtil.isAtLeastN()) { return sConnectivityUtilInstanceCacheN.get(subId); } else { return sConnectivityUtilInstanceCachePreN; } } }