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 
17 package android.telephony;
18 
19 import android.annotation.MainThread;
20 import android.annotation.SdkConstant;
21 import android.annotation.SystemApi;
22 import android.app.PendingIntent;
23 import android.app.Service;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.os.Bundle;
27 import android.os.Handler;
28 import android.os.IBinder;
29 import android.os.Message;
30 import android.os.Messenger;
31 import android.os.RemoteException;
32 import android.telecom.PhoneAccountHandle;
33 import android.telecom.TelecomManager;
34 import 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  */
61 public 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 
VisualVoicemailTask(Messenger replyTo, int taskId)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          */
finish()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
equals(Object obj)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
hashCode()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
onBind(Intent intent)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
onCellServiceConnected(VisualVoicemailTask task, PhoneAccountHandle phoneAccountHandle)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
onSmsReceived(VisualVoicemailTask task, VisualVoicemailSms sms)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
onSimRemoved(VisualVoicemailTask task, PhoneAccountHandle phoneAccountHandle)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
onStopped(VisualVoicemailTask task)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
setSmsFilterSettings(Context context, PhoneAccountHandle phoneAccountHandle, VisualVoicemailSmsFilterSettings settings)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
sendVisualVoicemailSms(Context context, PhoneAccountHandle phoneAccountHandle, String number, short port, String text, PendingIntent sentIntent)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 
getSubId(Context context, PhoneAccountHandle phoneAccountHandle)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