1 // Copyright (c) 2013 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.xwalk.core.internal.extension.api.messaging;
7 import android.app.Activity;
8 import android.app.PendingIntent;
9 import android.content.BroadcastReceiver;
10 import android.content.ContentResolver;
11 import android.content.ContentValues;
12 import android.content.Context;
13 import android.content.Intent;
14 import android.content.IntentFilter;
15 import android.os.Bundle;
16 import android.telephony.SmsManager;
17 import android.telephony.SmsMessage;
18 import android.telephony.TelephonyManager;
19 import android.net.Uri;
20 import android.util.Log;
22 import java.lang.ref.WeakReference;
23 import java.text.SimpleDateFormat;
24 import java.util.ArrayList;
26 import org.json.JSONArray;
27 import org.json.JSONException;
28 import org.json.JSONObject;
29 import org.xwalk.core.internal.extension.api.messaging.Messaging;
31 public class MessagingSmsManager {
32 private final static String TAG = "MessagingSmsManager";
33 private final static String EXTRA_MSGID = "asyncCallId";
34 private final static String EXTRA_MSGTEXT = "message";
35 private final static String EXTRA_MSGTO = "to";
36 private final static String EXTRA_MSGINSTANCEID = "instanceid";
37 private final static String DEFAULT_SERVICE_ID = "sim0";
38 private final WeakReference<Activity> mActivity;
39 private final Messaging mMessagingHandler;
40 private BroadcastReceiver mSmsSentReceiver, mSmsDeliveredReceiver,
41 mSmsReceiveReceiver, mSmsServiceReceiver;
43 private abstract class MessagingReceiver extends BroadcastReceiver {
44 protected Messaging mMessaging;
46 public MessagingReceiver(Messaging messaging) {
47 mMessaging = messaging;
51 MessagingSmsManager(Activity activity, Messaging messaging) {
52 mActivity = new WeakReference<Activity>(activity);
53 mMessagingHandler = messaging;
56 private boolean checkService(String serviceID) {
57 Activity activity = mActivity.get();
58 if (activity == null) return false;
60 (TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE);
61 return (TelephonyManager.SIM_STATE_READY == tm.getSimState());
64 public void onSmsSend(int instanceID, JSONObject jsonMsg) {
65 if (!checkService(DEFAULT_SERVICE_ID)) {
66 Log.e(TAG, "No Sim Card");
68 Activity activity = mActivity.get();
69 if (activity == null) return;
71 String asyncCallId = null;
72 JSONObject eventBody = null;
74 String smsMessage = null;
76 asyncCallId = jsonMsg.getString("asyncCallId");
77 eventBody = jsonMsg.getJSONObject("data");
78 phone = eventBody.getString("phone");
79 smsMessage = eventBody.getString("message");
80 } catch (JSONException e) {
85 SmsManager sms = SmsManager.getDefault();
86 Intent intentSmsSent = new Intent("SMS_SENT");
87 intentSmsSent.putExtra(EXTRA_MSGID, asyncCallId);
88 intentSmsSent.putExtra(EXTRA_MSGTEXT, smsMessage);
89 intentSmsSent.putExtra(EXTRA_MSGTO, phone);
90 String instanceIDString = Integer.toString(instanceID);
91 intentSmsSent.putExtra(EXTRA_MSGINSTANCEID, instanceIDString);
92 int promiseIdInt = Integer.valueOf(asyncCallId);
93 PendingIntent piSent = PendingIntent.getBroadcast(activity,
96 PendingIntent.FLAG_ONE_SHOT);
97 Intent intentSmsDelivered = new Intent("SMS_DELIVERED");
98 intentSmsDelivered.putExtra(EXTRA_MSGID, asyncCallId);
99 intentSmsDelivered.putExtra(EXTRA_MSGTEXT, smsMessage);
100 intentSmsDelivered.putExtra(EXTRA_MSGINSTANCEID, instanceIDString);
101 PendingIntent piDelivered = PendingIntent.getBroadcast(activity,
104 PendingIntent.FLAG_ONE_SHOT);
106 sms.sendTextMessage(phone, null, smsMessage, piSent, piDelivered);
107 } catch (Exception e) {
108 Log.e(TAG, "Failed to send SMS message.", e);
112 public void onSmsClear(int instanceID, JSONObject jsonMsg) {
113 Activity activity = mActivity.get();
114 if (activity == null) return;
116 String asyncCallId = null, cmd = null;
117 JSONObject eventBody = null;
118 String serviceID = null;
120 asyncCallId = jsonMsg.getString("asyncCallId");
121 cmd = jsonMsg.getString("cmd");
122 eventBody = jsonMsg.getJSONObject("data");
123 serviceID = eventBody.getString("serviceID");
124 } catch (JSONException e) {
129 ContentResolver cr = activity.getContentResolver();
130 cr.delete(Uri.parse("content://sms"), null, null);
132 JSONObject jsonMsgRet = null;
134 jsonMsgRet = new JSONObject();
135 jsonMsgRet.put("asyncCallId", asyncCallId);
136 jsonMsgRet.put("cmd", cmd + "_ret");
137 JSONObject jsData = new JSONObject();
138 jsonMsgRet.put("data", jsData);
139 jsData.put("error", false);
140 JSONObject jsBody = new JSONObject();
141 jsData.put("body", jsBody);
142 jsBody.put("value", serviceID);
143 } catch (JSONException e) {
148 mMessagingHandler.postMessage(instanceID, jsonMsgRet.toString());
151 public void onSmsSegmentInfo(int instanceID, JSONObject jsonMsg) {
152 String asyncCallId = null;
153 JSONObject eventBody = null;
156 asyncCallId = jsonMsg.getString("asyncCallId");
157 eventBody = jsonMsg.getJSONObject("data");
158 text = eventBody.getString("text");
161 Log.e(TAG, "No \"text\" attribute.");
164 } catch (JSONException e) {
169 SmsManager sms = SmsManager.getDefault();
170 ArrayList<String> segs = sms.divideMessage(text);
172 JSONObject jsonMsgRet = new JSONObject();
173 jsonMsgRet.put("cmd", "msg_smsSegmentInfo_ret");
174 jsonMsgRet.put("asyncCallId", asyncCallId);
175 JSONObject jsData = new JSONObject();
176 jsonMsgRet.put("data", jsData);
177 jsData.put("error", false);
178 JSONObject jsBody = new JSONObject();
179 jsData.put("body", jsBody);
180 jsBody.put("segments", segs.size());
181 jsBody.put("charsPerSegment", segs.get(0).length());
182 jsBody.put("charsAvailableInLastSegment", segs.get(segs.size() - 1).length());
184 mMessagingHandler.postMessage(instanceID, jsonMsgRet.toString());
185 } catch (JSONException e) {
191 public void registerIntentFilters() {
192 Activity activity = mActivity.get();
193 if (activity == null) return;
195 mSmsReceiveReceiver = new MessagingReceiver(mMessagingHandler) {
197 public void onReceive(Context context, Intent intent) {
198 Bundle bundle = intent.getExtras();
204 Object[] pdus = (Object[]) bundle.get("pdus");
205 for (int i=0; i < pdus.length; ++i) {
207 JSONObject jsonMsg = new JSONObject();
208 jsonMsg.put("cmd", "received");
210 SmsMessage msgs = SmsMessage.createFromPdu((byte[])pdus[i]);
212 JSONObject jsData = new JSONObject();
213 jsonMsg.put("data", jsData);
214 JSONObject jsMsg = new JSONObject();
215 jsData.put("message", jsMsg);
216 jsMsg.put("messageID", "");
217 jsMsg.put("type", "sms");
218 jsMsg.put("serviceID", DEFAULT_SERVICE_ID);
219 jsMsg.put("from", msgs.getOriginatingAddress());
220 SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
221 jsMsg.put("timestamp", sDateFormat.format(new java.util.Date()));
222 jsMsg.put("body", msgs.getMessageBody().toString());
224 mMessaging.broadcastMessage(jsonMsg.toString());
225 } catch (JSONException e) {
233 mSmsSentReceiver = new MessagingReceiver(mMessagingHandler) {
235 public void onReceive(Context content, Intent intent) {
236 Activity activity = mActivity.get();
237 if (activity == null) return;
239 boolean error = getResultCode() != Activity.RESULT_OK;
240 String asyncCallId = intent.getStringExtra(EXTRA_MSGID);
241 String smsMessage = intent.getStringExtra(EXTRA_MSGTEXT);
242 String to = intent.getStringExtra(EXTRA_MSGTO);
243 int instanceID = Integer.valueOf(intent.getStringExtra(EXTRA_MSGINSTANCEID));
246 JSONObject jsSentMsg = new JSONObject();
247 jsSentMsg.put("type", "sms");
248 jsSentMsg.put("from", "");
249 jsSentMsg.put("read", true);
250 jsSentMsg.put("to", to);
251 jsSentMsg.put("body", smsMessage);
252 jsSentMsg.put("messageClass", "class1");
253 jsSentMsg.put("state", error ? "failed" : "sending");
254 jsSentMsg.put("deliveryStatus", error ? "error" : "pending");
256 JSONObject jsonMsgPromise = new JSONObject();
257 jsonMsgPromise.put("asyncCallId", asyncCallId);
258 jsonMsgPromise.put("cmd", "msg_smsSend_ret");
259 JSONObject jsData = new JSONObject();
260 jsonMsgPromise.put("data", jsData);
261 jsData.put("error", error);
262 jsData.put("body", jsSentMsg);
264 mMessaging.postMessage(instanceID, jsonMsgPromise.toString());
266 JSONObject jsonMsgEvent = new JSONObject();
267 jsonMsgEvent.put("cmd", "sent");
268 jsonMsgEvent.put("data", jsSentMsg);
270 mMessaging.broadcastMessage(jsonMsgEvent.toString());
271 } catch (JSONException e) {
276 ContentValues values = new ContentValues();
277 values.put("address", to);
278 values.put("body", smsMessage);
279 activity.getContentResolver().insert(Uri.parse("content://sms/sent"), values);
283 mSmsDeliveredReceiver = new MessagingReceiver(mMessagingHandler) {
285 public void onReceive(Context content, Intent intent) {
286 boolean error = getResultCode() != Activity.RESULT_OK;
287 String asyncCallId = intent.getStringExtra(EXTRA_MSGID);
288 int instanceID = Integer.valueOf(intent.getStringExtra(EXTRA_MSGINSTANCEID));
291 JSONObject jsonMsg = new JSONObject();
292 jsonMsg.put("asyncCallId", asyncCallId);
293 jsonMsg.put("cmd", error ? "deliveryerror": "deliverysuccess");
294 JSONObject jsData = new JSONObject();
295 jsonMsg.put("data", jsData);
296 JSONObject jsEvent = new JSONObject();
297 jsData.put("event", jsEvent);
298 jsEvent.put("serviceID", DEFAULT_SERVICE_ID);
299 jsEvent.put("messageID", "");
300 jsEvent.put("recipients", "");
301 SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
302 jsEvent.put("deliveryTimestamps", sDateFormat.format(new java.util.Date()));
303 jsData.put("error", error);
304 mMessaging.postMessage(instanceID, jsonMsg.toString());
305 } catch (JSONException e) {
312 mSmsServiceReceiver = new MessagingReceiver(mMessagingHandler) {
314 public void onReceive(Context content, Intent intent) {
316 JSONObject jsonMsg = new JSONObject();
318 checkService(DEFAULT_SERVICE_ID) ? "serviceadded": "serviceremoved");
319 JSONObject jsData = new JSONObject();
320 jsonMsg.put("data", jsData);
321 JSONObject jsEvent = new JSONObject();
322 jsData.put("event", jsEvent);
323 jsEvent.put("serviceID", DEFAULT_SERVICE_ID);
324 mMessaging.broadcastMessage(jsonMsg.toString());
325 } catch (JSONException e) {
332 activity.registerReceiver(
333 mSmsReceiveReceiver, new IntentFilter("android.provider.Telephony.SMS_RECEIVED"));
334 activity.registerReceiver(
335 mSmsSentReceiver, new IntentFilter("SMS_SENT"));
336 activity.registerReceiver(
337 mSmsDeliveredReceiver,new IntentFilter("SMS_DELIVERED"));
338 activity.registerReceiver(
339 mSmsServiceReceiver,new IntentFilter("android.intent.action.SIM_STATE_CHANGED"));
342 public void unregisterIntentFilters() {
343 Activity activity = mActivity.get();
344 if (activity == null) return;
346 activity.unregisterReceiver(mSmsReceiveReceiver);
347 activity.unregisterReceiver(mSmsSentReceiver);
348 activity.unregisterReceiver(mSmsDeliveredReceiver);
349 activity.unregisterReceiver(mSmsServiceReceiver);
352 public String getServiceIds() {
353 JSONArray serviceIds = new JSONArray();
355 // FIXME:(shawn) Android doesn't has the concept of service ID, which means messages are
356 // bundled to given SIM card. And official SDK does not support multiple SIM cards.
357 // So mock the default one to satisfy the spec.
358 serviceIds.put(DEFAULT_SERVICE_ID);
359 return serviceIds.toString();