Home | History | Annotate | Download | only in telephony
      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 
    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