PorcessPendingMessagesAction queues one message for sending/downloading associated with a subscription triggering current action at a time. And the ConnectivityUtil also works based on subscriptions so that pending messages can be processed regardless of other phones' state in multi-sim case. It includes cleanup code as well. Test: Manual Change-Id: Id6b4f4a0aa6a3291e7a4d8a5d3f0fbb9db3c5b86 Signed-off-by: Taesu Lee <taesu82.lee@samsung.com>
481 lines
20 KiB
Java
481 lines
20 KiB
Java
/*
|
|
* 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.action;
|
|
|
|
import android.content.ContentProvider;
|
|
import android.content.pm.ProviderInfo;
|
|
import android.database.Cursor;
|
|
import android.net.Uri;
|
|
import android.test.suitebuilder.annotation.SmallTest;
|
|
import android.text.TextUtils;
|
|
|
|
import com.android.messaging.BugleTestCase;
|
|
import com.android.messaging.FakeContext;
|
|
import com.android.messaging.FakeFactory;
|
|
import com.android.messaging.datamodel.BugleDatabaseOperations;
|
|
import com.android.messaging.datamodel.DataModel;
|
|
import com.android.messaging.datamodel.DatabaseHelper;
|
|
import com.android.messaging.datamodel.DatabaseHelper.ConversationColumns;
|
|
import com.android.messaging.datamodel.DatabaseWrapper;
|
|
import com.android.messaging.datamodel.FakeDataModel;
|
|
import com.android.messaging.datamodel.MediaScratchFileProvider;
|
|
import com.android.messaging.datamodel.MessagingContentProvider;
|
|
import com.android.messaging.datamodel.action.ActionTestHelpers.StubActionService;
|
|
import com.android.messaging.datamodel.action.ActionTestHelpers.StubActionService.StubActionServiceCallLog;
|
|
import com.android.messaging.datamodel.action.ReadDraftDataAction.ReadDraftDataActionListener;
|
|
import com.android.messaging.datamodel.data.MessageData;
|
|
import com.android.messaging.datamodel.data.MessagePartData;
|
|
import com.android.messaging.datamodel.data.ParticipantData;
|
|
import com.android.messaging.util.ContentType;
|
|
|
|
import org.mockito.Mock;
|
|
|
|
import java.io.FileNotFoundException;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.util.ArrayList;
|
|
|
|
@SmallTest
|
|
public class ReadWriteDraftMessageActionTest extends BugleTestCase {
|
|
|
|
@Mock ReadDraftDataActionListener mockListener;
|
|
|
|
// TODO: Add test cases
|
|
// 1. Make sure drafts can include attachments and multiple parts
|
|
// 2. Make sure attachments get cleaned up appropriately
|
|
// 3. Make sure messageId and partIds not reused (currently each draft is a new message).
|
|
public void testWriteDraft() {
|
|
final String draftMessage = "draftMessage";
|
|
final long threadId = 1234567;
|
|
final boolean senderBlocked = false;
|
|
final String participantNumber = "5551234567";
|
|
|
|
final DatabaseWrapper db = DataModel.get().getDatabase();
|
|
|
|
final String conversationId = getOrCreateConversation(db, participantNumber, threadId,
|
|
senderBlocked);
|
|
final String selfId = getOrCreateSelfId(db);
|
|
|
|
// Should clear/stub DB
|
|
final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
|
|
|
|
final MessageData message = MessageData.createDraftSmsMessage(conversationId, selfId,
|
|
draftMessage);
|
|
|
|
WriteDraftMessageAction.writeDraftMessage(conversationId, message);
|
|
|
|
assertEquals("Failed to start service once for action", calls.size(), 1);
|
|
assertTrue("Action not SaveDraftMessageAction",
|
|
calls.get(0).action instanceof WriteDraftMessageAction);
|
|
|
|
final Action save = calls.get(0).action;
|
|
|
|
final Object result = save.executeAction();
|
|
|
|
assertTrue("Expect row number string as result", result instanceof String);
|
|
final String messageId = (String) result;
|
|
|
|
// Should check DB
|
|
final MessageData actual = BugleDatabaseOperations.readMessage(db, messageId);
|
|
assertNotNull("Database missing draft", actual);
|
|
assertEquals("Draft text changed", draftMessage, actual.getMessageText());
|
|
}
|
|
|
|
private static String getOrCreateSelfId(final DatabaseWrapper db) {
|
|
db.beginTransaction();
|
|
final String selfId = BugleDatabaseOperations.getOrCreateParticipantInTransaction(db,
|
|
ParticipantData.getSelfParticipant(ParticipantData.DEFAULT_SELF_SUB_ID));
|
|
db.setTransactionSuccessful();
|
|
db.endTransaction();
|
|
return selfId;
|
|
}
|
|
|
|
private static String getOrCreateConversation(final DatabaseWrapper db,
|
|
final String participantNumber, final long threadId, final boolean senderBlocked) {
|
|
final ArrayList<ParticipantData> participants =
|
|
new ArrayList<ParticipantData>();
|
|
participants.add(ParticipantData.getFromRawPhoneBySystemLocale(participantNumber));
|
|
|
|
final String conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
|
|
senderBlocked, participants, false, false, null);
|
|
assertNotNull("No conversation", conversationId);
|
|
return conversationId;
|
|
}
|
|
|
|
public void testReadDraft() {
|
|
final Object data = "data";
|
|
final String draftMessage = "draftMessage";
|
|
final long threadId = 1234567;
|
|
final boolean senderBlocked = false;
|
|
final String participantNumber = "5552345678";
|
|
|
|
final DatabaseWrapper db = DataModel.get().getDatabase();
|
|
|
|
final String conversationId = getOrCreateConversation(db, participantNumber, threadId,
|
|
senderBlocked);
|
|
final String selfId = getOrCreateSelfId(db);
|
|
|
|
// Should clear/stub DB
|
|
final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
|
|
|
|
final MessageData message = MessageData.createDraftSmsMessage(conversationId, selfId,
|
|
draftMessage);
|
|
|
|
BugleDatabaseOperations.updateDraftMessageData(db, conversationId, message,
|
|
BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
|
|
|
|
final ActionMonitor monitor =
|
|
ReadDraftDataAction.readDraftData(conversationId, null, data, mockListener);
|
|
|
|
assertEquals("Unexpected number of calls to service", 1, calls.size());
|
|
assertTrue("Action not of type ReadDraftMessageAction",
|
|
calls.get(0).action instanceof ReadDraftDataAction);
|
|
|
|
final Action read = calls.get(0).action;
|
|
|
|
final Object result = read.executeAction();
|
|
|
|
assertTrue(result instanceof ReadDraftDataAction.DraftData);
|
|
final ReadDraftDataAction.DraftData draft = (ReadDraftDataAction.DraftData) result;
|
|
|
|
assertEquals("Draft message text differs", draftMessage, draft.message.getMessageText());
|
|
assertEquals("Draft self differs", selfId, draft.message.getSelfId());
|
|
assertEquals("Draft conversation differs", conversationId,
|
|
draft.conversation.getConversationId());
|
|
}
|
|
|
|
public void testReadDraftForNewConversation() {
|
|
final Object data = "data";
|
|
long threadId = 1234567;
|
|
final boolean senderBlocked = false;
|
|
long phoneNumber = 5557654567L;
|
|
final String notConversationId = "ThisIsNotValidConversationId";
|
|
|
|
final DatabaseWrapper db = DataModel.get().getDatabase();
|
|
final String selfId = getOrCreateSelfId(db);
|
|
|
|
// Unless set a new conversation should have a null draft message
|
|
final MessageData blank = BugleDatabaseOperations.readDraftMessageData(db,
|
|
notConversationId, selfId);
|
|
assertNull(blank);
|
|
|
|
String conversationId = null;
|
|
do {
|
|
conversationId = BugleDatabaseOperations.getExistingConversation(db,
|
|
threadId, senderBlocked);
|
|
threadId++;
|
|
phoneNumber++;
|
|
}
|
|
while(!TextUtils.isEmpty(conversationId));
|
|
|
|
final ArrayList<ParticipantData> participants =
|
|
new ArrayList<ParticipantData>();
|
|
participants.add(ParticipantData.getFromRawPhoneBySystemLocale(Long.toString(phoneNumber)));
|
|
|
|
conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
|
|
senderBlocked, participants, false, false, null);
|
|
assertNotNull("No conversation", conversationId);
|
|
|
|
final MessageData actual = BugleDatabaseOperations.readDraftMessageData(db, conversationId,
|
|
selfId);
|
|
assertNull(actual);
|
|
|
|
// Should clear/stub DB
|
|
final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
|
|
|
|
final ActionMonitor monitor =
|
|
ReadDraftDataAction.readDraftData(conversationId, null, data, mockListener);
|
|
|
|
assertEquals("Unexpected number of calls to service", 1, calls.size());
|
|
assertTrue("Action not of type ReadDraftMessageAction",
|
|
calls.get(0).action instanceof ReadDraftDataAction);
|
|
|
|
final Action read = calls.get(0).action;
|
|
|
|
final Object result = read.executeAction();
|
|
|
|
assertTrue(result instanceof ReadDraftDataAction.DraftData);
|
|
final ReadDraftDataAction.DraftData draft = (ReadDraftDataAction.DraftData) result;
|
|
|
|
assertEquals("Draft message text differs", "", draft.message.getMessageText());
|
|
assertEquals("Draft self differs", selfId, draft.message.getSelfId());
|
|
assertEquals("Draft conversation differs", conversationId,
|
|
draft.conversation.getConversationId());
|
|
}
|
|
|
|
public void testWriteAndReadDraft() {
|
|
final Object data = "data";
|
|
final String draftMessage = "draftMessage";
|
|
|
|
final DatabaseWrapper db = DataModel.get().getDatabase();
|
|
final Cursor conversations = db.query(DatabaseHelper.CONVERSATIONS_TABLE,
|
|
new String[] { ConversationColumns._ID, ConversationColumns.CURRENT_SELF_ID }, null,
|
|
null, null /* groupBy */, null /* having */, null /* orderBy */);
|
|
|
|
if (conversations.moveToFirst()) {
|
|
final String conversationId = conversations.getString(0);
|
|
final String selfId = getOrCreateSelfId(db);
|
|
|
|
// Should clear/stub DB
|
|
final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
|
|
|
|
final MessageData message = MessageData.createDraftSmsMessage(conversationId, selfId,
|
|
draftMessage);
|
|
|
|
WriteDraftMessageAction.writeDraftMessage(conversationId, message);
|
|
|
|
assertEquals("Failed to start service once for action", calls.size(), 1);
|
|
assertTrue("Action not SaveDraftMessageAction",
|
|
calls.get(0).action instanceof WriteDraftMessageAction);
|
|
|
|
final Action save = calls.get(0).action;
|
|
|
|
Object result = save.executeAction();
|
|
|
|
assertTrue("Expect row number string as result", result instanceof String);
|
|
|
|
// Should check DB
|
|
|
|
final ActionMonitor monitor =
|
|
ReadDraftDataAction.readDraftData(conversationId, null, data,
|
|
mockListener);
|
|
|
|
assertEquals("Expect two calls queued", 2, calls.size());
|
|
assertTrue("Expect action", calls.get(1).action instanceof ReadDraftDataAction);
|
|
|
|
final Action read = calls.get(1).action;
|
|
|
|
result = read.executeAction();
|
|
|
|
assertTrue(result instanceof ReadDraftDataAction.DraftData);
|
|
final ReadDraftDataAction.DraftData draft = (ReadDraftDataAction.DraftData) result;
|
|
|
|
assertEquals("Draft message text differs", draftMessage, draft.message.getMessageText());
|
|
// The conversation's self id is used as the draft's self id.
|
|
assertEquals("Draft self differs", conversations.getString(1),
|
|
draft.message.getSelfId());
|
|
assertEquals("Draft conversation differs", conversationId,
|
|
draft.conversation.getConversationId());
|
|
} else {
|
|
fail("No conversations in database");
|
|
}
|
|
}
|
|
|
|
public void testUpdateDraft() {
|
|
final String initialMessage = "initialMessage";
|
|
final String draftMessage = "draftMessage";
|
|
final long threadId = 1234567;
|
|
final boolean senderBlocked = false;
|
|
final String participantNumber = "5553456789";
|
|
|
|
final DatabaseWrapper db = DataModel.get().getDatabase();
|
|
|
|
final String conversationId = getOrCreateConversation(db, participantNumber, threadId,
|
|
senderBlocked);
|
|
final String selfId = getOrCreateSelfId(db);
|
|
|
|
final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
|
|
|
|
// Insert initial message
|
|
MessageData initial = MessageData.createDraftSmsMessage(conversationId, selfId,
|
|
initialMessage);
|
|
|
|
BugleDatabaseOperations.updateDraftMessageData(db, conversationId, initial,
|
|
BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
|
|
|
|
initial = BugleDatabaseOperations.readDraftMessageData(db,
|
|
conversationId, selfId);
|
|
assertEquals("Initial text mismatch", initialMessage, initial.getMessageText());
|
|
|
|
// Now update the draft
|
|
final MessageData message = MessageData.createDraftSmsMessage(conversationId, selfId,
|
|
draftMessage);
|
|
WriteDraftMessageAction.writeDraftMessage(conversationId, message);
|
|
|
|
assertEquals("Failed to start service once for action", calls.size(), 1);
|
|
assertTrue("Action not SaveDraftMessageAction",
|
|
calls.get(0).action instanceof WriteDraftMessageAction);
|
|
|
|
final Action save = calls.get(0).action;
|
|
|
|
final Object result = save.executeAction();
|
|
|
|
assertTrue("Expect row number string as result", result instanceof String);
|
|
|
|
// Check DB
|
|
final MessageData actual = BugleDatabaseOperations.readDraftMessageData(db,
|
|
conversationId, selfId);
|
|
assertNotNull("Database missing draft", actual);
|
|
assertEquals("Draft text mismatch", draftMessage, actual.getMessageText());
|
|
assertNull("Draft messageId should be null", actual.getMessageId());
|
|
}
|
|
|
|
public void testBugleDatabaseDraftOperations() {
|
|
final String initialMessage = "initialMessage";
|
|
final String draftMessage = "draftMessage";
|
|
final long threadId = 1234599;
|
|
final boolean senderBlocked = false;
|
|
final String participantNumber = "5553456798";
|
|
final String subject = "subject here";
|
|
|
|
final DatabaseWrapper db = DataModel.get().getDatabase();
|
|
|
|
final String conversationId = getOrCreateConversation(db, participantNumber, threadId,
|
|
senderBlocked);
|
|
final String selfId = getOrCreateSelfId(db);
|
|
|
|
final String text = "This is some text";
|
|
final Uri mOutputUri = MediaScratchFileProvider.buildMediaScratchSpaceUri("txt");
|
|
OutputStream outputStream = null;
|
|
try {
|
|
outputStream = mContext.getContentResolver().openOutputStream(mOutputUri);
|
|
outputStream.write(text.getBytes());
|
|
} catch (final FileNotFoundException e) {
|
|
fail("Cannot open output file");
|
|
} catch (final IOException e) {
|
|
fail("Cannot write output file");
|
|
}
|
|
|
|
final MessageData initial =
|
|
MessageData.createDraftMmsMessage(conversationId, selfId, initialMessage, subject);
|
|
initial.addPart(MessagePartData.createMediaMessagePart(ContentType.MULTIPART_MIXED,
|
|
mOutputUri, 0, 0));
|
|
|
|
final String initialMessageId = BugleDatabaseOperations.updateDraftMessageData(db,
|
|
conversationId, initial, BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
|
|
assertNotNull(initialMessageId);
|
|
|
|
final MessageData initialDraft = BugleDatabaseOperations.readMessage(db, initialMessageId);
|
|
assertNotNull(initialDraft);
|
|
int cnt = 0;
|
|
for(final MessagePartData part : initialDraft.getParts()) {
|
|
if (part.isAttachment()) {
|
|
assertEquals(part.getContentUri(), mOutputUri);
|
|
} else {
|
|
assertEquals(part.getText(), initialMessage);
|
|
}
|
|
cnt++;
|
|
}
|
|
assertEquals("Wrong number of parts", 2, cnt);
|
|
|
|
InputStream inputStream = null;
|
|
try {
|
|
inputStream = mContext.getContentResolver().openInputStream(mOutputUri);
|
|
final byte[] buffer = new byte[256];
|
|
final int read = inputStream.read(buffer);
|
|
assertEquals(read, text.getBytes().length);
|
|
} catch (final FileNotFoundException e) {
|
|
fail("Cannot open input file");
|
|
} catch (final IOException e) {
|
|
fail("Cannot read input file");
|
|
}
|
|
|
|
final String moreText = "This is some more text";
|
|
final Uri mAnotherUri = MediaScratchFileProvider.buildMediaScratchSpaceUri("txt");
|
|
outputStream = null;
|
|
try {
|
|
outputStream = mContext.getContentResolver().openOutputStream(mAnotherUri);
|
|
outputStream.write(moreText.getBytes());
|
|
} catch (final FileNotFoundException e) {
|
|
fail("Cannot open output file");
|
|
} catch (final IOException e) {
|
|
fail("Cannot write output file");
|
|
}
|
|
|
|
final MessageData another =
|
|
MessageData.createDraftMmsMessage(conversationId, selfId, draftMessage, subject);
|
|
another.addPart(MessagePartData.createMediaMessagePart(ContentType.MMS_MULTIPART_MIXED,
|
|
mAnotherUri, 0, 0));
|
|
|
|
final String anotherMessageId = BugleDatabaseOperations.updateDraftMessageData(db,
|
|
conversationId, another, BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
|
|
assertNotNull(anotherMessageId);
|
|
|
|
final MessageData anotherDraft = BugleDatabaseOperations.readMessage(db, anotherMessageId);
|
|
assertNotNull(anotherDraft);
|
|
cnt = 0;
|
|
for(final MessagePartData part : anotherDraft.getParts()) {
|
|
if (part.isAttachment()) {
|
|
assertEquals(part.getContentUri(), mAnotherUri);
|
|
} else {
|
|
assertEquals(part.getText(), draftMessage);
|
|
}
|
|
cnt++;
|
|
}
|
|
assertEquals("Wrong number of parts", 2, cnt);
|
|
|
|
inputStream = null;
|
|
try {
|
|
inputStream = mContext.getContentResolver().openInputStream(mOutputUri);
|
|
assertNull("Original draft content should have been deleted", inputStream);
|
|
} catch (final FileNotFoundException e) {
|
|
}
|
|
inputStream = null;
|
|
try {
|
|
inputStream = mContext.getContentResolver().openInputStream(mAnotherUri);
|
|
final byte[] buffer = new byte[256];
|
|
final int read = inputStream.read(buffer);
|
|
assertEquals(read, moreText.getBytes().length);
|
|
} catch (final FileNotFoundException e) {
|
|
fail("Cannot open input file");
|
|
} catch (final IOException e) {
|
|
fail("Cannot read input file");
|
|
}
|
|
|
|
final MessageData last = null;
|
|
final String lastPartId = BugleDatabaseOperations.updateDraftMessageData(db,
|
|
conversationId, last, BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
|
|
assertNull(lastPartId);
|
|
|
|
inputStream = null;
|
|
try {
|
|
inputStream = mContext.getContentResolver().openInputStream(mAnotherUri);
|
|
assertNull("Original draft content should have been deleted", inputStream);
|
|
} catch (final FileNotFoundException e) {
|
|
}
|
|
|
|
}
|
|
|
|
private StubActionService mService;
|
|
|
|
@Override
|
|
public void setUp() throws Exception {
|
|
super.setUp();
|
|
|
|
final FakeContext context = new FakeContext(getTestContext());
|
|
|
|
final ContentProvider bugleProvider = new MessagingContentProvider();
|
|
final ProviderInfo bugleProviderInfo = new ProviderInfo();
|
|
bugleProviderInfo.authority = MessagingContentProvider.AUTHORITY;
|
|
bugleProvider.attachInfo(mContext, bugleProviderInfo);
|
|
context.addContentProvider(MessagingContentProvider.AUTHORITY, bugleProvider);
|
|
final ContentProvider mediaProvider = new MediaScratchFileProvider();
|
|
final ProviderInfo mediaProviderInfo = new ProviderInfo();
|
|
mediaProviderInfo.authority = MediaScratchFileProvider.AUTHORITY;
|
|
mediaProvider.attachInfo(mContext, mediaProviderInfo);
|
|
context.addContentProvider(MediaScratchFileProvider.AUTHORITY, mediaProvider);
|
|
|
|
mService = new StubActionService();
|
|
final FakeDataModel fakeDataModel = new FakeDataModel(context)
|
|
.withActionService(mService);
|
|
FakeFactory.registerWithFakeContext(getTestContext(), context)
|
|
.withDataModel(fakeDataModel);
|
|
|
|
}
|
|
}
|