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 17 package com.android.voicemail.impl.sms; 18 19 import android.annotation.TargetApi; 20 import android.app.Activity; 21 import android.app.PendingIntent; 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.os.Build.VERSION_CODES; 27 import android.os.Bundle; 28 import android.support.annotation.MainThread; 29 import android.support.annotation.Nullable; 30 import android.support.annotation.WorkerThread; 31 import android.telecom.PhoneAccountHandle; 32 import android.telephony.SmsManager; 33 import android.telephony.VisualVoicemailSms; 34 import com.android.voicemail.impl.Assert; 35 import com.android.voicemail.impl.OmtpConstants; 36 import com.android.voicemail.impl.OmtpService; 37 import com.android.voicemail.impl.OmtpVvmCarrierConfigHelper; 38 import com.android.voicemail.impl.VvmLog; 39 import com.android.voicemail.impl.protocol.VisualVoicemailProtocol; 40 import java.io.Closeable; 41 import java.io.IOException; 42 import java.util.concurrent.CancellationException; 43 import java.util.concurrent.CompletableFuture; 44 import java.util.concurrent.ExecutionException; 45 import java.util.concurrent.TimeUnit; 46 import java.util.concurrent.TimeoutException; 47 48 /** Intercepts a incoming STATUS SMS with a blocking call. */ 49 @TargetApi(VERSION_CODES.O) 50 public class StatusSmsFetcher extends BroadcastReceiver implements Closeable { 51 52 private static final String TAG = "VvmStatusSmsFetcher"; 53 54 private static final long STATUS_SMS_TIMEOUT_MILLIS = 60_000; 55 56 private static final String PERMISSION_DIALER_ORIGIN = 57 "com.android.dialer.permission.DIALER_ORIGIN"; 58 59 private static final String ACTION_REQUEST_SENT_INTENT = 60 "com.android.voicemailomtp.sms.REQUEST_SENT"; 61 62 private static final int ACTION_REQUEST_SENT_REQUEST_CODE = 0; 63 64 private CompletableFuture<Bundle> future = new CompletableFuture<>(); 65 66 private final Context context; 67 private final PhoneAccountHandle phoneAccountHandle; 68 StatusSmsFetcher(Context context, PhoneAccountHandle phoneAccountHandle)69 public StatusSmsFetcher(Context context, PhoneAccountHandle phoneAccountHandle) { 70 this.context = context; 71 this.phoneAccountHandle = phoneAccountHandle; 72 IntentFilter filter = new IntentFilter(ACTION_REQUEST_SENT_INTENT); 73 filter.addAction(OmtpService.ACTION_SMS_RECEIVED); 74 context.registerReceiver(this, filter, PERMISSION_DIALER_ORIGIN, /* scheduler= */ null); 75 } 76 77 @Override close()78 public void close() throws IOException { 79 context.unregisterReceiver(this); 80 } 81 82 @WorkerThread 83 @Nullable get()84 public Bundle get() 85 throws InterruptedException, ExecutionException, TimeoutException, CancellationException { 86 Assert.isNotMainThread(); 87 return future.get(STATUS_SMS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 88 } 89 getSentIntent()90 public PendingIntent getSentIntent() { 91 Intent intent = new Intent(ACTION_REQUEST_SENT_INTENT); 92 intent.setPackage(context.getPackageName()); 93 // Because the receiver is registered dynamically, implicit intent must be used. 94 // There should only be a single status SMS request at a time. 95 return PendingIntent.getBroadcast( 96 context, 97 ACTION_REQUEST_SENT_REQUEST_CODE, 98 intent, 99 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); 100 } 101 102 @Override 103 @MainThread onReceive(Context context, Intent intent)104 public void onReceive(Context context, Intent intent) { 105 Assert.isMainThread(); 106 if (ACTION_REQUEST_SENT_INTENT.equals(intent.getAction())) { 107 int resultCode = getResultCode(); 108 109 if (resultCode == Activity.RESULT_OK) { 110 VvmLog.d(TAG, "Request SMS successfully sent"); 111 return; 112 } 113 114 VvmLog.e(TAG, "Request SMS send failed: " + sentSmsResultToString(resultCode)); 115 future.cancel(true); 116 return; 117 } 118 119 VisualVoicemailSms sms = intent.getExtras().getParcelable(OmtpService.EXTRA_VOICEMAIL_SMS); 120 121 if (!phoneAccountHandle.equals(sms.getPhoneAccountHandle())) { 122 return; 123 } 124 String eventType = sms.getPrefix(); 125 126 if (eventType.equals(OmtpConstants.STATUS_SMS_PREFIX)) { 127 future.complete(sms.getFields()); 128 return; 129 } 130 131 if (eventType.equals(OmtpConstants.SYNC_SMS_PREFIX)) { 132 return; 133 } 134 135 VvmLog.i( 136 TAG, 137 "VVM SMS with event " + eventType + " received, attempting to translate to STATUS SMS"); 138 OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(context, phoneAccountHandle); 139 VisualVoicemailProtocol protocol = helper.getProtocol(); 140 if (protocol == null) { 141 return; 142 } 143 Bundle translatedBundle = protocol.translateStatusSmsBundle(helper, eventType, sms.getFields()); 144 145 if (translatedBundle != null) { 146 VvmLog.i(TAG, "Translated to STATUS SMS"); 147 future.complete(translatedBundle); 148 } 149 } 150 sentSmsResultToString(int resultCode)151 private static String sentSmsResultToString(int resultCode) { 152 switch (resultCode) { 153 case Activity.RESULT_OK: 154 return "OK"; 155 case SmsManager.RESULT_ERROR_GENERIC_FAILURE: 156 return "RESULT_ERROR_GENERIC_FAILURE"; 157 case SmsManager.RESULT_ERROR_NO_SERVICE: 158 return "RESULT_ERROR_GENERIC_FAILURE"; 159 case SmsManager.RESULT_ERROR_NULL_PDU: 160 return "RESULT_ERROR_GENERIC_FAILURE"; 161 case SmsManager.RESULT_ERROR_RADIO_OFF: 162 return "RESULT_ERROR_GENERIC_FAILURE"; 163 default: 164 return "UNKNOWN CODE: " + resultCode; 165 } 166 } 167 } 168