blob: 4820b33b6feaced8f289481795b7e82ab3bb5adc [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;
28import android.os.RemoteException;
29import android.os.SystemProperties;
30import android.util.Log;
31
Santos Cordon9b7bac72013-08-06 08:04:52 -070032import com.android.phone.AudioRouter.AudioModeListener;
33import com.android.services.telephony.common.AudioMode;
Santos Cordonf4046882013-07-25 18:49:27 -070034import com.android.services.telephony.common.Call;
Santos Cordon345350e2013-07-19 17:16:14 -070035import com.android.services.telephony.common.ICallHandlerService;
Chiao Cheng6c6b2722013-08-22 18:35:54 -070036import com.google.common.collect.Lists;
Santos Cordon89647a62013-07-16 13:38:09 -070037
Santos Cordona3d05142013-07-29 11:25:17 -070038import java.util.List;
39
Santos Cordon89647a62013-07-16 13:38:09 -070040/**
Santos Cordon345350e2013-07-19 17:16:14 -070041 * This class is responsible for passing through call state changes to the CallHandlerService.
Santos Cordon89647a62013-07-16 13:38:09 -070042 */
Chiao Cheng6c6b2722013-08-22 18:35:54 -070043public class CallHandlerServiceProxy extends Handler
44 implements CallModeler.Listener, AudioModeListener {
Santos Cordon89647a62013-07-16 13:38:09 -070045
Santos Cordon345350e2013-07-19 17:16:14 -070046 private static final String TAG = CallHandlerServiceProxy.class.getSimpleName();
Chiao Cheng3e6486e2013-09-03 19:27:46 -070047 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 0) && (SystemProperties.getInt(
Chiao Cheng6c6b2722013-08-22 18:35:54 -070048 "ro.debuggable", 0) == 1);
Chiao Chenge41661c2013-07-23 13:28:26 -070049
Chiao Cheng6c6b2722013-08-22 18:35:54 -070050 public static final int RETRY_DELAY_MILLIS = 2000;
51 private static final int BIND_RETRY_MSG = 1;
52 private static final int MAX_RETRY_COUNT = 5;
Santos Cordon89647a62013-07-16 13:38:09 -070053
Santos Cordon593ab382013-08-06 21:58:23 -070054 private AudioRouter mAudioRouter;
Santos Cordoncba1b442013-07-18 12:43:58 -070055 private CallCommandService mCallCommandService;
Santos Cordon593ab382013-08-06 21:58:23 -070056 private CallModeler mCallModeler;
57 private Context mContext;
Chiao Chengd38eebc2013-08-28 14:38:14 -070058
Chiao Cheng6c6b2722013-08-22 18:35:54 -070059 private ICallHandlerService mCallHandlerServiceGuarded; // Guarded by mServiceAndQueueLock
Chiao Chengd38eebc2013-08-28 14:38:14 -070060 // Single queue to guarantee ordering
61 private List<QueueParams> mQueue; // Guarded by mServiceAndQueueLock
62
Chiao Cheng6c6b2722013-08-22 18:35:54 -070063 private final Object mServiceAndQueueLock = new Object();
64 private int mBindRetryCount = 0;
65
66 @Override
67 public void handleMessage(Message msg) {
68 super.handleMessage(msg);
69
70 switch (msg.what) {
71 case BIND_RETRY_MSG:
72 setupServiceConnection();
73 break;
74 }
75 }
Santos Cordon89647a62013-07-16 13:38:09 -070076
Santos Cordon63a84242013-07-23 13:32:52 -070077 public CallHandlerServiceProxy(Context context, CallModeler callModeler,
Santos Cordon593ab382013-08-06 21:58:23 -070078 CallCommandService callCommandService, AudioRouter audioRouter) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -070079 if (DBG) {
80 Log.d(TAG, "init CallHandlerServiceProxy");
81 }
Santos Cordon89647a62013-07-16 13:38:09 -070082 mContext = context;
Santos Cordoncba1b442013-07-18 12:43:58 -070083 mCallCommandService = callCommandService;
Santos Cordon63a84242013-07-23 13:32:52 -070084 mCallModeler = callModeler;
Santos Cordon593ab382013-08-06 21:58:23 -070085 mAudioRouter = audioRouter;
Santos Cordon89647a62013-07-16 13:38:09 -070086
Santos Cordon593ab382013-08-06 21:58:23 -070087 mAudioRouter.addAudioModeListener(this);
Christine Chendaf7bf62013-08-05 19:12:31 -070088 mCallModeler.addListener(this);
Santos Cordon63a84242013-07-23 13:32:52 -070089 }
Santos Cordon89647a62013-07-16 13:38:09 -070090
Santos Cordon63a84242013-07-23 13:32:52 -070091 @Override
Santos Cordon995c8162013-07-29 09:22:22 -070092 public void onDisconnect(Call call) {
Chiao Cheng3e6486e2013-09-03 19:27:46 -070093 synchronized (mServiceAndQueueLock) {
94 if (mCallHandlerServiceGuarded == null) {
95 if (DBG) {
96 Log.d(TAG, "CallHandlerService not connected. Enqueue disconnect");
Chiao Cheng6c6b2722013-08-22 18:35:54 -070097 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -070098 enqueueDisconnect(call);
99 setupServiceConnection();
100 return;
Santos Cordon63a84242013-07-23 13:32:52 -0700101 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700102 }
103 processDisconnect(call);
104 }
105
106 private void processDisconnect(Call call) {
107 try {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700108 if (DBG) {
109 Log.d(TAG, "onDisconnect: " + call);
110 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700111 synchronized (mServiceAndQueueLock) {
112 if (mCallHandlerServiceGuarded != null) {
113 mCallHandlerServiceGuarded.onDisconnect(call);
114 }
115 }
116 if (!mCallModeler.hasLiveCall()) {
117 unbind();
118 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700119 } catch (Exception e) {
120 Log.e(TAG, "Remote exception handling onDisconnect ", e);
Santos Cordon89647a62013-07-16 13:38:09 -0700121 }
122 }
123
Santos Cordona3d05142013-07-29 11:25:17 -0700124 @Override
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700125 public void onIncoming(Call call) {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700126 synchronized (mServiceAndQueueLock) {
127 if (mCallHandlerServiceGuarded == null) {
128 if (DBG) {
129 Log.d(TAG, "CallHandlerService not connected. Enqueue incoming.");
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700130 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700131 enqueueIncoming(call);
132 setupServiceConnection();
133 return;
Christine Chenee09a492013-08-06 16:02:29 -0700134 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700135 }
136 processIncoming(call);
137 }
138
139 private void processIncoming(Call call) {
140 if (DBG) {
141 Log.d(TAG, "onIncoming: " + call);
142 }
143 try {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700144 // TODO(klp): check RespondViaSmsManager.allowRespondViaSmsForCall()
145 // must refactor call method to accept proper call object.
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700146 synchronized (mServiceAndQueueLock) {
147 if (mCallHandlerServiceGuarded != null) {
148 mCallHandlerServiceGuarded.onIncoming(call,
149 RejectWithTextMessageManager.loadCannedResponses());
150 }
151 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700152 } catch (Exception e) {
153 Log.e(TAG, "Remote exception handling onUpdate", e);
Christine Chenee09a492013-08-06 16:02:29 -0700154 }
155 }
156
157 @Override
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700158 public void onUpdate(List<Call> calls) {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700159 synchronized (mServiceAndQueueLock) {
160 if (mCallHandlerServiceGuarded == null) {
161 if (DBG) {
162 Log.d(TAG, "CallHandlerService not connected. Enqueue update.");
163 }
164 enqueueUpdate(calls);
165 setupServiceConnection();
166 return;
167 }
168 }
169 processUpdate(calls);
170 }
171
172 private void processUpdate(List<Call> calls) {
173 if (DBG) {
174 Log.d(TAG, "onUpdate: " + calls.toString());
175 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700176 try {
177 synchronized (mServiceAndQueueLock) {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700178 if (mCallHandlerServiceGuarded != null) {
179 mCallHandlerServiceGuarded.onUpdate(calls);
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700180 }
Santos Cordona3d05142013-07-29 11:25:17 -0700181 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700182 if (!mCallModeler.hasLiveCall()) {
183 // TODO: unbinding happens in both onUpdate and onDisconnect because the ordering
184 // is not deterministic. Unbinding in both ensures that the service is unbound.
185 // But it also makes this in-efficient because we are unbinding twice, which leads
186 // to the CallHandlerService performing onCreate() and onDestroy() twice for each
187 // disconnect.
188 unbind();
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700189 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700190 } catch (Exception e) {
191 Log.e(TAG, "Remote exception handling onUpdate", e);
Santos Cordona3d05142013-07-29 11:25:17 -0700192 }
193 }
194
Chiao Cheng3f015c92013-09-06 15:56:27 -0700195
196 @Override
197 public void onPostDialWait(int callId, String remainingChars) {
198 try {
199 synchronized (mServiceAndQueueLock) {
200 if (mCallHandlerServiceGuarded == null) {
201 if (DBG) {
202 Log.d(TAG, "CallHandlerService not conneccted. Skipping "
203 + "onPostDialWait().");
204 }
205 return;
206 }
207 }
208
209 mCallHandlerServiceGuarded.onPostDialWait(callId, remainingChars);
210 } catch (Exception e) {
211 Log.e(TAG, "Remote exception handling onUpdate", e);
212 }
213 }
214
Santos Cordon9b7bac72013-08-06 08:04:52 -0700215 @Override
Santos Cordoncd95f622013-08-29 03:38:52 -0700216 public void onAudioModeChange(int newMode, boolean muted) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700217 try {
218 synchronized (mServiceAndQueueLock) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700219 if (mCallHandlerServiceGuarded == null) {
220 if (DBG) {
221 Log.d(TAG, "CallHandlerService not conneccted. Skipping "
222 + "onAudioModeChange().");
223 }
224 return;
225 }
Santos Cordon9b7bac72013-08-06 08:04:52 -0700226 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700227
228 // Just do a simple log for now.
229 Log.i(TAG, "Updating with new audio mode: " + AudioMode.toString(newMode) +
Santos Cordoncd95f622013-08-29 03:38:52 -0700230 " with mute " + muted);
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700231
232 if (DBG) {
233 Log.d(TAG, "onSupportAudioModeChange");
234 }
235
Santos Cordoncd95f622013-08-29 03:38:52 -0700236 mCallHandlerServiceGuarded.onAudioModeChange(newMode, muted);
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700237 } catch (Exception e) {
238 Log.e(TAG, "Remote exception handling onAudioModeChange", e);
Santos Cordon9b7bac72013-08-06 08:04:52 -0700239 }
240 }
241
Santos Cordon593ab382013-08-06 21:58:23 -0700242 @Override
243 public void onSupportedAudioModeChange(int modeMask) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700244 try {
245 synchronized (mServiceAndQueueLock) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700246 if (mCallHandlerServiceGuarded == null) {
247 if (DBG) {
248 Log.d(TAG, "CallHandlerService not conneccted. Skipping"
249 + "onSupportedAudioModeChange().");
250 }
251 return;
252 }
253 }
Santos Cordon593ab382013-08-06 21:58:23 -0700254
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700255 if (DBG) {
256 Log.d(TAG, "onSupportAudioModeChange: " + AudioMode.toString(modeMask));
257 }
258
259 mCallHandlerServiceGuarded.onSupportedAudioModeChange(modeMask);
260 } catch (Exception e) {
261 Log.e(TAG, "Remote exception handling onAudioModeChange", e);
262 }
263
264 }
265
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700266 private ServiceConnection mConnection = null;
267
268 private class InCallServiceConnection implements ServiceConnection {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700269 @Override public void onServiceConnected (ComponentName className, IBinder service){
270 if (DBG) {
271 Log.d(TAG, "Service Connected");
272 }
273 onCallHandlerServiceConnected(ICallHandlerService.Stub.asInterface(service));
Chiao Cheng11a4b652013-09-02 01:08:19 -0700274 mBindRetryCount = 0;
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700275 }
276
277 @Override public void onServiceDisconnected (ComponentName className){
278 Log.i(TAG, "Disconnected from UI service.");
279 synchronized (mServiceAndQueueLock) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700280 // Technically, unbindService is un-necessary since the framework will schedule and
281 // restart the crashed service. But there is a exponential backoff for the restart.
282 // Unbind explicitly and setup again to avoid the backoff since it's important to
283 // always have an in call ui.
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700284 unbind();
285
286 // TODO(klp): hang up all calls.
Santos Cordon593ab382013-08-06 21:58:23 -0700287 }
288 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700289 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700290
Santos Cordon406c0342013-08-28 00:07:47 -0700291 public void bringToForeground() {
292 // only support this call if the service is already connected.
Santos Cordon19d814b2013-08-28 14:58:17 -0700293 synchronized (mServiceAndQueueLock) {
294 if (mCallHandlerServiceGuarded != null && mCallModeler.hasLiveCall()) {
295 try {
296 if (DBG) Log.d(TAG, "bringToForeground");
297 mCallHandlerServiceGuarded.bringToForeground();
298 } catch (RemoteException e) {
299 Log.e(TAG, "Exception handling bringToForeground", e);
300 }
Santos Cordon406c0342013-08-28 00:07:47 -0700301 }
302 }
303 }
304
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700305 private static Intent getInCallServiceIntent(Context context) {
306 final Intent serviceIntent = new Intent(ICallHandlerService.class.getName());
307 final ComponentName component = new ComponentName(context.getResources().getString(
308 R.string.incall_ui_default_package), context.getResources().getString(
309 R.string.incall_ui_default_class));
310 serviceIntent.setComponent(component);
311 return serviceIntent;
312 }
313
Santos Cordon89647a62013-07-16 13:38:09 -0700314 /**
Santos Cordon345350e2013-07-19 17:16:14 -0700315 * Sets up the connection with ICallHandlerService
Santos Cordon89647a62013-07-16 13:38:09 -0700316 */
317 private void setupServiceConnection() {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700318 if (!PhoneGlobals.sVoiceCapable) {
319 return;
320 }
Chiao Cheng11a4b652013-09-02 01:08:19 -0700321
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700322 final Intent serviceIntent = getInCallServiceIntent(mContext);
Chiao Cheng11a4b652013-09-02 01:08:19 -0700323 if (DBG) {
324 Log.d(TAG, "binding to service " + serviceIntent);
325 }
326
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700327 synchronized (mServiceAndQueueLock) {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700328 if (mConnection == null) {
329 mConnection = new InCallServiceConnection();
330
331 final PackageManager packageManger = mContext.getPackageManager();
332 final List<ResolveInfo> services = packageManger.queryIntentServices(serviceIntent,
333 0);
334 if (services.size() == 0) {
335 // Service not found, retry again after some delay
336 // This can happen if the service is being installed by the package manager.
337 // Between deletes and installs, bindService could get a silent service not
338 // found error.
339 mBindRetryCount++;
340 if (mBindRetryCount < MAX_RETRY_COUNT) {
341 Log.w(TAG, "InCallUI service not found. " + serviceIntent
342 + ". This happens if the service is being installed and should be"
343 + " transient. Retrying" + RETRY_DELAY_MILLIS + " ms.");
344 sendMessageDelayed(Message.obtain(this, BIND_RETRY_MSG),
345 RETRY_DELAY_MILLIS);
346 } else {
347 Log.e(TAG, "Tried to bind to in-call UI " + MAX_RETRY_COUNT + " times."
348 + " Giving up.");
349 }
350 return;
351 }
352
353 if (DBG) {
354 Log.d(TAG, "binding to service " + serviceIntent);
355 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700356 if (!mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)) {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700357 // This happens when the in-call package is in the middle of being
358 // installed.
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700359 // Delay the retry.
360 mBindRetryCount++;
361 if (mBindRetryCount < MAX_RETRY_COUNT) {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700362 Log.e(TAG, "bindService failed on " + serviceIntent + ". Retrying in "
363 + RETRY_DELAY_MILLIS + " ms.");
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700364 sendMessageDelayed(Message.obtain(this, BIND_RETRY_MSG),
365 RETRY_DELAY_MILLIS);
366 } else {
367 Log.wtf(TAG, "Tried to bind to in-call UI " + MAX_RETRY_COUNT + " times."
368 + " Giving up.");
369 }
370 }
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700371
372 } else {
373 Log.d(TAG, "Service connection to in call service already started.");
Santos Cordonaf763a12013-08-19 20:04:58 -0700374 }
375 }
376 }
377
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700378 private void unbind() {
379 synchronized (mServiceAndQueueLock) {
380 if (mCallHandlerServiceGuarded != null) {
381 Log.d(TAG, "Unbinding service.");
382 mCallHandlerServiceGuarded = null;
383 mContext.unbindService(mConnection);
384 }
385 mConnection = null;
386 }
387 }
388
Santos Cordonaf763a12013-08-19 20:04:58 -0700389 /**
Santos Cordoncba1b442013-07-18 12:43:58 -0700390 * Called when the in-call UI service is connected. Send command interface to in-call.
391 */
Santos Cordon63a84242013-07-23 13:32:52 -0700392 private void onCallHandlerServiceConnected(ICallHandlerService callHandlerService) {
Chiao Chengd38eebc2013-08-28 14:38:14 -0700393
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700394 synchronized (mServiceAndQueueLock) {
395 mCallHandlerServiceGuarded = callHandlerService;
396
Santos Cordonad078192013-08-28 15:14:54 -0700397 // Before we send any updates, we need to set up the initial service calls.
398 makeInitialServiceCalls();
399
Chiao Chengd38eebc2013-08-28 14:38:14 -0700400 processQueue();
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700401 }
Santos Cordonad078192013-08-28 15:14:54 -0700402 }
Santos Cordoncba1b442013-07-18 12:43:58 -0700403
Santos Cordonad078192013-08-28 15:14:54 -0700404 /**
405 * Makes initial service calls to set up callcommandservice and audio modes.
406 */
407 private void makeInitialServiceCalls() {
Santos Cordoncba1b442013-07-18 12:43:58 -0700408 try {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700409 mCallHandlerServiceGuarded.setCallCommandService(mCallCommandService);
Santos Cordonad078192013-08-28 15:14:54 -0700410
411 onSupportedAudioModeChange(mAudioRouter.getSupportedAudioModes());
Santos Cordon8fd0ec72013-08-29 16:44:43 -0700412 onAudioModeChange(mAudioRouter.getAudioMode(), mAudioRouter.getMute());
Santos Cordoncba1b442013-07-18 12:43:58 -0700413 } catch (RemoteException e) {
Santos Cordon63a84242013-07-23 13:32:52 -0700414 Log.e(TAG, "Remote exception calling CallHandlerService::setCallCommandService", e);
Santos Cordon89647a62013-07-16 13:38:09 -0700415 }
416 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700417
Chiao Chengd38eebc2013-08-28 14:38:14 -0700418 private List<QueueParams> getQueue() {
419 if (mQueue == null) {
420 mQueue = Lists.newArrayList();
421 }
422 return mQueue;
423 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700424
425 private void enqueueDisconnect(Call call) {
Chiao Chengd38eebc2013-08-28 14:38:14 -0700426 getQueue().add(new QueueParams(QueueParams.METHOD_DISCONNECT, new Call(call)));
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700427 }
428
429 private void enqueueIncoming(Call call) {
Chiao Chengd38eebc2013-08-28 14:38:14 -0700430 getQueue().add(new QueueParams(QueueParams.METHOD_INCOMING, new Call(call)));
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700431 }
432
433 private void enqueueUpdate(List<Call> calls) {
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700434 final List<Call> copy = Lists.newArrayList();
435 for (Call call : calls) {
436 copy.add(new Call(call));
437 }
Chiao Chengc340ba92013-08-30 13:04:46 -0700438 getQueue().add(new QueueParams(QueueParams.METHOD_UPDATE, copy));
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700439 }
440
Chiao Chengd38eebc2013-08-28 14:38:14 -0700441 private void processQueue() {
Chiao Cheng3e6486e2013-09-03 19:27:46 -0700442 synchronized (mServiceAndQueueLock) {
443 if (mQueue != null) {
444 for (QueueParams params : mQueue) {
445 switch (params.mMethod) {
446 case QueueParams.METHOD_INCOMING:
447 processIncoming((Call) params.mArg);
448 break;
449 case QueueParams.METHOD_UPDATE:
450 processUpdate((List<Call>) params.mArg);
451 break;
452 case QueueParams.METHOD_DISCONNECT:
453 processDisconnect((Call) params.mArg);
454 break;
455 default:
456 throw new IllegalArgumentException("Method type " + params.mMethod +
457 " not recognized.");
458 }
459 }
460 mQueue.clear();
461 mQueue = null;
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700462 }
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700463 }
464 }
465
Chiao Chengd38eebc2013-08-28 14:38:14 -0700466 /**
467 * Holds method parameters.
468 */
469 private static class QueueParams {
470 private static final int METHOD_INCOMING = 1;
471 private static final int METHOD_UPDATE = 2;
472 private static final int METHOD_DISCONNECT = 3;
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700473
Chiao Chengd38eebc2013-08-28 14:38:14 -0700474 private final int mMethod;
475 private final Object mArg;
476
477 private QueueParams(int method, Object arg) {
478 mMethod = method;
479 this.mArg = arg;
Chiao Cheng6c6b2722013-08-22 18:35:54 -0700480 }
481 }
Santos Cordon89647a62013-07-16 13:38:09 -0700482}