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