Merge "VT Settings Toggle Should be Blocked During Active Calls" into nyc-mr1-dev
diff --git a/res/xml/vvm_config.xml b/res/xml/vvm_config.xml
index d55fdb2..3bfdf75 100644
--- a/res/xml/vvm_config.xml
+++ b/res/xml/vvm_config.xml
@@ -135,5 +135,8 @@
<string name="vvm_client_prefix_string">//VZWVVM</string>
<boolean name="vvm_cellular_data_required_bool" value="true"/>
<boolean name="vvm_legacy_mode_enabled_bool" value="true"/>
+ <!-- VVM3 specific value for the voicemail management gateway to use if the SMS didn't provide
+ one -->
+ <string name="default_vmg_url">https://mobile.vzw.com/VMGIMS/VMServices</string>
</pbundle_as_map>
</list>
\ No newline at end of file
diff --git a/src/com/android/phone/settings/VoicemailChangePinActivity.java b/src/com/android/phone/settings/VoicemailChangePinActivity.java
index 68cc621..fcf5bd3 100644
--- a/src/com/android/phone/settings/VoicemailChangePinActivity.java
+++ b/src/com/android/phone/settings/VoicemailChangePinActivity.java
@@ -44,7 +44,6 @@
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;
-
import com.android.phone.PhoneUtils;
import com.android.phone.R;
import com.android.phone.common.mail.MessagingException;
@@ -55,6 +54,7 @@
import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
import com.android.phone.vvm.omtp.VvmLog;
import com.android.phone.vvm.omtp.imap.ImapHelper;
+import com.android.phone.vvm.omtp.imap.ImapHelper.InitializingException;
import com.android.phone.vvm.omtp.sync.VvmNetworkRequestCallback;
/**
@@ -594,7 +594,7 @@
@ChangePinResult int result =
helper.changePin(mOldPin, mNewPin);
sendResult(result);
- } catch (MessagingException e) {
+ } catch (InitializingException | MessagingException e) {
sendResult(OmtpConstants.CHANGE_PIN_SYSTEM_ERROR);
}
}
diff --git a/src/com/android/phone/vvm/omtp/ActivationTask.java b/src/com/android/phone/vvm/omtp/ActivationTask.java
index b37f0d3..101a96f 100644
--- a/src/com/android/phone/vvm/omtp/ActivationTask.java
+++ b/src/com/android/phone/vvm/omtp/ActivationTask.java
@@ -22,12 +22,10 @@
import android.content.Intent;
import android.os.Bundle;
import android.telecom.PhoneAccountHandle;
-
import com.android.phone.Assert;
import com.android.phone.PhoneGlobals;
import com.android.phone.vvm.omtp.protocol.VisualVoicemailProtocol;
import com.android.phone.vvm.omtp.scheduling.BaseTask;
-import com.android.phone.vvm.omtp.scheduling.MinimalIntervalPolicy;
import com.android.phone.vvm.omtp.scheduling.RetryPolicy;
import com.android.phone.vvm.omtp.sms.StatusMessage;
import com.android.phone.vvm.omtp.sms.StatusSmsFetcher;
@@ -35,7 +33,6 @@
import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService;
import com.android.phone.vvm.omtp.sync.SyncTask;
import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@@ -53,7 +50,6 @@
private static final int RETRY_TIMES = 4;
private static final int RETRY_INTERVAL_MILLIS = 5_000;
- private static final int MINIMAL_INTERVAL_MILLIS = 30_000;
private static final String EXTRA_MESSAGE_DATA_BUNDLE = "extra_message_data_bundle";
@@ -62,7 +58,6 @@
public ActivationTask() {
super(TASK_ACTIVATION);
addPolicy(new RetryPolicy(RETRY_TIMES, RETRY_INTERVAL_MILLIS));
- addPolicy(new MinimalIntervalPolicy(MINIMAL_INTERVAL_MILLIS));
}
public static void start(Context context, int subId, @Nullable Bundle data) {
diff --git a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
index b50e291..00a70be 100644
--- a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
+++ b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
@@ -27,14 +27,12 @@
import android.telephony.VisualVoicemailSmsFilterSettings;
import android.text.TextUtils;
import android.util.ArraySet;
-
import com.android.internal.annotations.VisibleForTesting;
import com.android.phone.VoicemailStatus;
import com.android.phone.vvm.omtp.protocol.VisualVoicemailProtocol;
import com.android.phone.vvm.omtp.protocol.VisualVoicemailProtocolFactory;
import com.android.phone.vvm.omtp.sms.StatusMessage;
import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
import java.util.Arrays;
import java.util.Set;
@@ -162,6 +160,14 @@
return mProtocol;
}
+ /**
+ * @returns arbitrary String stored in the config file. Used for protocol specific values.
+ */
+ @Nullable
+ public String getString(String key) {
+ return (String) getValue(key);
+ }
+
@Nullable
public Set<String> getCarrierVvmPackageNames() {
Set<String> names = getCarrierVvmPackageNames(mCarrierConfig);
diff --git a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
index 375109d..24f7a2a 100644
--- a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
+++ b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
@@ -24,6 +24,7 @@
import android.os.UserManager;
import android.telecom.PhoneAccountHandle;
import android.telephony.CarrierConfigManager;
+import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -89,14 +90,22 @@
PhoneAccountHandle phoneAccount = PhoneAccountHandleConverter.fromSubId(subId);
if (VisualVoicemailSettingsUtil.isEnabled(context, phoneAccount)) {
- VvmLog.i(TAG, "Sim state or carrier config changed: requesting"
- + " activation for " + subId);
-
+ VvmLog.i(TAG, "Sim state or carrier config changed for " + subId);
// Add a phone state listener so that changes to the communication channels
// can be recorded.
OmtpVvmSourceManager.getInstance(context).addPhoneStateListener(
phoneAccount);
- carrierConfigHelper.startActivation();
+ // Check for signal before activating. The event often happen while boot and the
+ // network is not connected yet. Launching activation will likely to cause the SMS
+ // sending to fail and waste unnecessary time waiting for time out.
+ if (context.getSystemService(TelephonyManager.class)
+ .getServiceStateForSubscriber(subId).getState()
+ == ServiceState.STATE_IN_SERVICE) {
+ VvmLog.i(TAG, "Sim/config changed while in service, requesting activation");
+ carrierConfigHelper.startActivation();
+ } else {
+ VvmLog.i(TAG, "Sim/config changed while not in service.");
+ }
} else {
if (carrierConfigHelper.isLegacyModeEnabled()) {
// SMS still need to be filtered under legacy mode.
diff --git a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
index d267e68..5ec190f 100644
--- a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
+++ b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
@@ -35,6 +35,7 @@
import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
import com.android.phone.vvm.omtp.VvmLog;
import com.android.phone.vvm.omtp.imap.ImapHelper;
+import com.android.phone.vvm.omtp.imap.ImapHelper.InitializingException;
import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
import com.android.phone.vvm.omtp.sync.VvmNetworkRequestCallback;
@@ -161,11 +162,6 @@
VvmLog.i(TAG, "fetching voicemail, retry count=" + mRetryCount);
try (ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount,
network)) {
- if (!imapHelper.isSuccessfullyInitialized()) {
- VvmLog.w(TAG, "Can't retrieve Imap credentials.");
- return;
- }
-
boolean success = imapHelper.fetchVoicemailPayload(
new VoicemailFetchedCallback(mContext, mUri), mUid);
if (!success && mRetryCount > 0) {
@@ -174,6 +170,9 @@
} else {
return;
}
+ } catch (InitializingException e) {
+ VvmLog.w(TAG, "Can't retrieve Imap credentials ", e);
+ return;
}
}
} finally {
diff --git a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
index 5f7722c..532991f 100644
--- a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
+++ b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
@@ -23,7 +23,6 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.Voicemail;
import android.util.Base64;
-
import com.android.phone.PhoneUtils;
import com.android.phone.VoicemailStatus;
import com.android.phone.common.mail.Address;
@@ -50,9 +49,6 @@
import com.android.phone.vvm.omtp.VvmLog;
import com.android.phone.vvm.omtp.fetch.VoicemailFetchedCallback;
import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService.TranscriptionFetchedCallback;
-
-import libcore.io.IoUtils;
-
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
@@ -61,6 +57,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
+import libcore.io.IoUtils;
/**
* A helper interface to abstract commands sent across IMAP interface for a given account.
@@ -85,13 +82,21 @@
private final OmtpVvmCarrierConfigHelper mConfig;
- public ImapHelper(Context context, PhoneAccountHandle phoneAccount, Network network) {
+ public class InitializingException extends Exception {
+
+ public InitializingException(String message) {
+ super(message);
+ }
+ }
+
+ public ImapHelper(Context context, PhoneAccountHandle phoneAccount, Network network)
+ throws InitializingException {
this(context, new OmtpVvmCarrierConfigHelper(context,
PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount)), phoneAccount, network);
}
public ImapHelper(Context context, OmtpVvmCarrierConfigHelper config,
- PhoneAccountHandle phoneAccount, Network network) {
+ PhoneAccountHandle phoneAccount, Network network) throws InitializingException {
mContext = context;
mPhoneAccount = phoneAccount;
mNetwork = network;
@@ -120,6 +125,7 @@
} catch (NumberFormatException e) {
mConfig.handleEvent(OmtpEvents.DATA_INVALID_PORT);
LogUtils.w(TAG, "Could not parse port number");
+ throw new InitializingException("cannot initialize ImapHelper:" + e.toString());
}
mQuotaOccupied = mPrefs
@@ -133,15 +139,6 @@
mImapStore.closeConnection();
}
- /**
- * If mImapStore is null, this means that there was a missing or badly formatted port number,
- * which means there aren't sufficient credentials for login. If mImapStore is succcessfully
- * initialized, then ImapHelper is ready to go.
- */
- public boolean isSuccessfullyInitialized() {
- return mImapStore != null;
- }
-
public boolean isRoaming() {
ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
diff --git a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java b/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
index 6416cfb..5f89471 100644
--- a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
+++ b/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
@@ -16,11 +16,11 @@
package com.android.phone.vvm.omtp.protocol;
+import android.annotation.Nullable;
import android.content.Context;
import android.os.Bundle;
import android.telecom.PhoneAccountHandle;
import android.telephony.SmsManager;
-
import com.android.phone.vvm.omtp.ActivationTask;
import com.android.phone.vvm.omtp.DefaultOmtpEventHandler;
import com.android.phone.vvm.omtp.OmtpEvents;
@@ -82,4 +82,14 @@
OmtpEvents event) {
DefaultOmtpEventHandler.handleEvent(context, config, event);
}
+
+ /**
+ * Given an VVM SMS with an unknown {@code event}, let the protocol attempt to translate it into
+ * an equivalent STATUS SMS. Returns {@code null} if it cannot be translated.
+ */
+ @Nullable
+ public Bundle translateStatusSmsBundle(OmtpVvmCarrierConfigHelper config, String event,
+ Bundle data) {
+ return null;
+ }
}
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3EventHandler.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3EventHandler.java
index 5a3c7aa..3a3adb8 100644
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3EventHandler.java
+++ b/src/com/android/phone/vvm/omtp/protocol/Vvm3EventHandler.java
@@ -20,7 +20,6 @@
import android.content.Context;
import android.telecom.PhoneAccountHandle;
import android.util.Log;
-
import com.android.phone.VoicemailStatus;
import com.android.phone.settings.VoicemailChangePinActivity;
import com.android.phone.vvm.omtp.DefaultOmtpEventHandler;
@@ -28,7 +27,6 @@
import com.android.phone.vvm.omtp.OmtpEvents.Type;
import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -142,8 +140,14 @@
switch (event) {
case DATA_NO_CONNECTION:
case DATA_NO_CONNECTION_CELLULAR_REQUIRED:
+ case DATA_ALL_SOCKET_CONNECTION_FAILED:
postError(context, config, VMS_NO_CELLULAR);
break;
+ case DATA_SSL_INVALID_HOST_NAME:
+ case DATA_CANNOT_ESTABLISH_SSL_SESSION:
+ case DATA_IOE_ON_OPEN:
+ postError(context, config, VMS_TIMEOUT);
+ break;
case DATA_CANNOT_RESOLVE_HOST_ON_NETWORK:
postError(context, config, VMS_DNS_FAILURE);
break;
@@ -171,18 +175,11 @@
case DATA_AUTH_USER_IS_BLOCKED:
postError(context, config, USER_BLOCKED);
break;
-
- case DATA_INVALID_PORT:
- case DATA_SSL_INVALID_HOST_NAME:
- case DATA_CANNOT_ESTABLISH_SSL_SESSION:
- case DATA_IOE_ON_OPEN:
case DATA_REJECTED_SERVER_RESPONSE:
case DATA_INVALID_INITIAL_SERVER_RESPONSE:
case DATA_SSL_EXCEPTION:
- case DATA_ALL_SOCKET_CONNECTION_FAILED:
postError(context, config, IMAP_ERROR);
break;
-
default:
return false;
}
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
index af424f5..c6dd434 100644
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
+++ b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
@@ -22,6 +22,7 @@
import android.os.Bundle;
import android.telecom.PhoneAccountHandle;
import android.telephony.SmsManager;
+import android.text.TextUtils;
import com.android.phone.common.mail.MessagingException;
import com.android.phone.settings.VisualVoicemailSettingsUtil;
@@ -33,6 +34,7 @@
import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
import com.android.phone.vvm.omtp.VvmLog;
import com.android.phone.vvm.omtp.imap.ImapHelper;
+import com.android.phone.vvm.omtp.imap.ImapHelper.InitializingException;
import com.android.phone.vvm.omtp.sms.OmtpMessageSender;
import com.android.phone.vvm.omtp.sms.StatusMessage;
import com.android.phone.vvm.omtp.sms.Vvm3MessageSender;
@@ -50,13 +52,18 @@
*/
public class Vvm3Protocol extends VisualVoicemailProtocol {
- private static String TAG = "Vvm3Protocol";
+ private static final String TAG = "Vvm3Protocol";
- private static String IMAP_CHANGE_TUI_PWD_FORMAT = "CHANGE_TUI_PWD PWD=%1$s OLD_PWD=%2$s";
- private static String IMAP_CHANGE_VM_LANG_FORMAT = "CHANGE_VM_LANG Lang=%1$s";
- private static String IMAP_CLOSE_NUT = "CLOSE_NUT";
+ private static final String SMS_EVENT_UNRECOGNIZED = "UNRECOGNIZED";
+ private static final String SMS_EVENT_UNRECOGNIZED_CMD = "cmd";
+ private static final String SMS_EVENT_UNRECOGNIZED_STATUS = "STATUS";
+ private static final String DEFAULT_VMG_URL_KEY = "default_vmg_url";
- private static String ISO639_Spanish = "es";
+ private static final String IMAP_CHANGE_TUI_PWD_FORMAT = "CHANGE_TUI_PWD PWD=%1$s OLD_PWD=%2$s";
+ private static final String IMAP_CHANGE_VM_LANG_FORMAT = "CHANGE_VM_LANG Lang=%1$s";
+ private static final String IMAP_CLOSE_NUT = "CLOSE_NUT";
+
+ private static final String ISO639_Spanish = "es";
/**
* For VVM3, if the STATUS SMS returns {@link StatusMessage#getProvisioningStatus()} of {@link
@@ -150,14 +157,40 @@
return super.getCommand(command);
}
+ @Override
+ public Bundle translateStatusSmsBundle(OmtpVvmCarrierConfigHelper config, String event,
+ Bundle data) {
+ // UNRECOGNIZED?cmd=STATUS is the response of a STATUS request when the user is provisioned
+ // with iPhone visual voicemail without VoLTE. Translate it into an unprovisioned status
+ // so provisioning can be done.
+ if (!SMS_EVENT_UNRECOGNIZED.equals(event)) {
+ return null;
+ }
+ if (!SMS_EVENT_UNRECOGNIZED_STATUS.equals(data.getString(SMS_EVENT_UNRECOGNIZED_CMD))) {
+ return null;
+ }
+ Bundle bundle = new Bundle();
+ bundle.putString(OmtpConstants.PROVISIONING_STATUS, OmtpConstants.SUBSCRIBER_UNKNOWN);
+ bundle.putString(OmtpConstants.RETURN_CODE,
+ VVM3_UNKNOWN_SUBSCRIBER_CAN_SUBSCRIBE_RESPONSE_CODE);
+ String vmgUrl = config.getString(DEFAULT_VMG_URL_KEY);
+ if (TextUtils.isEmpty(vmgUrl)) {
+ VvmLog.e(TAG, "Unable to translate STATUS SMS: VMG URL is not set in config");
+ return null;
+ }
+ bundle.putString(Vvm3Subscriber.VMG_URL_KEY, vmgUrl);
+ VvmLog.i(TAG, "UNRECOGNIZED?cmd=STATUS translated into unprovisioned STATUS SMS");
+ return bundle;
+ }
+
private void startProvisionNewUser(PhoneAccountHandle phoneAccountHandle,
OmtpVvmCarrierConfigHelper config, StatusMessage message) {
try (NetworkWrapper wrapper = VvmNetworkRequest.getNetwork(config, phoneAccountHandle)) {
Network network = wrapper.get();
VvmLog.i(TAG, "new user: network available");
- ImapHelper helper = new ImapHelper(config.getContext(), phoneAccountHandle, network);
- try {
+ try (ImapHelper helper = new ImapHelper(config.getContext(), phoneAccountHandle,
+ network)) {
// VVM3 has inconsistent error language code to OMTP. Just issue a raw command
// here.
// TODO(b/29082671): use LocaleList
@@ -180,11 +213,9 @@
config.requestStatus();
}
- } catch (MessagingException | IOException e) {
- helper.handleEvent(OmtpEvents.VVM3_NEW_USER_SETUP_FAILED);
+ } catch (InitializingException | MessagingException | IOException e) {
+ config.handleEvent(OmtpEvents.VVM3_NEW_USER_SETUP_FAILED);
VvmLog.e(TAG, e.toString());
- } finally {
- helper.close();
}
}
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java
index a000527..7562275 100644
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java
+++ b/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java
@@ -26,15 +26,11 @@
import android.text.Spanned;
import android.text.style.URLSpan;
import android.util.ArrayMap;
-
import com.android.phone.Assert;
import com.android.phone.vvm.omtp.ActivationTask;
-import com.android.phone.vvm.omtp.OmtpConstants;
import com.android.phone.vvm.omtp.OmtpEvents;
import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.sms.StatusMessage;
-import com.android.phone.vvm.omtp.sms.StatusSmsFetcher;
import com.android.phone.vvm.omtp.sync.VvmNetworkRequest;
import com.android.phone.vvm.omtp.sync.VvmNetworkRequest.NetworkWrapper;
import com.android.volley.AuthFailureError;
@@ -44,7 +40,6 @@
import com.android.volley.toolbox.RequestFuture;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
-
import java.io.IOException;
import java.net.CookieHandler;
import java.net.CookieManager;
@@ -96,7 +91,7 @@
+ " </MessageBody>"
+ "</VMGVVMRequest>";
- private static final String VMG_URL_KEY = "vmg_url";
+ static final String VMG_URL_KEY = "vmg_url";
// Self provisioning POST key/values. VVM3 API 2.1.0 12.3
private static final String SPG_VZW_MDN_PARAM = "VZW_MDN";
@@ -232,36 +227,16 @@
StringRequest stringRequest = new StringRequest(Request.Method.POST,
subscribeLink, future, future);
mRequestQueue.add(stringRequest);
- try (StatusSmsFetcher fetcher = new StatusSmsFetcher(mHelper.getContext(),
- mHelper.getSubId())) {
- try {
- // A new STATUS SMS will be sent after this request.
- future.get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- } catch (TimeoutException e) {
- mHelper.handleEvent(OmtpEvents.VVM3_SPG_CONNECTION_FAILED);
- throw new ProvisioningException(e.toString());
- }
- Bundle data = fetcher.get();
- StatusMessage message = new StatusMessage(data);
- switch (message.getProvisioningStatus()) {
- case OmtpConstants.SUBSCRIBER_READY:
- ActivationTask.updateSource(mHelper.getContext(), mHandle,
- mHelper.getSubId(), message);
- break;
- case OmtpConstants.SUBSCRIBER_NEW:
- mHelper.getProtocol().startProvisioning(mTask, mHandle, mHelper, message, data);
- break;
- default:
- mHelper.handleEvent(OmtpEvents.VVM3_SPG_CONNECTION_FAILED);
- throw new ProvisioningException("status is not ready or new after subscribed");
- }
- } catch (TimeoutException e) {
- mHelper.handleEvent(OmtpEvents.CONFIG_STATUS_SMS_TIME_OUT);
- throw new ProvisioningException("Timed out waiting for STATUS SMS after subscribed");
- } catch (InterruptedException | ExecutionException | IOException e) {
+ try {
+ // A new STATUS SMS will be sent after this request.
+ future.get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ } catch (TimeoutException | ExecutionException | InterruptedException e) {
mHelper.handleEvent(OmtpEvents.VVM3_SPG_CONNECTION_FAILED);
throw new ProvisioningException(e.toString());
}
+ // It could take very long for the STATUS SMS to return. Waiting for it is unreliable.
+ // Just leave the CONFIG STATUS as CONFIGURING and end the task. The user can always
+ // manually retry if it took too long.
}
private String vvm3XmlRequest(String operation) throws ProvisioningException {
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
index 183d86d..7b4d2c3 100644
--- a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
+++ b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
@@ -25,12 +25,12 @@
import android.provider.VoicemailContract;
import android.telecom.PhoneAccountHandle;
import android.telecom.Voicemail;
-
import com.android.phone.settings.VisualVoicemailSettingsUtil;
import com.android.phone.vvm.omtp.ActivationTask;
import com.android.phone.vvm.omtp.OmtpConstants;
import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
import com.android.phone.vvm.omtp.VvmLog;
+import com.android.phone.vvm.omtp.protocol.VisualVoicemailProtocol;
import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService;
import com.android.phone.vvm.omtp.sync.SyncOneTask;
import com.android.phone.vvm.omtp.sync.SyncTask;
@@ -48,12 +48,6 @@
@Override
public void onReceive(Context context, Intent intent) {
- if (!UserManager.get(context).isUserUnlocked()) {
- VvmLog.i(TAG, "Received message on locked device");
- // A full sync will happen after the device is unlocked, so nothing need to be done.
- return;
- }
-
mContext = context;
int subId = intent.getExtras().getInt(VoicemailContract.EXTRA_VOICEMAIL_SMS_SUBID);
PhoneAccountHandle phone = PhoneAccountHandleConverter.fromSubId(subId);
@@ -63,6 +57,15 @@
return;
}
+ if (!UserManager.get(context).isUserUnlocked()) {
+ VvmLog.i(TAG, "Received message on locked device");
+ // LegacyModeSmsHandler can handle new message notifications without storage access
+ LegacyModeSmsHandler.handle(context, intent, phone);
+ // A full sync will happen after the device is unlocked, so nothing else need to be
+ // done.
+ return;
+ }
+
OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(mContext, subId);
if (!VisualVoicemailSettingsUtil.isEnabled(mContext, phone)) {
if (helper.isLegacyModeEnabled()) {
@@ -91,7 +94,17 @@
// spontaneous send a STATUS SMS, in that case, the VVM service should be reactivated.
ActivationTask.start(context, subId, data);
} else {
- VvmLog.e(TAG, "Unknown prefix: " + eventType);
+ VvmLog.w(TAG, "Unknown prefix: " + eventType);
+ VisualVoicemailProtocol protocol = helper.getProtocol();
+ if (protocol == null) {
+ return;
+ }
+ Bundle statusData = helper.getProtocol()
+ .translateStatusSmsBundle(helper, eventType, data);
+ if (statusData != null) {
+ VvmLog.i(TAG, "Protocol recognized the SMS as STATUS, activating");
+ ActivationTask.start(context, subId, data);
+ }
}
}
@@ -107,6 +120,12 @@
Intent serviceIntent = null;
switch (message.getSyncTriggerEvent()) {
case OmtpConstants.NEW_MESSAGE:
+ if (!OmtpConstants.VOICE.equals(message.getContentType())) {
+ VvmLog.i(TAG, "Non-voice message of type '" + message.getContentType()
+ + "' received, ignoring");
+ return;
+ }
+
Voicemail.Builder builder = Voicemail.createForInsertion(
message.getTimestampMillis(), message.getSender())
.setPhoneAccount(phone)
diff --git a/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java b/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
index 23abf9b..2c37dd9 100644
--- a/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
+++ b/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
@@ -24,10 +24,11 @@
import android.content.IntentFilter;
import android.os.Bundle;
import android.provider.VoicemailContract;
-
import com.android.phone.Assert;
import com.android.phone.vvm.omtp.OmtpConstants;
-
+import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VvmLog;
+import com.android.phone.vvm.omtp.protocol.VisualVoicemailProtocol;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
@@ -40,6 +41,8 @@
*/
public class StatusSmsFetcher extends BroadcastReceiver implements Closeable {
+ private static final String TAG = "VvmStatusSmsFetcher";
+
private static final long STATUS_SMS_TIMEOUT_MILLIS = 60_000;
private CompletableFuture<Bundle> mFuture = new CompletableFuture<>();
@@ -78,10 +81,28 @@
String eventType = intent.getExtras()
.getString(VoicemailContract.EXTRA_VOICEMAIL_SMS_PREFIX);
- if (!eventType.equals(OmtpConstants.STATUS_SMS_PREFIX)) {
+ if (eventType.equals(OmtpConstants.STATUS_SMS_PREFIX)) {
+ mFuture.complete(intent.getBundleExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_FIELDS));
return;
}
- mFuture.complete(intent.getBundleExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_FIELDS));
+ if (eventType.equals(OmtpConstants.SYNC_SMS_PREFIX)) {
+ return;
+ }
+
+ VvmLog.i(TAG, "VVM SMS with event " + eventType
+ + " received, attempting to translate to STATUS SMS");
+ OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(context, subId);
+ VisualVoicemailProtocol protocol = helper.getProtocol();
+ if (protocol == null) {
+ return;
+ }
+ Bundle translatedBundle = protocol.translateStatusSmsBundle(helper, eventType,
+ intent.getBundleExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_FIELDS));
+
+ if (translatedBundle != null) {
+ VvmLog.i(TAG, "Translated to STATUS SMS");
+ mFuture.complete(translatedBundle);
+ }
}
}
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
index 8abc2b3..2140e02 100644
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
@@ -22,7 +22,6 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.Voicemail;
import android.text.TextUtils;
-
import com.android.phone.PhoneUtils;
import com.android.phone.settings.VisualVoicemailSettingsUtil;
import com.android.phone.vvm.omtp.ActivationTask;
@@ -31,10 +30,10 @@
import com.android.phone.vvm.omtp.VvmLog;
import com.android.phone.vvm.omtp.fetch.VoicemailFetchedCallback;
import com.android.phone.vvm.omtp.imap.ImapHelper;
+import com.android.phone.vvm.omtp.imap.ImapHelper.InitializingException;
import com.android.phone.vvm.omtp.scheduling.BaseTask;
import com.android.phone.vvm.omtp.sync.VvmNetworkRequest.NetworkWrapper;
import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -123,11 +122,6 @@
private void doSync(BaseTask task, Network network, PhoneAccountHandle phoneAccount,
Voicemail voicemail, String action) {
try(ImapHelper imapHelper = new ImapHelper(mContext, phoneAccount, network)) {
- if (!imapHelper.isSuccessfullyInitialized()) {
- VvmLog.w(TAG, "Can't retrieve Imap credentials.");
- return;
- }
-
boolean success;
if (voicemail == null) {
success = syncAll(action, imapHelper, phoneAccount);
@@ -141,6 +135,9 @@
} else {
task.fail();
}
+ } catch (InitializingException e) {
+ VvmLog.w(TAG, "Can't retrieve Imap credentials.", e);
+ return;
}
}
diff --git a/src/com/android/services/telephony/ConferenceParticipantConnection.java b/src/com/android/services/telephony/ConferenceParticipantConnection.java
index 78f9ca3..3b8d89a 100644
--- a/src/com/android/services/telephony/ConferenceParticipantConnection.java
+++ b/src/com/android/services/telephony/ConferenceParticipantConnection.java
@@ -292,6 +292,10 @@
sb.append(System.identityHashCode(this));
sb.append(" endPoint:");
sb.append(Log.pii(mEndpoint));
+ sb.append(" address:");
+ sb.append(Log.pii(getAddress()));
+ sb.append(" addressPresentation:");
+ sb.append(getAddressPresentation());
sb.append(" parentConnection:");
sb.append(Log.pii(mParentConnection.getAddress()));
sb.append(" state:");
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index fcee589..2c60242 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -175,7 +175,10 @@
Log.d(this, "onConnectionCapabilitiesChanged: Connection: %s," +
" connectionCapabilities: %s", c, connectionCapabilities);
int capabilites = ImsConference.this.getConnectionCapabilities();
- setConnectionCapabilities(applyHostCapabilities(capabilites, connectionCapabilities));
+ boolean isVideoConferencingSupported = mConferenceHost == null ? false :
+ mConferenceHost.isCarrierVideoConferencingSupported();
+ setConnectionCapabilities(applyHostCapabilities(capabilites, connectionCapabilities,
+ isVideoConferencingSupported));
}
@Override
@@ -277,7 +280,8 @@
int capabilities = Connection.CAPABILITY_SUPPORT_HOLD | Connection.CAPABILITY_HOLD |
Connection.CAPABILITY_MUTE | Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN;
capabilities = applyHostCapabilities(capabilities,
- mConferenceHost.getConnectionCapabilities());
+ mConferenceHost.getConnectionCapabilities(),
+ mConferenceHost.isCarrierVideoConferencingSupported());
setConnectionCapabilities(capabilities);
}
@@ -287,24 +291,36 @@
*
* @param conferenceCapabilities The current conference capabilities.
* @param capabilities The new conference host capabilities.
+ * @param isVideoConferencingSupported Whether video conferencing is supported.
* @return The merged capabilities to be applied to the conference.
*/
- private int applyHostCapabilities(int conferenceCapabilities, int capabilities) {
+ private int applyHostCapabilities(int conferenceCapabilities, int capabilities,
+ boolean isVideoConferencingSupported) {
+
conferenceCapabilities = changeBitmask(conferenceCapabilities,
Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
can(capabilities, Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL));
- conferenceCapabilities = changeBitmask(conferenceCapabilities,
+ if (isVideoConferencingSupported) {
+ conferenceCapabilities = changeBitmask(conferenceCapabilities,
Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
can(capabilities, Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL));
-
- conferenceCapabilities = changeBitmask(conferenceCapabilities,
- Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
- can(capabilities, Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO));
-
- conferenceCapabilities = changeBitmask(conferenceCapabilities,
+ conferenceCapabilities = changeBitmask(conferenceCapabilities,
Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
can(capabilities, Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO));
+ } else {
+ // If video conferencing is not supported, explicitly turn off the remote video
+ // capability and the ability to upgrade to video.
+ Log.v(this, "applyHostCapabilities : video conferencing not supported");
+ conferenceCapabilities = changeBitmask(conferenceCapabilities,
+ Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL, false);
+ conferenceCapabilities = changeBitmask(conferenceCapabilities,
+ Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO, false);
+ }
+
+ conferenceCapabilities = changeBitmask(conferenceCapabilities,
+ Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
+ can(capabilities, Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO));
return conferenceCapabilities;
}
@@ -572,7 +588,8 @@
mConferenceHost.addConnectionListener(mConferenceHostListener);
mConferenceHost.addTelephonyConnectionListener(mTelephonyConnectionListener);
setConnectionCapabilities(applyHostCapabilities(getConnectionCapabilities(),
- mConferenceHost.getConnectionCapabilities()));
+ mConferenceHost.getConnectionCapabilities(),
+ mConferenceHost.isCarrierVideoConferencingSupported()));
setConnectionProperties(applyHostProperties(getConnectionProperties(),
mConferenceHost.getConnectionProperties()));
@@ -593,6 +610,8 @@
return;
}
+ Log.i(this, "handleConferenceParticipantsUpdate: size=%d", participants.size());
+
// Perform the update in a synchronized manner. It is possible for the IMS framework to
// trigger two onConferenceParticipantsChanged callbacks in quick succession. If the first
// update adds new participants, and the second does something like update the status of one
@@ -605,7 +624,7 @@
// Add any new participants and update existing.
for (ConferenceParticipant participant : participants) {
- Uri userEntity = participant.getHandle();
+ Uri userEntity = participant.getEndpoint();
participantUserEntities.add(userEntity);
if (!mConferenceParticipantConnections.containsKey(userEntity)) {
@@ -619,6 +638,8 @@
} else {
ConferenceParticipantConnection connection =
mConferenceParticipantConnections.get(userEntity);
+ Log.i(this, "handleConferenceParticipantsUpdate: updateState, participant = %s",
+ participant);
connection.updateState(participant.getState());
}
}
@@ -628,7 +649,7 @@
// Set the state of the new participants at once and add to the conference
for (ConferenceParticipant newParticipant : newParticipants) {
ConferenceParticipantConnection connection =
- mConferenceParticipantConnections.get(newParticipant.getHandle());
+ mConferenceParticipantConnections.get(newParticipant.getEndpoint());
connection.updateState(newParticipant.getState());
}
}
@@ -679,12 +700,11 @@
connection.addConnectionListener(mParticipantListener);
connection.setConnectTimeMillis(parent.getConnectTimeMillis());
- if (Log.VERBOSE) {
- Log.v(this, "createConferenceParticipantConnection: %s", connection);
- }
+ Log.i(this, "createConferenceParticipantConnection: participant=%s, connection=%s",
+ participant, connection);
synchronized(mUpdateSyncRoot) {
- mConferenceParticipantConnections.put(participant.getHandle(), connection);
+ mConferenceParticipantConnections.put(participant.getEndpoint(), connection);
}
mTelephonyConnectionService.addExistingConnection(mConferenceHostPhoneAccountHandle,
connection);
@@ -697,7 +717,7 @@
* @param participant The participant to remove.
*/
private void removeConferenceParticipant(ConferenceParticipantConnection participant) {
- Log.d(this, "removeConferenceParticipant: %s", participant);
+ Log.i(this, "removeConferenceParticipant: %s", participant);
participant.removeConnectionListener(mParticipantListener);
synchronized(mUpdateSyncRoot) {
@@ -805,32 +825,34 @@
if (originalConnection != null &&
originalConnection.getPhoneType() != PhoneConstants.PHONE_TYPE_IMS) {
- if (Log.VERBOSE) {
- Log.v(this,
- "Original connection for conference host is no longer an IMS connection; " +
- "new connection: %s", originalConnection);
- }
+ Log.i(this,
+ "handleOriginalConnectionChange : handover from IMS connection to " +
+ "new connection: %s", originalConnection);
PhoneAccountHandle phoneAccountHandle = null;
if (mConferenceHost.getPhone() != null) {
if (mConferenceHost.getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
Phone imsPhone = mConferenceHost.getPhone();
- // The phone account handle for an ImsPhone is based on the default phone (ie the
- // base GSM or CDMA phone, not on the ImsPhone itself).
+ // The phone account handle for an ImsPhone is based on the default phone (ie
+ // the base GSM or CDMA phone, not on the ImsPhone itself).
phoneAccountHandle =
PhoneUtils.makePstnPhoneAccountHandle(imsPhone.getDefaultPhone());
} else {
- // In the case of SRVCC, we still need a phone account, so use the top level phone
- // to create a phone account.
+ // In the case of SRVCC, we still need a phone account, so use the top level
+ // phone to create a phone account.
phoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(
mConferenceHost.getPhone());
}
}
if (mConferenceHost.getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {
+ Log.i(this,"handleOriginalConnectionChange : SRVCC to GSM");
GsmConnection c = new GsmConnection(originalConnection, getTelecomCallId());
// This is a newly created conference connection as a result of SRVCC
c.setConferenceSupported(true);
+ c.addCapability(Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
+ c.setConnectionProperties(
+ c.getConnectionProperties() | Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE);
c.updateState();
// Copy the connect time from the conferenceHost
c.setConnectTimeMillis(mConferenceHost.getConnectTimeMillis());
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 7354b10..d931f32 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -235,6 +235,13 @@
};
/**
+ * @return {@code true} if carrier video conferencing is supported, {@code false} otherwise.
+ */
+ public boolean isCarrierVideoConferencingSupported() {
+ return mIsCarrierVideoConferencingSupported;
+ }
+
+ /**
* A listener/callback mechanism that is specific communication from TelephonyConnections
* to TelephonyConnectionService (for now). It is more specific that Connection.Listener
* because it is only exposed in Telephony.
@@ -412,6 +419,13 @@
private boolean mIsConferenceSupported;
/**
+ * Indicates whether the carrier supports video conferencing; captures the current state of the
+ * carrier config
+ * {@link android.telephony.CarrierConfigManager#KEY_SUPPORT_VIDEO_CONFERENCE_CALL_BOOL}.
+ */
+ private boolean mIsCarrierVideoConferencingSupported;
+
+ /**
* Indicates whether or not this connection has CDMA Enhanced Voice Privacy enabled.
*/
private boolean mIsCdmaVoicePrivacyEnabled;
@@ -1515,15 +1529,15 @@
.getInstance(getPhone().getContext());
boolean isConferencingSupported = telecomAccountRegistry
.isMergeCallSupported(phoneAccountHandle);
- boolean isVideoConferencingSupported = telecomAccountRegistry
+ mIsCarrierVideoConferencingSupported = telecomAccountRegistry
.isVideoConferencingSupported(phoneAccountHandle);
boolean isMergeOfWifiCallsAllowedWhenVoWifiOff = telecomAccountRegistry
.isMergeOfWifiCallsAllowedWhenVoWifiOff(phoneAccountHandle);
Log.v(this, "refreshConferenceSupported : isConfSupp=%b, isVidConfSupp=%b, " +
"isMergeOfWifiAllowed=%b, isWifi=%b, isVoWifiEnabled=%b", isConferencingSupported,
- isVideoConferencingSupported, isMergeOfWifiCallsAllowedWhenVoWifiOff, isWifi(),
- isVoWifiEnabled);
+ mIsCarrierVideoConferencingSupported, isMergeOfWifiCallsAllowedWhenVoWifiOff,
+ isWifi(), isVoWifiEnabled);
boolean isConferenceSupported = true;
if (mTreatAsEmergencyCall) {
isConferenceSupported = false;
@@ -1531,7 +1545,7 @@
} else if (!isConferencingSupported) {
isConferenceSupported = false;
Log.d(this, "refreshConferenceSupported = false; carrier doesn't support conf.");
- } else if (isVideoCall && !isVideoConferencingSupported) {
+ } else if (isVideoCall && !mIsCarrierVideoConferencingSupported) {
isConferenceSupported = false;
Log.d(this, "refreshConferenceSupported = false; video conf not supported.");
} else if (!isMergeOfWifiCallsAllowedWhenVoWifiOff && isWifi() && !isVoWifiEnabled) {