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.ContentUris; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.net.Uri; 23 import android.os.UserManager; 24 import android.provider.Telephony; 25 import android.provider.VoicemailContract; 26 import android.telecom.PhoneAccountHandle; 27 import android.telecom.Voicemail; 28 import android.telephony.SmsMessage; 29 import android.util.Log; 30 31 import com.android.internal.telephony.PhoneConstants; 32 import com.android.phone.PhoneGlobals; 33 import com.android.phone.PhoneUtils; 34 import com.android.phone.settings.VisualVoicemailSettingsUtil; 35 import com.android.phone.vvm.omtp.LocalLogHelper; 36 import com.android.phone.vvm.omtp.OmtpConstants; 37 import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager; 38 import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService; 39 import com.android.phone.vvm.omtp.sync.VoicemailsQueryHelper; 40 41 /** 42 * Receive SMS messages and send for processing by the OMTP visual voicemail source. 43 */ 44 public class OmtpMessageReceiver extends BroadcastReceiver { 45 private static final String TAG = "OmtpMessageReceiver"; 46 47 private Context mContext; 48 private PhoneAccountHandle mPhoneAccount; 49 50 @Override onReceive(Context context, Intent intent)51 public void onReceive(Context context, Intent intent) { 52 if (!UserManager.get(context).isUserUnlocked()) { 53 Log.i(TAG, "Received message on locked device"); 54 // A full sync will happen after the device is unlocked, so nothing need to be done. 55 return; 56 } 57 58 mContext = context; 59 mPhoneAccount = PhoneUtils.makePstnPhoneAccountHandle( 60 intent.getExtras().getInt(PhoneConstants.PHONE_KEY)); 61 62 if (mPhoneAccount == null) { 63 Log.w(TAG, "Received message for null phone account"); 64 return; 65 } 66 67 if (!VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(mContext, mPhoneAccount)) { 68 Log.v(TAG, "Received vvm message for disabled vvm source."); 69 return; 70 } 71 72 SmsMessage[] messages = Telephony.Sms.Intents.getMessagesFromIntent(intent); 73 74 if (messages == null) { 75 Log.w(TAG, "Message does not exist in the intent."); 76 return; 77 } 78 79 StringBuilder messageBody = new StringBuilder(); 80 81 for (int i = 0; i < messages.length; i++) { 82 if (messages[i].mWrappedSmsMessage != null) { 83 messageBody.append(messages[i].getMessageBody()); 84 } 85 } 86 87 WrappedMessageData messageData = OmtpSmsParser.parse(messageBody.toString()); 88 if (messageData != null) { 89 if (messageData.getPrefix() == OmtpConstants.SYNC_SMS_PREFIX) { 90 SyncMessage message = new SyncMessage(messageData); 91 92 Log.v(TAG, "Received SYNC sms for " + mPhoneAccount.getId() + 93 " with event " + message.getSyncTriggerEvent()); 94 LocalLogHelper.log(TAG, "Received SYNC sms for " + mPhoneAccount.getId() + 95 " with event " + message.getSyncTriggerEvent()); 96 processSync(message); 97 } else if (messageData.getPrefix() == OmtpConstants.STATUS_SMS_PREFIX) { 98 Log.v(TAG, "Received STATUS sms for " + mPhoneAccount.getId()); 99 LocalLogHelper.log(TAG, "Received Status sms for " + mPhoneAccount.getId()); 100 StatusMessage message = new StatusMessage(messageData); 101 updateSource(message); 102 } else { 103 Log.e(TAG, "This should never have happened"); 104 } 105 } 106 // Let this fall through: this is not a message we're interested in. 107 } 108 109 /** 110 * A sync message has two purposes: to signal a new voicemail message, and to indicate the 111 * voicemails on the server have changed remotely (usually through the TUI). Save the new 112 * message to the voicemail provider if it is the former case and perform a full sync in the 113 * latter case. 114 * 115 * @param message The sync message to extract data from. 116 */ processSync(SyncMessage message)117 private void processSync(SyncMessage message) { 118 Intent serviceIntent = null; 119 switch (message.getSyncTriggerEvent()) { 120 case OmtpConstants.NEW_MESSAGE: 121 Voicemail.Builder builder = Voicemail.createForInsertion( 122 message.getTimestampMillis(), message.getSender()) 123 .setPhoneAccount(mPhoneAccount) 124 .setSourceData(message.getId()) 125 .setDuration(message.getLength()) 126 .setSourcePackage(mContext.getPackageName()); 127 Voicemail voicemail = builder.build(); 128 129 VoicemailsQueryHelper queryHelper = new VoicemailsQueryHelper(mContext); 130 if (queryHelper.isVoicemailUnique(voicemail)) { 131 Uri uri = VoicemailContract.Voicemails.insert(mContext, voicemail); 132 voicemail = builder.setId(ContentUris.parseId(uri)).setUri(uri).build(); 133 serviceIntent = OmtpVvmSyncService.getSyncIntent(mContext, 134 OmtpVvmSyncService.SYNC_DOWNLOAD_ONE_TRANSCRIPTION, mPhoneAccount, 135 voicemail, true /* firstAttempt */); 136 } 137 break; 138 case OmtpConstants.MAILBOX_UPDATE: 139 serviceIntent = OmtpVvmSyncService.getSyncIntent( 140 mContext, OmtpVvmSyncService.SYNC_DOWNLOAD_ONLY, mPhoneAccount, 141 true /* firstAttempt */); 142 break; 143 case OmtpConstants.GREETINGS_UPDATE: 144 // Not implemented in V1 145 break; 146 default: 147 Log.e(TAG, "Unrecognized sync trigger event: " + message.getSyncTriggerEvent()); 148 break; 149 } 150 151 if (serviceIntent != null) { 152 mContext.startService(serviceIntent); 153 } 154 } 155 updateSource(StatusMessage message)156 private void updateSource(StatusMessage message) { 157 OmtpVvmSourceManager vvmSourceManager = 158 OmtpVvmSourceManager.getInstance(mContext); 159 160 if (OmtpConstants.SUCCESS.equals(message.getReturnCode())) { 161 VoicemailContract.Status.setStatus(mContext, mPhoneAccount, 162 VoicemailContract.Status.CONFIGURATION_STATE_OK, 163 VoicemailContract.Status.DATA_CHANNEL_STATE_OK, 164 VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE_OK); 165 166 // Save the IMAP credentials in preferences so they are persistent and can be retrieved. 167 VisualVoicemailSettingsUtil.setVisualVoicemailCredentialsFromStatusMessage( 168 mContext, 169 mPhoneAccount, 170 message); 171 172 // Add the source to indicate that it is active. 173 vvmSourceManager.addSource(mPhoneAccount); 174 175 Intent serviceIntent = OmtpVvmSyncService.getSyncIntent( 176 mContext, OmtpVvmSyncService.SYNC_FULL_SYNC, mPhoneAccount, 177 true /* firstAttempt */); 178 mContext.startService(serviceIntent); 179 180 PhoneGlobals.getInstance().clearMwiIndicator( 181 PhoneUtils.getSubIdForPhoneAccountHandle(mPhoneAccount)); 182 } else { 183 Log.w(TAG, "Visual voicemail not available for subscriber."); 184 // Override default isEnabled setting to false since visual voicemail is unable to 185 // be accessed for some reason. 186 VisualVoicemailSettingsUtil.setVisualVoicemailEnabled(mContext, mPhoneAccount, 187 /* isEnabled */ false, /* isUserSet */ true); 188 } 189 } 190 } 191