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