1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 package com.android.phone.vvm.omtp.sms; 17 18 import android.content.BroadcastReceiver; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.provider.Telephony; 22 import android.provider.VoicemailContract; 23 import android.telecom.PhoneAccountHandle; 24 import android.telecom.Voicemail; 25 import android.telephony.SmsMessage; 26 import android.telephony.SubscriptionManager; 27 import android.util.Log; 28 29 import com.android.internal.telephony.PhoneConstants; 30 import com.android.phone.PhoneGlobals; 31 import com.android.phone.PhoneUtils; 32 import com.android.phone.settings.VisualVoicemailSettingsUtil; 33 import com.android.phone.vvm.omtp.LocalLogHelper; 34 import com.android.phone.vvm.omtp.OmtpConstants; 35 import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager; 36 import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService; 37 import com.android.phone.vvm.omtp.sync.VoicemailsQueryHelper; 38 39 /** 40 * Receive SMS messages and send for processing by the OMTP visual voicemail source. 41 */ 42 public class OmtpMessageReceiver extends BroadcastReceiver { 43 private static final String TAG = "OmtpMessageReceiver"; 44 45 private Context mContext; 46 private PhoneAccountHandle mPhoneAccount; 47 48 @Override onReceive(Context context, Intent intent)49 public void onReceive(Context context, Intent intent) { 50 mContext = context; 51 mPhoneAccount = PhoneUtils.makePstnPhoneAccountHandle( 52 intent.getExtras().getInt(PhoneConstants.PHONE_KEY)); 53 54 if (mPhoneAccount == null) { 55 Log.w(TAG, "Received message for null phone account"); 56 return; 57 } 58 59 if (!VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(mContext, mPhoneAccount)) { 60 Log.v(TAG, "Received vvm message for disabled vvm source."); 61 return; 62 } 63 64 SmsMessage[] messages = Telephony.Sms.Intents.getMessagesFromIntent(intent); 65 StringBuilder messageBody = new StringBuilder(); 66 67 for (int i = 0; i < messages.length; i++) { 68 if (messages[i].mWrappedSmsMessage != null) { 69 messageBody.append(messages[i].getMessageBody()); 70 } 71 } 72 73 WrappedMessageData messageData = OmtpSmsParser.parse(messageBody.toString()); 74 if (messageData != null) { 75 if (messageData.getPrefix() == OmtpConstants.SYNC_SMS_PREFIX) { 76 SyncMessage message = new SyncMessage(messageData); 77 78 Log.v(TAG, "Received SYNC sms for " + mPhoneAccount.getId() + 79 " with event" + message.getSyncTriggerEvent()); 80 LocalLogHelper.log(TAG, "Received SYNC sms for " + mPhoneAccount.getId() + 81 " with event" + message.getSyncTriggerEvent()); 82 processSync(message); 83 } else if (messageData.getPrefix() == OmtpConstants.STATUS_SMS_PREFIX) { 84 Log.v(TAG, "Received STATUS sms for " + mPhoneAccount.getId()); 85 LocalLogHelper.log(TAG, "Received Status sms for " + mPhoneAccount.getId()); 86 StatusMessage message = new StatusMessage(messageData); 87 updateSource(message); 88 } else { 89 Log.e(TAG, "This should never have happened"); 90 } 91 } 92 // Let this fall through: this is not a message we're interested in. 93 } 94 95 /** 96 * A sync message has two purposes: to signal a new voicemail message, and to indicate the 97 * voicemails on the server have changed remotely (usually through the TUI). Save the new 98 * message to the voicemail provider if it is the former case and perform a full sync in the 99 * latter case. 100 * 101 * @param message The sync message to extract data from. 102 */ processSync(SyncMessage message)103 private void processSync(SyncMessage message) { 104 switch (message.getSyncTriggerEvent()) { 105 case OmtpConstants.NEW_MESSAGE: 106 Voicemail voicemail = Voicemail.createForInsertion( 107 message.getTimestampMillis(), message.getSender()) 108 .setPhoneAccount(mPhoneAccount) 109 .setSourceData(message.getId()) 110 .setDuration(message.getLength()) 111 .setSourcePackage(mContext.getPackageName()) 112 .build(); 113 VoicemailsQueryHelper queryHelper = new VoicemailsQueryHelper(mContext); 114 queryHelper.insertIfUnique(voicemail); 115 break; 116 case OmtpConstants.MAILBOX_UPDATE: 117 Intent serviceIntent = OmtpVvmSyncService.getSyncIntent( 118 mContext, OmtpVvmSyncService.SYNC_DOWNLOAD_ONLY, mPhoneAccount, 119 true /* firstAttempt */); 120 mContext.startService(serviceIntent); 121 break; 122 case OmtpConstants.GREETINGS_UPDATE: 123 // Not implemented in V1 124 break; 125 default: 126 Log.e(TAG, "Unrecognized sync trigger event: " + message.getSyncTriggerEvent()); 127 break; 128 } 129 } 130 updateSource(StatusMessage message)131 private void updateSource(StatusMessage message) { 132 OmtpVvmSourceManager vvmSourceManager = 133 OmtpVvmSourceManager.getInstance(mContext); 134 135 if (OmtpConstants.SUCCESS.equals(message.getReturnCode())) { 136 VoicemailContract.Status.setStatus(mContext, mPhoneAccount, 137 VoicemailContract.Status.CONFIGURATION_STATE_OK, 138 VoicemailContract.Status.DATA_CHANNEL_STATE_OK, 139 VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_OK); 140 141 // Save the IMAP credentials in preferences so they are persistent and can be retrieved. 142 VisualVoicemailSettingsUtil.setVisualVoicemailCredentialsFromStatusMessage( 143 mContext, 144 mPhoneAccount, 145 message); 146 147 // Add the source to indicate that it is active. 148 vvmSourceManager.addSource(mPhoneAccount); 149 150 Intent serviceIntent = OmtpVvmSyncService.getSyncIntent( 151 mContext, OmtpVvmSyncService.SYNC_FULL_SYNC, mPhoneAccount, 152 true /* firstAttempt */); 153 mContext.startService(serviceIntent); 154 155 PhoneGlobals.getInstance().clearMwiIndicator( 156 PhoneUtils.getSubIdForPhoneAccountHandle(mPhoneAccount)); 157 } else { 158 Log.w(TAG, "Visual voicemail not available for subscriber."); 159 // Override default isEnabled setting to false since visual voicemail is unable to 160 // be accessed for some reason. 161 VisualVoicemailSettingsUtil.setVisualVoicemailEnabled(mContext, mPhoneAccount, 162 /* isEnabled */ false, /* isUserSet */ true); 163 } 164 } 165 }