Merge "Implementation of business logic for voicemail status."
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 806b33f..547f3e7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1619,4 +1619,26 @@
<!-- The header in the call log used to identify items that have been already consumed [CHAR LIMIT=10] -->
<string name="call_log_old_header">Older</string>
+
+ <!-- Voicemail status message shown at the top of call log to notify the user that no new
+ voicemails are currently available. This can happen when both notification as well as data
+ connection to the voicemail server is lost. [CHAR LIMIT=64] -->
+ <string name="voicemail_status_voicemail_not_available">Cannot connect to voicemail server.</string>
+ <!-- Voicemail status message shown at the top of call log to notify the user that there is no
+ data connection to the voicemail server, but there are new voicemails waiting on the server.
+ [CHAR LIMIT=64] -->
+ <string name="voicemail_status_messages_waiting">Cannot connect to voicemail server. New voicemails waiting.</string>
+ <!-- Voicemail status message shown at the top of call log to invite the user to configure
+ visual voicemail. [CHAR LIMIT=64] -->
+ <string name="voicemail_status_configure_voicemail">Configure your voicemail.</string>
+ <!-- Voicemail status message shown at the top of call details screen to notify the user that
+ the audio of this voicemail is not available. [CHAR LIMIT=64] -->
+ <string name="voicemail_status_audio_not_available">Audio not available.</string>
+
+ <!-- User action prompt shown next to a voicemail status message to let the user configure
+ visual voicemail. [CHAR LIMIT=20] -->
+ <string name="voicemail_status_action_configure">Configure</string>
+ <!-- User action prompt shown next to a voicemail status message to let the user call voicemail
+ server directly to listen to the voicemails. [CHAR LIMIT=20] -->
+ <string name="voicemail_status_action_call_server">Call voicemail</string>
</resources>
diff --git a/src/com/android/contacts/calllog/VoicemailStatusHelper.java b/src/com/android/contacts/calllog/VoicemailStatusHelper.java
new file mode 100644
index 0000000..d4a3965
--- /dev/null
+++ b/src/com/android/contacts/calllog/VoicemailStatusHelper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 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.contacts.calllog;
+
+import android.net.Uri;
+
+import java.util.List;
+
+/**
+ * Interface used by the call log UI to determine what user message, if any, related to voicemail
+ * source status needs to be shown. The messages are returned in the order of importance.
+ * <p>
+ * The implementation of this interface interacts with the voicemail content provider to fetch
+ * statuses of all the registered voicemail sources and determines if any status message needs to
+ * be shown. The user of this interface must observe/listen to provider changes and invoke
+ * this class to check if any message needs to be shown.
+ */
+public interface VoicemailStatusHelper {
+ public class Message {
+ /** Package of the source on behalf of which this message has to be shown.*/
+ public final String sourcePackage;
+ /** The string resource id of the status message that should be shown. */
+ public final int statusMessageId;
+ /** The string resource id of the action message that should be shown. */
+ public final int actionMessageId;
+ /** URI for the corrective action, where applicable. Null if no action URI is available. */
+ public final Uri actionUri;
+ public Message(String sourcePackage, int statusMessageId, int actionMessageId,
+ Uri actionUri) {
+ this.sourcePackage = sourcePackage;
+ this.statusMessageId = statusMessageId;
+ this.actionMessageId = actionMessageId;
+ this.actionUri = actionUri;
+ }
+ }
+
+ /**
+ * Returns a list of messages, in the order or priority that should be shown to the user. An
+ * empty list is returned if no message needs to be shown.
+ */
+ public List<Message> getStatusMessages();
+}
diff --git a/src/com/android/contacts/calllog/VoicemailStatusHelperImpl.java b/src/com/android/contacts/calllog/VoicemailStatusHelperImpl.java
new file mode 100644
index 0000000..9738fd7
--- /dev/null
+++ b/src/com/android/contacts/calllog/VoicemailStatusHelperImpl.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2011 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.contacts.calllog;
+
+import static android.provider.VoicemailContract.Status.CONFIGURATION_STATE_CAN_BE_CONFIGURED;
+import static android.provider.VoicemailContract.Status.CONFIGURATION_STATE_OK;
+import static android.provider.VoicemailContract.Status.DATA_CHANNEL_STATE_NO_CONNECTION;
+import static android.provider.VoicemailContract.Status.DATA_CHANNEL_STATE_OK;
+import static android.provider.VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING;
+import static android.provider.VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION;
+import static android.provider.VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_OK;
+
+import com.android.common.io.MoreCloseables;
+import com.android.contacts.R;
+
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.VoicemailContract.Status;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/** Implementation of {@link VoicemailStatusHelper}. */
+public class VoicemailStatusHelperImpl implements VoicemailStatusHelper {
+ private static final int SOURCE_PACKAGE_INDEX = 0;
+ private static final int CONFIGURATION_STATE_INDEX = 1;
+ private static final int DATA_CHANNEL_STATE_INDEX = 2;
+ private static final int NOTIFICATION_CHANNEL_STATE_INDEX = 3;
+ private static final int SETTINGS_URI_INDEX = 4;
+ private static final int VOICEMAIL_ACCESS_URI_INDEX = 5;
+ private static final int NUM_COLUMNS = 6;
+ private static final String[] PROJECTION = new String[NUM_COLUMNS];
+ static {
+ PROJECTION[SOURCE_PACKAGE_INDEX] = Status.SOURCE_PACKAGE;
+ PROJECTION[CONFIGURATION_STATE_INDEX] = Status.CONFIGURATION_STATE;
+ PROJECTION[DATA_CHANNEL_STATE_INDEX] = Status.DATA_CHANNEL_STATE;
+ PROJECTION[NOTIFICATION_CHANNEL_STATE_INDEX] = Status.NOTIFICATION_CHANNEL_STATE;
+ PROJECTION[SETTINGS_URI_INDEX] = Status.SETTINGS_URI;
+ PROJECTION[VOICEMAIL_ACCESS_URI_INDEX] = Status.VOICEMAIL_ACCESS_URI;
+ }
+
+ /** Possible user actions. */
+ public static enum Action {
+ NONE(-1),
+ CALL_VOICEMAIL(R.string.voicemail_status_action_call_server),
+ CONFIGURE_VOICEMAIL(R.string.voicemail_status_action_configure);
+
+ private final int mMessageId;
+ private Action(int messageId) {
+ mMessageId = messageId;
+ }
+
+ public int getMessageId() {
+ return mMessageId;
+ }
+ }
+
+ /**
+ * Overall state of the source status. Each state is associated with the corresponding display
+ * string and the corrective action. The states are also assigned a relative priority which is
+ * used to order the messages from different sources.
+ */
+ private static enum OverallState {
+ // TODO: Add separate string for call details and call log pages for the states that needs
+ // to be shown in both.
+ /** Both notification and data channel are not working. */
+ NO_CONNECTION(0, Action.CALL_VOICEMAIL, R.string.voicemail_status_voicemail_not_available),
+ /** Notifications working, but data channel is not working. Audio cannot be downloaded. */
+ NO_DATA(1, Action.CALL_VOICEMAIL, R.string.voicemail_status_audio_not_available),
+ /** Messages are known to be waiting but data channel is not working. */
+ MESSAGE_WAITING(2, Action.CALL_VOICEMAIL, R.string.voicemail_status_messages_waiting),
+ /** Notification channel not working, but data channel is. */
+ NO_NOTIFICATIONS(3, Action.CALL_VOICEMAIL,
+ R.string.voicemail_status_voicemail_not_available),
+ /** Invite user to set up voicemail. */
+ INVITE_FOR_CONFIGURATION(4, Action.CONFIGURE_VOICEMAIL,
+ R.string.voicemail_status_configure_voicemail),
+ /**
+ * No detailed notifications, but data channel is working.
+ * This is normal mode of operation for certain sources. No action needed.
+ */
+ NO_DETAILED_NOTIFICATION(5, Action.NONE, -1),
+ /** Visual voicemail not yet set up. No local action needed. */
+ NOT_CONFIGURED(6, Action.NONE, -1),
+ /** Everything is OK. */
+ OK(7, Action.NONE, -1),
+ /** If one or more state value set by the source is not valid. */
+ INVALID(8, Action.NONE, -1);
+
+ private final int mPriority;
+ private final Action mAction;
+ private final int mMessageId;
+
+ private OverallState(int priority, Action action, int messageId) {
+ mPriority = priority;
+ mAction = action;
+ mMessageId = messageId;
+ }
+
+ public Action getAction() {
+ return mAction;
+ }
+
+ public int getPriority() {
+ return mPriority;
+ }
+
+ public int getMessageId() {
+ return mMessageId;
+ }
+ }
+
+ private final ContentResolver mContentResolver;
+
+ public VoicemailStatusHelperImpl(ContentResolver contentResolver) {
+ mContentResolver = contentResolver;
+ }
+
+ /** A wrapper on {@link Message} which additionally stores the priority of the message. */
+ private static class MessageWrapper {
+ private final Message mMessage;
+ private final int mPriority;
+
+ public MessageWrapper(Message message, int priority) {
+ mMessage = message;
+ mPriority = priority;
+ }
+ }
+
+ @Override
+ public List<Message> getStatusMessages() {
+ Cursor cursor = null;
+ try {
+ cursor = mContentResolver.query(Status.CONTENT_URI, PROJECTION, null, null, null);
+ List<MessageWrapper> messages =
+ new ArrayList<VoicemailStatusHelperImpl.MessageWrapper>();
+ while(cursor.moveToNext()) {
+ MessageWrapper message = getMessageForStatusEntry(cursor);
+ if (message != null) {
+ messages.add(message);
+ }
+ }
+ // Finally reorder the messages by their priority.
+ return reorderMessages(messages);
+ } finally {
+ MoreCloseables.closeQuietly(cursor);
+ }
+ }
+
+ private List<Message> reorderMessages(List<MessageWrapper> messageWrappers) {
+ Collections.sort(messageWrappers, new Comparator<MessageWrapper>() {
+ @Override
+ public int compare(MessageWrapper msg1, MessageWrapper msg2) {
+ return msg1.mPriority - msg2.mPriority;
+ }
+ });
+ List<Message> reorderMessages = new ArrayList<VoicemailStatusHelper.Message>();
+ // Copy the ordered message objects into the final list.
+ for (MessageWrapper messageWrapper : messageWrappers) {
+ reorderMessages.add(messageWrapper.mMessage);
+ }
+ return reorderMessages;
+ }
+
+ /**
+ * Returns the message for the status entry pointed to by the cursor.
+ */
+ private MessageWrapper getMessageForStatusEntry(Cursor cursor) {
+ final String sourcePackage = cursor.getString(SOURCE_PACKAGE_INDEX);
+ if (sourcePackage == null) {
+ return null;
+ }
+ final OverallState overallState = getOverallState(cursor.getInt(CONFIGURATION_STATE_INDEX),
+ cursor.getInt(DATA_CHANNEL_STATE_INDEX),
+ cursor.getInt(NOTIFICATION_CHANNEL_STATE_INDEX));
+ final Action action = overallState.getAction();
+
+ // No source package or no action, means no message shown.
+ if (action == Action.NONE) {
+ return null;
+ }
+
+ Uri actionUri = null;
+ if (action == Action.CALL_VOICEMAIL) {
+ actionUri = Uri.parse(cursor.getString(VOICEMAIL_ACCESS_URI_INDEX));
+ } else if (action == Action.CONFIGURE_VOICEMAIL) {
+ actionUri = Uri.parse(cursor.getString(SETTINGS_URI_INDEX));
+ }
+ return new MessageWrapper(
+ new Message(sourcePackage, overallState.getMessageId(), action.getMessageId(),
+ actionUri),
+ overallState.getPriority());
+ }
+
+ private OverallState getOverallState(int configurationState, int dataChannelState,
+ int notificationChannelState) {
+ if (configurationState == CONFIGURATION_STATE_OK) {
+ // Voicemail is configured. Let's see how is the data channel.
+ if (dataChannelState == DATA_CHANNEL_STATE_OK) {
+ // Data channel is fine. What about notification channel?
+ if (notificationChannelState == NOTIFICATION_CHANNEL_STATE_OK) {
+ return OverallState.OK;
+ } else if (notificationChannelState == NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING) {
+ return OverallState.NO_DETAILED_NOTIFICATION;
+ } else if (notificationChannelState == NOTIFICATION_CHANNEL_STATE_NO_CONNECTION) {
+ return OverallState.NO_NOTIFICATIONS;
+ }
+ } else if (dataChannelState == DATA_CHANNEL_STATE_NO_CONNECTION) {
+ // Data channel is not working. What about notification channel?
+ if (notificationChannelState == NOTIFICATION_CHANNEL_STATE_OK) {
+ return OverallState.NO_DATA;
+ } else if (notificationChannelState == NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING) {
+ return OverallState.MESSAGE_WAITING;
+ } else if (notificationChannelState == NOTIFICATION_CHANNEL_STATE_NO_CONNECTION) {
+ return OverallState.NO_CONNECTION;
+ }
+ }
+ } else if (configurationState == CONFIGURATION_STATE_CAN_BE_CONFIGURED) {
+ // Voicemail not configured. data/notification channel states are irrelevant.
+ return OverallState.INVITE_FOR_CONFIGURATION;
+ } else if (configurationState == Status.CONFIGURATION_STATE_NOT_CONFIGURED) {
+ // Voicemail not configured. data/notification channel states are irrelevant.
+ return OverallState.NOT_CONFIGURED;
+ }
+ // Will reach here only if the source has set an invalid value.
+ return OverallState.INVALID;
+ }
+}
diff --git a/tests/src/com/android/contacts/calllog/VoicemailStatusHelperImplTest.java b/tests/src/com/android/contacts/calllog/VoicemailStatusHelperImplTest.java
new file mode 100644
index 0000000..d577d4c
--- /dev/null
+++ b/tests/src/com/android/contacts/calllog/VoicemailStatusHelperImplTest.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2011 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.contacts.calllog;
+
+import static android.provider.VoicemailContract.Status.CONFIGURATION_STATE;
+import static android.provider.VoicemailContract.Status.CONFIGURATION_STATE_CAN_BE_CONFIGURED;
+import static android.provider.VoicemailContract.Status.CONFIGURATION_STATE_NOT_CONFIGURED;
+import static android.provider.VoicemailContract.Status.DATA_CHANNEL_STATE;
+import static android.provider.VoicemailContract.Status.DATA_CHANNEL_STATE_NO_CONNECTION;
+import static android.provider.VoicemailContract.Status.DATA_CHANNEL_STATE_OK;
+import static android.provider.VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE;
+import static android.provider.VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING;
+import static android.provider.VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION;
+import static android.provider.VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_OK;
+
+import com.android.contacts.R;
+import com.android.contacts.calllog.VoicemailStatusHelper.Message;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.net.Uri;
+import android.provider.VoicemailContract.Status;
+import android.test.AndroidTestCase;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link VoicemailStatusHelperImpl}.
+ */
+public class VoicemailStatusHelperImplTest extends AndroidTestCase {
+ private static final String TEST_PACKAGE_1 = "com.test.package1";
+ private static final String TEST_PACKAGE_2 = "com.test.package2";
+
+ private static final Uri TEST_SETTINGS_URI = Uri.parse("http://www.visual.voicemail.setup");
+ private static final Uri TEST_VOICEMAIL_URI = Uri.parse("tel:901");
+
+ private static final int ACTION_MSG_CALL_VOICEMAIL = R.string.voicemail_status_action_call_server;
+ private static final int ACTION_MSG_CONFIGURE = R.string.voicemail_status_action_configure;
+
+ private static final int STATUS_MSG_VOICEMAIL_NOT_AVAILABLE =
+ R.string.voicemail_status_voicemail_not_available;
+ private static final int STATUS_MSG_AUDIO_NOT_AVAIALABLE =
+ R.string.voicemail_status_audio_not_available;
+ private static final int STATUS_MSG_MESSAGE_WAITING = R.string.voicemail_status_messages_waiting;
+ private static final int STATUS_MSG_INVITE_FOR_CONFIGURATION =
+ R.string.voicemail_status_configure_voicemail;
+
+ // The packages whose status entries have been added during the test and needs to be cleaned
+ // up in teardown.
+ private Set<String> mPackagesToCleanup = new HashSet<String>();
+ // Object under test.
+ private VoicemailStatusHelper mStatusHelper;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mStatusHelper = new VoicemailStatusHelperImpl(getContentResolver());
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ for (String sourcePackage : mPackagesToCleanup) {
+ deleteEntryForPackage(sourcePackage);
+ }
+ mPackagesToCleanup.clear();
+ // Set member variables to null so that they are garbage collected across different runs
+ // of the tests.
+ mStatusHelper = null;
+ mPackagesToCleanup = null;
+ super.tearDown();
+ }
+
+ public void testNoStatusEntries() {
+ assertEquals(0, mStatusHelper.getStatusMessages().size());
+ }
+
+ public void testAllOK() {
+ insertEntryForPackage(TEST_PACKAGE_1, getAllOkStatusValues());
+ insertEntryForPackage(TEST_PACKAGE_2, getAllOkStatusValues());
+ assertEquals(0, mStatusHelper.getStatusMessages().size());
+ }
+
+ public void testNotAllOKForOnePackage() {
+ insertEntryForPackage(TEST_PACKAGE_1, getAllOkStatusValues());
+ insertEntryForPackage(TEST_PACKAGE_2, getAllOkStatusValues());
+
+ ContentValues values = new ContentValues();
+ // No notification + good data channel - for now same as no connection.
+ values.put(NOTIFICATION_CHANNEL_STATE, NOTIFICATION_CHANNEL_STATE_NO_CONNECTION);
+ values.put(DATA_CHANNEL_STATE, DATA_CHANNEL_STATE_OK);
+ updateEntryForPackage(TEST_PACKAGE_2, values);
+ checkExpectedMessage(TEST_PACKAGE_2, values, STATUS_MSG_VOICEMAIL_NOT_AVAILABLE,
+ ACTION_MSG_CALL_VOICEMAIL);
+
+ // Message waiting + good data channel - no action.
+ values.put(NOTIFICATION_CHANNEL_STATE, NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING);
+ values.put(DATA_CHANNEL_STATE, DATA_CHANNEL_STATE_OK);
+ updateEntryForPackage(TEST_PACKAGE_2, values);
+ checkNoMessages(TEST_PACKAGE_2, values);
+
+ // Notification OK + no data channel - call voicemail/no audio.
+ values.put(NOTIFICATION_CHANNEL_STATE, NOTIFICATION_CHANNEL_STATE_OK);
+ values.put(DATA_CHANNEL_STATE, DATA_CHANNEL_STATE_NO_CONNECTION);
+ updateEntryForPackage(TEST_PACKAGE_2, values);
+ checkExpectedMessage(TEST_PACKAGE_2, values, STATUS_MSG_AUDIO_NOT_AVAIALABLE,
+ ACTION_MSG_CALL_VOICEMAIL);
+
+ // No notification + no data channel - call voicemail/no connection.
+ values.put(NOTIFICATION_CHANNEL_STATE, NOTIFICATION_CHANNEL_STATE_NO_CONNECTION);
+ values.put(DATA_CHANNEL_STATE, DATA_CHANNEL_STATE_NO_CONNECTION);
+ updateEntryForPackage(TEST_PACKAGE_2, values);
+ checkExpectedMessage(TEST_PACKAGE_2, values, STATUS_MSG_VOICEMAIL_NOT_AVAILABLE,
+ ACTION_MSG_CALL_VOICEMAIL);
+
+ // Message waiting + no data channel - call voicemail.
+ values.put(NOTIFICATION_CHANNEL_STATE, NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING);
+ values.put(DATA_CHANNEL_STATE, DATA_CHANNEL_STATE_NO_CONNECTION);
+ updateEntryForPackage(TEST_PACKAGE_2, values);
+ checkExpectedMessage(TEST_PACKAGE_2, values, STATUS_MSG_MESSAGE_WAITING,
+ ACTION_MSG_CALL_VOICEMAIL);
+
+ // Not configured. No user action, so no message.
+ values.put(CONFIGURATION_STATE, CONFIGURATION_STATE_NOT_CONFIGURED);
+ updateEntryForPackage(TEST_PACKAGE_2, values);
+ checkNoMessages(TEST_PACKAGE_2, values);
+
+ // Can be configured - invite user for configure voicemail.
+ values.put(CONFIGURATION_STATE, CONFIGURATION_STATE_CAN_BE_CONFIGURED);
+ updateEntryForPackage(TEST_PACKAGE_2, values);
+ checkExpectedMessage(TEST_PACKAGE_2, values, STATUS_MSG_INVITE_FOR_CONFIGURATION,
+ ACTION_MSG_CONFIGURE, TEST_SETTINGS_URI);
+ }
+
+ // Test that priority of messages are handled well.
+ public void testMessageOrdering() {
+ insertEntryForPackage(TEST_PACKAGE_1, getAllOkStatusValues());
+ insertEntryForPackage(TEST_PACKAGE_2, getAllOkStatusValues());
+
+ final ContentValues valuesNoNotificationGoodDataChannel = new ContentValues();
+ valuesNoNotificationGoodDataChannel.put(NOTIFICATION_CHANNEL_STATE,
+ NOTIFICATION_CHANNEL_STATE_NO_CONNECTION);
+ valuesNoNotificationGoodDataChannel.put(DATA_CHANNEL_STATE, DATA_CHANNEL_STATE_OK);
+
+ final ContentValues valuesNoNotificationNoDataChannel = new ContentValues();
+ valuesNoNotificationNoDataChannel.put(NOTIFICATION_CHANNEL_STATE,
+ NOTIFICATION_CHANNEL_STATE_NO_CONNECTION);
+ valuesNoNotificationNoDataChannel.put(DATA_CHANNEL_STATE, DATA_CHANNEL_STATE_NO_CONNECTION);
+
+ // Package1 with valuesNoNotificationGoodDataChannel and
+ // package2 with valuesNoNotificationNoDataChannel. Package2 should be above.
+ updateEntryForPackage(TEST_PACKAGE_1, valuesNoNotificationGoodDataChannel);
+ updateEntryForPackage(TEST_PACKAGE_2, valuesNoNotificationNoDataChannel);
+ List<Message> messages = mStatusHelper.getStatusMessages();
+ assertEquals(2, messages.size());
+ assertEquals(TEST_PACKAGE_1, messages.get(1).sourcePackage);
+ assertEquals(TEST_PACKAGE_2, messages.get(0).sourcePackage);
+
+ // Now reverse the values - ordering should be reversed as well.
+ updateEntryForPackage(TEST_PACKAGE_1, valuesNoNotificationNoDataChannel);
+ updateEntryForPackage(TEST_PACKAGE_2, valuesNoNotificationGoodDataChannel);
+ messages = mStatusHelper.getStatusMessages();
+ assertEquals(2, messages.size());
+ assertEquals(TEST_PACKAGE_1, messages.get(0).sourcePackage);
+ assertEquals(TEST_PACKAGE_2, messages.get(1).sourcePackage);
+ }
+
+ /** Checks for the expected message with given values and actionUri as TEST_VOICEMAIL_URI. */
+ private void checkExpectedMessage(String sourcePackage, ContentValues values,
+ int expectedStatusMsg, int expectedActionMsg) {
+ checkExpectedMessage(sourcePackage, values, expectedStatusMsg, expectedActionMsg,
+ TEST_VOICEMAIL_URI);
+ }
+
+ private void checkExpectedMessage(String sourcePackage, ContentValues values,
+ int expectedStatusMsg, int expectedActionMsg, Uri expectedUri) {
+ List<Message> messages = mStatusHelper.getStatusMessages();
+ assertEquals(1, messages.size());
+ checkMessageMatches(messages.get(0), sourcePackage, expectedStatusMsg, expectedActionMsg,
+ expectedUri);
+ }
+
+ private void checkMessageMatches(Message message, String expectedSourcePackage,
+ int expectedStatusMsg, int expectedActionMsg, Uri expectedUri) {
+ assertEquals(expectedSourcePackage, message.sourcePackage);
+ assertEquals(expectedStatusMsg, message.statusMessageId);
+ assertEquals(expectedActionMsg, message.actionMessageId);
+ if (expectedUri == null) {
+ assertNull(message.actionUri);
+ } else {
+ assertEquals(expectedUri, message.actionUri);
+ }
+ }
+
+ private void checkNoMessages(String sourcePackage, ContentValues values) {
+ assertEquals(1, updateEntryForPackage(sourcePackage, values));
+ List<Message> messages = mStatusHelper.getStatusMessages();
+ assertEquals(0, messages.size());
+ }
+
+ private ContentValues getAllOkStatusValues() {
+ ContentValues values = new ContentValues();
+ values.put(Status.SETTINGS_URI, TEST_SETTINGS_URI.toString());
+ values.put(Status.VOICEMAIL_ACCESS_URI, TEST_VOICEMAIL_URI.toString());
+ values.put(Status.CONFIGURATION_STATE, Status.CONFIGURATION_STATE_OK);
+ values.put(Status.DATA_CHANNEL_STATE, Status.DATA_CHANNEL_STATE_OK);
+ values.put(Status.NOTIFICATION_CHANNEL_STATE, Status.NOTIFICATION_CHANNEL_STATE_OK);
+ return values;
+ }
+
+ private void insertEntryForPackage(String sourcePackage, ContentValues values) {
+ // If insertion fails then try update as the record might already exist.
+ if (getContentResolver().insert(Status.buildSourceUri(sourcePackage), values) == null) {
+ updateEntryForPackage(sourcePackage, values);
+ }
+ mPackagesToCleanup.add(sourcePackage);
+ }
+
+ private void deleteEntryForPackage(String sourcePackage) {
+ getContentResolver().delete(Status.buildSourceUri(sourcePackage), null, null);
+ }
+
+ private int updateEntryForPackage(String sourcePackage, ContentValues values) {
+ return getContentResolver().update(
+ Status.buildSourceUri(sourcePackage), values, null, null);
+ }
+
+ private ContentResolver getContentResolver() {
+ return getContext().getContentResolver();
+ }
+}