Merge "Support unknown user provisioning for VVM3" into nyc-mr1-dev
diff --git a/Android.mk b/Android.mk
index f3fff79..cbebc44 100644
--- a/Android.mk
+++ b/Android.mk
@@ -11,7 +11,9 @@
LOCAL_JAVA_LIBRARIES := telephony-common voip-common ims-common
LOCAL_STATIC_JAVA_LIBRARIES := \
- guava
+ org.apache.http.legacy \
+ guava \
+ volley
LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
LOCAL_SRC_FILES += \
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 334e186..0a9a6a5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -676,18 +676,18 @@
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
- <receiver
- android:name="com.android.phone.vvm.omtp.fetch.FetchVoicemailReceiver"
- android:exported="true"
- android:permission="com.android.voicemail.permission.READ_VOICEMAIL">
- <intent-filter>
- <action android:name="android.intent.action.FETCH_VOICEMAIL" />
- <data
- android:scheme="content"
- android:host="com.android.voicemail"
- android:mimeType="vnd.android.cursor.item/voicemail" />
- </intent-filter>
- </receiver>
+ <receiver
+ android:name="com.android.phone.vvm.omtp.fetch.FetchVoicemailReceiver"
+ android:exported="true"
+ android:permission="com.android.voicemail.permission.READ_VOICEMAIL">
+ <intent-filter>
+ <action android:name="android.intent.action.FETCH_VOICEMAIL" />
+ <data
+ android:scheme="content"
+ android:host="com.android.voicemail"
+ android:mimeType="vnd.android.cursor.item/voicemail" />
+ </intent-filter>
+ </receiver>
<receiver
android:name="com.android.phone.vvm.omtp.sync.OmtpVvmSyncReceiver"
android:exported="true"
@@ -696,27 +696,31 @@
<action android:name="android.provider.action.SYNC_VOICEMAIL"/>
</intent-filter>
</receiver>
- <receiver
- android:name="com.android.phone.vvm.omtp.sync.VoicemailProviderChangeReceiver"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.PROVIDER_CHANGED" />
- <data
- android:scheme="content"
- android:host="com.android.voicemail"
- android:mimeType="vnd.android.cursor.dir/voicemails"/>
- </intent-filter>
- </receiver>
- <service
+ <receiver
+ android:name="com.android.phone.vvm.omtp.sync.VoicemailProviderChangeReceiver"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.PROVIDER_CHANGED" />
+ <data
+ android:scheme="content"
+ android:host="com.android.voicemail"
+ android:mimeType="vnd.android.cursor.dir/voicemails"/>
+ </intent-filter>
+ </receiver>
+ <service
android:name="com.android.phone.vvm.omtp.sync.OmtpVvmSyncService"
- android:exported="false"
- />
- <receiver android:name="com.android.phone.vvm.omtp.VvmPackageInstallReceiver">
- <intent-filter>
- <action android:name="android.intent.action.PACKAGE_INSTALL" />
- <action android:name="android.intent.action.PACKAGE_ADDED" />
- <data android:scheme="package"/>
- </intent-filter>
- </receiver>
+ android:exported="false" />
+
+ <service
+ android:name="com.android.phone.vvm.omtp.sms.OmtpProvisioningService"
+ android:exported="false" />
+
+ <receiver android:name="com.android.phone.vvm.omtp.VvmPackageInstallReceiver">
+ <intent-filter>
+ <action android:name="android.intent.action.PACKAGE_INSTALL" />
+ <action android:name="android.intent.action.PACKAGE_ADDED" />
+ <data android:scheme="package"/>
+ </intent-filter>
+ </receiver>
</application>
</manifest>
diff --git a/src/com/android/phone/Assert.java b/src/com/android/phone/Assert.java
new file mode 100644
index 0000000..d4233b2
--- /dev/null
+++ b/src/com/android/phone/Assert.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 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.phone;
+
+import android.os.Looper;
+
+/**
+ * Assertions which will result in program termination.
+ */
+public class Assert {
+
+ public static void isTrue(boolean condition) {
+ if (!condition) {
+ throw new AssertionError("Expected condition to be true");
+ }
+ }
+
+ public static void isNotMainThread() {
+ isTrue(!Looper.getMainLooper().equals(Looper.myLooper()));
+ }
+
+ public static void fail() {
+ throw new AssertionError("Fail");
+ }
+}
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
index d2e30f7..e62d1cf 100644
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
+++ b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
@@ -81,8 +81,8 @@
OmtpVvmCarrierConfigHelper config, StatusMessage message, Bundle data) {
Log.i(TAG, "start vvm3 provisioning");
if ("U".equals(message.getProvisioningStatus())) {
- Log.i(TAG, "Provisioning status: Unknown. VVM subscription not implemented.");
- // TODO: implement (b/28697797).
+ Log.i(TAG, "Provisioning status: Unknown, subscribing");
+ new Vvm3Subscriber(phoneAccountHandle, config, data).subscribe();
} else if ("N".equals(message.getProvisioningStatus())) {
Log.i(TAG, "setting up new user");
VisualVoicemailSettingsUtil.setVisualVoicemailCredentialsFromStatusMessage(
@@ -204,8 +204,6 @@
}
}
-
-
private static String generatePin() {
SecureRandom random = new SecureRandom();
// TODO(b/29102412): generate base on the length requirement from the server
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java
new file mode 100644
index 0000000..c314ff5
--- /dev/null
+++ b/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2016 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.phone.vvm.omtp.protocol;
+
+import android.annotation.WorkerThread;
+import android.net.Network;
+import android.os.Build;
+import android.os.Bundle;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.TelephonyManager;
+import android.text.Html;
+import android.text.Spanned;
+import android.text.style.URLSpan;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.phone.Assert;
+import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.sync.VvmNetworkRequestCallback;
+import com.android.volley.AuthFailureError;
+import com.android.volley.Request;
+import com.android.volley.RequestQueue;
+import com.android.volley.toolbox.HurlStack;
+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;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Class to subscribe to basic VVM3 visual voicemail, for example, Verizon. Subscription is required
+ * when the user is unprovisioned. This could happen when the user is on a legacy service, or
+ * switched over from devices that used other type of visual voicemail.
+ *
+ * The STATUS SMS will come with a URL to the voicemail management gateway. From it we can find the
+ * self provisioning gateway URL that we can modify voicemail services.
+ *
+ * A request to the self provisioning gateway to activate basic visual voicemail will return us with
+ * a web page. If the user hasn't subscribe to it yet it will contain a link to confirm the
+ * subscription. This link should be clicked through cellular network, and have cookies enabled.
+ *
+ * After the process is completed, the carrier should send us another STATUS SMS with a new or ready
+ * user.
+ */
+public class Vvm3Subscriber {
+
+ private static final String TAG = "Vvm3Subscriber";
+
+ private static final String OPERATION_GET_SPG_URL = "retrieveSPGURL";
+ private static final String SPG_URL_TAG = "spgurl";
+ private static final String TRANSACTION_ID_TAG = "transactionid";
+ //language=XML
+ private static final String VMG_XML_REQUEST_FORMAT = ""
+ + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ + "<VMGVVMRequest>"
+ + " <MessageHeader>"
+ + " <transactionid>%1$s</transactionid>"
+ + " </MessageHeader>"
+ + " <MessageBody>"
+ + " <mdn>%2$s</mdn>"
+ + " <operation>%3$s</operation>"
+ + " <source>Device</source>"
+ + " <devicemodel>%4$s</devicemodel>"
+ + " </MessageBody>"
+ + "</VMGVVMRequest>";
+
+ private 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";
+ private static final String SPG_VZW_SERVICE_PARAM = "VZW_SERVICE";
+ private static final String SPG_VZW_SERVICE_BASIC = "BVVM";
+ private static final String SPG_DEVICE_MODEL_PARAM = "DEVICE_MODEL";
+ // Value for all android device
+ private static final String SPG_DEVICE_MODEL_ANDROID = "DROID_4G";
+ private static final String SPG_APP_TOKEN_PARAM = "APP_TOKEN";
+ private static final String SPG_APP_TOKEN = "q8e3t5u2o1";
+ private static final String SPG_LANGUAGE_PARAM = "SPG_LANGUAGE_PARAM";
+ private static final String SPG_LANGUAGE_EN = "ENGLISH";
+
+ private static final String BASIC_SUBSCRIBE_LINK_TEXT = "Subscribe to Basic Visual Voice Mail";
+
+ private static final int REQUEST_TIMEOUT_SECONDS = 30;
+
+ private final PhoneAccountHandle mHandle;
+ private final OmtpVvmCarrierConfigHelper mHelper;
+ private final Bundle mData;
+
+ private final String mNumber;
+
+ private RequestQueue mRequestQueue;
+
+ private static class ProvisioningException extends Exception {
+
+ public ProvisioningException(String message) {
+ super(message);
+ }
+ }
+
+ static {
+ // Set the default cookie handler to retain session data for the self provisioning gateway.
+ // Note; this is not ideal as it is application-wide, and can easily get clobbered.
+ // But it seems to be the preferred way to manage cookie for HttpURLConnection, and manually
+ // managing cookies will greatly increase complexity.
+ CookieManager cookieManager = new CookieManager();
+ CookieHandler.setDefault(cookieManager);
+ }
+
+ @WorkerThread
+ public Vvm3Subscriber(PhoneAccountHandle handle, OmtpVvmCarrierConfigHelper helper,
+ Bundle data) {
+ Assert.isNotMainThread();
+ mHandle = handle;
+ mHelper = helper;
+ mData = data;
+
+ // Assuming getLine1Number() will work with VVM3. For unprovisioned users the IMAP username
+ // is not included in the status SMS, thus no other way to get the current phone number.
+ mNumber = mHelper.getContext().getSystemService(TelephonyManager.class)
+ .getLine1Number(mHelper.getSubId());
+ }
+
+ @WorkerThread
+ public void subscribe() {
+ Assert.isNotMainThread();
+ // Cellular data is required to subscribe.
+ // processSubscription() is called after network is available.
+ new Vvm3ProvisioningNetworkRequestCallback(mHelper, mHandle).requestNetwork();
+ }
+
+ private void processSubscription() {
+ try {
+ String gatewayUrl = getSelfProvisioningGateway();
+ String selfProvisionResponse = getSelfProvisionResponse(gatewayUrl);
+ String subscribeLink = findSubscribeLink(selfProvisionResponse);
+ clickSubscribeLink(subscribeLink);
+ } catch (ProvisioningException e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ /**
+ * Get the URL to perform self-provisioning from the voicemail management gateway.
+ */
+ private String getSelfProvisioningGateway() throws ProvisioningException {
+ String response = vvm3XmlRequest(OPERATION_GET_SPG_URL);
+ return extractText(response, SPG_URL_TAG);
+ }
+
+ /**
+ * Sent a request to the self-provisioning gateway, which will return us with a webpage. The
+ * page might contain a "Subscribe to Basic Visual Voice Mail" link to complete the
+ * subscription. The cookie from this response and cellular data is required to click the link.
+ */
+ private String getSelfProvisionResponse(String url) throws ProvisioningException {
+ RequestFuture<String> future = RequestFuture.newFuture();
+
+ StringRequest stringRequest = new StringRequest(Request.Method.POST, url, future, future) {
+ @Override
+ protected Map<String, String> getParams() {
+ Map<String, String> params = new ArrayMap<>();
+ params.put(SPG_VZW_MDN_PARAM, mNumber);
+ params.put(SPG_VZW_SERVICE_PARAM, SPG_VZW_SERVICE_BASIC);
+ params.put(SPG_DEVICE_MODEL_PARAM, SPG_DEVICE_MODEL_ANDROID);
+ params.put(SPG_APP_TOKEN_PARAM, SPG_APP_TOKEN);
+ // Language to display the subscription page. The page is never shown to the user
+ // so just use English.
+ params.put(SPG_LANGUAGE_PARAM, SPG_LANGUAGE_EN);
+ return params;
+ }
+ };
+
+ mRequestQueue.add(stringRequest);
+ try {
+ return future.get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ throw new ProvisioningException(e.toString());
+ }
+ }
+
+ private void clickSubscribeLink(String subscribeLink) throws ProvisioningException {
+ RequestFuture<String> future = RequestFuture.newFuture();
+
+ StringRequest stringRequest = new StringRequest(Request.Method.POST,
+ subscribeLink, future, future);
+ mRequestQueue.add(stringRequest);
+
+ try {
+ future.get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ throw new ProvisioningException(e.toString());
+ }
+ }
+
+ private String vvm3XmlRequest(String operation) throws ProvisioningException {
+ Log.d(TAG, "Sending vvm3XmlRequest for " + operation);
+ String voicemailManagementGateway = mData.getString(VMG_URL_KEY);
+ if (voicemailManagementGateway == null) {
+ Log.e(TAG, "voicemailManagementGateway url unknown");
+ return null;
+ }
+ String transactionId = createTransactionId();
+ String body = String.format(Locale.US, VMG_XML_REQUEST_FORMAT,
+ transactionId, mNumber, operation, Build.MODEL);
+
+ RequestFuture<String> future = RequestFuture.newFuture();
+ StringRequest stringRequest = new StringRequest(Request.Method.POST,
+ voicemailManagementGateway, future, future) {
+ @Override
+ public byte[] getBody() throws AuthFailureError {
+ return body.getBytes();
+ }
+ };
+ mRequestQueue.add(stringRequest);
+
+ try {
+ String response = future.get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ if (!transactionId.equals(extractText(response, TRANSACTION_ID_TAG))) {
+ throw new ProvisioningException("transactionId mismatch");
+ }
+ return response;
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ throw new ProvisioningException(e.toString());
+ }
+ }
+
+ private String findSubscribeLink(String response) throws ProvisioningException {
+ Spanned doc = Html.fromHtml(response, Html.FROM_HTML_MODE_LEGACY);
+ URLSpan[] spans = doc.getSpans(0, doc.length(), URLSpan.class);
+ for (URLSpan span : spans) {
+ String text = doc.subSequence(doc.getSpanStart(span), doc.getSpanEnd(span)).toString();
+ if (BASIC_SUBSCRIBE_LINK_TEXT.equals(text)) {
+ return span.getURL();
+ }
+ }
+ throw new ProvisioningException("Subscribe link not found");
+ }
+
+ private String createTransactionId() {
+ return String.valueOf(Math.abs(new Random().nextLong()));
+ }
+
+ private String extractText(String xml, String tag) throws ProvisioningException {
+ Pattern pattern = Pattern.compile("<" + tag + ">(.*)<\\/" + tag + ">");
+ Matcher matcher = pattern.matcher(xml);
+ if (matcher.find()) {
+ return matcher.group(1);
+ }
+ throw new ProvisioningException("Tag " + tag + " not found in xml response");
+ }
+
+ private class Vvm3ProvisioningNetworkRequestCallback extends VvmNetworkRequestCallback {
+
+ public Vvm3ProvisioningNetworkRequestCallback(OmtpVvmCarrierConfigHelper config,
+ PhoneAccountHandle phoneAccountHandle) {
+ super(config, phoneAccountHandle);
+ }
+
+ @Override
+ public void onAvailable(Network network) {
+ super.onAvailable(network);
+ Log.d(TAG, "provisioning: network available");
+ mRequestQueue = Volley
+ .newRequestQueue(mContext, new NetworkSpecifiedHurlStack(network));
+ processSubscription();
+ }
+ }
+
+ private static class NetworkSpecifiedHurlStack extends HurlStack {
+
+ private final Network mNetwork;
+
+ public NetworkSpecifiedHurlStack(Network network) {
+ mNetwork = network;
+ }
+
+ @Override
+ protected HttpURLConnection createConnection(URL url) throws IOException {
+ return (HttpURLConnection) mNetwork.openConnection(url);
+ }
+
+ }
+}
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
index b668ad8..feb3c5a 100644
--- a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
+++ b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
@@ -28,7 +28,6 @@
import android.util.Log;
import com.android.phone.PhoneGlobals;
-import com.android.phone.PhoneUtils;
import com.android.phone.settings.VisualVoicemailSettingsUtil;
import com.android.phone.vvm.omtp.LocalLogHelper;
import com.android.phone.vvm.omtp.OmtpConstants;
@@ -89,19 +88,13 @@
updateSource(phone, subId, message);
} else {
Log.v(TAG, "Subscriber not ready, start provisioning");
- startProvisioning(phone, message, data);
+ mContext.startService(OmtpProvisioningService.getProvisionIntent(mContext, intent));
}
} else {
Log.e(TAG, "Unknown prefix: " + eventType);
}
}
- private void startProvisioning(PhoneAccountHandle phone, StatusMessage message, Bundle data) {
- OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(mContext,
- PhoneUtils.getSubIdForPhoneAccountHandle(phone));
- helper.startProvisioning(phone, message, data);
- }
-
/**
* A sync message has two purposes: to signal a new voicemail message, and to indicate the
* voicemails on the server have changed remotely (usually through the TUI). Save the new
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpProvisioningService.java b/src/com/android/phone/vvm/omtp/sms/OmtpProvisioningService.java
new file mode 100644
index 0000000..ced9490
--- /dev/null
+++ b/src/com/android/phone/vvm/omtp/sms/OmtpProvisioningService.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 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.phone.vvm.omtp.sms;
+
+import android.app.IntentService;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.VoicemailContract;
+import android.telecom.PhoneAccountHandle;
+
+import com.android.phone.PhoneUtils;
+import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
+
+/**
+ * Performs visual voicemail provisioning in background thread. Not exported.
+ */
+public class OmtpProvisioningService extends IntentService {
+
+ public OmtpProvisioningService() {
+ super("OmtpProvisioningService");
+ }
+
+ /**
+ * Create an intent to start OmtpProvisioningService from a {@link
+ * VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED} intent.
+ */
+ public static Intent getProvisionIntent(Context context, Intent messageIntent) {
+ Intent serviceIntent = new Intent(context, OmtpProvisioningService.class);
+
+ serviceIntent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_SUBID,
+ messageIntent.getExtras().getInt(VoicemailContract.EXTRA_VOICEMAIL_SMS_SUBID));
+ serviceIntent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_FIELDS,
+ messageIntent.getExtras().getBundle(VoicemailContract.EXTRA_VOICEMAIL_SMS_FIELDS));
+
+ return serviceIntent;
+ }
+
+ @Override
+ public void onHandleIntent(Intent intent) {
+ int subId = intent.getExtras().getInt(VoicemailContract.EXTRA_VOICEMAIL_SMS_SUBID);
+ PhoneAccountHandle phone = PhoneAccountHandleConverter.fromSubId(subId);
+
+ Bundle data = intent.getExtras().getBundle(VoicemailContract.EXTRA_VOICEMAIL_SMS_FIELDS);
+
+ StatusMessage message = new StatusMessage(data);
+ startProvisioning(phone, message, data);
+ }
+
+ private void startProvisioning(PhoneAccountHandle phone, StatusMessage message, Bundle data) {
+ OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(this,
+ PhoneUtils.getSubIdForPhoneAccountHandle(phone));
+ helper.startProvisioning(phone, message, data);
+ }
+}
diff --git a/src/com/android/phone/vvm/omtp/sms/SyncMessage.java b/src/com/android/phone/vvm/omtp/sms/SyncMessage.java
index 1e565da..4dddba4 100644
--- a/src/com/android/phone/vvm/omtp/sms/SyncMessage.java
+++ b/src/com/android/phone/vvm/omtp/sms/SyncMessage.java
@@ -15,6 +15,7 @@
*/
package com.android.phone.vvm.omtp.sms;
+import android.annotation.Nullable;
import android.os.Bundle;
import com.android.phone.vvm.omtp.OmtpConstants;
@@ -36,6 +37,7 @@
// UID of the new message.
private final String mMessageId;
// Length of the message.
+ @Nullable
private final Integer mMessageLength;
// Content type (voice, video, fax...) of the new message.
private final String mContentType;
@@ -58,7 +60,12 @@
public SyncMessage(Bundle wrappedData) {
mSyncTriggerEvent = wrappedData.getString(OmtpConstants.SYNC_TRIGGER_EVENT);
mMessageId = wrappedData.getString(OmtpConstants.MESSAGE_UID);
- mMessageLength = Integer.parseInt(wrappedData.getString(OmtpConstants.MESSAGE_LENGTH));
+ if (wrappedData.getString(OmtpConstants.MESSAGE_LENGTH) != null) {
+ mMessageLength = Integer.parseInt(wrappedData.getString(OmtpConstants.MESSAGE_LENGTH));
+ } else {
+ // Optional field
+ mMessageLength = null;
+ }
mContentType = wrappedData.getString(OmtpConstants.CONTENT_TYPE);
mSender = wrappedData.getString(OmtpConstants.SENDER);
mNewMessageCount = Integer.parseInt(wrappedData.getString(OmtpConstants.NUM_MESSAGE_COUNT));