blob: e0aaa18738240a89f0da38fc6d3e7d0a358ce979 [file] [log] [blame]
Santos Cordonb64c1502014-05-21 21:21:49 -07001/*
2 * Copyright (C) 2014 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.telecomm;
18
Santos Cordon46592f02014-07-07 15:11:35 -070019import android.app.AppOpsManager;
Yorke Leeceb96c92014-06-11 16:34:44 -070020import android.content.ComponentName;
Ihab Awad98a55602014-06-30 21:27:28 -070021import android.content.Context;
Santos Cordonfd86bd42014-07-19 14:59:04 -070022
23import android.content.Intent;
Yorke Leeceb96c92014-06-11 16:34:44 -070024import android.content.res.Resources;
Santos Cordon46592f02014-07-07 15:11:35 -070025import android.os.Binder;
Santos Cordonfd86bd42014-07-19 14:59:04 -070026import android.os.Bundle;
Santos Cordonb64c1502014-05-21 21:21:49 -070027import android.os.Handler;
Santos Cordonfd86bd42014-07-19 14:59:04 -070028import android.os.IBinder;
Santos Cordon23baed32014-06-27 14:45:39 -070029import android.os.Looper;
Santos Cordonb64c1502014-05-21 21:21:49 -070030import android.os.Message;
31import android.os.ServiceManager;
Santos Cordon46592f02014-07-07 15:11:35 -070032import android.phone.PhoneManager;
Santos Cordon23baed32014-06-27 14:45:39 -070033import android.telecomm.CallState;
Evan Charlton94d01622014-07-20 12:32:05 -070034import android.telecomm.PhoneAccount;
Evan Charlton89176372014-07-19 18:23:09 -070035import android.telecomm.PhoneAccountHandle;
Santos Cordon46592f02014-07-07 15:11:35 -070036import android.telecomm.TelecommManager;
37import android.telephony.TelephonyManager;
38
39import com.android.internal.telecomm.ITelecommService;
Santos Cordonb64c1502014-05-21 21:21:49 -070040
Ihab Awad60509462014-06-14 16:43:08 -070041import java.util.List;
Santos Cordonb64c1502014-05-21 21:21:49 -070042
43/**
44 * Implementation of the ITelecomm interface.
45 */
46public class TelecommServiceImpl extends ITelecommService.Stub {
Ihab Awadf2a84912014-07-22 21:09:25 -070047 private static final String TELEPHONY_PACKAGE_NAME = "com.android.phone";
48
Santos Cordonfd86bd42014-07-19 14:59:04 -070049 /** ${inheritDoc} */
50 @Override
51 public IBinder asBinder() {
52 return super.asBinder();
53 }
54
55 /**
Santos Cordon23baed32014-06-27 14:45:39 -070056 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
57 * request after sending. The main thread will notify the request when it is complete.
58 */
59 private static final class MainThreadRequest {
60 /** The result of the request that is run on the main thread */
61 public Object result;
62 }
Santos Cordonb64c1502014-05-21 21:21:49 -070063
64 /**
65 * A handler that processes messages on the main thread in the phone process. Since many
66 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
67 * inbound binder threads to the main thread in the phone process.
68 */
Santos Cordon23baed32014-06-27 14:45:39 -070069 private final class MainThreadHandler extends Handler {
Santos Cordonb64c1502014-05-21 21:21:49 -070070 @Override
71 public void handleMessage(Message msg) {
Santos Cordon23baed32014-06-27 14:45:39 -070072 if (msg.obj instanceof MainThreadRequest) {
73 MainThreadRequest request = (MainThreadRequest) msg.obj;
74 Object result = null;
75 switch (msg.what) {
76 case MSG_SILENCE_RINGER:
77 mCallsManager.getRinger().silence();
78 break;
79 case MSG_SHOW_CALL_SCREEN:
80 mCallsManager.getInCallController().bringToForeground(msg.arg1 == 1);
81 break;
Santos Cordon23baed32014-06-27 14:45:39 -070082 case MSG_END_CALL:
83 result = endCallInternal();
84 break;
85 case MSG_ACCEPT_RINGING_CALL:
86 acceptRingingCallInternal();
87 break;
Santos Cordon64c7e962014-07-02 15:15:27 -070088 case MSG_CANCEL_MISSED_CALLS_NOTIFICATION:
89 mMissedCallNotifier.clearMissedCalls();
90 break;
Sailesh Nepalb88795a2014-07-15 14:53:27 -070091 case MSG_IS_TTY_SUPPORTED:
92 result = mCallsManager.isTtySupported();
93 break;
94 case MSG_GET_CURRENT_TTY_MODE:
95 result = mCallsManager.getCurrentTtyMode();
96 break;
Santos Cordon23baed32014-06-27 14:45:39 -070097 }
98
99 if (result != null) {
100 request.result = result;
101 synchronized(request) {
102 request.notifyAll();
103 }
104 }
Santos Cordonb64c1502014-05-21 21:21:49 -0700105 }
106 }
Santos Cordon23baed32014-06-27 14:45:39 -0700107 }
Santos Cordonb64c1502014-05-21 21:21:49 -0700108
Santos Cordon7da72ef2014-06-25 15:50:22 -0700109 /** Private constructor; @see init() */
Santos Cordon23baed32014-06-27 14:45:39 -0700110 private static final String TAG = TelecommServiceImpl.class.getSimpleName();
111
112 private static final String SERVICE_NAME = "telecomm";
113
114 private static final int MSG_SILENCE_RINGER = 1;
115 private static final int MSG_SHOW_CALL_SCREEN = 2;
Santos Cordon626697a2014-07-10 22:36:37 -0700116 private static final int MSG_END_CALL = 3;
117 private static final int MSG_ACCEPT_RINGING_CALL = 4;
118 private static final int MSG_CANCEL_MISSED_CALLS_NOTIFICATION = 5;
Sailesh Nepalb88795a2014-07-15 14:53:27 -0700119 private static final int MSG_IS_TTY_SUPPORTED = 6;
120 private static final int MSG_GET_CURRENT_TTY_MODE = 7;
Santos Cordon23baed32014-06-27 14:45:39 -0700121
122 /** The singleton instance. */
123 private static TelecommServiceImpl sInstance;
124
Santos Cordon46592f02014-07-07 15:11:35 -0700125 private final MainThreadHandler mMainThreadHandler = new MainThreadHandler();
Santos Cordon23baed32014-06-27 14:45:39 -0700126 private final CallsManager mCallsManager = CallsManager.getInstance();
Santos Cordon64c7e962014-07-02 15:15:27 -0700127 private final MissedCallNotifier mMissedCallNotifier;
Santos Cordon176ae282014-07-14 02:02:14 -0700128 private final PhoneAccountRegistrar mPhoneAccountRegistrar;
Santos Cordon46592f02014-07-07 15:11:35 -0700129 private final AppOpsManager mAppOpsManager;
Santos Cordon23baed32014-06-27 14:45:39 -0700130
Santos Cordon176ae282014-07-14 02:02:14 -0700131 private TelecommServiceImpl(
132 MissedCallNotifier missedCallNotifier, PhoneAccountRegistrar phoneAccountRegistrar) {
Santos Cordon64c7e962014-07-02 15:15:27 -0700133 mMissedCallNotifier = missedCallNotifier;
Santos Cordon176ae282014-07-14 02:02:14 -0700134 mPhoneAccountRegistrar = phoneAccountRegistrar;
Santos Cordon46592f02014-07-07 15:11:35 -0700135 mAppOpsManager =
136 (AppOpsManager) TelecommApp.getInstance().getSystemService(Context.APP_OPS_SERVICE);
137
Santos Cordon7da72ef2014-06-25 15:50:22 -0700138 publish();
139 }
140
Santos Cordonb64c1502014-05-21 21:21:49 -0700141 /**
142 * Initialize the singleton TelecommServiceImpl instance.
143 * This is only done once, at startup, from TelecommApp.onCreate().
144 */
Santos Cordon176ae282014-07-14 02:02:14 -0700145 static TelecommServiceImpl init(
146 MissedCallNotifier missedCallNotifier, PhoneAccountRegistrar phoneAccountRegistrar) {
Santos Cordonb64c1502014-05-21 21:21:49 -0700147 synchronized (TelecommServiceImpl.class) {
148 if (sInstance == null) {
Santos Cordon176ae282014-07-14 02:02:14 -0700149 sInstance = new TelecommServiceImpl(missedCallNotifier, phoneAccountRegistrar);
Santos Cordonb64c1502014-05-21 21:21:49 -0700150 } else {
151 Log.wtf(TAG, "init() called multiple times! sInstance %s", sInstance);
152 }
153 return sInstance;
154 }
155 }
156
Santos Cordonb64c1502014-05-21 21:21:49 -0700157 //
Santos Cordon23baed32014-06-27 14:45:39 -0700158 // Implementation of the ITelecommService interface.
Santos Cordonb64c1502014-05-21 21:21:49 -0700159 //
160
Santos Cordon7da72ef2014-06-25 15:50:22 -0700161 @Override
Evan Charlton89176372014-07-19 18:23:09 -0700162 public PhoneAccountHandle getDefaultOutgoingPhoneAccount() {
Ihab Awad104f8062014-07-17 11:29:35 -0700163 try {
164 return mPhoneAccountRegistrar.getDefaultOutgoingPhoneAccount();
165 } catch (Exception e) {
166 Log.e(this, e, "getDefaultOutgoingPhoneAccount");
167 throw e;
168 }
169 }
170
171 @Override
Evan Charlton89176372014-07-19 18:23:09 -0700172 public List<PhoneAccountHandle> getEnabledPhoneAccounts() {
Ihab Awad104f8062014-07-17 11:29:35 -0700173 try {
174 return mPhoneAccountRegistrar.getEnabledPhoneAccounts();
175 } catch (Exception e) {
176 Log.e(this, e, "getEnabledPhoneAccounts");
177 throw e;
178 }
Santos Cordon7da72ef2014-06-25 15:50:22 -0700179 }
180
181 @Override
Evan Charlton94d01622014-07-20 12:32:05 -0700182 public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle) {
Ihab Awad104f8062014-07-17 11:29:35 -0700183 try {
Evan Charlton94d01622014-07-20 12:32:05 -0700184 return mPhoneAccountRegistrar.getPhoneAccount(accountHandle);
Ihab Awad104f8062014-07-17 11:29:35 -0700185 } catch (Exception e) {
Evan Charlton94d01622014-07-20 12:32:05 -0700186 Log.e(this, e, "getPhoneAccount %s", accountHandle);
Ihab Awad104f8062014-07-17 11:29:35 -0700187 throw e;
Santos Cordon176ae282014-07-14 02:02:14 -0700188 }
Ihab Awad502e5fe2014-07-09 12:34:48 -0700189 }
190
191 @Override
Evan Charlton94d01622014-07-20 12:32:05 -0700192 public void registerPhoneAccount(PhoneAccount account) {
Ihab Awad104f8062014-07-17 11:29:35 -0700193 try {
194 enforceModifyPermissionOrCallingPackage(
Evan Charlton94d01622014-07-20 12:32:05 -0700195 account.getAccountHandle().getComponentName().getPackageName());
Ihab Awad293edf22014-07-24 17:52:29 -0700196 if (PhoneAccountRegistrar.has(account, PhoneAccount.CAPABILITY_CALL_PROVIDER) ||
197 PhoneAccountRegistrar.has(account, PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
Ihab Awadf2a84912014-07-22 21:09:25 -0700198 enforceModifyPermissionOrCallingPackage(TELEPHONY_PACKAGE_NAME);
199 }
Evan Charlton94d01622014-07-20 12:32:05 -0700200 mPhoneAccountRegistrar.registerPhoneAccount(account);
Ihab Awad104f8062014-07-17 11:29:35 -0700201 } catch (Exception e) {
Evan Charlton94d01622014-07-20 12:32:05 -0700202 Log.e(this, e, "registerPhoneAccount %s", account);
Ihab Awad104f8062014-07-17 11:29:35 -0700203 throw e;
204 }
Ihab Awad502e5fe2014-07-09 12:34:48 -0700205 }
206
207 @Override
Evan Charlton94d01622014-07-20 12:32:05 -0700208 public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
Ihab Awad104f8062014-07-17 11:29:35 -0700209 try {
Evan Charlton94d01622014-07-20 12:32:05 -0700210 enforceModifyPermissionOrCallingPackage(
211 accountHandle.getComponentName().getPackageName());
212 mPhoneAccountRegistrar.unregisterPhoneAccount(accountHandle);
Ihab Awad104f8062014-07-17 11:29:35 -0700213 } catch (Exception e) {
Evan Charlton94d01622014-07-20 12:32:05 -0700214 Log.e(this, e, "unregisterPhoneAccount %s", accountHandle);
Ihab Awad104f8062014-07-17 11:29:35 -0700215 throw e;
216 }
Ihab Awad502e5fe2014-07-09 12:34:48 -0700217 }
218
219 @Override
220 public void clearAccounts(String packageName) {
Ihab Awad104f8062014-07-17 11:29:35 -0700221 try {
222 enforceModifyPermissionOrCallingPackage(packageName);
223 mPhoneAccountRegistrar.clearAccounts(packageName);
224 } catch (Exception e) {
225 Log.e(this, e, "clearAccounts %s", packageName);
226 throw e;
227 }
Santos Cordon7da72ef2014-06-25 15:50:22 -0700228 }
229
Santos Cordon23baed32014-06-27 14:45:39 -0700230 /**
Santos Cordon176ae282014-07-14 02:02:14 -0700231 * @see TelecommManager#silenceRinger
Santos Cordon23baed32014-06-27 14:45:39 -0700232 */
Santos Cordon7da72ef2014-06-25 15:50:22 -0700233 @Override
Santos Cordonb64c1502014-05-21 21:21:49 -0700234 public void silenceRinger() {
235 Log.d(this, "silenceRinger");
Santos Cordonb64c1502014-05-21 21:21:49 -0700236 enforceModifyPermission();
Santos Cordon23baed32014-06-27 14:45:39 -0700237 sendRequestAsync(MSG_SILENCE_RINGER, 0);
Santos Cordonb64c1502014-05-21 21:21:49 -0700238 }
239
Santos Cordon23baed32014-06-27 14:45:39 -0700240 /**
241 * @see TelecommManager#getDefaultPhoneApp
242 */
Santos Cordon7da72ef2014-06-25 15:50:22 -0700243 @Override
244 public ComponentName getDefaultPhoneApp() {
245 Resources resources = TelecommApp.getInstance().getResources();
246 return new ComponentName(
247 resources.getString(R.string.ui_default_package),
248 resources.getString(R.string.dialer_default_class));
249 }
250
Santos Cordon23baed32014-06-27 14:45:39 -0700251 /**
252 * @see TelecommManager#isInAPhoneCall
253 */
254 @Override
255 public boolean isInAPhoneCall() {
256 enforceReadPermission();
Santos Cordon626697a2014-07-10 22:36:37 -0700257 // Do not use sendRequest() with this method since it could cause a deadlock with
258 // audio service, which we call into from the main thread: AudioManager.setMode().
259 return mCallsManager.hasAnyCalls();
Santos Cordon23baed32014-06-27 14:45:39 -0700260 }
261
262 /**
263 * @see TelecommManager#isRinging
264 */
265 @Override
266 public boolean isRinging() {
267 enforceReadPermission();
Santos Cordon626697a2014-07-10 22:36:37 -0700268 return mCallsManager.hasRingingCall();
Santos Cordon23baed32014-06-27 14:45:39 -0700269 }
270
271 /**
272 * @see TelecommManager#endCall
273 */
274 @Override
275 public boolean endCall() {
276 enforceModifyPermission();
277 return (boolean) sendRequest(MSG_END_CALL);
278 }
279
280 /**
281 * @see TelecommManager#acceptRingingCall
282 */
283 @Override
284 public void acceptRingingCall() {
285 enforceModifyPermission();
286 sendRequestAsync(MSG_ACCEPT_RINGING_CALL, 0);
287 }
288
Santos Cordon46592f02014-07-07 15:11:35 -0700289 /**
290 * @see PhoneManager#showCallScreen
291 */
Santos Cordon23baed32014-06-27 14:45:39 -0700292 @Override
293 public void showCallScreen(boolean showDialpad) {
Santos Cordon46592f02014-07-07 15:11:35 -0700294 enforceReadPermissionOrDefaultDialer();
Santos Cordon64c7e962014-07-02 15:15:27 -0700295 sendRequestAsync(MSG_SHOW_CALL_SCREEN, showDialpad ? 1 : 0);
296 }
297
Santos Cordon46592f02014-07-07 15:11:35 -0700298 /**
299 * @see PhoneManager#cancelMissedCallsNotification
300 */
Santos Cordon64c7e962014-07-02 15:15:27 -0700301 @Override
302 public void cancelMissedCallsNotification() {
Santos Cordon46592f02014-07-07 15:11:35 -0700303 enforceModifyPermissionOrDefaultDialer();
Santos Cordon64c7e962014-07-02 15:15:27 -0700304 sendRequestAsync(MSG_CANCEL_MISSED_CALLS_NOTIFICATION, 0);
Santos Cordon23baed32014-06-27 14:45:39 -0700305 }
306
Santos Cordon46592f02014-07-07 15:11:35 -0700307 /**
308 * @see PhoneManager#handlePinMmi
309 */
310 @Override
311 public boolean handlePinMmi(String dialString) {
312 enforceModifyPermissionOrDefaultDialer();
313
314 // Switch identity so that TelephonyManager checks Telecomm's permissions instead.
315 long token = Binder.clearCallingIdentity();
316 boolean retval = getTelephonyManager().handlePinMmi(dialString);
317 Binder.restoreCallingIdentity(token);
318
319 return retval;
320 }
321
Sailesh Nepalb88795a2014-07-15 14:53:27 -0700322 /**
323 * @see TelecommManager#isTtySupported
324 */
325 @Override
326 public boolean isTtySupported() {
327 enforceReadPermission();
328 return (boolean) sendRequest(MSG_IS_TTY_SUPPORTED);
329 }
330
331 /**
332 * @see TelecommManager#getCurrentTtyMode
333 */
334 @Override
335 public int getCurrentTtyMode() {
336 enforceReadPermission();
337 return (int) sendRequest(MSG_GET_CURRENT_TTY_MODE);
338 }
339
Santos Cordonfd86bd42014-07-19 14:59:04 -0700340 /**
341 * @see TelecommManager#addNewIncomingCall
342 */
343 @Override
344 public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
345 if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) {
346 mAppOpsManager.checkPackage(
347 Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName());
348
349 Intent intent = new Intent(TelecommManager.ACTION_INCOMING_CALL);
350 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
351 intent.putExtra(TelecommManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
352 if (extras != null) {
353 intent.putExtra(TelecommManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
354 }
355
356 long token = Binder.clearCallingIdentity();
357 TelecommApp.getInstance().startActivity(intent);
358 Binder.restoreCallingIdentity(token);
359 }
360 }
361
Santos Cordon7da72ef2014-06-25 15:50:22 -0700362 //
Santos Cordon46592f02014-07-07 15:11:35 -0700363 // Supporting methods for the ITelecommService interface implementation.
Santos Cordon7da72ef2014-06-25 15:50:22 -0700364 //
365
Santos Cordon23baed32014-06-27 14:45:39 -0700366 private void acceptRingingCallInternal() {
367 Call call = mCallsManager.getFirstCallWithState(CallState.RINGING);
368 if (call != null) {
Andrew Lee38931d02014-07-16 10:17:36 -0700369 call.answer(call.getVideoState());
Santos Cordon23baed32014-06-27 14:45:39 -0700370 }
371 }
372
373 private boolean endCallInternal() {
374 // Always operate on the foreground call if one exists, otherwise get the first call in
375 // priority order by call-state.
376 Call call = mCallsManager.getForegroundCall();
377 if (call == null) {
378 call = mCallsManager.getFirstCallWithState(
379 CallState.ACTIVE,
380 CallState.DIALING,
381 CallState.RINGING,
382 CallState.ON_HOLD);
383 }
384
385 if (call != null) {
386 if (call.getState() == CallState.RINGING) {
387 call.reject(false /* rejectWithMessage */, null);
388 } else {
389 call.disconnect();
390 }
391 return true;
392 }
393
394 return false;
Santos Cordonb64c1502014-05-21 21:21:49 -0700395 }
396
397 /**
398 * Make sure the caller has the MODIFY_PHONE_STATE permission.
399 *
400 * @throws SecurityException if the caller does not have the required permission
401 */
402 private void enforceModifyPermission() {
403 TelecommApp.getInstance().enforceCallingOrSelfPermission(
404 android.Manifest.permission.MODIFY_PHONE_STATE, null);
405 }
Santos Cordonf3671a62014-05-29 21:51:53 -0700406
Santos Cordon46592f02014-07-07 15:11:35 -0700407 private void enforceModifyPermissionOrDefaultDialer() {
408 if (!isDefaultDialerCalling()) {
409 enforceModifyPermission();
410 }
411 }
412
Ihab Awad502e5fe2014-07-09 12:34:48 -0700413 private void enforceModifyPermissionOrCallingPackage(String packageName) {
Santos Cordondf399862014-08-06 04:39:15 -0700414 // TODO: Use a new telecomm permission for this instead of reusing modify.
Ihab Awad502e5fe2014-07-09 12:34:48 -0700415 try {
416 enforceModifyPermission();
417 } catch (SecurityException e) {
418 enforceCallingPackage(packageName);
419 }
420 }
421
Santos Cordon23baed32014-06-27 14:45:39 -0700422 private void enforceReadPermission() {
423 TelecommApp.getInstance().enforceCallingOrSelfPermission(
424 android.Manifest.permission.READ_PHONE_STATE, null);
Santos Cordonf3671a62014-05-29 21:51:53 -0700425 }
Yorke Leeceb96c92014-06-11 16:34:44 -0700426
Santos Cordon46592f02014-07-07 15:11:35 -0700427 private void enforceReadPermissionOrDefaultDialer() {
428 if (!isDefaultDialerCalling()) {
429 enforceReadPermission();
430 }
431 }
432
Ihab Awad502e5fe2014-07-09 12:34:48 -0700433 private void enforceCallingPackage(String packageName) {
434 mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
435 }
436
Ihab Awad98a55602014-06-30 21:27:28 -0700437 private void showCallScreenInternal(boolean showDialpad) {
438 CallsManager.getInstance().getInCallController().bringToForeground(showDialpad);
439 }
Ihab Awad60509462014-06-14 16:43:08 -0700440
Santos Cordon46592f02014-07-07 15:11:35 -0700441 private boolean isDefaultDialerCalling() {
442 ComponentName defaultDialerComponent = getDefaultPhoneApp();
443 if (defaultDialerComponent != null) {
444 try {
445 mAppOpsManager.checkPackage(
446 Binder.getCallingUid(), defaultDialerComponent.getPackageName());
447 return true;
448 } catch (SecurityException e) {
449 Log.e(TAG, e, "Could not get default dialer.");
450 }
451 }
452 return false;
453 }
454
455 private TelephonyManager getTelephonyManager() {
456 return (TelephonyManager)
457 TelecommApp.getInstance().getSystemService(Context.TELEPHONY_SERVICE);
458 }
459
Santos Cordon7da72ef2014-06-25 15:50:22 -0700460 private void publish() {
461 Log.d(this, "publish: %s", this);
462 ServiceManager.addService(SERVICE_NAME, this);
Ihab Awad60509462014-06-14 16:43:08 -0700463 }
Santos Cordon23baed32014-06-27 14:45:39 -0700464
465 private MainThreadRequest sendRequestAsync(int command, int arg1) {
466 MainThreadRequest request = new MainThreadRequest();
467 mMainThreadHandler.obtainMessage(command, arg1, 0, request).sendToTarget();
468 return request;
469 }
470
471 /**
472 * Posts the specified command to be executed on the main thread, waits for the request to
473 * complete, and returns the result.
474 */
475 private Object sendRequest(int command) {
476 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
Sailesh Nepalbca199f2014-07-02 15:57:44 -0700477 MainThreadRequest request = new MainThreadRequest();
478 mMainThreadHandler.handleMessage(mMainThreadHandler.obtainMessage(command, request));
479 return request.result;
480 } else {
481 MainThreadRequest request = sendRequestAsync(command, 0);
Santos Cordon23baed32014-06-27 14:45:39 -0700482
Sailesh Nepalbca199f2014-07-02 15:57:44 -0700483 // Wait for the request to complete
484 synchronized (request) {
485 while (request.result == null) {
486 try {
487 request.wait();
488 } catch (InterruptedException e) {
489 // Do nothing, go back and wait until the request is complete
490 }
Santos Cordon23baed32014-06-27 14:45:39 -0700491 }
492 }
Sailesh Nepalbca199f2014-07-02 15:57:44 -0700493 return request.result;
Santos Cordon23baed32014-06-27 14:45:39 -0700494 }
Santos Cordon23baed32014-06-27 14:45:39 -0700495 }
Santos Cordonb64c1502014-05-21 21:21:49 -0700496}