summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/voicemailstatus
diff options
context:
space:
mode:
authorEric Erfanian <erfanian@google.com>2017-03-20 20:40:36 +0000
committerEric Erfanian <erfanian@google.com>2017-03-20 20:40:36 +0000
commit30ccc4f3aa6da94f0bb8a01a880a6353b883b263 (patch)
tree2f55365aaf87df9ba7c1fe0be56a7d0988eadf30 /java/com/android/dialer/voicemailstatus
parent06b6b56e9eaa91ebf757ea641e38a9c885fa40bd (diff)
Revert "Update AOSP Dialer source from internal google3 repository at cl/150622237"
This reverts commit 06b6b56e9eaa91ebf757ea641e38a9c885fa40bd. Change-Id: Ida8c5ee67669524dc63b9adc60a6dd392cb9b9a6
Diffstat (limited to 'java/com/android/dialer/voicemailstatus')
-rw-r--r--java/com/android/dialer/voicemailstatus/VisualVoicemailEnabledChecker.java7
-rw-r--r--java/com/android/dialer/voicemailstatus/VoicemailStatusHelper.java84
-rw-r--r--java/com/android/dialer/voicemailstatus/VoicemailStatusHelperImpl.java278
3 files changed, 336 insertions, 33 deletions
diff --git a/java/com/android/dialer/voicemailstatus/VisualVoicemailEnabledChecker.java b/java/com/android/dialer/voicemailstatus/VisualVoicemailEnabledChecker.java
index a1fc29edf..142bb63ed 100644
--- a/java/com/android/dialer/voicemailstatus/VisualVoicemailEnabledChecker.java
+++ b/java/com/android/dialer/voicemailstatus/VisualVoicemailEnabledChecker.java
@@ -53,7 +53,7 @@ public class VisualVoicemailEnabledChecker implements CallLogQueryHandler.Listen
mContext = context;
mCallback = callback;
mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
- mVoicemailStatusHelper = new VoicemailStatusHelper();
+ mVoicemailStatusHelper = new VoicemailStatusHelperImpl();
mHasActiveVoicemailProvider = mPrefs.getBoolean(PREF_KEY_HAS_ACTIVE_VOICEMAIL_PROVIDER, false);
}
@@ -80,10 +80,7 @@ public class VisualVoicemailEnabledChecker implements CallLogQueryHandler.Listen
mVoicemailStatusHelper.getNumberActivityVoicemailSources(statusCursor) > 0;
if (hasActiveVoicemailProvider != mHasActiveVoicemailProvider) {
mHasActiveVoicemailProvider = hasActiveVoicemailProvider;
- mPrefs
- .edit()
- .putBoolean(PREF_KEY_HAS_ACTIVE_VOICEMAIL_PROVIDER, mHasActiveVoicemailProvider)
- .apply();
+ mPrefs.edit().putBoolean(PREF_KEY_HAS_ACTIVE_VOICEMAIL_PROVIDER, mHasActiveVoicemailProvider);
if (mCallback != null) {
mCallback.onVisualVoicemailEnabledStatusChanged(mHasActiveVoicemailProvider);
}
diff --git a/java/com/android/dialer/voicemailstatus/VoicemailStatusHelper.java b/java/com/android/dialer/voicemailstatus/VoicemailStatusHelper.java
index 9df45c211..16bfe704d 100644
--- a/java/com/android/dialer/voicemailstatus/VoicemailStatusHelper.java
+++ b/java/com/android/dialer/voicemailstatus/VoicemailStatusHelper.java
@@ -17,8 +17,10 @@
package com.android.dialer.voicemailstatus;
import android.database.Cursor;
+import android.net.Uri;
import android.provider.VoicemailContract.Status;
-import com.android.dialer.database.VoicemailStatusQuery;
+import android.support.annotation.VisibleForTesting;
+import java.util.List;
/**
* Interface used by the call log UI to determine what user message, if any, related to voicemail
@@ -29,40 +31,66 @@ import com.android.dialer.database.VoicemailStatusQuery;
* 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 class VoicemailStatusHelper {
+public interface VoicemailStatusHelper {
+
+ /**
+ * 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.
+ *
+ * @param cursor The cursor pointing to the query on {@link Status#CONTENT_URI}. The projection to
+ * be used is defined by the implementation class of this interface.
+ */
+ @VisibleForTesting
+ List<StatusMessage> getStatusMessages(Cursor cursor);
/**
* Returns the number of active voicemail sources installed.
*
* <p>The number of sources is counted by querying the voicemail status table.
- *
- * @param cursor The caller is responsible for the life cycle of the cursor and resetting the
- * position
*/
- public int getNumberActivityVoicemailSources(Cursor cursor) {
- int count = 0;
- if (!cursor.moveToFirst()) {
- return 0;
+ int getNumberActivityVoicemailSources(Cursor cursor);
+
+ @VisibleForTesting
+ class StatusMessage {
+
+ /** 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 in the call log page. Set
+ * to -1, if this message is not to be shown in call log.
+ */
+ public final int callLogMessageId;
+ /**
+ * The string resource id of the status message that should be shown in the call details page.
+ * Set to -1, if this message is not to be shown in call details page.
+ */
+ public final int callDetailsMessageId;
+ /** 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 StatusMessage(
+ String sourcePackage,
+ int callLogMessageId,
+ int callDetailsMessageId,
+ int actionMessageId,
+ Uri actionUri) {
+ this.sourcePackage = sourcePackage;
+ this.callLogMessageId = callLogMessageId;
+ this.callDetailsMessageId = callDetailsMessageId;
+ this.actionMessageId = actionMessageId;
+ this.actionUri = actionUri;
}
- do {
- if (isVoicemailSourceActive(cursor)) {
- ++count;
- }
- } while (cursor.moveToNext());
- return count;
- }
- /**
- * Returns whether the source status in the cursor corresponds to an active source. A source is
- * active if its' configuration state is not NOT_CONFIGURED. For most voicemail sources, only OK
- * and NOT_CONFIGURED are used. The OMTP visual voicemail client has the same behavior pre-NMR1.
- * NMR1 visual voicemail will only set it to NOT_CONFIGURED when it is deactivated. As soon as
- * activation is attempted, it will transition into CONFIGURING then into OK or other error state,
- * NOT_CONFIGURED is never set through an error.
- */
- private boolean isVoicemailSourceActive(Cursor cursor) {
- return cursor.getString(VoicemailStatusQuery.SOURCE_PACKAGE_INDEX) != null
- && cursor.getInt(VoicemailStatusQuery.CONFIGURATION_STATE_INDEX)
- != Status.CONFIGURATION_STATE_NOT_CONFIGURED;
+ /** Whether this message should be shown in the call log page. */
+ public boolean showInCallLog() {
+ return callLogMessageId != -1;
+ }
+
+ /** Whether this message should be shown in the call details page. */
+ public boolean showInCallDetails() {
+ return callDetailsMessageId != -1;
+ }
}
}
diff --git a/java/com/android/dialer/voicemailstatus/VoicemailStatusHelperImpl.java b/java/com/android/dialer/voicemailstatus/VoicemailStatusHelperImpl.java
new file mode 100644
index 000000000..404897fde
--- /dev/null
+++ b/java/com/android/dialer/voicemailstatus/VoicemailStatusHelperImpl.java
@@ -0,0 +1,278 @@
+/*
+ * 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.dialer.voicemailstatus;
+
+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 android.database.Cursor;
+import android.net.Uri;
+import android.provider.VoicemailContract.Status;
+import com.android.contacts.common.util.UriUtils;
+import com.android.dialer.database.VoicemailStatusQuery;
+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 {
+
+ @Override
+ public List<StatusMessage> getStatusMessages(Cursor cursor) {
+ List<MessageStatusWithPriority> messages =
+ new ArrayList<VoicemailStatusHelperImpl.MessageStatusWithPriority>();
+ cursor.moveToPosition(-1);
+ while (cursor.moveToNext()) {
+ MessageStatusWithPriority message = getMessageForStatusEntry(cursor);
+ if (message != null) {
+ messages.add(message);
+ }
+ }
+ // Finally reorder the messages by their priority.
+ return reorderMessages(messages);
+ }
+
+ @Override
+ public int getNumberActivityVoicemailSources(Cursor cursor) {
+ int count = 0;
+ cursor.moveToPosition(-1);
+ while (cursor.moveToNext()) {
+ if (isVoicemailSourceActive(cursor)) {
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Returns whether the source status in the cursor corresponds to an active source. A source is
+ * active if its' configuration state is not NOT_CONFIGURED. For most voicemail sources, only OK
+ * and NOT_CONFIGURED are used. The OMTP visual voicemail client has the same behavior pre-NMR1.
+ * NMR1 visual voicemail will only set it to NOT_CONFIGURED when it is deactivated. As soon as
+ * activation is attempted, it will transition into CONFIGURING then into OK or other error state,
+ * NOT_CONFIGURED is never set through an error.
+ */
+ private boolean isVoicemailSourceActive(Cursor cursor) {
+ return cursor.getString(VoicemailStatusQuery.SOURCE_PACKAGE_INDEX) != null
+ && cursor.getInt(VoicemailStatusQuery.CONFIGURATION_STATE_INDEX)
+ != Status.CONFIGURATION_STATE_NOT_CONFIGURED;
+ }
+
+ private List<StatusMessage> reorderMessages(List<MessageStatusWithPriority> messageWrappers) {
+ Collections.sort(
+ messageWrappers,
+ new Comparator<MessageStatusWithPriority>() {
+ @Override
+ public int compare(MessageStatusWithPriority msg1, MessageStatusWithPriority msg2) {
+ return msg1.mPriority - msg2.mPriority;
+ }
+ });
+ List<StatusMessage> reorderMessages = new ArrayList<VoicemailStatusHelper.StatusMessage>();
+ // Copy the ordered message objects into the final list.
+ for (MessageStatusWithPriority messageWrapper : messageWrappers) {
+ reorderMessages.add(messageWrapper.mMessage);
+ }
+ return reorderMessages;
+ }
+
+ /** Returns the message for the status entry pointed to by the cursor. */
+ private MessageStatusWithPriority getMessageForStatusEntry(Cursor cursor) {
+ final String sourcePackage = cursor.getString(VoicemailStatusQuery.SOURCE_PACKAGE_INDEX);
+ if (sourcePackage == null) {
+ return null;
+ }
+ final OverallState overallState =
+ getOverallState(
+ cursor.getInt(VoicemailStatusQuery.CONFIGURATION_STATE_INDEX),
+ cursor.getInt(VoicemailStatusQuery.DATA_CHANNEL_STATE_INDEX),
+ cursor.getInt(VoicemailStatusQuery.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 =
+ UriUtils.parseUriOrNull(
+ cursor.getString(VoicemailStatusQuery.VOICEMAIL_ACCESS_URI_INDEX));
+ // Even if actionUri is null, it is still be useful to show the notification.
+ } else if (action == Action.CONFIGURE_VOICEMAIL) {
+ actionUri =
+ UriUtils.parseUriOrNull(cursor.getString(VoicemailStatusQuery.SETTINGS_URI_INDEX));
+ // If there is no settings URI, there is no point in showing the notification.
+ if (actionUri == null) {
+ return null;
+ }
+ }
+ return new MessageStatusWithPriority(
+ new StatusMessage(
+ sourcePackage,
+ overallState.getCallLogMessageId(),
+ overallState.getCallDetailsMessageId(),
+ 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;
+ }
+
+ /** Possible user actions. */
+ public 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;
+
+ 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 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,
+ R.string.voicemail_status_audio_not_available),
+ /** Notifications working, but data channel is not working. Audio cannot be downloaded. */
+ NO_DATA(
+ 1,
+ Action.CALL_VOICEMAIL,
+ R.string.voicemail_status_voicemail_not_available,
+ 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,
+ R.string.voicemail_status_audio_not_available),
+ /** 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 mCallLogMessageId;
+ private final int mCallDetailsMessageId;
+
+ OverallState(int priority, Action action, int callLogMessageId) {
+ this(priority, action, callLogMessageId, -1);
+ }
+
+ OverallState(int priority, Action action, int callLogMessageId, int callDetailsMessageId) {
+ mPriority = priority;
+ mAction = action;
+ mCallLogMessageId = callLogMessageId;
+ mCallDetailsMessageId = callDetailsMessageId;
+ }
+
+ public Action getAction() {
+ return mAction;
+ }
+
+ public int getPriority() {
+ return mPriority;
+ }
+
+ public int getCallLogMessageId() {
+ return mCallLogMessageId;
+ }
+
+ public int getCallDetailsMessageId() {
+ return mCallDetailsMessageId;
+ }
+ }
+
+ /** A wrapper on {@link StatusMessage} which additionally stores the priority of the message. */
+ private static class MessageStatusWithPriority {
+
+ private final StatusMessage mMessage;
+ private final int mPriority;
+
+ public MessageStatusWithPriority(StatusMessage message, int priority) {
+ mMessage = message;
+ mPriority = priority;
+ }
+ }
+}