1 /*
2  * Copyright (C) 2019 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.service.carrier;
18 
19 import android.annotation.CallbackExecutor;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.ServiceConnection;
27 import android.net.Uri;
28 import android.os.Binder;
29 import android.os.IBinder;
30 import android.os.RemoteException;
31 import android.telephony.SmsMessage;
32 
33 import com.android.internal.util.Preconditions;
34 
35 import java.util.List;
36 import java.util.Objects;
37 import java.util.concurrent.Executor;
38 
39 /**
40  * Provides basic structure for platform to connect to the carrier messaging service.
41  * <p>
42  * <code>
43  * CarrierMessagingServiceWrapper carrierMessagingServiceWrapper =
44  *     new CarrierMessagingServiceWrapperImpl();
45  * if (carrierMessagingServiceWrapper.bindToCarrierMessagingService(context, carrierPackageName)) {
46  *   // wait for onServiceReady callback
47  * } else {
48  *   // Unable to bind: handle error.
49  * }
50  * </code>
51  * <p> Upon completion {@link #disconnect} should be called to unbind the
52  * CarrierMessagingService.
53  * @hide
54  */
55 @SystemApi
56 public final class CarrierMessagingServiceWrapper implements AutoCloseable {
57     // Populated by bindToCarrierMessagingService. bindToCarrierMessagingService must complete
58     // prior to calling disposeConnection so that mCarrierMessagingServiceConnection is initialized.
59     private volatile CarrierMessagingServiceConnection mCarrierMessagingServiceConnection;
60 
61     private volatile ICarrierMessagingService mICarrierMessagingService;
62     private Runnable mOnServiceReadyCallback;
63     private Executor mServiceReadyCallbackExecutor;
64     private Context mContext;
65 
66     /**
67      * Binds to the carrier messaging service under package {@code carrierPackageName}. This method
68      * should be called exactly once.
69      *
70      * @param context the context
71      * @param carrierPackageName the carrier package name
72      * @param executor the executor to run the callback.
73      * @param onServiceReadyCallback the callback when service becomes ready.
74      * @return true upon successfully binding to a carrier messaging service, false otherwise
75      * @hide
76      */
77     @SystemApi
bindToCarrierMessagingService(@onNull Context context, @NonNull String carrierPackageName, @NonNull @CallbackExecutor Executor executor, @NonNull Runnable onServiceReadyCallback)78     public boolean bindToCarrierMessagingService(@NonNull Context context,
79             @NonNull String carrierPackageName,
80             @NonNull @CallbackExecutor Executor executor,
81             @NonNull Runnable onServiceReadyCallback) {
82         Preconditions.checkState(mCarrierMessagingServiceConnection == null);
83         Objects.requireNonNull(context);
84         Objects.requireNonNull(carrierPackageName);
85         Objects.requireNonNull(executor);
86         Objects.requireNonNull(onServiceReadyCallback);
87 
88         Intent intent = new Intent(CarrierMessagingService.SERVICE_INTERFACE);
89         intent.setPackage(carrierPackageName);
90         mCarrierMessagingServiceConnection = new CarrierMessagingServiceConnection();
91         mOnServiceReadyCallback = onServiceReadyCallback;
92         mServiceReadyCallbackExecutor = executor;
93         mContext = context;
94         return context.bindService(intent, mCarrierMessagingServiceConnection,
95                 Context.BIND_AUTO_CREATE);
96     }
97 
98     /**
99      * Unbinds the carrier messaging service. This method should be called exactly once.
100      *
101      * @hide
102      */
103     @SystemApi
disconnect()104     public void disconnect() {
105         Preconditions.checkNotNull(mCarrierMessagingServiceConnection);
106         mContext.unbindService(mCarrierMessagingServiceConnection);
107         mCarrierMessagingServiceConnection = null;
108         mOnServiceReadyCallback = null;
109         mServiceReadyCallbackExecutor = null;
110     }
111 
112     /**
113      * Called when connection with service is established.
114      *
115      * @param carrierMessagingService the carrier messaing service interface
116      */
onServiceReady(ICarrierMessagingService carrierMessagingService)117     private void onServiceReady(ICarrierMessagingService carrierMessagingService) {
118         mICarrierMessagingService = carrierMessagingService;
119         if (mOnServiceReadyCallback != null && mServiceReadyCallbackExecutor != null) {
120             final long identity = Binder.clearCallingIdentity();
121             try {
122                 mServiceReadyCallbackExecutor.execute(mOnServiceReadyCallback);
123             } finally {
124                 Binder.restoreCallingIdentity(identity);
125             }
126         }
127     }
128 
129     /**
130      * Request the CarrierMessagingService to process an incoming SMS text or data message.
131      * The service will call callback.onFilterComplete with the filtering result.
132      *
133      * @param pdu the PDUs of the message
134      * @param format the format of the PDUs, typically "3gpp" or "3gpp2".
135      *               See {@link SmsMessage#FORMAT_3GPP} and {@link SmsMessage#FORMAT_3GPP2} for
136      *               more details.
137      * @param destPort the destination port of a data SMS. It will be -1 for text SMS
138      * @param subId SMS subscription ID of the SIM
139      * @param executor the executor to run the callback.
140      * @param callback the callback to notify upon completion
141      * @hide
142      */
143     @SystemApi
receiveSms(@onNull MessagePdu pdu, @NonNull @SmsMessage.Format String format, int destPort, int subId, @NonNull @CallbackExecutor final Executor executor, @NonNull final CarrierMessagingCallback callback)144     public void receiveSms(@NonNull MessagePdu pdu, @NonNull @SmsMessage.Format String format,
145             int destPort, int subId, @NonNull @CallbackExecutor final Executor executor,
146             @NonNull final CarrierMessagingCallback callback) {
147         if (mICarrierMessagingService != null) {
148             try {
149                 mICarrierMessagingService.filterSms(pdu, format, destPort, subId,
150                         new CarrierMessagingCallbackInternal(callback, executor));
151             } catch (RemoteException e) {
152                 throw new RuntimeException(e);
153             }
154         }
155     }
156 
157     /**
158      * Request sending a new text SMS from the device.
159      * The service will call {@link ICarrierMessagingCallback#onSendSmsComplete} with the send
160      * status.
161      *
162      * @param text the text to send
163      * @param subId SMS subscription ID of the SIM
164      * @param destAddress phone number of the recipient of the message
165      * @param sendSmsFlag Flag for sending SMS. Acceptable values are 0 and
166      *        {@link CarrierMessagingService#SEND_FLAG_REQUEST_DELIVERY_STATUS}.
167      * @param executor the executor to run the callback.
168      * @param callback the callback to notify upon completion
169      * @hide
170      */
171     @SystemApi
sendTextSms(@onNull String text, int subId, @NonNull String destAddress, @CarrierMessagingService.SendRequest int sendSmsFlag, @NonNull @CallbackExecutor final Executor executor, @NonNull final CarrierMessagingCallback callback)172     public void sendTextSms(@NonNull String text, int subId, @NonNull String destAddress,
173             @CarrierMessagingService.SendRequest int sendSmsFlag,
174             @NonNull @CallbackExecutor final Executor executor,
175             @NonNull final CarrierMessagingCallback callback) {
176         Objects.requireNonNull(mICarrierMessagingService);
177         try {
178             mICarrierMessagingService.sendTextSms(text, subId, destAddress, sendSmsFlag,
179                     new CarrierMessagingCallbackInternal(callback, executor));
180         } catch (RemoteException e) {
181             throw new RuntimeException(e);
182         }
183     }
184 
185     /**
186      * Request sending a new data SMS from the device.
187      * The service will call {@link ICarrierMessagingCallback#onSendSmsComplete} with the send
188      * status.
189      *
190      * @param data the data to send
191      * @param subId SMS subscription ID of the SIM
192      * @param destAddress phone number of the recipient of the message
193      * @param destPort port number of the recipient of the message
194      * @param sendSmsFlag Flag for sending SMS. Acceptable values are 0 and
195      *        {@link CarrierMessagingService#SEND_FLAG_REQUEST_DELIVERY_STATUS}.
196      * @param executor the executor to run the callback.
197      * @param callback the callback to notify upon completion
198      * @hide
199      */
200     @SystemApi
sendDataSms(@onNull byte[] data, int subId, @NonNull String destAddress, int destPort, @CarrierMessagingService.SendRequest int sendSmsFlag, @NonNull @CallbackExecutor final Executor executor, @NonNull final CarrierMessagingCallback callback)201     public void sendDataSms(@NonNull byte[] data, int subId, @NonNull String destAddress,
202             int destPort, @CarrierMessagingService.SendRequest int sendSmsFlag,
203             @NonNull @CallbackExecutor final Executor executor,
204             @NonNull final CarrierMessagingCallback callback) {
205         Objects.requireNonNull(mICarrierMessagingService);
206         try {
207             mICarrierMessagingService.sendDataSms(data, subId, destAddress, destPort,
208                     sendSmsFlag, new CarrierMessagingCallbackInternal(
209                             callback, executor));
210         } catch (RemoteException e) {
211             throw new RuntimeException(e);
212         }
213     }
214 
215     /**
216      * Request sending a new multi-part text SMS from the device.
217      * The service will call {@link ICarrierMessagingCallback#onSendMultipartSmsComplete}
218      * with the send status.
219      *
220      * @param parts the parts of the multi-part text SMS to send
221      * @param subId SMS subscription ID of the SIM
222      * @param destAddress phone number of the recipient of the message
223      * @param sendSmsFlag Flag for sending SMS. Acceptable values are 0 and
224      *        {@link CarrierMessagingService#SEND_FLAG_REQUEST_DELIVERY_STATUS}.
225      * @param executor the executor to run the callback.
226      * @param callback the callback to notify upon completion
227      * @hide
228      */
229     @SystemApi
sendMultipartTextSms(@onNull List<String> parts, int subId, @NonNull String destAddress, @CarrierMessagingService.SendRequest int sendSmsFlag, @NonNull @CallbackExecutor final Executor executor, @NonNull final CarrierMessagingCallback callback)230     public void sendMultipartTextSms(@NonNull List<String> parts, int subId,
231             @NonNull String destAddress,
232             @CarrierMessagingService.SendRequest int sendSmsFlag,
233             @NonNull @CallbackExecutor final Executor executor,
234             @NonNull final CarrierMessagingCallback callback) {
235         Objects.requireNonNull(mICarrierMessagingService);
236         try {
237             mICarrierMessagingService.sendMultipartTextSms(parts, subId, destAddress,
238                     sendSmsFlag, new CarrierMessagingCallbackInternal(callback, executor));
239         } catch (RemoteException e) {
240             throw new RuntimeException(e);
241         }
242     }
243 
244     /**
245      * Request sending a new MMS PDU from the device.
246      * The service will call {@link ICarrierMessagingCallback#onSendMmsComplete} with the send
247      * status.
248      *
249      * @param pduUri the content provider URI of the PDU to send
250      * @param subId SMS subscription ID of the SIM
251      * @param location the optional URI to send this MMS PDU. If this is {code null},
252      *        the PDU should be sent to the default MMSC URL.
253      * @param executor the executor to run the callback.
254      * @param callback the callback to notify upon completion
255      * @hide
256      */
257     @SystemApi
sendMms(@onNull Uri pduUri, int subId, @NonNull Uri location, @NonNull @CallbackExecutor final Executor executor, @NonNull final CarrierMessagingCallback callback)258     public void sendMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
259             @NonNull @CallbackExecutor final Executor executor,
260             @NonNull final CarrierMessagingCallback callback) {
261         Objects.requireNonNull(mICarrierMessagingService);
262         try {
263             mICarrierMessagingService.sendMms(pduUri, subId, location,
264                     new CarrierMessagingCallbackInternal(callback, executor));
265         } catch (RemoteException e) {
266             throw new RuntimeException(e);
267         }
268     }
269 
270     /**
271      * Request downloading a new MMS.
272      * The service will call {@link ICarrierMessagingCallback#onDownloadMmsComplete} with the
273      * download status.
274      *
275      * @param pduUri the content provider URI of the PDU to be downloaded.
276      * @param subId SMS subscription ID of the SIM
277      * @param location the URI of the message to be downloaded.
278      * @param executor the executor to run the callback.
279      * @param callback the callback to notify upon completion
280      * @hide
281      */
282     @SystemApi
downloadMms(@onNull Uri pduUri, int subId, @NonNull Uri location, @NonNull @CallbackExecutor final Executor executor, @NonNull final CarrierMessagingCallback callback)283     public void downloadMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
284             @NonNull @CallbackExecutor final Executor executor,
285             @NonNull final CarrierMessagingCallback callback) {
286         Objects.requireNonNull(mICarrierMessagingService);
287         try {
288             mICarrierMessagingService.downloadMms(pduUri, subId, location,
289                     new CarrierMessagingCallbackInternal(callback, executor));
290         } catch (RemoteException e) {
291             throw new RuntimeException(e);
292         }
293     }
294 
295     /** @hide */
296     @Override
close()297     public void close() {
298         disconnect();
299     }
300 
301     /**
302      * A basic {@link ServiceConnection}.
303      */
304     private final class CarrierMessagingServiceConnection implements ServiceConnection {
305         @Override
onServiceConnected(ComponentName name, IBinder service)306         public void onServiceConnected(ComponentName name, IBinder service) {
307             onServiceReady(ICarrierMessagingService.Stub.asInterface(service));
308         }
309 
310         @Override
onServiceDisconnected(ComponentName name)311         public void onServiceDisconnected(ComponentName name) {
312         }
313     }
314 
315     /**
316      * Callback wrapper used for response to requests exposed by
317      * {@link CarrierMessagingServiceWrapper}.
318      * @hide
319      */
320     @SystemApi
321     public interface CarrierMessagingCallback {
322         /**
323          * Response callback for {@link CarrierMessagingServiceWrapper#receiveSms}.
324          * @param result a bitmask integer to indicate how the incoming text SMS should be handled
325          *               by the platform. Bits set can be
326          *               {@link CarrierMessagingService#RECEIVE_OPTIONS_DROP} and
327          *               {@link CarrierMessagingService#
328          *               RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE}.
329          *               {@link CarrierMessagingService#onReceiveTextSms}.
330          */
onReceiveSmsComplete( @arrierMessagingService.FilterCompleteResult int result)331         default void onReceiveSmsComplete(
332                 @CarrierMessagingService.FilterCompleteResult int result) {
333 
334         }
335 
336         /**
337          * Response callback for {@link CarrierMessagingServiceWrapper#sendTextSms} and
338          * {@link CarrierMessagingServiceWrapper#sendDataSms}.
339          * @param result send status, one of {@link CarrierMessagingService#SEND_STATUS_OK},
340          *               {@link CarrierMessagingService#SEND_STATUS_RETRY_ON_CARRIER_NETWORK},
341          *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
342          * @param messageRef message reference of the just-sent message. This field is applicable
343          *                   only if result is {@link CarrierMessagingService#SEND_STATUS_OK}.
344          */
onSendSmsComplete(@arrierMessagingService.SendResult int result, int messageRef)345         default void onSendSmsComplete(@CarrierMessagingService.SendResult
346                 int result, int messageRef) {
347         }
348 
349         /**
350          * Response callback for {@link CarrierMessagingServiceWrapper#sendMultipartTextSms}.
351          * @param result send status, one of {@link CarrierMessagingService#SEND_STATUS_OK},
352          *               {@link CarrierMessagingService#SEND_STATUS_RETRY_ON_CARRIER_NETWORK},
353          *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
354          * @param messageRefs an array of message references, one for each part of the
355          *                    multipart SMS. This field is applicable only if result is
356          *                    {@link CarrierMessagingService#SEND_STATUS_OK}.
357          */
onSendMultipartSmsComplete(@arrierMessagingService.SendResult int result, @Nullable int[] messageRefs)358         default void onSendMultipartSmsComplete(@CarrierMessagingService.SendResult
359                 int result, @Nullable int[] messageRefs) {
360 
361         }
362 
363         /**
364          * Response callback for {@link CarrierMessagingServiceWrapper#sendMms}.
365          * @param result send status, one of {@link CarrierMessagingService#SEND_STATUS_OK},
366          *               {@link CarrierMessagingService#SEND_STATUS_RETRY_ON_CARRIER_NETWORK},
367          *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
368          * @param sendConfPdu a possibly {code null} SendConf PDU, which confirms that the message
369          *                    was sent. sendConfPdu is ignored if the {@code result} is not
370          *                    {@link CarrierMessagingService#SEND_STATUS_OK}.
371          */
onSendMmsComplete(@arrierMessagingService.SendResult int result, @Nullable byte[] sendConfPdu)372         default void onSendMmsComplete(@CarrierMessagingService.SendResult
373                 int result, @Nullable byte[] sendConfPdu) {
374 
375         }
376 
377         /**
378          * Response callback for {@link CarrierMessagingServiceWrapper#downloadMms}.
379          * @param result download status, one of {@link CarrierMessagingService#DOWNLOAD_STATUS_OK},
380          *               {@link CarrierMessagingService#DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK},
381          *               and {@link CarrierMessagingService#DOWNLOAD_STATUS_ERROR}.
382          */
onDownloadMmsComplete(@arrierMessagingService.DownloadResult int result)383         default void onDownloadMmsComplete(@CarrierMessagingService.DownloadResult
384                 int result) {
385 
386         }
387     }
388 
389     private final class CarrierMessagingCallbackInternal
390             extends ICarrierMessagingCallback.Stub {
391         final CarrierMessagingCallback mCarrierMessagingCallback;
392         final Executor mExecutor;
393 
CarrierMessagingCallbackInternal(CarrierMessagingCallback callback, final Executor executor)394         CarrierMessagingCallbackInternal(CarrierMessagingCallback callback,
395                 final Executor executor) {
396             mCarrierMessagingCallback = callback;
397             mExecutor = executor;
398         }
399 
400         @Override
onFilterComplete(int result)401         public void onFilterComplete(int result) throws RemoteException {
402             mExecutor.execute(() -> mCarrierMessagingCallback.onReceiveSmsComplete(result));
403         }
404 
405         @Override
onSendSmsComplete(int result, int messageRef)406         public void onSendSmsComplete(int result, int messageRef) throws RemoteException {
407             mExecutor.execute(() -> mCarrierMessagingCallback.onSendSmsComplete(
408                     result, messageRef));
409         }
410 
411         @Override
onSendMultipartSmsComplete(int result, int[] messageRefs)412         public void onSendMultipartSmsComplete(int result, int[] messageRefs)
413                 throws RemoteException {
414             mExecutor.execute(() -> mCarrierMessagingCallback.onSendMultipartSmsComplete(
415                     result, messageRefs));
416         }
417 
418         @Override
onSendMmsComplete(int result, byte[] sendConfPdu)419         public void onSendMmsComplete(int result, byte[] sendConfPdu) throws RemoteException {
420             mExecutor.execute(() -> mCarrierMessagingCallback.onSendMmsComplete(
421                     result, sendConfPdu));
422         }
423 
424         @Override
onDownloadMmsComplete(int result)425         public void onDownloadMmsComplete(int result) throws RemoteException {
426             mExecutor.execute(() -> mCarrierMessagingCallback.onDownloadMmsComplete(result));
427         }
428     }
429 }
430