1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/*
2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project
3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License");
5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License.
6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at
7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *      http://www.apache.org/licenses/LICENSE-2.0
9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software
11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS,
12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and
14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License.
15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.datamodel;
18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ContentValues;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.ContentObserver;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.Cursor;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.DatabaseUtils;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.graphics.Color;
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.ContactsContract.CommonDataKinds.Phone;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.support.v4.util.ArrayMap;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.telephony.SubscriptionInfo;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.TextUtils;
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.Factory;
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DatabaseHelper.ConversationColumns;
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DatabaseHelper.ConversationParticipantsColumns;
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DatabaseHelper.ParticipantColumns;
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.ParticipantData;
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.ParticipantData.ParticipantsQuery;
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.UIIntents;
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert;
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.ContactUtil;
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.LogUtil;
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.OsUtil;
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.PhoneUtils;
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.SafeAsyncTask;
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.common.annotations.VisibleForTesting;
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.common.base.Joiner;
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.ArrayList;
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.HashSet;
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.List;
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Locale;
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Set;
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.concurrent.atomic.AtomicBoolean;
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/**
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Utility class for refreshing participant information based on matching contact. This updates
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *     1. name, photo_uri, matching contact_id of participants.
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *     2. generated_name of conversations.
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * There are two kinds of participant refreshes,
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *     1. Full refresh, this is triggered at application start or activity resumes after contact
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *        change is detected.
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *     2. Partial refresh, this is triggered when a participant is added to a conversation. This
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *        normally happens during SMS sync.
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd@VisibleForTesting
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class ParticipantRefresh {
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Refresh all participants including ones that were resolved before.
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int REFRESH_MODE_FULL = 0;
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Refresh all unresolved participants.
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int REFRESH_MODE_INCREMENTAL = 1;
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Force refresh all self participants.
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int REFRESH_MODE_SELF_ONLY = 2;
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static class ConversationParticipantsQuery {
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static final String[] PROJECTION = new String[] {
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            ConversationParticipantsColumns._ID,
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            ConversationParticipantsColumns.CONVERSATION_ID,
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            ConversationParticipantsColumns.PARTICIPANT_ID
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        };
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static final int INDEX_ID                        = 0;
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static final int INDEX_CONVERSATION_ID           = 1;
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static final int INDEX_PARTICIPANT_ID            = 2;
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // Track whether observer is initialized or not.
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static volatile boolean sObserverInitialized = false;
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final Object sLock = new Object();
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final AtomicBoolean sFullRefreshScheduled = new AtomicBoolean(false);
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final Runnable sFullRefreshRunnable = new Runnable() {
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public void run() {
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final boolean oldScheduled = sFullRefreshScheduled.getAndSet(false);
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Assert.isTrue(oldScheduled);
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            refreshParticipants(REFRESH_MODE_FULL);
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final Runnable sSelfOnlyRefreshRunnable = new Runnable() {
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public void run() {
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            refreshParticipants(REFRESH_MODE_SELF_ONLY);
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * A customized content resolver to track contact changes.
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static class ContactContentObserver extends ContentObserver {
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        private volatile boolean mContactChanged = false;
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public ContactContentObserver() {
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            super(null);
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public void onChange(final boolean selfChange) {
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            super.onChange(selfChange);
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.v(TAG, "Contacts changed");
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mContactChanged = true;
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean getContactChanged() {
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return mContactChanged;
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public void resetContactChanged() {
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mContactChanged = false;
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public void initialize() {
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // TODO: Handle enterprise contacts post M once contacts provider supports it
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Factory.get().getApplicationContext().getContentResolver().registerContentObserver(
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    Phone.CONTENT_URI, true, this);
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mContactChanged = true; // Force a full refresh on initialization.
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Refresh participants only if needed, i.e., application start or contact changed.
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void refreshParticipantsIfNeeded() {
152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (ParticipantRefresh.getNeedFullRefresh() &&
153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                sFullRefreshScheduled.compareAndSet(false, true)) {
154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.v(TAG, "Started full participant refresh");
156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            SafeAsyncTask.executeOnThreadPool(sFullRefreshRunnable);
158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.v(TAG, "Skipped full participant refresh");
160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Refresh self participants on subscription or settings change.
165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void refreshSelfParticipants() {
167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        SafeAsyncTask.executeOnThreadPool(sSelfOnlyRefreshRunnable);
168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean getNeedFullRefresh() {
171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ContactContentObserver observer = Factory.get().getContactContentObserver();
172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (observer == null) {
173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // If there is no observer (for unittest cases), we don't need to refresh participants.
174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return false;
175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!sObserverInitialized) {
178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            synchronized (sLock) {
179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (!sObserverInitialized) {
180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    observer.initialize();
181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    sObserverInitialized = true;
182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return observer.getContactChanged();
187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static void resetNeedFullRefresh() {
190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ContactContentObserver observer = Factory.get().getContactContentObserver();
191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (observer != null) {
192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            observer.resetContactChanged();
193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * This class is totally static. Make constructor to be private so that an instance
198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * of this class would not be created by by mistake.
199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private ParticipantRefresh() {
201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Refresh participants in Bugle.
205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param refreshMode the refresh mode desired. See {@link #REFRESH_MODE_FULL},
207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *        {@link #REFRESH_MODE_INCREMENTAL}, and {@link #REFRESH_MODE_SELF_ONLY}
208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     @VisibleForTesting
210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     static void refreshParticipants(final int refreshMode) {
211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Assert.inRange(refreshMode, REFRESH_MODE_FULL, REFRESH_MODE_SELF_ONLY);
212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            switch (refreshMode) {
214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case REFRESH_MODE_FULL:
215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    LogUtil.v(TAG, "Start full participant refresh");
216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case REFRESH_MODE_INCREMENTAL:
218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    LogUtil.v(TAG, "Start partial participant refresh");
219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case REFRESH_MODE_SELF_ONLY:
221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    LogUtil.v(TAG, "Start self participant refresh");
222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!ContactUtil.hasReadContactsPermission() || !OsUtil.hasPhonePermission()) {
227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.v(TAG, "Skipping participant referesh because of permissions");
229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return;
231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (refreshMode == REFRESH_MODE_FULL) {
234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // resetNeedFullRefresh right away so that we will skip duplicated full refresh
235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // requests.
236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            resetNeedFullRefresh();
237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (refreshMode == REFRESH_MODE_FULL || refreshMode == REFRESH_MODE_SELF_ONLY) {
240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            refreshSelfParticipantList();
241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ArrayList<String> changedParticipants = new ArrayList<String>();
244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String selection = null;
246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String[] selectionArgs = null;
247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (refreshMode == REFRESH_MODE_INCREMENTAL) {
249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // In case of incremental refresh, filter out participants that are already resolved.
250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            selection = ParticipantColumns.CONTACT_ID + "=?";
251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            selectionArgs = new String[] {
252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    String.valueOf(ParticipantData.PARTICIPANT_CONTACT_ID_NOT_RESOLVED) };
253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else if (refreshMode == REFRESH_MODE_SELF_ONLY) {
254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // In case of self-only refresh, filter out non-self participants.
255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            selection = SELF_PARTICIPANTS_CLAUSE;
256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            selectionArgs = null;
257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final DatabaseWrapper db = DataModel.get().getDatabase();
260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Cursor cursor = null;
261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean selfUpdated = false;
262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            cursor = db.query(DatabaseHelper.PARTICIPANTS_TABLE,
264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    ParticipantsQuery.PROJECTION, selection, selectionArgs, null, null, null);
265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (cursor != null) {
267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                while (cursor.moveToNext()) {
268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    try {
269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        final ParticipantData participantData =
270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                ParticipantData.getFromCursor(cursor);
271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        if (refreshParticipant(db, participantData)) {
272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            if (participantData.isSelf()) {
273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                selfUpdated = true;
274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            }
275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            updateParticipant(db, participantData);
276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            final String id = participantData.getId();
277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            changedParticipants.add(id);
278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        }
279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    } catch (final Exception exception) {
280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // Failure to update one participant shouldn't cancel the entire refresh.
281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // Log the failure so we know what's going on and resume the loop.
282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        LogUtil.e(LogUtil.BUGLE_DATAMODEL_TAG, "ParticipantRefresh: Failed to " +
283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                "update participant", exception);
284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (cursor != null) {
289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                cursor.close();
290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.v(TAG, "Number of participants refreshed:" + changedParticipants.size());
295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Refresh conversations for participants that are changed.
298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (changedParticipants.size() > 0) {
299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            BugleDatabaseOperations.refreshConversationsForParticipants(changedParticipants);
300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (selfUpdated) {
302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Boom
303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            MessagingContentProvider.notifyAllParticipantsChanged();
304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            MessagingContentProvider.notifyAllMessagesChanged();
305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String SELF_PARTICIPANTS_CLAUSE = ParticipantColumns.SUB_ID
309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            + " NOT IN ( "
310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            + ParticipantData.OTHER_THAN_SELF_SUB_ID
311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            + " )";
312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final Set<Integer> getExistingSubIds() {
314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final DatabaseWrapper db = DataModel.get().getDatabase();
315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final HashSet<Integer> existingSubIds = new HashSet<Integer>();
316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Cursor cursor = null;
318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            cursor = db.query(DatabaseHelper.PARTICIPANTS_TABLE,
320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    ParticipantsQuery.PROJECTION,
321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    SELF_PARTICIPANTS_CLAUSE, null, null, null, null);
322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (cursor != null) {
324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                while (cursor.moveToNext()) {
325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final int subId = cursor.getInt(ParticipantsQuery.INDEX_SUB_ID);
326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    existingSubIds.add(subId);
327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (cursor != null) {
331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                cursor.close();
332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return existingSubIds;
335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String UPDATE_SELF_PARTICIPANT_SUBSCRIPTION_SQL =
338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            "UPDATE " + DatabaseHelper.PARTICIPANTS_TABLE + " SET "
339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            +  ParticipantColumns.SIM_SLOT_ID + " = %d, "
340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            +  ParticipantColumns.SUBSCRIPTION_COLOR + " = %d, "
341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            +  ParticipantColumns.SUBSCRIPTION_NAME + " = %s "
342d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            + " WHERE %s";
343d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
344d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static String getUpdateSelfParticipantSubscriptionInfoSql(final int slotId,
345d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int subscriptionColor, final String subscriptionName, final String where) {
346d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return String.format((Locale) null /* construct SQL string without localization */,
347d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                UPDATE_SELF_PARTICIPANT_SUBSCRIPTION_SQL,
348d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                slotId, subscriptionColor, subscriptionName, where);
349d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
350d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
351d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
352d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Ensure that there is a self participant corresponding to every active SIM. Also, ensure
353d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * that any other older SIM self participants are marked as inactive.
354d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
355d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static void refreshSelfParticipantList() {
356d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!OsUtil.isAtLeastL_MR1()) {
357d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return;
358d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
359d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
360d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final DatabaseWrapper db = DataModel.get().getDatabase();
361d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
362d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final List<SubscriptionInfo> subInfoRecords =
363d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                PhoneUtils.getDefault().toLMr1().getActiveSubscriptionInfoList();
364d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ArrayMap<Integer, SubscriptionInfo> activeSubscriptionIdToRecordMap =
365d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                new ArrayMap<Integer, SubscriptionInfo>();
366d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        db.beginTransaction();
367d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Set<Integer> existingSubIds = getExistingSubIds();
368d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
369d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
370d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (subInfoRecords != null) {
371d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                for (final SubscriptionInfo subInfoRecord : subInfoRecords) {
372d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final int subId = subInfoRecord.getSubscriptionId();
373d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // If its a new subscription, add it to the database.
374d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (!existingSubIds.contains(subId)) {
375d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        db.execSQL(DatabaseHelper.getCreateSelfParticipantSql(subId));
376d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // Add it to the local set to guard against duplicated entries returned
377d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // by subscription manager.
378d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        existingSubIds.add(subId);
379d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
380d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    activeSubscriptionIdToRecordMap.put(subId, subInfoRecord);
381d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
382d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (subId == PhoneUtils.getDefault().getDefaultSmsSubscriptionId()) {
383d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // This is the system default subscription, so update the default self.
384d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        activeSubscriptionIdToRecordMap.put(ParticipantData.DEFAULT_SELF_SUB_ID,
385d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                subInfoRecord);
386d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
387d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
388d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
389d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
390d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // For subscriptions already in the database, refresh ParticipantColumns.SIM_SLOT_ID.
391d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (final Integer subId : activeSubscriptionIdToRecordMap.keySet()) {
392d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final SubscriptionInfo record = activeSubscriptionIdToRecordMap.get(subId);
393d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final String displayName =
394d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        DatabaseUtils.sqlEscapeString(record.getDisplayName().toString());
395d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                db.execSQL(getUpdateSelfParticipantSubscriptionInfoSql(record.getSimSlotIndex(),
396d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        record.getIconTint(), displayName,
397d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        ParticipantColumns.SUB_ID + " = " + subId));
398d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
399d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            db.execSQL(getUpdateSelfParticipantSubscriptionInfoSql(
400d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    ParticipantData.INVALID_SLOT_ID, Color.TRANSPARENT, "''",
401d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    ParticipantColumns.SUB_ID + " NOT IN (" +
402d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    Joiner.on(", ").join(activeSubscriptionIdToRecordMap.keySet()) + ")"));
403d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            db.setTransactionSuccessful();
404d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
405d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            db.endTransaction();
406d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
407d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Fix up conversation self ids by reverting to default self for conversations whose self
408d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // ids are no longer active.
409d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        refreshConversationSelfIds();
410d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
411d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
412d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
413d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Refresh one participant.
414d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return true if the ParticipantData was changed
415d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
416d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean refreshParticipant(final DatabaseWrapper db,
417d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ParticipantData participantData) {
418d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean updated = false;
419d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
420d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (participantData.isSelf()) {
421d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int selfChange = refreshFromSelfProfile(db, participantData);
422d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
423d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (selfChange == SELF_PROFILE_EXISTS) {
424d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // If a self-profile exists, it takes precedence over Contacts data. So we are done.
425d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return true;
426d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
427d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
428d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            updated = (selfChange == SELF_PHONE_NUMBER_OR_SUBSCRIPTION_CHANGED);
429d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
430d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Fall-through and try to update based on Contacts data
431d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
432d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
433d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        updated |= refreshFromContacts(db, participantData);
434d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return updated;
435d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
436d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
437d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int SELF_PHONE_NUMBER_OR_SUBSCRIPTION_CHANGED = 1;
438d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int SELF_PROFILE_EXISTS = 2;
439d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
440d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static int refreshFromSelfProfile(final DatabaseWrapper db,
441d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ParticipantData participantData) {
442d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int changed = 0;
443d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Refresh the phone number based on information from telephony
444d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (participantData.updatePhoneNumberForSelfIfChanged()) {
445d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            changed = SELF_PHONE_NUMBER_OR_SUBSCRIPTION_CHANGED;
446d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
447d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
448d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (OsUtil.isAtLeastL_MR1()) {
449d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Refresh the subscription info based on information from SubscriptionManager.
450d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final SubscriptionInfo subscriptionInfo =
451d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PhoneUtils.get(participantData.getSubId()).toLMr1().getActiveSubscriptionInfo();
452d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (participantData.updateSubscriptionInfoForSelfIfChanged(subscriptionInfo)) {
453d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                changed = SELF_PHONE_NUMBER_OR_SUBSCRIPTION_CHANGED;
454d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
455d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
456d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
457d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // For self participant, try getting name/avatar from self profile in CP2 first.
458d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // TODO: in case of multi-sim, profile would not be able to be used for
459d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // different numbers. Need to figure out that.
460d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Cursor selfCursor = null;
461d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
462d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            selfCursor = ContactUtil.getSelf(db.getContext()).performSynchronousQuery();
463d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (selfCursor != null && selfCursor.getCount() > 0) {
464d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                selfCursor.moveToNext();
465d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final long selfContactId = selfCursor.getLong(ContactUtil.INDEX_CONTACT_ID);
466d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                participantData.setContactId(selfContactId);
467d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                participantData.setFullName(selfCursor.getString(
468d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        ContactUtil.INDEX_DISPLAY_NAME));
469d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                participantData.setFirstName(
470d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        ContactUtil.lookupFirstName(db.getContext(), selfContactId));
471d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                participantData.setProfilePhotoUri(selfCursor.getString(
472d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        ContactUtil.INDEX_PHOTO_URI));
473d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                participantData.setLookupKey(selfCursor.getString(
474d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        ContactUtil.INDEX_SELF_QUERY_LOOKUP_KEY));
475d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return SELF_PROFILE_EXISTS;
476d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
477d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final Exception exception) {
478d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // It's possible for contact query to fail and we don't want that to crash our app.
479d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // However, we need to at least log the exception so we know something was wrong.
480d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.e(LogUtil.BUGLE_DATAMODEL_TAG, "Participant refresh: failed to refresh " +
481d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    "participant. exception=" + exception);
482d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
483d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (selfCursor != null) {
484d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                selfCursor.close();
485d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
486d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
487d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return changed;
488d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
489d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
490d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean refreshFromContacts(final DatabaseWrapper db,
491d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ParticipantData participantData) {
492d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String normalizedDestination = participantData.getNormalizedDestination();
493d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long currentContactId = participantData.getContactId();
494d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String currentDisplayName = participantData.getFullName();
495d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String currentFirstName = participantData.getFirstName();
496d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String currentPhotoUri = participantData.getProfilePhotoUri();
497d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String currentContactDestination = participantData.getContactDestination();
498d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
499d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Cursor matchingContactCursor = null;
500d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        long matchingContactId = -1;
501d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String matchingDisplayName = null;
502d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String matchingFirstName = null;
503d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String matchingPhotoUri = null;
504d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String matchingLookupKey = null;
505d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String matchingDestination = null;
506d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean updated = false;
507d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
508d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (TextUtils.isEmpty(normalizedDestination)) {
509d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // The normalized destination can be "" for the self id if we can't get it from the
510d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // SIM.  Some contact providers throw an IllegalArgumentException if you lookup "",
511d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // so we early out.
512d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return false;
513d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
514d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
515d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
516d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            matchingContactCursor = ContactUtil.lookupDestination(db.getContext(),
517d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    normalizedDestination).performSynchronousQuery();
518d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (matchingContactCursor == null || matchingContactCursor.getCount() == 0) {
519d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // If there is no match, mark the participant as contact not found.
520d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (currentContactId != ParticipantData.PARTICIPANT_CONTACT_ID_NOT_FOUND) {
521d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    participantData.setContactId(ParticipantData.PARTICIPANT_CONTACT_ID_NOT_FOUND);
522d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    participantData.setFullName(null);
523d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    participantData.setFirstName(null);
524d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    participantData.setProfilePhotoUri(null);
525d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    participantData.setLookupKey(null);
526d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    updated = true;
527d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
528d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return updated;
529d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
530d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
531d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            while (matchingContactCursor.moveToNext()) {
532d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final long contactId = matchingContactCursor.getLong(ContactUtil.INDEX_CONTACT_ID);
533d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Pick either the first contact or the contact with same id as previous matched
534d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // contact id.
535d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (matchingContactId == -1 || currentContactId == contactId) {
536d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    matchingContactId = contactId;
537d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    matchingDisplayName = matchingContactCursor.getString(
538d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            ContactUtil.INDEX_DISPLAY_NAME);
539d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    matchingFirstName = ContactUtil.lookupFirstName(db.getContext(), contactId);
540d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    matchingPhotoUri = matchingContactCursor.getString(
541d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            ContactUtil.INDEX_PHOTO_URI);
542d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    matchingLookupKey = matchingContactCursor.getString(
543d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            ContactUtil.INDEX_LOOKUP_KEY);
544d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    matchingDestination = matchingContactCursor.getString(
545d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            ContactUtil.INDEX_PHONE_EMAIL);
546d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
547d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
548d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // There is no need to try other contacts if the current contactId was not filled...
549d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (currentContactId < 0
550d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // or we found the matching contact id
551d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        || currentContactId == contactId) {
552d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
553d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
554d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
555d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final Exception exception) {
556d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // It's possible for contact query to fail and we don't want that to crash our app.
557d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // However, we need to at least log the exception so we know something was wrong.
558d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.e(LogUtil.BUGLE_DATAMODEL_TAG, "Participant refresh: failed to refresh " +
559d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    "participant. exception=" + exception);
560d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return false;
561d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
562d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (matchingContactCursor != null) {
563d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                matchingContactCursor.close();
564d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
565d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
566d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
567d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Update participant only if something changed.
568d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean isContactIdChanged = (matchingContactId != currentContactId);
569d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean isDisplayNameChanged =
570d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                !TextUtils.equals(matchingDisplayName, currentDisplayName);
571d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean isFirstNameChanged = !TextUtils.equals(matchingFirstName, currentFirstName);
572d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean isPhotoUrlChanged = !TextUtils.equals(matchingPhotoUri, currentPhotoUri);
573d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean isDestinationChanged = !TextUtils.equals(matchingDestination,
574d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                currentContactDestination);
575d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
576d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (isContactIdChanged || isDisplayNameChanged || isFirstNameChanged || isPhotoUrlChanged
577d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                || isDestinationChanged) {
578d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            participantData.setContactId(matchingContactId);
579d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            participantData.setFullName(matchingDisplayName);
580d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            participantData.setFirstName(matchingFirstName);
581d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            participantData.setProfilePhotoUri(matchingPhotoUri);
582d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            participantData.setLookupKey(matchingLookupKey);
583d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            participantData.setContactDestination(matchingDestination);
584d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (isDestinationChanged) {
585d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Update the send destination to the new one entered by user in Contacts.
586d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                participantData.setSendDestination(matchingDestination);
587d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
588d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            updated = true;
589d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
590d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
591d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return updated;
592d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
593d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
594d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
595d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Update participant with matching contact's contactId, displayName and photoUri.
596d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
597d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static void updateParticipant(final DatabaseWrapper db,
598d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ParticipantData participantData) {
599d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ContentValues values = new ContentValues();
600d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (participantData.isSelf()) {
601d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Self participants can refresh their normalized phone numbers
602d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(ParticipantColumns.NORMALIZED_DESTINATION,
603d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    participantData.getNormalizedDestination());
604d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(ParticipantColumns.DISPLAY_DESTINATION,
605d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    participantData.getDisplayDestination());
606d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
607d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        values.put(ParticipantColumns.CONTACT_ID, participantData.getContactId());
608d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        values.put(ParticipantColumns.LOOKUP_KEY, participantData.getLookupKey());
609d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        values.put(ParticipantColumns.FULL_NAME, participantData.getFullName());
610d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        values.put(ParticipantColumns.FIRST_NAME, participantData.getFirstName());
611d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        values.put(ParticipantColumns.PROFILE_PHOTO_URI, participantData.getProfilePhotoUri());
612d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        values.put(ParticipantColumns.CONTACT_DESTINATION, participantData.getContactDestination());
613d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        values.put(ParticipantColumns.SEND_DESTINATION, participantData.getSendDestination());
614d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
615d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        db.beginTransaction();
616d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
617d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            db.update(DatabaseHelper.PARTICIPANTS_TABLE, values, ParticipantColumns._ID + "=?",
618d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new String[] { participantData.getId() });
619d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            db.setTransactionSuccessful();
620d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
621d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            db.endTransaction();
622d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
623d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
624d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
625d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
626d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Get a list of inactive self ids in the participants table.
627d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
628d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static List<String> getInactiveSelfParticipantIds() {
629d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final DatabaseWrapper db = DataModel.get().getDatabase();
630d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final List<String> inactiveSelf = new ArrayList<String>();
631d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
632d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String selection = ParticipantColumns.SIM_SLOT_ID + "=? AND " +
633d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                SELF_PARTICIPANTS_CLAUSE;
634d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Cursor cursor = null;
635d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
636d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            cursor = db.query(DatabaseHelper.PARTICIPANTS_TABLE,
637d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new String[] { ParticipantColumns._ID },
638d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    selection, new String[] { String.valueOf(ParticipantData.INVALID_SLOT_ID) },
639d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    null, null, null);
640d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
641d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (cursor != null) {
642d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                while (cursor.moveToNext()) {
643d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final String participantId = cursor.getString(0);
644d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    inactiveSelf.add(participantId);
645d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
646d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
647d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
648d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (cursor != null) {
649d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                cursor.close();
650d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
651d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
652d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
653d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return inactiveSelf;
654d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
655d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
656d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
657d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Gets a list of conversations with the given self ids.
658d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
659d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static List<String> getConversationsWithSelfParticipantIds(final List<String> selfIds) {
660d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final DatabaseWrapper db = DataModel.get().getDatabase();
661d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final List<String> conversationIds = new ArrayList<String>();
662d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
663d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Cursor cursor = null;
664d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
665d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final StringBuilder selectionList = new StringBuilder();
666d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (int i = 0; i < selfIds.size(); i++) {
667d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                selectionList.append('?');
668d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (i < selfIds.size() - 1) {
669d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    selectionList.append(',');
670d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
671d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
672d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String selection =
673d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    ConversationColumns.CURRENT_SELF_ID + " IN (" + selectionList + ")";
674d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            cursor = db.query(DatabaseHelper.CONVERSATIONS_TABLE,
675d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new String[] { ConversationColumns._ID },
676d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    selection, selfIds.toArray(new String[0]),
677d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    null, null, null);
678d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
679d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (cursor != null) {
680d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                while (cursor.moveToNext()) {
681d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final String conversationId = cursor.getString(0);
682d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    conversationIds.add(conversationId);
683d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
684d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
685d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
686d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (cursor != null) {
687d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                cursor.close();
688d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
689d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
690d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return conversationIds;
691d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
692d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
693d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
694d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Refresh one conversation's self id.
695d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
696d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static void updateConversationSelfId(final String conversationId,
697d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String selfId) {
698d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final DatabaseWrapper db = DataModel.get().getDatabase();
699d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
700d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        db.beginTransaction();
701d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
702d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            BugleDatabaseOperations.updateConversationSelfIdInTransaction(db, conversationId,
703d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    selfId);
704d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            db.setTransactionSuccessful();
705d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
706d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            db.endTransaction();
707d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
708d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
709d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        MessagingContentProvider.notifyMessagesChanged(conversationId);
710d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        MessagingContentProvider.notifyConversationMetadataChanged(conversationId);
711d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        UIIntents.get().broadcastConversationSelfIdChange(db.getContext(), conversationId, selfId);
712d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
713d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
714d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
715d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * After refreshing the self participant list, find all conversations with inactive self ids,
716d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * and switch them back to system default.
717d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
718d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static void refreshConversationSelfIds() {
719d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final List<String> inactiveSelfs = getInactiveSelfParticipantIds();
720d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (inactiveSelfs.size() == 0) {
721d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return;
722d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
723d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final List<String> conversationsToRefresh =
724d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                getConversationsWithSelfParticipantIds(inactiveSelfs);
725d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (conversationsToRefresh.size() == 0) {
726d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return;
727d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
728d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final DatabaseWrapper db = DataModel.get().getDatabase();
729d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ParticipantData defaultSelf =
730d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                BugleDatabaseOperations.getOrCreateSelf(db, ParticipantData.DEFAULT_SELF_SUB_ID);
731d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
732d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (defaultSelf != null) {
733d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (final String conversationId : conversationsToRefresh) {
734d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                updateConversationSelfId(conversationId, defaultSelf.getId());
735d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
736d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
737d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
738d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
739