/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.telephony;

import android.annotation.MainThread;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.util.Log;

This service is implemented by dialer apps that wishes to handle OMTP or similar visual voicemails. Telephony binds to this service when the cell service is first connected, a visual voicemail SMS has been received, or when a SIM has been removed. Telephony will only bind to the default dialer for such events (See TelecomManager.getDefaultDialerPackage()). The CarrierMessagingService precedes the VisualVoicemailService in the SMS filtering chain and may intercept the visual voicemail SMS before it reaches this service.

To extend this class, The service must be declared in the manifest file with the BIND_VISUAL_VOICEMAIL_SERVICE.BIND_VISUAL_VOICEMAIL_SERVICE permission and include an intent filter with the SERVICE_INTERFACE action.

Below is an example manifest registration for a VisualVoicemailService.


<service android:name="your.package.YourVisualVoicemailServiceImplementation"
         android:permission="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE">
     <intent-filter>
         <action android:name="android.telephony.VisualVoicemailService"/>
     </intent-filter>
</service>
 
/** * This service is implemented by dialer apps that wishes to handle OMTP or similar visual * voicemails. Telephony binds to this service when the cell service is first connected, a visual * voicemail SMS has been received, or when a SIM has been removed. Telephony will only bind to the * default dialer for such events (See {@link TelecomManager#getDefaultDialerPackage()}). The * {@link android.service.carrier.CarrierMessagingService} precedes the VisualVoicemailService in * the SMS filtering chain and may intercept the visual voicemail SMS before it reaches this * service. * <p> * To extend this class, The service must be declared in the manifest file with * the {@link android.Manifest.permission#BIND_VISUAL_VOICEMAIL_SERVICE} permission and include an * intent filter with the {@link #SERVICE_INTERFACE} action. * <p> * Below is an example manifest registration for a {@code VisualVoicemailService}. * <pre> * {@code * <service android:name="your.package.YourVisualVoicemailServiceImplementation" * android:permission="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"> * <intent-filter> * <action android:name="android.telephony.VisualVoicemailService"/> * </intent-filter> * </service> * } * </pre> */
public abstract class VisualVoicemailService extends Service { private static final String TAG = "VvmService";
The Intent that must be declared as handled by the service.
/** * The {@link Intent} that must be declared as handled by the service. */
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) public static final String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService";
@hide
/** * @hide */
public static final int MSG_ON_CELL_SERVICE_CONNECTED = 1;
@hide
/** * @hide */
public static final int MSG_ON_SMS_RECEIVED = 2;
@hide
/** * @hide */
public static final int MSG_ON_SIM_REMOVED = 3;
@hide
/** * @hide */
public static final int MSG_TASK_ENDED = 4;
@hide
/** * @hide */
public static final int MSG_TASK_STOPPED = 5;
@hide
/** * @hide */
public static final String DATA_PHONE_ACCOUNT_HANDLE = "data_phone_account_handle";
@hide
/** * @hide */
public static final String DATA_SMS = "data_sms";
Represents a visual voicemail event which needs to be handled. While the task is being processed telephony will hold a wakelock for the VisualVoicemailService. The service can unblock the main thread and pass the task to a worker thread. Once the task is finished, finish() should be called to signal telephony to release the resources. Telephony will call VisualVoicemailService.onStopped(VisualVoicemailTask) when the task is going to be terminated before completion.
See Also:
/** * Represents a visual voicemail event which needs to be handled. While the task is being * processed telephony will hold a wakelock for the VisualVoicemailService. The service can * unblock the main thread and pass the task to a worker thread. Once the task is finished, * {@link VisualVoicemailTask#finish()} should be called to signal telephony to release the * resources. Telephony will call {@link VisualVoicemailService#onStopped(VisualVoicemailTask)} * when the task is going to be terminated before completion. * * @see #onCellServiceConnected(VisualVoicemailTask, PhoneAccountHandle) * @see #onSmsReceived(VisualVoicemailTask, VisualVoicemailSms) * @see #onSimRemoved(VisualVoicemailTask, PhoneAccountHandle) * @see #onStopped(VisualVoicemailTask) */
public static class VisualVoicemailTask { private final int mTaskId; private final Messenger mReplyTo; private VisualVoicemailTask(Messenger replyTo, int taskId) { mTaskId = taskId; mReplyTo = replyTo; }
Call to signal telephony the task has completed. Must be called for every task.
/** * Call to signal telephony the task has completed. Must be called for every task. */
public final void finish() { Message message = Message.obtain(); try { message.what = MSG_TASK_ENDED; message.arg1 = mTaskId; mReplyTo.send(message); } catch (RemoteException e) { Log.e(TAG, "Cannot send MSG_TASK_ENDED, remote handler no longer exist"); } } @Override public boolean equals(Object obj) { if (!(obj instanceof VisualVoicemailTask)) { return false; } return mTaskId == ((VisualVoicemailTask) obj).mTaskId; } @Override public int hashCode() { return mTaskId; } }
Handles messages sent by telephony.
/** * Handles messages sent by telephony. */
private final Messenger mMessenger = new Messenger(new Handler() { @Override public void handleMessage(final Message msg) { final PhoneAccountHandle handle = msg.getData() .getParcelable(DATA_PHONE_ACCOUNT_HANDLE); VisualVoicemailTask task = new VisualVoicemailTask(msg.replyTo, msg.arg1); switch (msg.what) { case MSG_ON_CELL_SERVICE_CONNECTED: onCellServiceConnected(task, handle); break; case MSG_ON_SMS_RECEIVED: VisualVoicemailSms sms = msg.getData().getParcelable(DATA_SMS); onSmsReceived(task, sms); break; case MSG_ON_SIM_REMOVED: onSimRemoved(task, handle); break; case MSG_TASK_STOPPED: onStopped(task); break; default: super.handleMessage(msg); break; } } }); @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); }
Called when the cellular service is connected on a PhoneAccountHandle for the first time, or when the carrier config has changed. It will not be called when the signal is lost then restored.
Params:
/** * Called when the cellular service is connected on a {@link PhoneAccountHandle} for the first * time, or when the carrier config has changed. It will not be called when the signal is lost * then restored. * * @param task The task representing this event. {@link VisualVoicemailTask#finish()} must be * called when the task is completed. * @param phoneAccountHandle The {@link PhoneAccountHandle} triggering this event. */
@MainThread public abstract void onCellServiceConnected(VisualVoicemailTask task, PhoneAccountHandle phoneAccountHandle);
Params:
  • task – The task representing this event. VisualVoicemailTask.finish() must be called when the task is completed.
  • sms – The content of the received SMS.
