blob: 0681fb4dfe5f564075969be3d3f126e64dba769d [file] [log] [blame]
Santos Cordon89647a62013-07-16 13:38:09 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.phone;
18
19import android.content.ComponentName;
20import android.content.Context;
21import android.content.Intent;
22import android.content.ServiceConnection;
Chiao Cheng11a4b652013-09-02 01:08:19 -070023import android.content.pm.PackageManager;
24import android.content.pm.ResolveInfo;
Santos Cordon89647a62013-07-16 13:38:09 -070025import android.os.Handler;
26import android.os.IBinder;
27import android.os.Message;
Chiao Cheng26c6e922013-09-14 16:45:38 -070028import android.os.PowerManager;
Santos Cordon89647a62013-07-16 13:38:09 -070029import android.os.RemoteException;
Chiao Cheng26c6e922013-09-14 16:45:38 -070030import android.os.SystemClock;
Santos Cordon89647a62013-07-16 13:38:09 -070031import android.os.SystemProperties;
32import android.util.Log;
33
Santos Cordon9b7bac72013-08-06 08:04:52 -070034import com.android.phone.AudioRouter.AudioModeListener;
Yorke Lee362cec22013-09-18 15:20:26 -070035import com.android.phone.NotificationMgr.StatusBarHelper;
Santos Cordon9b7bac72013-08-06 08:04:52 -070036import com.android.services.telephony.common.AudioMode;
Santos Cordonf4046882013-07-25 18:49:27 -070037import com.android.services.telephony.common.Call;
Santos Cordon345350e2013-07-19 17:16:14 -070038import com.android.services.telephony.common.ICallHandlerService;
Chiao Cheng6c6b2722013-08-22 18:35:54 -070039import com.google.common.collect.Lists;
Santos Cordon89647a62013-07-16 13:38:09 -070040
Santos Cordona3d05142013-07-29 11:25:17 -070041import java.util.List;
42
Santos Cordon89647a62013-07-16 13:38:09 -070043/**
Santos Cordon345350e2013-07-19 17:16:14 -070044 * This class is responsible for passing through call state changes to the CallHandlerService.
Santos Cordon89647a62013-07-16 13:38:09 -070045 */
Chiao Cheng6c6b2722013-08-22 18:35:54 -070046public class CallHandlerServiceProxy extends Handler
47 implements CallModeler.Listener, AudioModeListener {
Santos Cordon89647a62013-07-16 13:38:09 -070048
Santos Cordon345350e2013-07-19 17:16:14 -070049 private static final String TAG = CallHandlerServiceProxy.class.getSimpleName();
Santos Cordon71d5c6e2013-09-05 21:34:33 -070050 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt(
Chiao Cheng6c6b2722013-08-22 18:35:54 -070051 "ro.debuggable", 0) == 1);
Chiao Chenge41661c2013-07-23 13:28:26 -070052
Chiao Cheng6c6b2722013-08-22 18:35:54 -070053 public static final int RETRY_DELAY_MILLIS = 2000;
54 private static final int BIND_RETRY_MSG = 1;
55 private static final int MAX_RETRY_COUNT = 5;
Santos Cordon89647a62013-07-16 13:38:09 -070056
Santos Cordon593ab382013-08-06 21:58:23 -070057 private AudioRouter mAudioRouter;
Santos Cordoncba1b442013-07-18 12:43:58 -070058 private CallCommandService mCallCommandService;
Santos Cordon593ab382013-08-06 21:58:23 -070059 private CallModeler mCallModeler;
60 private Context mContext;
Chiao Chengd38eebc2013-08-28 14:38:14 -070061
Chiao Cheng6c6b2722013-08-22 18:35:54 -070062 private ICallHandlerService mCallHandlerServiceGuarded; // Guarded by mServiceAndQueueLock
Chiao Chengd38eebc2013-08-28 14:38:14 -070063 // Single queue to guarantee ordering
64 private List<QueueParams> mQueue; // Guarded by mServiceAndQueueLock
65
Chiao Cheng6c6b2722013-08-22 18:35:54 -070066 private final Object mServiceAndQueueLock = new Object();
67 private int mBindRetryCount = 0;
68
69 @Override
70 public void handleMessage(Message msg) {
71 super.handleMessage(msg);
72
73 switch (msg.what) {
74 case BIND_RETRY_MSG:
75 setupServiceConnection();
76 break;
77 }
78 }
Santos Cordon89647a62013-07-16 13:38:09 -070079
Santos Cordon63a84242013-07-23 13:32:52 -070080 public CallHandlerServiceProxy(Context context, CallModeler callModeler,
Santos Cordon593ab382013-08-06 21:58:23 -070081 CallCommandService callCommandService, AudioRouter audioRouter) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -070082 if (DBG) {
83 Log.d(TAG, "init CallHandlerServiceProxy");
84 }
Santos Cordon89647a62013-07-16 13:38:09 -070085 mContext = context;
Santos Cordoncba1b442013-07-18 12:43:58 -070086 mCallCommandService = callCommandService;
Santos Cordon63a84242013-07-23 13:32:52 -070087 mCallModeler = callModeler;
Santos Cordon593ab382013-08-06 21:58:23 -070088 mAudioRouter = audioRouter;
Santos Cordon89647a62013-07-16 13:38:09 -070089
Santos Cordon593ab382013-08-06 21:58:23 -070090 mAudioRouter.addAudioModeListener(this);
Christine Chendaf7bf62013-08-05 19:12:31 -070091 mCallModeler.addListener(this);
Santos Cordon63a84242013-07-23 13:32:52 -070092 }
Santos Cordon89647a62013-07-16 13:38:09 -070093
Santos Cordon63a84242013-07-23 13:32:52 -070094 @Override
Santos Cordon995c8162013-07-29 09:22:22 -070095 public void onDisconnect(Call call) {
Chiao Cheng26c6e922013-09-14 16:45:38 -070096 // Wake up in case the screen was off.
97 wakeUpScreen();
Chiao Cheng3e6486e2013-09-03 19:27:46 -070098 synchronized (mServiceAndQueueLock) {
99 if (mCallHandlerServiceGuarded == null) {
100 if (DBG) {
101 Log.d(TAG, "CallHandlerService not connected. Enqueue disconnect");
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700102 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700103 enqueueDisconnect(call);
104 setupServiceConnection();
105 return;
Santos Cordon63a84242013-07-23 13:32:52 -0700106 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700107 }
108 processDisconnect(call);
109 }
110
Chiao Cheng26c6e922013-09-14 16:45:38 -0700111 private void wakeUpScreen() {
112 Log.d(TAG, "wakeUpScreen()");
113 final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
114 pm.wakeUp(SystemClock.uptimeMillis());
115 }
116
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700117 private void processDisconnect(Call call) {
118 try {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700119 if (DBG) {
120 Log.d(TAG, "onDisconnect: " + call);
121 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700122 synchronized (mServiceAndQueueLock) {
123 if (mCallHandlerServiceGuarded != null) {
124 mCallHandlerServiceGuarded.onDisconnect(call);
125 }
126 }
127 if (!mCallModeler.hasLiveCall()) {
128 unbind();
129 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700130 } catch (Exception e) {
131 Log.e(TAG, "Remote exception handling onDisconnect ", e);
Santos Cordon89647a62013-07-16 13:38:09 -0700132 }
133 }
134
Santos Cordona3d05142013-07-29 11:25:17 -0700135 @Override
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700136 public void onIncoming(Call call) {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700137 synchronized (mServiceAndQueueLock) {
138 if (mCallHandlerServiceGuarded == null) {
139 if (DBG) {
140 Log.d(TAG, "CallHandlerService not connected. Enqueue incoming.");
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700141 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700142 enqueueIncoming(call);
143 setupServiceConnection();
144 return;
Christine Chenee09a492013-08-06 16:02:29 -0700145 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700146 }
147 processIncoming(call);
148 }
149
150 private void processIncoming(Call call) {
151 if (DBG) {
152 Log.d(TAG, "onIncoming: " + call);
153 }
154 try {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700155 // TODO(klp): check RespondViaSmsManager.allowRespondViaSmsForCall()
156 // must refactor call method to accept proper call object.
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700157 synchronized (mServiceAndQueueLock) {
158 if (mCallHandlerServiceGuarded != null) {
159 mCallHandlerServiceGuarded.onIncoming(call,
160 RejectWithTextMessageManager.loadCannedResponses());
161 }
162 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700163 } catch (Exception e) {
164 Log.e(TAG, "Remote exception handling onUpdate", e);
Christine Chenee09a492013-08-06 16:02:29 -0700165 }
166 }
167
168 @Override
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700169 public void onUpdate(List<Call> calls) {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700170 synchronized (mServiceAndQueueLock) {
171 if (mCallHandlerServiceGuarded == null) {
172 if (DBG) {
173 Log.d(TAG, "CallHandlerService not connected. Enqueue update.");
174 }
175 enqueueUpdate(calls);
176 setupServiceConnection();
177 return;
178 }
179 }
180 processUpdate(calls);
181 }
182
183 private void processUpdate(List<Call> calls) {
184 if (DBG) {
185 Log.d(TAG, "onUpdate: " + calls.toString());
186 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700187 try {
188 synchronized (mServiceAndQueueLock) {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700189 if (mCallHandlerServiceGuarded != null) {
190 mCallHandlerServiceGuarded.onUpdate(calls);
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700191 }
Santos Cordona3d05142013-07-29 11:25:17 -0700192 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700193 if (!mCallModeler.hasLiveCall()) {
194 // TODO: unbinding happens in both onUpdate and onDisconnect because the ordering
195 // is not deterministic. Unbinding in both ensures that the service is unbound.
196 // But it also makes this in-efficient because we are unbinding twice, which leads
197 // to the CallHandlerService performing onCreate() and onDestroy() twice for each
198 // disconnect.
199 unbind();
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700200 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700201 } catch (Exception e) {
202 Log.e(TAG, "Remote exception handling onUpdate", e);
Santos Cordona3d05142013-07-29 11:25:17 -0700203 }
204 }
205
Chiao Cheng3f015c92013-09-06 15:56:27 -0700206
207 @Override
208 public void onPostDialWait(int callId, String remainingChars) {
209 try {
210 synchronized (mServiceAndQueueLock) {
211 if (mCallHandlerServiceGuarded == null) {
212 if (DBG) {
213 Log.d(TAG, "CallHandlerService not conneccted. Skipping "
214 + "onPostDialWait().");
215 }
216 return;
217 }
218 }
219
220 mCallHandlerServiceGuarded.onPostDialWait(callId, remainingChars);
221 } catch (Exception e) {
222 Log.e(TAG, "Remote exception handling onUpdate", e);
223 }
224 }
225
Santos Cordon9b7bac72013-08-06 08:04:52 -0700226 @Override
Santos Cordoncd95f622013-08-29 03:38:52 -0700227 public void onAudioModeChange(int newMode, boolean muted) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700228 try {
229 synchronized (mServiceAndQueueLock) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700230 if (mCallHandlerServiceGuarded == null) {
231 if (DBG) {
232 Log.d(TAG, "CallHandlerService not conneccted. Skipping "
233 + "onAudioModeChange().");
234 }
235 return;
236 }
Santos Cordon9b7bac72013-08-06 08:04:52 -0700237 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700238
239 // Just do a simple log for now.
240 Log.i(TAG, "Updating with new audio mode: " + AudioMode.toString(newMode) +
Santos Cordoncd95f622013-08-29 03:38:52 -0700241 " with mute " + muted);
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700242
Santos Cordoncd95f622013-08-29 03:38:52 -0700243 mCallHandlerServiceGuarded.onAudioModeChange(newMode, muted);
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700244 } catch (Exception e) {
245 Log.e(TAG, "Remote exception handling onAudioModeChange", e);
Santos Cordon9b7bac72013-08-06 08:04:52 -0700246 }
247 }
248
Santos Cordon593ab382013-08-06 21:58:23 -0700249 @Override
250 public void onSupportedAudioModeChange(int modeMask) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700251 try {
252 synchronized (mServiceAndQueueLock) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700253 if (mCallHandlerServiceGuarded == null) {
254 if (DBG) {
255 Log.d(TAG, "CallHandlerService not conneccted. Skipping"
256 + "onSupportedAudioModeChange().");
257 }
258 return;
259 }
260 }
Santos Cordon593ab382013-08-06 21:58:23 -0700261
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700262 if (DBG) {
263 Log.d(TAG, "onSupportAudioModeChange: " + AudioMode.toString(modeMask));
264 }
265
266 mCallHandlerServiceGuarded.onSupportedAudioModeChange(modeMask);
267 } catch (Exception e) {
268 Log.e(TAG, "Remote exception handling onAudioModeChange", e);
269 }
270
271 }
272
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700273 private ServiceConnection mConnection = null;
274
275 private class InCallServiceConnection implements ServiceConnection {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700276 @Override public void onServiceConnected (ComponentName className, IBinder service){
277 if (DBG) {
278 Log.d(TAG, "Service Connected");
279 }
280 onCallHandlerServiceConnected(ICallHandlerService.Stub.asInterface(service));
Chiao Cheng11a4b652013-09-02 01:08:19 -0700281 mBindRetryCount = 0;
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700282 }
283
284 @Override public void onServiceDisconnected (ComponentName className){
285 Log.i(TAG, "Disconnected from UI service.");
286 synchronized (mServiceAndQueueLock) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700287 // Technically, unbindService is un-necessary since the framework will schedule and
288 // restart the crashed service. But there is a exponential backoff for the restart.
289 // Unbind explicitly and setup again to avoid the backoff since it's important to
290 // always have an in call ui.
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700291 unbind();
292
293 // TODO(klp): hang up all calls.
Santos Cordon593ab382013-08-06 21:58:23 -0700294 }
295 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700296 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700297
Makoto Onukibcf20992013-09-12 17:59:30 -0700298 public void bringToForeground(boolean showDialpad) {
Santos Cordon406c0342013-08-28 00:07:47 -0700299 // only support this call if the service is already connected.
Santos Cordon19d814b2013-08-28 14:58:17 -0700300 synchronized (mServiceAndQueueLock) {
301 if (mCallHandlerServiceGuarded != null && mCallModeler.hasLiveCall()) {
302 try {
Makoto Onukibcf20992013-09-12 17:59:30 -0700303 if (DBG) Log.d(TAG, "bringToForeground: " + showDialpad);
304 mCallHandlerServiceGuarded.bringToForeground(showDialpad);
Santos Cordon19d814b2013-08-28 14:58:17 -0700305 } catch (RemoteException e) {
306 Log.e(TAG, "Exception handling bringToForeground", e);
307 }
Santos Cordon406c0342013-08-28 00:07:47 -0700308 }
309 }
310 }
311
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700312 private static Intent getInCallServiceIntent(Context context) {
313 final Intent serviceIntent = new Intent(ICallHandlerService.class.getName());
314 final ComponentName component = new ComponentName(context.getResources().getString(
315 R.string.incall_ui_default_package), context.getResources().getString(
316 R.string.incall_ui_default_class));
317 serviceIntent.setComponent(component);
318 return serviceIntent;
319 }
320
Santos Cordon89647a62013-07-16 13:38:09 -0700321 /**
Santos Cordon345350e2013-07-19 17:16:14 -0700322 * Sets up the connection with ICallHandlerService
Santos Cordon89647a62013-07-16 13:38:09 -0700323 */
324 private void setupServiceConnection() {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700325 if (!PhoneGlobals.sVoiceCapable) {
326 return;
327 }
Chiao Cheng11a4b652013-09-02 01:08:19 -0700328
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700329 final Intent serviceIntent = getInCallServiceIntent(mContext);
Chiao Cheng11a4b652013-09-02 01:08:19 -0700330 if (DBG) {
331 Log.d(TAG, "binding to service " + serviceIntent);
332 }
333
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700334 synchronized (mServiceAndQueueLock) {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700335 if (mConnection == null) {
336 mConnection = new InCallServiceConnection();
337
338 final PackageManager packageManger = mContext.getPackageManager();
339 final List<ResolveInfo> services = packageManger.queryIntentServices(serviceIntent,
340 0);
341 if (services.size() == 0) {
342 // Service not found, retry again after some delay
343 // This can happen if the service is being installed by the package manager.
344 // Between deletes and installs, bindService could get a silent service not
345 // found error.
346 mBindRetryCount++;
347 if (mBindRetryCount < MAX_RETRY_COUNT) {
348 Log.w(TAG, "InCallUI service not found. " + serviceIntent
349 + ". This happens if the service is being installed and should be"
350 + " transient. Retrying" + RETRY_DELAY_MILLIS + " ms.");
351 sendMessageDelayed(Message.obtain(this, BIND_RETRY_MSG),
352 RETRY_DELAY_MILLIS);
353 } else {
354 Log.e(TAG, "Tried to bind to in-call UI " + MAX_RETRY_COUNT + " times."
355 + " Giving up.");
356 }
357 return;
358 }
359
360 if (DBG) {
361 Log.d(TAG, "binding to service " + serviceIntent);
362 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700363 if (!mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)) {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700364 // This happens when the in-call package is in the middle of being
365 // installed.
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700366 // Delay the retry.
367 mBindRetryCount++;
368 if (mBindRetryCount < MAX_RETRY_COUNT) {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700369 Log.e(TAG, "bindService failed on " + serviceIntent + ". Retrying in "
370 + RETRY_DELAY_MILLIS + " ms.");
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700371 sendMessageDelayed(Message.obtain(this, BIND_RETRY_MSG),
372 RETRY_DELAY_MILLIS);
373 } else {
374 Log.wtf(TAG, "Tried to bind to in-call UI " + MAX_RETRY_COUNT + " times."
375 + " Giving up.");
376 }
377 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700378
379 } else {
380 Log.d(TAG, "Service connection to in call service already started.");
Santos Cordonaf763a12013-08-19 20:04:58 -0700381 }
382 }
383 }
384
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700385 private void unbind() {
386 synchronized (mServiceAndQueueLock) {
Yorke Lee362cec22013-09-18 15:20:26 -0700387 // On unbind, reenable the notification shade and navigation bar just in case the
388 // in-call UI crashed on an incoming call.
389 final StatusBarHelper statusBarHelper = PhoneGlobals.getInstance().notificationMgr.
390 statusBarHelper;
391 statusBarHelper.enableSystemBarNavigation(true);
392 statusBarHelper.enableExpandedView(true);
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700393 if (mCallHandlerServiceGuarded != null) {
394 Log.d(TAG, "Unbinding service.");
395 mCallHandlerServiceGuarded = null;
396 mContext.unbindService(mConnection);
397 }
398 mConnection = null;
399 }
400 }
401
Santos Cordonaf763a12013-08-19 20:04:58 -0700402 /**
Santos Cordoncba1b442013-07-18 12:43:58 -0700403 * Called when the in-call UI service is connected. Send command interface to in-call.
404 */
Santos Cordon63a84242013-07-23 13:32:52 -0700405 private void onCallHandlerServiceConnected(ICallHandlerService callHandlerService) {
Chiao Chengd38eebc2013-08-28 14:38:14 -0700406
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700407 synchronized (mServiceAndQueueLock) {
408 mCallHandlerServiceGuarded = callHandlerService;
409
Santos Cordonad078192013-08-28 15:14:54 -0700410 // Before we send any updates, we need to set up the initial service calls.
411 makeInitialServiceCalls();
412
Chiao Chengd38eebc2013-08-28 14:38:14 -0700413 processQueue();
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700414 }
Santos Cordonad078192013-08-28 15:14:54 -0700415 }
Santos Cordoncba1b442013-07-18 12:43:58 -0700416
Santos Cordonad078192013-08-28 15:14:54 -0700417 /**
418 * Makes initial service calls to set up callcommandservice and audio modes.
419 */
420 private void makeInitialServiceCalls() {
Santos Cordoncba1b442013-07-18 12:43:58 -0700421 try {
Santos Cordon12a03aa2013-09-12 23:34:05 -0700422 mCallHandlerServiceGuarded.startCallService(mCallCommandService);
Santos Cordonad078192013-08-28 15:14:54 -0700423
424 onSupportedAudioModeChange(mAudioRouter.getSupportedAudioModes());
Santos Cordon8fd0ec72013-08-29 16:44:43 -0700425 onAudioModeChange(mAudioRouter.getAudioMode(), mAudioRouter.getMute());
Santos Cordoncba1b442013-07-18 12:43:58 -0700426 } catch (RemoteException e) {
Santos Cordon63a84242013-07-23 13:32:52 -0700427 Log.e(TAG, "Remote exception calling CallHandlerService::setCallCommandService", e);
Santos Cordon89647a62013-07-16 13:38:09 -0700428 }
429 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700430
Chiao Chengd38eebc2013-08-28 14:38:14 -0700431 private List<QueueParams> getQueue() {
432 if (mQueue == null) {
433 mQueue = Lists.newArrayList();
434 }
435 return mQueue;
436 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700437
438 private void enqueueDisconnect(Call call) {
Chiao Chengd38eebc2013-08-28 14:38:14 -0700439 getQueue().add(new QueueParams(QueueParams.METHOD_DISCONNECT, new Call(call)));
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700440 }
441
442 private void enqueueIncoming(Call call) {
Chiao Chengd38eebc2013-08-28 14:38:14 -0700443 getQueue().add(new QueueParams(QueueParams.METHOD_INCOMING, new Call(call)));
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700444 }
445
446 private void enqueueUpdate(List<Call> calls) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700447 final List<Call> copy = Lists.newArrayList();
448 for (Call call : calls) {
449 copy.add(new Call(call));
450 }
Chiao Chengc340ba92013-08-30 13:04:46 -0700451 getQueue().add(new QueueParams(QueueParams.METHOD_UPDATE, copy));
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700452 }
453
Chiao Chengd38eebc2013-08-28 14:38:14 -0700454 private void processQueue() {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700455 synchronized (mServiceAndQueueLock) {
456 if (mQueue != null) {
457 for (QueueParams params : mQueue) {
458 switch (params.mMethod) {
459 case QueueParams.METHOD_INCOMING:
460 processIncoming((Call) params.mArg);
461 break;
462 case QueueParams.METHOD_UPDATE:
463 processUpdate((List<Call>) params.mArg);
464 break;
465 case QueueParams.METHOD_DISCONNECT:
466 processDisconnect((Call) params.mArg);
467 break;
468 default:
469 throw new IllegalArgumentException("Method type " + params.mMethod +
470 " not recognized.");
471 }
472 }
473 mQueue.clear();
474 mQueue = null;
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700475 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700476 }
477 }
478
Chiao Chengd38eebc2013-08-28 14:38:14 -0700479 /**
480 * Holds method parameters.
481 */
482 private static class QueueParams {
483 private static final int METHOD_INCOMING = 1;
484 private static final int METHOD_UPDATE = 2;
485 private static final int METHOD_DISCONNECT = 3;
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700486
Chiao Chengd38eebc2013-08-28 14:38:14 -0700487 private final int mMethod;
488 private final Object mArg;
489
490 private QueueParams(int method, Object arg) {
491 mMethod = method;
492 this.mArg = arg;
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700493 }
494 }
Santos Cordon89647a62013-07-16 13:38:09 -0700495}