diff options
author | frankfeng <frankfeng@google.com> | 2021-12-23 22:16:17 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-12-23 22:16:17 +0000 |
commit | 233a9846391b42adcaa36eea9f39980dedb43be2 (patch) | |
tree | 71f65f7f55b0604e60173d7004994baa85e97c35 /src/main/java/com/google/android/mobly/snippet/bundled/SmsSnippet.java | |
parent | bcbece2f1ebff711bbb8358a4dc709420d93e3a1 (diff) | |
parent | b3028abea8c6094b70814268affd960294cb72a6 (diff) | |
download | mobly-bundled-snippets-233a9846391b42adcaa36eea9f39980dedb43be2.tar.gz |
Merge remote-tracking branch 'aosp/upstream-master' into mymerge am: b3028abea8
Original change: https://android-review.googlesource.com/c/platform/external/mobly-bundled-snippets/+/1932819
Change-Id: I1c95dee299fd6b1ebd2a4dd7e83252e5b0275bf7
Diffstat (limited to 'src/main/java/com/google/android/mobly/snippet/bundled/SmsSnippet.java')
-rw-r--r-- | src/main/java/com/google/android/mobly/snippet/bundled/SmsSnippet.java | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/SmsSnippet.java b/src/main/java/com/google/android/mobly/snippet/bundled/SmsSnippet.java new file mode 100644 index 0000000..be41e9e --- /dev/null +++ b/src/main/java/com/google/android/mobly/snippet/bundled/SmsSnippet.java @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2017 Google Inc. + * + * 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 com.google.android.mobly.snippet.bundled; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Build; +import android.os.Bundle; +import android.provider.Telephony.Sms.Intents; +import android.telephony.SmsManager; +import android.telephony.SmsMessage; +import androidx.test.platform.app.InstrumentationRegistry; +import com.google.android.mobly.snippet.Snippet; +import com.google.android.mobly.snippet.bundled.utils.Utils; +import com.google.android.mobly.snippet.event.EventCache; +import com.google.android.mobly.snippet.event.SnippetEvent; +import com.google.android.mobly.snippet.rpc.AsyncRpc; +import com.google.android.mobly.snippet.rpc.Rpc; +import java.util.ArrayList; +import org.json.JSONObject; + +/** Snippet class for SMS RPCs. */ +public class SmsSnippet implements Snippet { + + private static class SmsSnippetException extends Exception { + private static final long serialVersionUID = 1L; + + SmsSnippetException(String msg) { + super(msg); + } + } + + private static final int MAX_CHAR_COUNT_PER_SMS = 160; + private static final String SMS_SENT_ACTION = ".SMS_SENT"; + private static final int DEFAULT_TIMEOUT_MILLISECOND = 60 * 1000; + private static final String SMS_RECEIVED_EVENT_NAME = "ReceivedSms"; + private static final String SMS_SENT_EVENT_NAME = "SentSms"; + private static final String SMS_CALLBACK_ID_PREFIX = "sendSms-"; + + private static int mCallbackCounter = 0; + + private final Context mContext; + private final SmsManager mSmsManager; + + public SmsSnippet() { + this.mContext = InstrumentationRegistry.getInstrumentation().getContext(); + this.mSmsManager = SmsManager.getDefault(); + } + + /** + * Send SMS and return after waiting for send confirmation (with a timeout of 60 seconds). + * + * @param phoneNumber A String representing phone number with country code. + * @param message A String representing the message to send. + * @throws SmsSnippetException on SMS send error. + */ + @Rpc(description = "Send SMS to a specified phone number.") + public void sendSms(String phoneNumber, String message) throws Throwable { + String callbackId = SMS_CALLBACK_ID_PREFIX + (++mCallbackCounter); + OutboundSmsReceiver receiver = new OutboundSmsReceiver(mContext, callbackId); + + if (message.length() > MAX_CHAR_COUNT_PER_SMS) { + ArrayList<String> parts = mSmsManager.divideMessage(message); + ArrayList<PendingIntent> sIntents = new ArrayList<>(); + for (int i = 0; i < parts.size(); i++) { + sIntents.add( + PendingIntent.getBroadcast(mContext, 0, new Intent(SMS_SENT_ACTION), 0)); + } + receiver.setExpectedMessageCount(parts.size()); + mContext.registerReceiver(receiver, new IntentFilter(SMS_SENT_ACTION)); + mSmsManager.sendMultipartTextMessage(phoneNumber, null, parts, sIntents, null); + } else { + PendingIntent sentIntent = + PendingIntent.getBroadcast(mContext, 0, new Intent(SMS_SENT_ACTION), 0); + receiver.setExpectedMessageCount(1); + mContext.registerReceiver(receiver, new IntentFilter(SMS_SENT_ACTION)); + mSmsManager.sendTextMessage(phoneNumber, null, message, sentIntent, null); + } + + SnippetEvent result = + Utils.waitForSnippetEvent( + callbackId, SMS_SENT_EVENT_NAME, DEFAULT_TIMEOUT_MILLISECOND); + + if (result.getData().containsKey("error")) { + throw new SmsSnippetException( + "Failed to send SMS, error code: " + result.getData().getInt("error")); + } + } + + @TargetApi(Build.VERSION_CODES.KITKAT) + @AsyncRpc(description = "Async wait for incoming SMS message.") + public void asyncWaitForSms(String callbackId) { + SmsReceiver receiver = new SmsReceiver(mContext, callbackId); + mContext.registerReceiver(receiver, new IntentFilter(Intents.SMS_RECEIVED_ACTION)); + } + + @TargetApi(Build.VERSION_CODES.KITKAT) + @Rpc(description = "Wait for incoming SMS message.") + public JSONObject waitForSms(int timeoutMillis) throws Throwable { + String callbackId = SMS_CALLBACK_ID_PREFIX + (++mCallbackCounter); + SmsReceiver receiver = new SmsReceiver(mContext, callbackId); + mContext.registerReceiver(receiver, new IntentFilter(Intents.SMS_RECEIVED_ACTION)); + return Utils.waitForSnippetEvent(callbackId, SMS_RECEIVED_EVENT_NAME, timeoutMillis) + .toJson(); + } + + @Override + public void shutdown() {} + + private static class OutboundSmsReceiver extends BroadcastReceiver { + private final String mCallbackId; + private Context mContext; + private final EventCache mEventCache; + private int mExpectedMessageCount; + + public OutboundSmsReceiver(Context context, String callbackId) { + this.mCallbackId = callbackId; + this.mContext = context; + this.mEventCache = EventCache.getInstance(); + mExpectedMessageCount = 0; + } + + public void setExpectedMessageCount(int count) { + mExpectedMessageCount = count; + } + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + + if (SMS_SENT_ACTION.equals(action)) { + SnippetEvent event = new SnippetEvent(mCallbackId, SMS_SENT_EVENT_NAME); + switch (getResultCode()) { + case Activity.RESULT_OK: + if (mExpectedMessageCount == 1) { + event.getData().putBoolean("sent", true); + mEventCache.postEvent(event); + mContext.unregisterReceiver(this); + } + + if (mExpectedMessageCount > 0) { + mExpectedMessageCount--; + } + break; + case SmsManager.RESULT_ERROR_GENERIC_FAILURE: + case SmsManager.RESULT_ERROR_NO_SERVICE: + case SmsManager.RESULT_ERROR_NULL_PDU: + case SmsManager.RESULT_ERROR_RADIO_OFF: + event.getData().putBoolean("sent", false); + event.getData().putInt("error_code", getResultCode()); + mEventCache.postEvent(event); + mContext.unregisterReceiver(this); + break; + default: + event.getData().putBoolean("sent", false); + event.getData().putInt("error_code", -1 /* Unknown */); + mEventCache.postEvent(event); + mContext.unregisterReceiver(this); + break; + } + } + } + } + + private static class SmsReceiver extends BroadcastReceiver { + private final String mCallbackId; + private Context mContext; + private final EventCache mEventCache; + + public SmsReceiver(Context context, String callbackId) { + this.mCallbackId = callbackId; + this.mContext = context; + this.mEventCache = EventCache.getInstance(); + } + + @TargetApi(Build.VERSION_CODES.KITKAT) + @Override + public void onReceive(Context receivedContext, Intent intent) { + if (Intents.SMS_RECEIVED_ACTION.equals(intent.getAction())) { + SnippetEvent event = new SnippetEvent(mCallbackId, SMS_RECEIVED_EVENT_NAME); + Bundle extras = intent.getExtras(); + if (extras != null) { + SmsMessage[] msgs = Intents.getMessagesFromIntent(intent); + StringBuilder smsMsg = new StringBuilder(); + + SmsMessage sms = msgs[0]; + String sender = sms.getOriginatingAddress(); + event.getData().putString("OriginatingAddress", sender); + + for (SmsMessage msg : msgs) { + smsMsg.append(msg.getMessageBody()); + } + event.getData().putString("MessageBody", smsMsg.toString()); + mEventCache.postEvent(event); + mContext.unregisterReceiver(this); + } + } + } + } +} |