blob: 9366f84f3062330bb2ac51cc38c540d99505a809 [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 Awadc17294c2014-08-04 19:23:37 -070047 private static final String REGISTER_PROVIDER_OR_SUBSCRIPTION =
48 "com.android.telecomm.permission.REGISTER_PROVIDER_OR_SUBSCRIPTION";
Ihab Awadf2a84912014-07-22 21:09:25 -070049
Santos Cordonfd86bd42014-07-19 14:59:04 -070050 /** ${inheritDoc} */
51 @Override
52 public IBinder asBinder() {
53 return super.asBinder();
54 }
55
56 /**
Santos Cordon23baed32014-06-27 14:45:39 -070057 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
58 * request after sending. The main thread will notify the request when it is complete.
59 */
60 private static final class MainThreadRequest {
61 /** The result of the request that is run on the main thread */
62 public Object result;
63 }
Santos Cordonb64c1502014-05-21 21:21:49 -070064
65 /**
66 * A handler that processes messages on the main thread in the phone process. Since many
67 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
68 * inbound binder threads to the main thread in the phone process.
69 */
Santos Cordon23baed32014-06-27 14:45:39 -070070 private final class MainThreadHandler extends Handler {
Santos Cordonb64c1502014-05-21 21:21:49 -070071 @Override
72 public void handleMessage(Message msg) {
Santos Cordon23baed32014-06-27 14:45:39 -070073 if (msg.obj instanceof MainThreadRequest) {
74 MainThreadRequest request = (MainThreadRequest) msg.obj;
75 Object result = null;
76 switch (msg.what) {
77 case MSG_SILENCE_RINGER:
78 mCallsManager.getRinger().silence();
79 break;
80 case MSG_SHOW_CALL_SCREEN:
81 mCallsManager.getInCallController().bringToForeground(msg.arg1 == 1);
82 break;
Santos Cordon23baed32014-06-27 14:45:39 -070083 case MSG_END_CALL:
84 result = endCallInternal();
85 break;
86 case MSG_ACCEPT_RINGING_CALL:
87 acceptRingingCallInternal();
88 break;
Santos Cordon64c7e962014-07-02 15:15:27 -070089 case MSG_CANCEL_MISSED_CALLS_NOTIFICATION:
90 mMissedCallNotifier.clearMissedCalls();
91 break;
Sailesh Nepalb88795a2014-07-15 14:53:27 -070092 case MSG_IS_TTY_SUPPORTED:
93 result = mCallsManager.isTtySupported();
94 break;
95 case MSG_GET_CURRENT_TTY_MODE:
96 result = mCallsManager.getCurrentTtyMode();
97 break;
Santos Cordon23baed32014-06-27 14:45:39 -070098 }
99
100 if (result != null) {
101 request.result = result;
102 synchronized(request) {
103 request.notifyAll();
104 }
105 }
Santos Cordonb64c1502014-05-21 21:21:49 -0700106 }
107 }
Santos Cordon23baed32014-06-27 14:45:39 -0700108 }
Santos Cordonb64c1502014-05-21 21:21:49 -0700109
Santos Cordon7da72ef2014-06-25 15:50:22 -0700110 /** Private constructor; @see init() */
Santos Cordon23baed32014-06-27 14:45:39 -0700111 private static final String TAG = TelecommServiceImpl.class.getSimpleName();
112
113 private static final String SERVICE_NAME = "telecomm";
114
115 private static final int MSG_SILENCE_RINGER = 1;
116 private static final int MSG_SHOW_CALL_SCREEN = 2;
Santos Cordon626697a2014-07-10 22:36:37 -0700117 private static final int MSG_END_CALL = 3;
118 private static final int MSG_ACCEPT_RINGING_CALL = 4;
119 private static final int MSG_CANCEL_MISSED_CALLS_NOTIFICATION = 5;
Sailesh Nepalb88795a2014-07-15 14:53:27 -0700120 private static final int MSG_IS_TTY_SUPPORTED = 6;
121 private static final int MSG_GET_CURRENT_TTY_MODE = 7;
Santos Cordon23baed32014-06-27 14:45:39 -0700122
123 /** The singleton instance. */
124 private static TelecommServiceImpl sInstance;
125
Santos Cordon46592f02014-07-07 15:11:35 -0700126 private final MainThreadHandler mMainThreadHandler = new MainThreadHandler();
Santos Cordon23baed32014-06-27 14:45:39 -0700127 private final CallsManager mCallsManager = CallsManager.getInstance();
Santos Cordon64c7e962014-07-02 15:15:27 -0700128 private final MissedCallNotifier mMissedCallNotifier;
Santos Cordon176ae282014-07-14 02:02:14 -0700129 private final PhoneAccountRegistrar mPhoneAccountRegistrar;
Santos Cordon46592f02014-07-07 15:11:35 -0700130 private final AppOpsManager mAppOpsManager;
Santos Cordon23baed32014-06-27 14:45:39 -0700131
Santos Cordon176ae282014-07-14 02:02:14 -0700132 private TelecommServiceImpl(
133 MissedCallNotifier missedCallNotifier, PhoneAccountRegistrar phoneAccountRegistrar) {
Santos Cordon64c7e962014-07-02 15:15:27 -0700134 mMissedCallNotifier = missedCallNotifier;
Santos Cordon176ae282014-07-14 02:02:14 -0700135 mPhoneAccountRegistrar = phoneAccountRegistrar;
Santos Cordon46592f02014-07-07 15:11:35 -0700136 mAppOpsManager =
137 (AppOpsManager) TelecommApp.getInstance().getSystemService(Context.APP_OPS_SERVICE);
138
Santos Cordon7da72ef2014-06-25 15:50:22 -0700139 publish();
140 }
141
Santos Cordonb64c1502014-05-21 21:21:49 -0700142 /**
143 * Initialize the singleton TelecommServiceImpl instance.
144 * This is only done once, at startup, from TelecommApp.onCreate().
145 */
Santos Cordon176ae282014-07-14 02:02:14 -0700146 static TelecommServiceImpl init(
147 MissedCallNotifier missedCallNotifier, PhoneAccountRegistrar phoneAccountRegistrar) {
Santos Cordonb64c1502014-05-21 21:21:49 -0700148 synchronized (TelecommServiceImpl.class) {
149 if (sInstance == null) {
Santos Cordon176ae282014-07-14 02:02:14 -0700150 sInstance = new TelecommServiceImpl(missedCallNotifier, phoneAccountRegistrar);
Santos Cordonb64c1502014-05-21 21:21:49 -0700151 } else {
152 Log.wtf(TAG, "init() called multiple times! sInstance %s", sInstance);
153 }
154 return sInstance;
155 }
156 }
157
Santos Cordonb64c1502014-05-21 21:21:49 -0700158 //
Santos Cordon23baed32014-06-27 14:45:39 -0700159 // Implementation of the ITelecommService interface.
Santos Cordonb64c1502014-05-21 21:21:49 -0700160 //
161
Santos Cordon7da72ef2014-06-25 15:50:22 -0700162 @Override
Evan Charlton89176372014-07-19 18:23:09 -0700163 public PhoneAccountHandle getDefaultOutgoingPhoneAccount() {
Ihab Awad104f8062014-07-17 11:29:35 -0700164 try {
165 return mPhoneAccountRegistrar.getDefaultOutgoingPhoneAccount();
166 } catch (Exception e) {
167 Log.e(this, e, "getDefaultOutgoingPhoneAccount");
168 throw e;
169 }
170 }
171
172 @Override
Evan Charlton89176372014-07-19 18:23:09 -0700173 public List<PhoneAccountHandle> getEnabledPhoneAccounts() {
Ihab Awad104f8062014-07-17 11:29:35 -0700174 try {
175 return mPhoneAccountRegistrar.getEnabledPhoneAccounts();
176 } catch (Exception e) {
177 Log.e(this, e, "getEnabledPhoneAccounts");
178 throw e;
179 }
Santos Cordon7da72ef2014-06-25 15:50:22 -0700180 }
181
182 @Override
Evan Charlton94d01622014-07-20 12:32:05 -0700183 public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle) {
Ihab Awad104f8062014-07-17 11:29:35 -0700184 try {
Evan Charlton94d01622014-07-20 12:32:05 -0700185 return mPhoneAccountRegistrar.getPhoneAccount(accountHandle);
Ihab Awad104f8062014-07-17 11:29:35 -0700186 } catch (Exception e) {
Evan Charlton94d01622014-07-20 12:32:05 -0700187 Log.e(this, e, "getPhoneAccount %s", accountHandle);
Ihab Awad104f8062014-07-17 11:29:35 -0700188 throw e;
Santos Cordon176ae282014-07-14 02:02:14 -0700189 }
Ihab Awad502e5fe2014-07-09 12:34:48 -0700190 }
191
192 @Override
Evan Charlton94d01622014-07-20 12:32:05 -0700193 public void registerPhoneAccount(PhoneAccount account) {
Ihab Awad104f8062014-07-17 11:29:35 -0700194 try {
195 enforceModifyPermissionOrCallingPackage(
Evan Charlton94d01622014-07-20 12:32:05 -0700196 account.getAccountHandle().getComponentName().getPackageName());
Ihab Awad293edf22014-07-24 17:52:29 -0700197 if (PhoneAccountRegistrar.has(account, PhoneAccount.CAPABILITY_CALL_PROVIDER) ||
198 PhoneAccountRegistrar.has(account, PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
Ihab Awadc17294c2014-08-04 19:23:37 -0700199 enforceRegisterProviderOrSubscriptionPermission();
Ihab Awadf2a84912014-07-22 21:09:25 -0700200 }
Evan Charlton94d01622014-07-20 12:32:05 -0700201 mPhoneAccountRegistrar.registerPhoneAccount(account);
Ihab Awad104f8062014-07-17 11:29:35 -0700202 } catch (Exception e) {
Evan Charlton94d01622014-07-20 12:32:05 -0700203 Log.e(this, e, "registerPhoneAccount %s", account);
Ihab Awad104f8062014-07-17 11:29:35 -0700204 throw e;
205 }
Ihab Awad502e5fe2014-07-09 12:34:48 -0700206 }
207
208 @Override
Evan Charlton94d01622014-07-20 12:32:05 -0700209 public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
Ihab Awad104f8062014-07-17 11:29:35 -0700210 try {
Evan Charlton94d01622014-07-20 12:32:05 -0700211 enforceModifyPermissionOrCallingPackage(
212 accountHandle.getComponentName().getPackageName());
213 mPhoneAccountRegistrar.unregisterPhoneAccount(accountHandle);
Ihab Awad104f8062014-07-17 11:29:35 -0700214 } catch (Exception e) {
Evan Charlton94d01622014-07-20 12:32:05 -0700215 Log.e(this, e, "unregisterPhoneAccount %s", accountHandle);
Ihab Awad104f8062014-07-17 11:29:35 -0700216 throw e;
217 }
Ihab Awad502e5fe2014-07-09 12:34:48 -0700218 }
219
220 @Override
221 public void clearAccounts(String packageName) {
Ihab Awad104f8062014-07-17 11:29:35 -0700222 try {
223 enforceModifyPermissionOrCallingPackage(packageName);
224 mPhoneAccountRegistrar.clearAccounts(packageName);
225 } catch (Exception e) {
226 Log.e(this, e, "clearAccounts %s", packageName);
227 throw e;
228 }
Santos Cordon7da72ef2014-06-25 15:50:22 -0700229 }
230
Santos Cordon23baed32014-06-27 14:45:39 -0700231 /**
Santos Cordon176ae282014-07-14 02:02:14 -0700232 * @see TelecommManager#silenceRinger
Santos Cordon23baed32014-06-27 14:45:39 -0700233 */
Santos Cordon7da72ef2014-06-25 15:50:22 -0700234 @Override
Santos Cordonb64c1502014-05-21 21:21:49 -0700235 public void silenceRinger() {
236 Log.d(this, "silenceRinger");
Santos Cordonb64c1502014-05-21 21:21:49 -0700237 enforceModifyPermission();
Santos Cordon23baed32014-06-27 14:45:39 -0700238 sendRequestAsync(MSG_SILENCE_RINGER, 0);
Santos Cordonb64c1502014-05-21 21:21:49 -0700239 }
240
Santos Cordon23baed32014-06-27 14:45:39 -0700241 /**
242 * @see TelecommManager#getDefaultPhoneApp
243 */
Santos Cordon7da72ef2014-06-25 15:50:22 -0700244 @Override
245 public ComponentName getDefaultPhoneApp() {
246 Resources resources = TelecommApp.getInstance().getResources();
247 return new ComponentName(
248 resources.getString(R.string.ui_default_package),
249 resources.getString(R.string.dialer_default_class));
250 }
251
Santos Cordon23baed32014-06-27 14:45:39 -0700252 /**
253 * @see TelecommManager#isInAPhoneCall
254 */
255 @Override
256 public boolean isInAPhoneCall() {
257 enforceReadPermission();
Santos Cordon626697a2014-07-10 22:36:37 -0700258 // Do not use sendRequest() with this method since it could cause a deadlock with
259 // audio service, which we call into from the main thread: AudioManager.setMode().
260 return mCallsManager.hasAnyCalls();
Santos Cordon23baed32014-06-27 14:45:39 -0700261 }
262
263 /**
264 * @see TelecommManager#isRinging
265 */
266 @Override
267 public boolean isRinging() {
268 enforceReadPermission();
Santos Cordon626697a2014-07-10 22:36:37 -0700269 return mCallsManager.hasRingingCall();
Santos Cordon23baed32014-06-27 14:45:39 -0700270 }
271
272 /**
273 * @see TelecommManager#endCall
274 */
275 @Override
276 public boolean endCall() {
277 enforceModifyPermission();
278 return (boolean) sendRequest(MSG_END_CALL);
279 }
280
281 /**
282 * @see TelecommManager#acceptRingingCall
283 */
284 @Override
285 public void acceptRingingCall() {
286 enforceModifyPermission();
287 sendRequestAsync(MSG_ACCEPT_RINGING_CALL, 0);
288 }
289
Santos Cordon46592f02014-07-07 15:11:35 -0700290 /**
291 * @see PhoneManager#showCallScreen
292 */
Santos Cordon23baed32014-06-27 14:45:39 -0700293 @Override
294 public void showCallScreen(boolean showDialpad) {
Santos Cordon46592f02014-07-07 15:11:35 -0700295 enforceReadPermissionOrDefaultDialer();
Santos Cordon64c7e962014-07-02 15:15:27 -0700296 sendRequestAsync(MSG_SHOW_CALL_SCREEN, showDialpad ? 1 : 0);
297 }
298
Santos Cordon46592f02014-07-07 15:11:35 -0700299 /**
300 * @see PhoneManager#cancelMissedCallsNotification
301 */
Santos Cordon64c7e962014-07-02 15:15:27 -0700302 @Override
303 public void cancelMissedCallsNotification() {
Santos Cordon46592f02014-07-07 15:11:35 -0700304 enforceModifyPermissionOrDefaultDialer();
Santos Cordon64c7e962014-07-02 15:15:27 -0700305 sendRequestAsync(MSG_CANCEL_MISSED_CALLS_NOTIFICATION, 0);
Santos Cordon23baed32014-06-27 14:45:39 -0700306 }
307
Santos Cordon46592f02014-07-07 15:11:35 -0700308 /**
309 * @see PhoneManager#handlePinMmi
310 */
311 @Override
312 public boolean handlePinMmi(String dialString) {
313 enforceModifyPermissionOrDefaultDialer();
314
315 // Switch identity so that TelephonyManager checks Telecomm's permissions instead.
316 long token = Binder.clearCallingIdentity();
317 boolean retval = getTelephonyManager().handlePinMmi(dialString);
318 Binder.restoreCallingIdentity(token);
319
320 return retval;
321 }
322
Sailesh Nepalb88795a2014-07-15 14:53:27 -0700323 /**
324 * @see TelecommManager#isTtySupported
325 */
326 @Override
327 public boolean isTtySupported() {
328 enforceReadPermission();
329 return (boolean) sendRequest(MSG_IS_TTY_SUPPORTED);
330 }
331
332 /**
333 * @see TelecommManager#getCurrentTtyMode
334 */
335 @Override
336 public int getCurrentTtyMode() {
337 enforceReadPermission();
338 return (int) sendRequest(MSG_GET_CURRENT_TTY_MODE);
339 }
340
Santos Cordonfd86bd42014-07-19 14:59:04 -0700341 /**
342 * @see TelecommManager#addNewIncomingCall
343 */
344 @Override
345 public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
346 if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) {
347 mAppOpsManager.checkPackage(
348 Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName());
349
350 Intent intent = new Intent(TelecommManager.ACTION_INCOMING_CALL);
351 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
352 intent.putExtra(TelecommManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
353 if (extras != null) {
354 intent.putExtra(TelecommManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
355 }
356
357 long token = Binder.clearCallingIdentity();
358 TelecommApp.getInstance().startActivity(intent);
359 Binder.restoreCallingIdentity(token);
360 }
361 }
362
Santos Cordon7da72ef2014-06-25 15:50:22 -0700363 //
Santos Cordon46592f02014-07-07 15:11:35 -0700364 // Supporting methods for the ITelecommService interface implementation.
Santos Cordon7da72ef2014-06-25 15:50:22 -0700365 //
366
Santos Cordon23baed32014-06-27 14:45:39 -0700367 private void acceptRingingCallInternal() {
368 Call call = mCallsManager.getFirstCallWithState(CallState.RINGING);
369 if (call != null) {
Andrew Lee38931d02014-07-16 10:17:36 -0700370 call.answer(call.getVideoState());
Santos Cordon23baed32014-06-27 14:45:39 -0700371 }
372 }
373
374 private boolean endCallInternal() {
375 // Always operate on the foreground call if one exists, otherwise get the first call in
376 // priority order by call-state.
377 Call call = mCallsManager.getForegroundCall();
378 if (call == null) {
379 call = mCallsManager.getFirstCallWithState(
380 CallState.ACTIVE,
381 CallState.DIALING,
382 CallState.RINGING,
383 CallState.ON_HOLD);
384 }
385
386 if (call != null) {
387 if (call.getState() == CallState.RINGING) {
388 call.reject(false /* rejectWithMessage */, null);
389 } else {
390 call.disconnect();
391 }
392 return true;
393 }
394
395 return false;
Santos Cordonb64c1502014-05-21 21:21:49 -0700396 }
397
398 /**
399 * Make sure the caller has the MODIFY_PHONE_STATE permission.
400 *
401 * @throws SecurityException if the caller does not have the required permission
402 */
403 private void enforceModifyPermission() {
404 TelecommApp.getInstance().enforceCallingOrSelfPermission(
405 android.Manifest.permission.MODIFY_PHONE_STATE, null);
406 }
Santos Cordonf3671a62014-05-29 21:51:53 -0700407
Santos Cordon46592f02014-07-07 15:11:35 -0700408 private void enforceModifyPermissionOrDefaultDialer() {
409 if (!isDefaultDialerCalling()) {
410 enforceModifyPermission();
411 }
412 }
413
Ihab Awadc17294c2014-08-04 19:23:37 -0700414 private void enforceRegisterProviderOrSubscriptionPermission() {
415 TelecommApp.getInstance().enforceCallingOrSelfPermission(
416 REGISTER_PROVIDER_OR_SUBSCRIPTION, null);
417 }
418
Ihab Awad502e5fe2014-07-09 12:34:48 -0700419 private void enforceModifyPermissionOrCallingPackage(String packageName) {
420 // TODO(santoscordon): Use a new telecomm permission for this instead of reusing modify.
421 try {
422 enforceModifyPermission();
423 } catch (SecurityException e) {
424 enforceCallingPackage(packageName);
425 }
426 }
427
Santos Cordon23baed32014-06-27 14:45:39 -0700428 private void enforceReadPermission() {
429 TelecommApp.getInstance().enforceCallingOrSelfPermission(
430 android.Manifest.permission.READ_PHONE_STATE, null);
Santos Cordonf3671a62014-05-29 21:51:53 -0700431 }
Yorke Leeceb96c92014-06-11 16:34:44 -0700432
Santos Cordon46592f02014-07-07 15:11:35 -0700433 private void enforceReadPermissionOrDefaultDialer() {
434 if (!isDefaultDialerCalling()) {
435 enforceReadPermission();
436 }
437 }
438
Ihab Awad502e5fe2014-07-09 12:34:48 -0700439 private void enforceCallingPackage(String packageName) {
440 mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
441 }
442
Ihab Awad98a55602014-06-30 21:27:28 -0700443 private void showCallScreenInternal(boolean showDialpad) {
444 CallsManager.getInstance().getInCallController().bringToForeground(showDialpad);
445 }
Ihab Awad60509462014-06-14 16:43:08 -0700446
Santos Cordon46592f02014-07-07 15:11:35 -0700447 private boolean isDefaultDialerCalling() {
448 ComponentName defaultDialerComponent = getDefaultPhoneApp();
449 if (defaultDialerComponent != null) {
450 try {
451 mAppOpsManager.checkPackage(
452 Binder.getCallingUid(), defaultDialerComponent.getPackageName());
453 return true;
454 } catch (SecurityException e) {
455 Log.e(TAG, e, "Could not get default dialer.");
456 }
457 }
458 return false;
459 }
460
461 private TelephonyManager getTelephonyManager() {
462 return (TelephonyManager)
463 TelecommApp.getInstance().getSystemService(Context.TELEPHONY_SERVICE);
464 }
465
Santos Cordon7da72ef2014-06-25 15:50:22 -0700466 private void publish() {
467 Log.d(this, "publish: %s", this);
468 ServiceManager.addService(SERVICE_NAME, this);
Ihab Awad60509462014-06-14 16:43:08 -0700469 }
Santos Cordon23baed32014-06-27 14:45:39 -0700470
471 private MainThreadRequest sendRequestAsync(int command, int arg1) {
472 MainThreadRequest request = new MainThreadRequest();
473 mMainThreadHandler.obtainMessage(command, arg1, 0, request).sendToTarget();
474 return request;
475 }
476
477 /**
478 * Posts the specified command to be executed on the main thread, waits for the request to
479 * complete, and returns the result.
480 */
481 private Object sendRequest(int command) {
482 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
Sailesh Nepalbca199f2014-07-02 15:57:44 -0700483 MainThreadRequest request = new MainThreadRequest();
484 mMainThreadHandler.handleMessage(mMainThreadHandler.obtainMessage(command, request));
485 return request.result;
486 } else {
487 MainThreadRequest request = sendRequestAsync(command, 0);
Santos Cordon23baed32014-06-27 14:45:39 -0700488
Sailesh Nepalbca199f2014-07-02 15:57:44 -0700489 // Wait for the request to complete
490 synchronized (request) {
491 while (request.result == null) {
492 try {
493 request.wait();
494 } catch (InterruptedException e) {
495 // Do nothing, go back and wait until the request is complete
496 }
Santos Cordon23baed32014-06-27 14:45:39 -0700497 }
498 }
Sailesh Nepalbca199f2014-07-02 15:57:44 -0700499 return request.result;
Santos Cordon23baed32014-06-27 14:45:39 -0700500 }
Santos Cordon23baed32014-06-27 14:45:39 -0700501 }
Santos Cordonb64c1502014-05-21 21:21:49 -0700502}