1/* 2 * Copyright (C) 2016 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 17package android.telephony; 18 19import android.annotation.MainThread; 20import android.annotation.SdkConstant; 21import android.annotation.SystemApi; 22import android.app.PendingIntent; 23import android.app.Service; 24import android.content.Context; 25import android.content.Intent; 26import android.os.Bundle; 27import android.os.Handler; 28import android.os.IBinder; 29import android.os.Message; 30import android.os.Messenger; 31import android.os.RemoteException; 32import android.telecom.PhoneAccountHandle; 33import android.telecom.TelecomManager; 34import android.util.Log; 35 36/** 37 * This service is implemented by dialer apps that wishes to handle OMTP or similar visual 38 * voicemails. Telephony binds to this service when the cell service is first connected, a visual 39 * voicemail SMS has been received, or when a SIM has been removed. Telephony will only bind to the 40 * default dialer for such events (See {@link TelecomManager#getDefaultDialerPackage()}). The 41 * {@link android.service.carrier.CarrierMessagingService} precedes the VisualVoicemailService in 42 * the SMS filtering chain and may intercept the visual voicemail SMS before it reaches this 43 * service. 44 * <p> 45 * To extend this class, The service must be declared in the manifest file with 46 * the {@link android.Manifest.permission#BIND_VISUAL_VOICEMAIL_SERVICE} permission and include an 47 * intent filter with the {@link #SERVICE_INTERFACE} action. 48 * <p> 49 * Below is an example manifest registration for a {@code VisualVoicemailService}. 50 * <pre> 51 * {@code 52 * <service android:name="your.package.YourVisualVoicemailServiceImplementation" 53 * android:permission="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"> 54 * <intent-filter> 55 * <action android:name="android.telephony.VisualVoicemailService"/> 56 * </intent-filter> 57 * </service> 58 * } 59 * </pre> 60 */ 61public abstract class VisualVoicemailService extends Service { 62 63 private static final String TAG = "VvmService"; 64 65 /** 66 * The {@link Intent} that must be declared as handled by the service. 67 */ 68 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) 69 public static final String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService"; 70 71 /** 72 * @hide 73 */ 74 public static final int MSG_ON_CELL_SERVICE_CONNECTED = 1; 75 /** 76 * @hide 77 */ 78 public static final int MSG_ON_SMS_RECEIVED = 2; 79 /** 80 * @hide 81 */ 82 public static final int MSG_ON_SIM_REMOVED = 3; 83 /** 84 * @hide 85 */ 86 public static final int MSG_TASK_ENDED = 4; 87 /** 88 * @hide 89 */ 90 public static final int MSG_TASK_STOPPED = 5; 91 92 /** 93 * @hide 94 */ 95 public static final String DATA_PHONE_ACCOUNT_HANDLE = "data_phone_account_handle"; 96 /** 97 * @hide 98 */ 99 public static final String DATA_SMS = "data_sms"; 100 101 /** 102 * Represents a visual voicemail event which needs to be handled. While the task is being 103 * processed telephony will hold a wakelock for the VisualVoicemailService. The service can 104 * unblock the main thread and pass the task to a worker thread. Once the task is finished, 105 * {@link VisualVoicemailTask#finish()} should be called to signal telephony to release the 106 * resources. Telephony will call {@link VisualVoicemailService#onStopped(VisualVoicemailTask)} 107 * when the task is going to be terminated before completion. 108 * 109 * @see #onCellServiceConnected(VisualVoicemailTask, PhoneAccountHandle) 110 * @see #onSmsReceived(VisualVoicemailTask, VisualVoicemailSms) 111 * @see #onSimRemoved(VisualVoicemailTask, PhoneAccountHandle) 112 * @see #onStopped(VisualVoicemailTask) 113 */ 114 public static class VisualVoicemailTask { 115 116 private final int mTaskId; 117 private final Messenger mReplyTo; 118 119 private VisualVoicemailTask(Messenger replyTo, int taskId) { 120 mTaskId = taskId; 121 mReplyTo = replyTo; 122 } 123 124 /** 125 * Call to signal telephony the task has completed. Must be called for every task. 126 */ 127 public final void finish() { 128 Message message = Message.obtain(); 129 try { 130 message.what = MSG_TASK_ENDED; 131 message.arg1 = mTaskId; 132 mReplyTo.send(message); 133 } catch (RemoteException e) { 134 Log.e(TAG, 135 "Cannot send MSG_TASK_ENDED, remote handler no longer exist"); 136 } 137 } 138 139 @Override 140 public boolean equals(Object obj) { 141 if (!(obj instanceof VisualVoicemailTask)) { 142 return false; 143 } 144 return mTaskId == ((VisualVoicemailTask) obj).mTaskId; 145 } 146 147 @Override 148 public int hashCode() { 149 return mTaskId; 150 } 151 } 152 153 /** 154 * Handles messages sent by telephony. 155 */ 156 private final Messenger mMessenger = new Messenger(new Handler() { 157 @Override 158 public void handleMessage(final Message msg) { 159 final PhoneAccountHandle handle = msg.getData() 160 .getParcelable(DATA_PHONE_ACCOUNT_HANDLE); 161 VisualVoicemailTask task = new VisualVoicemailTask(msg.replyTo, msg.arg1); 162 switch (msg.what) { 163 case MSG_ON_CELL_SERVICE_CONNECTED: 164 onCellServiceConnected(task, handle); 165 break; 166 case MSG_ON_SMS_RECEIVED: 167 VisualVoicemailSms sms = msg.getData().getParcelable(DATA_SMS); 168 onSmsReceived(task, sms); 169 break; 170 case MSG_ON_SIM_REMOVED: 171 onSimRemoved(task, handle); 172 break; 173 case MSG_TASK_STOPPED: 174 onStopped(task); 175 break; 176 default: 177 super.handleMessage(msg); 178 break; 179 } 180 } 181 }); 182 183 @Override 184 public IBinder onBind(Intent intent) { 185 return mMessenger.getBinder(); 186 } 187 188 /** 189 * Called when the cellular service is connected on a {@link PhoneAccountHandle} for the first 190 * time, or when the carrier config has changed. It will not be called when the signal is lost 191 * then restored. 192 * 193 * @param task The task representing this event. {@link VisualVoicemailTask#finish()} must be 194 * called when the task is completed. 195 * @param phoneAccountHandle The {@link PhoneAccountHandle} triggering this event. 196 */ 197 @MainThread 198 public abstract void onCellServiceConnected(VisualVoicemailTask task, 199 PhoneAccountHandle phoneAccountHandle); 200 201 /** 202 * Called when a SMS matching the {@link VisualVoicemailSmsFilterSettings} set by 203 * {@link TelephonyManager#setVisualVoicemailSmsFilterSettings(VisualVoicemailSmsFilterSettings) 204 * } 205 * is received. 206 * 207 * @param task The task representing this event. {@link VisualVoicemailTask#finish()} must be 208 * called when the task is completed. 209 * @param sms The content of the received SMS. 210 */ 211 @MainThread 212 public abstract void onSmsReceived(VisualVoicemailTask task, 213 VisualVoicemailSms sms); 214 215 /** 216 * Called when a SIM is removed. 217 * 218 * @param task The task representing this event. {@link VisualVoicemailTask#finish()} must be 219 * called when the task is completed. 220 * @param phoneAccountHandle The {@link PhoneAccountHandle} triggering this event. 221 */ 222 @MainThread 223 public abstract void onSimRemoved(VisualVoicemailTask task, 224 PhoneAccountHandle phoneAccountHandle); 225 226 /** 227 * Called before the system is about to terminate a task. The service should persist any 228 * necessary data and call finish on the task immediately. 229 */ 230 @MainThread 231 public abstract void onStopped(VisualVoicemailTask task); 232 233 /** 234 * Set the visual voicemail SMS filter settings for the VisualVoicemailService. 235 * {@link #onSmsReceived(VisualVoicemailTask, VisualVoicemailSms)} will be called when 236 * a SMS matching the settings is received. The caller should have 237 * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} and implements a 238 * VisualVoicemailService. 239 * <p> 240 * <p>Requires Permission: 241 * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} 242 * 243 * @param phoneAccountHandle The account to apply the settings to. 244 * @param settings The settings for the filter, or {@code null} to disable the filter. 245 * 246 * @hide 247 */ 248 @SystemApi 249 public static final void setSmsFilterSettings(Context context, 250 PhoneAccountHandle phoneAccountHandle, 251 VisualVoicemailSmsFilterSettings settings) { 252 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 253 int subId = getSubId(context, phoneAccountHandle); 254 if (settings == null) { 255 telephonyManager.disableVisualVoicemailSmsFilter(subId); 256 } else { 257 telephonyManager.enableVisualVoicemailSmsFilter(subId, settings); 258 } 259 } 260 261 /** 262 * Send a visual voicemail SMS. The caller must be the current default dialer. 263 * <p> 264 * <p>Requires Permission: 265 * {@link android.Manifest.permission#SEND_SMS SEND_SMS} 266 * 267 * @param phoneAccountHandle The account to send the SMS with. 268 * @param number The destination number. 269 * @param port The destination port for data SMS, or 0 for text SMS. 270 * @param text The message content. For data sms, it will be encoded as a UTF-8 byte stream. 271 * @param sentIntent The sent intent passed to the {@link SmsManager} 272 * 273 * @throws SecurityException if the caller is not the current default dialer 274 * 275 * @see SmsManager#sendDataMessage(String, String, short, byte[], PendingIntent, PendingIntent) 276 * @see SmsManager#sendTextMessage(String, String, String, PendingIntent, PendingIntent) 277 * 278 * @hide 279 */ 280 @SystemApi 281 public static final void sendVisualVoicemailSms(Context context, 282 PhoneAccountHandle phoneAccountHandle, String number, 283 short port, String text, PendingIntent sentIntent) { 284 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 285 telephonyManager.sendVisualVoicemailSmsForSubscriber(getSubId(context, phoneAccountHandle), 286 number, port, text, sentIntent); 287 } 288 289 private static int getSubId(Context context, PhoneAccountHandle phoneAccountHandle) { 290 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 291 TelecomManager telecomManager = context.getSystemService(TelecomManager.class); 292 return telephonyManager 293 .getSubIdForPhoneAccount(telecomManager.getPhoneAccount(phoneAccountHandle)); 294 } 295 296} 297