blob: 1e89df70d7f154f1d31df8d1345fbd3882a9a608 [file] [log] [blame]
/*
* Copyright (C) 2014 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.googlecode.android_scripting.facade;
import android.app.Activity;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.provider.Telephony.Sms.Intents;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import com.googlecode.android_scripting.Log;
import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
import com.googlecode.android_scripting.rpc.Rpc;
import com.googlecode.android_scripting.rpc.RpcParameter;
import java.util.ArrayList;
//import android.telephony.ServiceState;
/**
* Exposes SmsManager functionality.
*
*/
public class SmsFacade extends RpcReceiver {
private final EventFacade mEventFacade;
private final SmsManager mSms;
private final Service mService;
private IntentFilter mSmsReceived;
private BroadcastReceiver mSmsSendListener;
private BroadcastReceiver mSmsIncomingListener;
private int mNumExpectedSentEvents;
private int mNumReceivedSentEvents;
private int mNumExpectedDeliveredEvents;
private int mNumReceivedDeliveredEvents;
private Intent mSendIntent;
private Intent mDeliveredIntent;
private static final String MESSAGE_STATUS_DELIVERED_ACTION =
"com.googlecode.android_scripting.sms.MESSAGE_STATUS_DELIVERED";
private static final String MESSAGE_SENT_ACTION =
"com.googlecode.android_scripting.sms.MESSAGE_SENT";
private static final String MESSAGE_RECEIVED_ACTION =
"android.provider.Telephony.SMS_RECEIVED";
private final int MAX_MESSAGE_LENGTH = 160;
private final int INTERNATIONAL_NUMBER_LENGTH = 12;
private final int DOMESTIC_NUMBER_LENGTH = 10;
public SmsFacade(FacadeManager manager) {
super(manager);
mService = manager.getService();
mSms = SmsManager.getDefault();
mEventFacade = manager.getReceiver(EventFacade.class);
mSmsSendListener = new SmsSendListener();
mSmsIncomingListener = new SmsIncomingListener();
mNumExpectedSentEvents = 0;
mNumReceivedSentEvents = 0;
mNumExpectedDeliveredEvents = 0;
mNumReceivedDeliveredEvents = 0;
mSendIntent = new Intent(MESSAGE_SENT_ACTION);
mDeliveredIntent = new Intent(MESSAGE_STATUS_DELIVERED_ACTION);
IntentFilter filter = new IntentFilter();
filter.addAction(MESSAGE_SENT_ACTION);
filter.addAction(MESSAGE_STATUS_DELIVERED_ACTION);
mService.registerReceiver(mSmsSendListener, filter);
}
@Rpc(description = "Starts tracking incoming SMS.")
public void smsStartTrackingIncomingMessage() {
mSmsReceived = new IntentFilter(MESSAGE_RECEIVED_ACTION);
mService.registerReceiver(mSmsIncomingListener, mSmsReceived);
}
@Rpc(description = "Stops tracking incoming SMS.")
public void smsStopTrackingIncomingMessage() {
mService.unregisterReceiver(mSmsIncomingListener);
}
@Rpc(description = "Send a text message to a specified number.")
public void smsSendTextMessage(
@RpcParameter(name = "phoneNumber")
String phoneNumber,
@RpcParameter(name = "message")
String message,
@RpcParameter(name = "deliveryReportRequired")
Boolean deliveryReportRequired) {
if(message.length() > MAX_MESSAGE_LENGTH) {
ArrayList<String> messagesParts = mSms.divideMessage(message);
mNumExpectedSentEvents = mNumExpectedDeliveredEvents = messagesParts.size();
ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();
ArrayList<PendingIntent> deliveredIntents = new ArrayList<PendingIntent>();
for (int i = 0; i < messagesParts.size(); i++) {
sentIntents.add(PendingIntent.getBroadcast(mService, 0, mSendIntent, 0));
deliveredIntents.add(PendingIntent.getBroadcast(mService, 0, mDeliveredIntent, 0));
}
mSms.sendMultipartTextMessage(phoneNumber, null, messagesParts, sentIntents, deliveredIntents);
} else {
mNumExpectedSentEvents = mNumExpectedDeliveredEvents = 1;
PendingIntent sentIntent = PendingIntent.getBroadcast(mService, 0, mSendIntent, 0);
PendingIntent deliveredIntent = PendingIntent.getBroadcast(mService, 0, mDeliveredIntent, 0);
mSms.sendTextMessage(phoneNumber, null, message, sentIntent, deliveredIntent);
}
}
@Rpc(description = "Retrieves all messages currently stored on ICC.")
public ArrayList<SmsMessage> smsGetAllMessagesFromIcc() {
return SmsManager.getDefault().getAllMessagesFromIcc();
}
private class SmsSendListener extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle event = new Bundle();
event.putString("Type", "SmsDeliverStatus");
String action = intent.getAction();
int resultCode = getResultCode();
if (MESSAGE_STATUS_DELIVERED_ACTION.equals(action)) {
if (resultCode == Activity.RESULT_OK) {
mNumReceivedDeliveredEvents++;
if(mNumReceivedDeliveredEvents == mNumExpectedDeliveredEvents ) {
Log.d("SMS Message delivered successfully");
mEventFacade.postEvent("onSmsDeliverSuccess", event);
mNumReceivedDeliveredEvents = 0;
}
} else {
Log.e("SMS Message delivery failed");
// TODO . Need to find the reason for failure from pdu
mEventFacade.postEvent("onSmsDeliverFailure", event);
}
} else if (MESSAGE_SENT_ACTION.equals(action)) {
if (resultCode == Activity.RESULT_OK) {
mNumReceivedSentEvents++;
if(mNumReceivedSentEvents == mNumExpectedSentEvents ) {
event.putString("Type", "SmsSentSuccess");
Log.d("SMS Message sent successfully");
mEventFacade.postEvent("onSmsSentSuccess", event);
mNumReceivedSentEvents = 0;
}
} else {
Log.e("SMS Message send failed");
event.putString("Type", "SmsSentFailure");
switch(resultCode) {
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
event.putString("Reason", "GenericFailure");
break;
case SmsManager.RESULT_ERROR_RADIO_OFF :
event.putString("Reason", "RadioOff");
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
event.putString("Reason", "NullPdu");
break;
case SmsManager.RESULT_ERROR_NO_SERVICE :
event.putString("Reason", "NoService");
break;
case SmsManager.RESULT_ERROR_LIMIT_EXCEEDED :
event.putString("Reason", "LimitExceeded");
break;
case SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE :
event.putString("Reason", "FdnCheckFailure");
break;
default:
event.putString("Reason", "Unknown");
break;
}
mEventFacade.postEvent("onSmsSentFailure", event);
}
}
}
}
private class SmsIncomingListener extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (MESSAGE_RECEIVED_ACTION.equals(action)) {
Log.d("New SMS Received");
Bundle extras = intent.getExtras();
if (extras != null) {
Bundle event = new Bundle();
event.putString("Type", "NewSmsReceived");
SmsMessage[] msgs = Intents.getMessagesFromIntent(intent);
StringBuilder smsMsg = new StringBuilder();
SmsMessage sms = msgs[0];
String sender = sms.getOriginatingAddress();
event.putString("Sender", formatPhoneNumber(sender));
for (int i = 0; i < msgs.length; i++) {
sms = msgs[i];
smsMsg.append(sms.getMessageBody());
}
event.putString("Text", smsMsg.toString());
mEventFacade.postEvent("onSmsReceived", event);
}
}
}
}
String formatPhoneNumber(String phoneNumber) {
String senderNumberStr = null;
int len = phoneNumber.length();
if (len > 0) {
/**
* Currently this incomingNumber modification is specific for US numbers.
*/
if ((INTERNATIONAL_NUMBER_LENGTH == len) && ('+' == phoneNumber.charAt(0))) {
senderNumberStr = phoneNumber.substring(1);
} else if (DOMESTIC_NUMBER_LENGTH == len) {
senderNumberStr = '1' + phoneNumber;
} else {
senderNumberStr = phoneNumber;
}
}
return senderNumberStr;
}
@Override
public void shutdown() {
smsStopTrackingIncomingMessage();
}
}