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