blob: 122ee334200d8bb8e1d6d5f08367656f0c336d37 [file] [log] [blame]
Alexandre Savard14323be2012-10-24 10:02:13 -04001/*
2 * Copyright (C) 2004-2012 Savoir-Faire Linux Inc.
3 *
4 * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
Adrien Béraud71b2f812013-04-26 18:51:02 +10005 * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
Alexandre Savard14323be2012-10-24 10:02:13 -04006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * Additional permission under GNU GPL version 3 section 7:
22 *
23 * If you modify this program, or any covered work, by linking or
24 * combining it with the OpenSSL project's OpenSSL library (or a
25 * modified version of that library), containing parts covered by the
26 * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
27 * grants you additional permission to convey the resulting work.
28 * Corresponding Source for a non-source form of such a combination
29 * shall include the source code for the parts of OpenSSL used as well
30 * as that of the covered work.
31 */
32
33package com.savoirfairelinux.sflphone.client;
34
Adrien Béraud33268882013-05-18 03:41:15 +100035import java.util.HashMap;
36import java.util.Random;
37import java.util.concurrent.ExecutorService;
38import java.util.concurrent.Executors;
39
Alexandre Savard14323be2012-10-24 10:02:13 -040040import android.app.Activity;
Alexandre Savard6d54bbc2012-10-24 11:04:23 -040041import android.content.ComponentName;
alision17052d42013-04-22 10:39:38 -040042import android.content.Context;
Alexandre Savard6d54bbc2012-10-24 11:04:23 -040043import android.content.Intent;
44import android.content.ServiceConnection;
Adrien Béraud33268882013-05-18 03:41:15 +100045import android.graphics.Bitmap;
46import android.graphics.PointF;
Alexandre Savard14323be2012-10-24 10:02:13 -040047import android.os.Bundle;
Alexandre Savard6d54bbc2012-10-24 11:04:23 -040048import android.os.IBinder;
alision9f7a6ec2013-05-24 16:26:26 -040049import android.os.Parcelable;
Adrien Béraud33268882013-05-18 03:41:15 +100050import android.os.RemoteException;
51import android.util.DisplayMetrics;
Alexandre Savard6d54bbc2012-10-24 11:04:23 -040052import android.util.Log;
Adrien Béraud33268882013-05-18 03:41:15 +100053import android.widget.Toast;
Alexandre Savard14323be2012-10-24 10:02:13 -040054
55import com.savoirfairelinux.sflphone.R;
Adrien Béraud33268882013-05-18 03:41:15 +100056import com.savoirfairelinux.sflphone.adapters.ContactPictureLoader;
57import com.savoirfairelinux.sflphone.client.receiver.CallListReceiver;
58import com.savoirfairelinux.sflphone.model.Attractor;
59import com.savoirfairelinux.sflphone.model.Bubble;
60import com.savoirfairelinux.sflphone.model.BubbleModel;
61import com.savoirfairelinux.sflphone.model.BubblesView;
62import com.savoirfairelinux.sflphone.model.CallContact;
alisionf76de3b2013-04-16 15:35:22 -040063import com.savoirfairelinux.sflphone.model.SipCall;
Adrien Béraud33268882013-05-18 03:41:15 +100064import com.savoirfairelinux.sflphone.service.ISipClient;
Alexandre Savard6d54bbc2012-10-24 11:04:23 -040065import com.savoirfairelinux.sflphone.service.ISipService;
66import com.savoirfairelinux.sflphone.service.SipService;
Alexandre Savard14323be2012-10-24 10:02:13 -040067
alision9f7a6ec2013-05-24 16:26:26 -040068public class CallActivity extends Activity {
69 static final String TAG = "CallActivity";
70 private ISipService service;
71 private String pendingAction = null;
72 private SipCall mCall;
Adrien Béraud7b50ba22013-04-26 23:57:43 +100073
alision9f7a6ec2013-05-24 16:26:26 -040074 private BubblesView view;
75 private BubbleModel model;
76 private PointF screenCenter;
77 private DisplayMetrics metrics;
Adrien Béraud33268882013-05-18 03:41:15 +100078
alision9f7a6ec2013-05-24 16:26:26 -040079 private HashMap<CallContact, Bubble> contacts = new HashMap<CallContact, Bubble>();
Adrien Béraud33268882013-05-18 03:41:15 +100080
alision9f7a6ec2013-05-24 16:26:26 -040081 private ExecutorService infos_fetcher = Executors.newCachedThreadPool();
Adrien Béraud33268882013-05-18 03:41:15 +100082
alision9f7a6ec2013-05-24 16:26:26 -040083 public interface CallFragment {
84 void setCall(SipCall c);
85 }
Alexandre Savard4f42ade2012-10-24 18:03:31 -040086
alision9f7a6ec2013-05-24 16:26:26 -040087 /*
88 * private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
89 *
90 * @Override public void onReceive(Context context, Intent intent) { String signalName = intent.getStringExtra(CallManagerCallBack.SIGNAL_NAME);
91 * Log.d(TAG, "Signal received: " + signalName);
92 *
93 * if (signalName.equals(CallManagerCallBack.NEW_CALL_CREATED)) { } else if (signalName.equals(CallManagerCallBack.CALL_STATE_CHANGED)) {
94 * processCallStateChangedSignal(intent); } else if (signalName.equals(CallManagerCallBack.INCOMING_CALL)) { } } };
95 */
96 private ISipClient callback = new ISipClient.Stub() {
Adrien Béraud33268882013-05-18 03:41:15 +100097
alision9f7a6ec2013-05-24 16:26:26 -040098 @Override
99 public void incomingCall(Intent call) throws RemoteException {
100 Log.i(TAG, "Incoming call transfered from Service");
101 SipCall.CallInfo infos = new SipCall.CallInfo(call);
102 SipCall c = new SipCall(infos);
103 //
104 }
Adrien Béraud33268882013-05-18 03:41:15 +1000105
alision9f7a6ec2013-05-24 16:26:26 -0400106 @Override
107 public void callStateChanged(Intent callState) throws RemoteException {
108 Bundle b = callState.getBundleExtra("com.savoirfairelinux.sflphone.service.newstate");
109 String cID = b.getString("CallID");
110 String state = b.getString("State");
111 Log.i(TAG, "callStateChanged" + cID + " " + state);
112 processCallStateChangedSignal(cID, state);
113 }
Adrien Béraud33268882013-05-18 03:41:15 +1000114
alision9f7a6ec2013-05-24 16:26:26 -0400115 @Override
116 public void incomingText(Intent msg) throws RemoteException {
117 Bundle b = msg.getBundleExtra("com.savoirfairelinux.sflphone.service.newtext");
118 b.getString("CallID");
119 String from = b.getString("From");
120 String mess = b.getString("Msg");
121 Toast.makeText(getApplicationContext(), "text from " + from + " : " + mess, Toast.LENGTH_LONG).show();
122 }
123 };
Alexandre Savard4f42ade2012-10-24 18:03:31 -0400124
alision9f7a6ec2013-05-24 16:26:26 -0400125 @Override
126 protected void onCreate(Bundle savedInstanceState) {
127 super.onCreate(savedInstanceState);
128 setContentView(R.layout.bubbleview_layout);
Adrien Béraud33268882013-05-18 03:41:15 +1000129
alision9f7a6ec2013-05-24 16:26:26 -0400130 model = new BubbleModel(getResources().getDisplayMetrics().density);
131 metrics = getResources().getDisplayMetrics();
132 screenCenter = new PointF(metrics.widthPixels / 2, metrics.heightPixels / 3);
133 // radiusCalls = metrics.widthPixels / 2 - 150;
134 // model.listBubbles.add(new Bubble(this, metrics.widthPixels / 2, metrics.heightPixels / 4, 150, R.drawable.me));
135 // model.listBubbles.add(new Bubble(this, metrics.widthPixels / 2, metrics.heightPixels / 4 * 3, 150, R.drawable.callee));
Adrien Béraud33268882013-05-18 03:41:15 +1000136
alision9f7a6ec2013-05-24 16:26:26 -0400137 view = (BubblesView) findViewById(R.id.main_view);
138 view.setModel(model);
Adrien Béraud33268882013-05-18 03:41:15 +1000139
alision9f7a6ec2013-05-24 16:26:26 -0400140 Bundle b = getIntent().getExtras();
Alexandre Savard6d54bbc2012-10-24 11:04:23 -0400141
alision9f7a6ec2013-05-24 16:26:26 -0400142
143 SipCall.CallInfo info = b.getParcelable("CallInfo");
144 Log.i(TAG, "Starting activity for call " + info.mCallID);
145 mCall = new SipCall(info);
Adrien Béraud6bbce912013-05-24 00:48:13 +1000146
alision9f7a6ec2013-05-24 16:26:26 -0400147 Intent intent = new Intent(this, SipService.class);
Alexandre Savard6d54bbc2012-10-24 11:04:23 -0400148
alision9f7a6ec2013-05-24 16:26:26 -0400149 // setCallStateDisplay(mCall.getCallStateString());
Adrien Béraud6bbce912013-05-24 00:48:13 +1000150
alision9f7a6ec2013-05-24 16:26:26 -0400151 pendingAction = b.getString("action");
152 if (pendingAction != null && pendingAction.equals("call")) {
153 CallContact contact = b.getParcelable("CallContact");
Adrien Béraud33268882013-05-18 03:41:15 +1000154
alision9f7a6ec2013-05-24 16:26:26 -0400155 Log.i(TAG, "Calling " + contact.getmDisplayName());
156 callContact(contact);
157 // SipCall.CallInfo info = new SipCall.CallInfo();
158 // Random random = new Random();
159 // String callID = Integer.toString(random.nextInt());
160 // Phone phone = contact.getSipPhone();
Adrien Béraud33268882013-05-18 03:41:15 +1000161
alision9f7a6ec2013-05-24 16:26:26 -0400162 // info.mCallID = callID;
163 // info.mAccountID = ""+contact.getId();
164 // info.mDisplayName = contact.getmDisplayName();
165 // info.mPhone = phone==null?null:phone.toString();
166 // info.mEmail = contact.getmEmail();
167 // info.mCallType = SipCall.CALL_TYPE_OUTGOING;
Adrien Béraud6bbce912013-05-24 00:48:13 +1000168
alision9f7a6ec2013-05-24 16:26:26 -0400169 // mCall = CallListReceiver.getCallInstance(info);
Adrien Béraud6bbce912013-05-24 00:48:13 +1000170
alision9f7a6ec2013-05-24 16:26:26 -0400171 // mCallbacks.onCallSelected(call);
Adrien Béraud33268882013-05-18 03:41:15 +1000172
alision9f7a6ec2013-05-24 16:26:26 -0400173 /*
174 * try { service.placeCall(info.mAccountID, info.mCallID, info.mPhone); } catch (RemoteException e) { Log.e(TAG,
175 * "Cannot call service method", e); }
176 */
Adrien Béraud33268882013-05-18 03:41:15 +1000177
alision9f7a6ec2013-05-24 16:26:26 -0400178 } else if (pendingAction.equals("incoming")) {
179 callIncoming();
180 }
Adrien Béraud33268882013-05-18 03:41:15 +1000181
alision9f7a6ec2013-05-24 16:26:26 -0400182 bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
Adrien Béraud33268882013-05-18 03:41:15 +1000183
alision9f7a6ec2013-05-24 16:26:26 -0400184 /*
185 * LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter(CallManagerCallBack.NEW_CALL_CREATED));
186 * LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter(CallManagerCallBack.CALL_STATE_CHANGED));
187 * LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter(CallManagerCallBack.INCOMING_CALL));
188 */
189 }
Adrien Béraud33268882013-05-18 03:41:15 +1000190
alision9f7a6ec2013-05-24 16:26:26 -0400191 private void callContact(final CallContact contact) {
192 // TODO off-thread image loading
193 Bubble contact_bubble;
194 if (contact.getPhoto_id() > 0) {
195 Bitmap photo = ContactPictureLoader.loadContactPhoto(getContentResolver(), contact.getId());
196 contact_bubble = new Bubble(this, screenCenter.x, screenCenter.y, 150, photo);
197 } else {
198 contact_bubble = new Bubble(this, screenCenter.x, screenCenter.y, 150, R.drawable.ic_contact_picture);
199 }
Adrien Béraud33268882013-05-18 03:41:15 +1000200
alision9f7a6ec2013-05-24 16:26:26 -0400201 model.attractors.clear();
202 model.attractors.add(new Attractor(new PointF(metrics.widthPixels / 2, metrics.heightPixels * .8f), new Attractor.Callback() {
203 @Override
204 public void onBubbleSucked(Bubble b) {
205 Log.w(TAG, "Bubble sucked ! ");
206 onCallEnded();
207 }
208 }));
Adrien Béraud33268882013-05-18 03:41:15 +1000209
alision9f7a6ec2013-05-24 16:26:26 -0400210 contact_bubble.contact = contact;
211 model.listBubbles.add(contact_bubble);
212 contacts.put(contact, contact_bubble);
213 }
Adrien Béraud33268882013-05-18 03:41:15 +1000214
alision9f7a6ec2013-05-24 16:26:26 -0400215 private void callIncoming() {
216 model.attractors.clear();
217 model.attractors.add(new Attractor(new PointF(3 * metrics.widthPixels / 4, metrics.heightPixels / 4), new Attractor.Callback() {
218 @Override
219 public void onBubbleSucked(Bubble b) {
220 onCallAccepted();
221 }
222 }));
223 model.attractors.add(new Attractor(new PointF(metrics.widthPixels / 4, metrics.heightPixels / 4), new Attractor.Callback() {
224 @Override
225 public void onBubbleSucked(Bubble b) {
226 onCallRejected();
227 }
228 }));
Alexandre Savard6d54bbc2012-10-24 11:04:23 -0400229
alision9f7a6ec2013-05-24 16:26:26 -0400230 }
Alexandre Savard6d54bbc2012-10-24 11:04:23 -0400231
alision9f7a6ec2013-05-24 16:26:26 -0400232 @Override
233 protected void onDestroy() {
234 // Log.i(TAG, "Destroying Call Activity for call " + mCall.getCallId());
235 // LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
236 unbindService(mConnection);
alisiond8c83882013-05-17 17:00:42 -0400237
alision9f7a6ec2013-05-24 16:26:26 -0400238 super.onDestroy();
239 }
Adrien Béraud6bbce912013-05-24 00:48:13 +1000240
alision9f7a6ec2013-05-24 16:26:26 -0400241 /** Defines callbacks for service binding, passed to bindService() */
242 private ServiceConnection mConnection = new ServiceConnection() {
243 @Override
244 public void onServiceConnected(ComponentName className, IBinder binder) {
245 service = ISipService.Stub.asInterface(binder);
246 try {
247 service.registerClient(callback);
248 if (pendingAction != null && pendingAction.contentEquals("call")) {
Adrien Béraud6bbce912013-05-24 00:48:13 +1000249
alision9f7a6ec2013-05-24 16:26:26 -0400250 Log.i(TAG, "Placing call");
251 CallContact contact = model.listBubbles.get(0).contact;
Adrien Béraud6bbce912013-05-24 00:48:13 +1000252
alision9f7a6ec2013-05-24 16:26:26 -0400253 String callID = Integer.toString(new Random().nextInt());
254 SipCall.CallInfo info = new SipCall.CallInfo();
255 info.mCallID = callID;
256 info.mAccountID = service.getAccountList().get(0).toString();
257 info.mDisplayName = contact.getmDisplayName();
258 info.mPhone = contact.getSipPhone().getNumber();
259 info.mEmail = contact.getmEmail();
260 info.mCallType = SipCall.CALL_TYPE_OUTGOING;
Alexandre Savard6d54bbc2012-10-24 11:04:23 -0400261
alision9f7a6ec2013-05-24 16:26:26 -0400262 mCall = CallListReceiver.getCallInstance(info);
Adrien Béraud7b50ba22013-04-26 23:57:43 +1000263
alision9f7a6ec2013-05-24 16:26:26 -0400264 service.placeCall(info.mAccountID, info.mCallID, info.mPhone);
265 pendingAction = null;
266 }
267 } catch (RemoteException e) {
268 Log.e(TAG, e.toString());
269 }
270 }
Alexandre Savarde41f5212012-10-26 14:23:50 -0400271
alision9f7a6ec2013-05-24 16:26:26 -0400272 @Override
273 public void onServiceDisconnected(ComponentName arg0) {
274 }
275 };
Alexandre Savarddf544262012-10-25 14:24:08 -0400276
alision9f7a6ec2013-05-24 16:26:26 -0400277 private void processCallStateChangedSignal(String callID, String newState) {
278 /*
279 * Bundle bundle = intent.getBundleExtra("com.savoirfairelinux.sflphone.service.newstate"); String callID = bundle.getString("CallID"); String
280 * newState = bundle.getString("State");
281 */
Adrien Béraud29556042013-04-26 17:35:43 +1000282
alision9f7a6ec2013-05-24 16:26:26 -0400283 if (newState.equals("INCOMING")) {
284 mCall.setCallState(SipCall.CALL_STATE_INCOMING);
285 setCallStateDisplay(newState);
286 } else if (newState.equals("RINGING")) {
287 mCall.setCallState(SipCall.CALL_STATE_RINGING);
288 setCallStateDisplay(newState);
289 } else if (newState.equals("CURRENT")) {
290 mCall.setCallState(SipCall.CALL_STATE_CURRENT);
291 setCallStateDisplay(newState);
292 } else if (newState.equals("HUNGUP")) {
293 mCall.setCallState(SipCall.CALL_STATE_HUNGUP);
294 setCallStateDisplay(newState);
295 finish();
296 } else if (newState.equals("BUSY")) {
297 mCall.setCallState(SipCall.CALL_STATE_BUSY);
298 setCallStateDisplay(newState);
299 } else if (newState.equals("FAILURE")) {
300 mCall.setCallState(SipCall.CALL_STATE_FAILURE);
301 setCallStateDisplay(newState);
302 } else if (newState.equals("HOLD")) {
303 mCall.setCallState(SipCall.CALL_STATE_HOLD);
304 setCallStateDisplay(newState);
305 } else if (newState.equals("UNHOLD")) {
306 mCall.setCallState(SipCall.CALL_STATE_CURRENT);
307 setCallStateDisplay("CURRENT");
308 } else {
309 mCall.setCallState(SipCall.CALL_STATE_NONE);
310 setCallStateDisplay(newState);
311 }
Adrien Béraudc99b8432013-04-25 16:27:46 +1000312
alision9f7a6ec2013-05-24 16:26:26 -0400313 Log.w(TAG, "processCallStateChangedSignal " + newState);
Adrien Béraud29556042013-04-26 17:35:43 +1000314
alision9f7a6ec2013-05-24 16:26:26 -0400315 }
Adrien Béraud71b2f812013-04-26 18:51:02 +1000316
alision9f7a6ec2013-05-24 16:26:26 -0400317 private void setCallStateDisplay(String newState) {
318 if (newState == null || newState.equals("NULL")) {
319 newState = "INCOMING";
320 }
Adrien Béraud29556042013-04-26 17:35:43 +1000321
alision9f7a6ec2013-05-24 16:26:26 -0400322 Log.w(TAG, "setCallStateDisplay " + newState);
Adrien Béraud7b50ba22013-04-26 23:57:43 +1000323
alision9f7a6ec2013-05-24 16:26:26 -0400324 /*
325 * mCall.printCallInfo();
326 *
327 * FragmentManager fm = getFragmentManager(); Fragment newf, f = fm.findFragmentByTag("call_fragment"); boolean replace = true; if
328 * (newState.equals("INCOMING") && !(f instanceof IncomingCallFragment)) { newf = new IncomingCallFragment(); } else if
329 * (!newState.equals("INCOMING") && !(f instanceof OngoingCallFragment)) { newf = new OngoingCallFragment(); } else { replace = false; newf =
330 * f; }
331 *
332 * ((CallFragment) newf).setCall(mCall);
333 *
334 * if (replace) { FragmentTransaction ft = fm.beginTransaction(); if(f != null) // do not animate if there is no previous fragment
335 * ft.setCustomAnimations(R.animator.slide_in, R.animator.slide_out); //ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
336 * ft.replace(R.id.fragment_layout, newf, "call_fragment").commit(); }
337 */
338 }
Adrien Béraud7b50ba22013-04-26 23:57:43 +1000339
alision9f7a6ec2013-05-24 16:26:26 -0400340 public void onCallAccepted() {
341 mCall.notifyServiceAnswer(service);
342 }
Adrien Béraud29556042013-04-26 17:35:43 +1000343
alision9f7a6ec2013-05-24 16:26:26 -0400344 public void onCallRejected() {
345 if (mCall.notifyServiceHangup(service))
346 finish();
347 }
Adrien Béraud29556042013-04-26 17:35:43 +1000348
alision9f7a6ec2013-05-24 16:26:26 -0400349 public void onCallEnded() {
350 if (mCall.notifyServiceHangup(service))
351 finish();
352 }
Adrien Béraud29556042013-04-26 17:35:43 +1000353
alision9f7a6ec2013-05-24 16:26:26 -0400354 public void onCallSuspended() {
355 mCall.notifyServiceHold(service);
356 }
Adrien Béraud71b2f812013-04-26 18:51:02 +1000357
alision9f7a6ec2013-05-24 16:26:26 -0400358 public void onCallResumed() {
359 mCall.notifyServiceUnhold(service);
360 }
Adrien Béraud71b2f812013-04-26 18:51:02 +1000361
alision9f7a6ec2013-05-24 16:26:26 -0400362 public void onCalltransfered(String to) {
363 mCall.notifyServiceTransfer(service, to);
Adrien Béraud71b2f812013-04-26 18:51:02 +1000364
alision9f7a6ec2013-05-24 16:26:26 -0400365 }
alision7f18fc82013-05-01 09:37:33 -0400366
alision9f7a6ec2013-05-24 16:26:26 -0400367 public void onRecordCall() {
368 mCall.notifyServiceRecord(service);
alision04a00182013-05-10 17:05:29 -0400369
alision9f7a6ec2013-05-24 16:26:26 -0400370 }
Adrien Béraud33268882013-05-18 03:41:15 +1000371
alision9f7a6ec2013-05-24 16:26:26 -0400372 public void onSendMessage(String msg) {
373 mCall.notifyServiceSendMsg(service, msg);
Adrien Béraud33268882013-05-18 03:41:15 +1000374
alision9f7a6ec2013-05-24 16:26:26 -0400375 }
alision04a00182013-05-10 17:05:29 -0400376
Alexandre Savard14323be2012-10-24 10:02:13 -0400377}