0a2d61e30f30719b8b95274b21efdb58fd6608fb
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / android / core_internal / src / org / xwalk / core / internal / extension / api / messaging / MessagingSmsManager.java
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.
4
5 package org.xwalk.core.internal.extension.api.messaging;
6
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; 
21
22 import java.lang.ref.WeakReference;
23 import java.text.SimpleDateFormat;
24 import java.util.ArrayList;
25
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;
30
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;
42
43     private abstract class MessagingReceiver extends BroadcastReceiver {
44         protected Messaging mMessaging;
45
46         public MessagingReceiver(Messaging messaging) {
47             mMessaging = messaging;
48         }
49     }
50
51     MessagingSmsManager(Activity activity, Messaging messaging) {
52         mActivity = new WeakReference<Activity>(activity);
53         mMessagingHandler = messaging;
54     }
55
56     private boolean checkService(String serviceID) {
57         Activity activity = mActivity.get();
58         if (activity == null) return false;
59         TelephonyManager tm = 
60             (TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE);
61         return (TelephonyManager.SIM_STATE_READY == tm.getSimState());
62     }
63
64     public void onSmsSend(int instanceID, JSONObject jsonMsg) {
65         if (!checkService(DEFAULT_SERVICE_ID)) {
66             Log.e(TAG, "No Sim Card");
67         }
68         Activity activity = mActivity.get();
69         if (activity == null) return;
70
71         String asyncCallId = null;
72         JSONObject eventBody = null;
73         String phone = null;
74         String smsMessage = null;
75         try {
76             asyncCallId = jsonMsg.getString("asyncCallId");
77             eventBody = jsonMsg.getJSONObject("data");
78             phone = eventBody.getString("phone");
79             smsMessage = eventBody.getString("message");
80         } catch (JSONException e) {
81             e.printStackTrace();
82             return;
83         }
84         
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, 
94                                                           promiseIdInt, 
95                                                           intentSmsSent, 
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, 
102                                                                -promiseIdInt, 
103                                                                intentSmsDelivered,
104                                                                PendingIntent.FLAG_ONE_SHOT);
105         try {
106             sms.sendTextMessage(phone, null, smsMessage, piSent, piDelivered);
107         } catch (Exception e) {
108             Log.e(TAG, "Failed to send SMS message.", e);
109         }
110     }
111
112     public void onSmsClear(int instanceID, JSONObject jsonMsg) {
113         Activity activity = mActivity.get();
114         if (activity == null) return;
115
116         String asyncCallId = null, cmd = null;
117         JSONObject eventBody = null;
118         String serviceID = null;
119         try {
120             asyncCallId = jsonMsg.getString("asyncCallId");
121             cmd = jsonMsg.getString("cmd");
122             eventBody = jsonMsg.getJSONObject("data");
123             serviceID = eventBody.getString("serviceID");
124         } catch (JSONException e) {
125             e.printStackTrace();
126             return;
127         }
128
129         ContentResolver cr = activity.getContentResolver();
130         cr.delete(Uri.parse("content://sms"), null, null);
131
132         JSONObject jsonMsgRet = null;
133         try {
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) {
144             e.printStackTrace();
145             return;
146         }
147
148         mMessagingHandler.postMessage(instanceID, jsonMsgRet.toString());
149     }
150
151     public void onSmsSegmentInfo(int instanceID, JSONObject jsonMsg) {
152         String asyncCallId = null;
153         JSONObject eventBody = null;
154         String text = null;
155         try {
156             asyncCallId = jsonMsg.getString("asyncCallId");
157             eventBody = jsonMsg.getJSONObject("data");
158             text = eventBody.getString("text");
159
160             if (null == text) {
161                 Log.e(TAG, "No \"text\" attribute.");
162                 return;
163             }
164         } catch (JSONException e) {
165             e.printStackTrace();
166             return;
167         }
168         
169         SmsManager sms = SmsManager.getDefault();
170         ArrayList<String> segs = sms.divideMessage(text);
171         try {
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());
183             
184             mMessagingHandler.postMessage(instanceID, jsonMsgRet.toString());
185          } catch (JSONException e) {
186             e.printStackTrace();
187             return;
188         }        
189     }
190
191     public void registerIntentFilters() {
192         Activity activity = mActivity.get();
193         if (activity == null) return;
194
195         mSmsReceiveReceiver = new MessagingReceiver(mMessagingHandler) {
196             @Override
197             public void onReceive(Context context, Intent intent) {
198                 Bundle bundle = intent.getExtras();        
199                 
200                 if(null == bundle) {
201                     return;
202                 }
203
204                 Object[] pdus = (Object[]) bundle.get("pdus");
205                 for (int i=0; i < pdus.length; ++i) {
206                     try {
207                         JSONObject jsonMsg = new JSONObject();
208                         jsonMsg.put("cmd", "received");
209
210                         SmsMessage msgs = SmsMessage.createFromPdu((byte[])pdus[i]);
211                         
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());
223                         
224                         mMessaging.broadcastMessage(jsonMsg.toString());
225                      } catch (JSONException e) {
226                         e.printStackTrace();
227                         return;
228                     }
229                 } 
230             }
231         };
232
233         mSmsSentReceiver = new MessagingReceiver(mMessagingHandler) {
234             @Override
235             public void onReceive(Context content, Intent intent) {
236                 Activity activity = mActivity.get();
237                 if (activity == null) return;
238
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));
244
245                 try {
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");
255
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);
263
264                     mMessaging.postMessage(instanceID, jsonMsgPromise.toString());
265
266                     JSONObject jsonMsgEvent = new JSONObject();
267                     jsonMsgEvent.put("cmd", "sent");
268                     jsonMsgEvent.put("data", jsSentMsg);
269
270                     mMessaging.broadcastMessage(jsonMsgEvent.toString());
271                 } catch (JSONException e) {
272                     e.printStackTrace();
273                     return;
274                 }
275
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);
280             }
281         };
282
283         mSmsDeliveredReceiver = new MessagingReceiver(mMessagingHandler) {
284             @Override
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));
289
290                 try {
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) {
306                     e.printStackTrace();
307                     return;
308                 }
309             }
310         };
311
312         mSmsServiceReceiver = new MessagingReceiver(mMessagingHandler) {
313             @Override
314             public void onReceive(Context content, Intent intent) {
315                 try {
316                     JSONObject jsonMsg = new JSONObject();
317                     jsonMsg.put("cmd", 
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) {
326                     e.printStackTrace();
327                     return;
328                 }
329             }
330         };
331
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"));
340     }
341
342     public void unregisterIntentFilters() {
343         Activity activity = mActivity.get();
344         if (activity == null) return;
345
346         activity.unregisterReceiver(mSmsReceiveReceiver);
347         activity.unregisterReceiver(mSmsSentReceiver);
348         activity.unregisterReceiver(mSmsDeliveredReceiver);
349         activity.unregisterReceiver(mSmsServiceReceiver);
350     }
351
352     public String getServiceIds() {
353         JSONArray serviceIds = new JSONArray();
354
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();
360     }
361 }