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.action; 18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Parcel; 20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Parcelable; 21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.TextUtils; 22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.Factory; 24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.BugleDatabaseOperations; 25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DataModel; 26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DatabaseWrapper; 27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.action.ActionMonitor.ActionCompletedListener; 28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.LaunchConversationData; 29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.ParticipantData; 30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.sms.MmsUtils; 31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert; 32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert.RunsOnMainThread; 33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.LogUtil; 34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.ArrayList; 36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/** 38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Action used to get or create a conversation for a list of conversation participants. 39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class GetOrCreateConversationAction extends Action implements Parcelable { 41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Interface for GetOrCreateConversationAction listeners 43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public interface GetOrCreateConversationActionListener { 45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @RunsOnMainThread 46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd abstract void onGetOrCreateConversationSucceeded(final ActionMonitor monitor, 47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Object data, final String conversationId); 48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @RunsOnMainThread 50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd abstract void onGetOrCreateConversationFailed(final ActionMonitor monitor, 51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Object data); 52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static GetOrCreateConversationActionMonitor getOrCreateConversation( 55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ArrayList<ParticipantData> participants, final Object data, 56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final GetOrCreateConversationActionListener listener) { 57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final GetOrCreateConversationActionMonitor monitor = new 58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd GetOrCreateConversationActionMonitor(data, listener); 59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final GetOrCreateConversationAction action = new GetOrCreateConversationAction(participants, 60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd monitor.getActionKey()); 61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd action.start(monitor); 62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return monitor; 63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static GetOrCreateConversationActionMonitor getOrCreateConversation( 67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String[] recipients, final Object data, final LaunchConversationData listener) { 68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ArrayList<ParticipantData> participants = new ArrayList<>(); 69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd for (String recipient : recipients) { 70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd recipient = recipient.trim(); 71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (!TextUtils.isEmpty(recipient)) { 72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd participants.add(ParticipantData.getFromRawPhoneBySystemLocale(recipient)); 73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } else { 74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.w(LogUtil.BUGLE_TAG, "getOrCreateConversation hit empty recipient"); 75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return getOrCreateConversation(participants, data, listener); 78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final String KEY_PARTICIPANTS_LIST = "participants_list"; 81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private GetOrCreateConversationAction(final ArrayList<ParticipantData> participants, 83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String actionKey) { 84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd super(actionKey); 85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd actionParameters.putParcelableArrayList(KEY_PARTICIPANTS_LIST, participants); 86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Lookup the conversation or create a new one. 90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected Object executeAction() { 93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final DatabaseWrapper db = DataModel.get().getDatabase(); 94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // First find the thread id for this list of participants. 96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ArrayList<ParticipantData> participants = 97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd actionParameters.getParcelableArrayList(KEY_PARTICIPANTS_LIST); 98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd BugleDatabaseOperations.sanitizeConversationParticipants(participants); 99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ArrayList<String> recipients = 100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd BugleDatabaseOperations.getRecipientsFromConversationParticipants(participants); 101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final long threadId = MmsUtils.getOrCreateThreadId(Factory.get().getApplicationContext(), 103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd recipients); 104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (threadId < 0) { 106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.w(LogUtil.BUGLE_TAG, "Couldn't create a threadId in SMS db for numbers : " + 107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.sanitizePII(recipients.toString())); 108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // TODO: Add a better way to indicate an error from executeAction. 109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId, 113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd false, participants, false, false, null); 114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return conversationId; 116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * A monitor that notifies a listener upon completion 120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static class GetOrCreateConversationActionMonitor extends ActionMonitor 122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd implements ActionCompletedListener { 123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private final GetOrCreateConversationActionListener mListener; 124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd GetOrCreateConversationActionMonitor(final Object data, 126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final GetOrCreateConversationActionListener listener) { 127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd super(STATE_CREATED, generateUniqueActionKey("GetOrCreateConversationAction"), data); 128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd setCompletedListener(this); 129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mListener = listener; 130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void onActionSucceeded(final ActionMonitor monitor, 134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Action action, final Object data, final Object result) { 135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (result == null) { 136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mListener.onGetOrCreateConversationFailed(monitor, data); 137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } else { 138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mListener.onGetOrCreateConversationSucceeded(monitor, data, (String) result); 139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void onActionFailed(final ActionMonitor monitor, 144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Action action, final Object data, final Object result) { 145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // TODO: Currently onActionFailed is only called if there is an error in 146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // processing requests, not for errors in the local processing. 147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Assert.fail("Unreachable"); 148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mListener.onGetOrCreateConversationFailed(monitor, data); 149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private GetOrCreateConversationAction(final Parcel in) { 153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd super(in); 154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static final Parcelable.Creator<GetOrCreateConversationAction> CREATOR 157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd = new Parcelable.Creator<GetOrCreateConversationAction>() { 158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public GetOrCreateConversationAction createFromParcel(final Parcel in) { 160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return new GetOrCreateConversationAction(in); 161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public GetOrCreateConversationAction[] newArray(final int size) { 165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return new GetOrCreateConversationAction[size]; 166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd }; 168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void writeToParcel(final Parcel parcel, final int flags) { 171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd writeActionToParcel(parcel, flags); 172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd} 174