/** * Called when a SMS matching the {@link VisualVoicemailSmsFilterSettings} set by * {@link TelephonyManager#setVisualVoicemailSmsFilterSettings(VisualVoicemailSmsFilterSettings) * } * is received. * * @param task The task representing this event. {@link VisualVoicemailTask#finish()} must be * called when the task is completed. * @param sms The content of the received SMS. */
@MainThread public abstract void onSmsReceived(VisualVoicemailTask task, VisualVoicemailSms sms);
Called when a SIM is removed.
Params:
/** * Called when a SIM is removed. * * @param task The task representing this event. {@link VisualVoicemailTask#finish()} must be * called when the task is completed. * @param phoneAccountHandle The {@link PhoneAccountHandle} triggering this event. */
@MainThread public abstract void onSimRemoved(VisualVoicemailTask task, PhoneAccountHandle phoneAccountHandle);
Called before the system is about to terminate a task. The service should persist any necessary data and call finish on the task immediately.
/** * Called before the system is about to terminate a task. The service should persist any * necessary data and call finish on the task immediately. */
@MainThread public abstract void onStopped(VisualVoicemailTask task);
Set the visual voicemail SMS filter settings for the VisualVoicemailService. onSmsReceived(VisualVoicemailTask, VisualVoicemailSms) will be called when a SMS matching the settings is received. The caller should have READ_PHONE_STATE and implements a VisualVoicemailService.

Requires Permission: READ_PHONE_STATE

Params:
  • phoneAccountHandle – The account to apply the settings to.
  • settings – The settings for the filter, or null to disable the filter.
@hide
/** * Set the visual voicemail SMS filter settings for the VisualVoicemailService. * {@link #onSmsReceived(VisualVoicemailTask, VisualVoicemailSms)} will be called when * a SMS matching the settings is received. The caller should have * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} and implements a * VisualVoicemailService. * <p> * <p>Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * * @param phoneAccountHandle The account to apply the settings to. * @param settings The settings for the filter, or {@code null} to disable the filter. * * @hide */
@SystemApi public static final void setSmsFilterSettings(Context context, PhoneAccountHandle phoneAccountHandle, VisualVoicemailSmsFilterSettings settings) { TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); int subId = getSubId(context, phoneAccountHandle); if (settings == null) { telephonyManager.disableVisualVoicemailSmsFilter(subId); } else { telephonyManager.enableVisualVoicemailSmsFilter(subId, settings); } }
Send a visual voicemail SMS. The caller must be the current default dialer.

Requires Permission: SEND_SMS

Params:
  • phoneAccountHandle – The account to send the SMS with.
  • number – The destination number.
  • port – The destination port for data SMS, or 0 for text SMS.
  • text – The message content. For data sms, it will be encoded as a UTF-8 byte stream.
  • sentIntent – The sent intent passed to the SmsManager
Throws:
See Also:
@hide
/** * Send a visual voicemail SMS. The caller must be the current default dialer. * <p> * <p>Requires Permission: * {@link android.Manifest.permission#SEND_SMS SEND_SMS} * * @param phoneAccountHandle The account to send the SMS with. * @param number The destination number. * @param port The destination port for data SMS, or 0 for text SMS. * @param text The message content. For data sms, it will be encoded as a UTF-8 byte stream. * @param sentIntent The sent intent passed to the {@link SmsManager} * * @throws SecurityException if the caller is not the current default dialer * * @see SmsManager#sendDataMessage(String, String, short, byte[], PendingIntent, PendingIntent) * @see SmsManager#sendTextMessage(String, String, String, PendingIntent, PendingIntent) * * @hide */
@SystemApi public static final void sendVisualVoicemailSms(Context context, PhoneAccountHandle phoneAccountHandle, String number, short port, String text, PendingIntent sentIntent) { TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); telephonyManager.sendVisualVoicemailSmsForSubscriber(getSubId(context, phoneAccountHandle), number, port, text, sentIntent); } private static int getSubId(Context context, PhoneAccountHandle phoneAccountHandle) { TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); TelecomManager telecomManager = context.getSystemService(TelecomManager.class); return telephonyManager .getSubIdForPhoneAccount(telecomManager.getPhoneAccount(phoneAccountHandle)); } }