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