blob: b655af9b97741d01ec5b5fbe1b4e358d81fc5799 [file] [log] [blame]
Santos Cordonacfebb62014-12-02 03:37:03 -08001/*
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.server.telecom;
18
19import android.Manifest;
20import android.annotation.SdkConstant;
21import android.app.AppOpsManager;
22import android.app.Service;
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.Intent;
26import android.content.pm.ApplicationInfo;
27import android.content.pm.PackageManager;
28import android.content.res.Resources;
29import android.net.Uri;
30import android.os.Binder;
31import android.os.Bundle;
32import android.os.Handler;
33import android.os.IBinder;
34import android.os.Looper;
35import android.os.Message;
36import android.os.UserHandle;
37import android.os.UserManager;
38import android.telecom.CallState;
39import android.telecom.PhoneAccount;
40import android.telecom.PhoneAccountHandle;
41import android.telecom.TelecomManager;
42import android.telephony.SubscriptionManager;
43import android.telephony.TelephonyManager;
44import android.text.TextUtils;
45
46// TODO: Needed for move to system service: import com.android.internal.R;
47import com.android.internal.telecom.ITelecomService;
48import com.android.internal.util.IndentingPrintWriter;
49
50import java.io.FileDescriptor;
51import java.io.PrintWriter;
52import java.util.ArrayList;
53import java.util.List;
54
55/**
56 * Implementation of the ITelecom interface.
57 */
58public class TelecomService extends Service {
59 /**
60 * The {@link Intent} that must be declared as handled by the service.
61 */
62 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
63 public static final String SERVICE_INTERFACE = "android.telecom.ITelecomService";
64
65 /** The context. */
66 private Context mContext;
67
68 /**
69 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
70 * request after sending. The main thread will notify the request when it is complete.
71 */
72 private static final class MainThreadRequest {
73 /** The result of the request that is run on the main thread */
74 public Object result;
75 /** Object that can be used to store non-integer arguments */
76 public Object arg;
77 }
78
79 /**
80 * A handler that processes messages on the main thread. Since many of the method calls are not
81 * thread safe this is needed to shuttle the requests from the inbound binder threads to the
82 * main thread.
83 */
84 private final class MainThreadHandler extends Handler {
85 @Override
86 public void handleMessage(Message msg) {
87 if (msg.obj instanceof MainThreadRequest) {
88 MainThreadRequest request = (MainThreadRequest) msg.obj;
89 Object result = null;
90 switch (msg.what) {
91 case MSG_SILENCE_RINGER:
92 mCallsManager.getRinger().silence();
93 break;
94 case MSG_SHOW_CALL_SCREEN:
95 mCallsManager.getInCallController().bringToForeground(msg.arg1 == 1);
96 break;
97 case MSG_END_CALL:
98 result = endCallInternal();
99 break;
100 case MSG_ACCEPT_RINGING_CALL:
101 acceptRingingCallInternal();
102 break;
103 case MSG_CANCEL_MISSED_CALLS_NOTIFICATION:
104 mMissedCallNotifier.clearMissedCalls();
105 break;
106 case MSG_IS_TTY_SUPPORTED:
107 result = mCallsManager.isTtySupported();
108 break;
109 case MSG_GET_CURRENT_TTY_MODE:
110 result = mCallsManager.getCurrentTtyMode();
111 break;
112 case MSG_NEW_INCOMING_CALL:
113 if (request.arg == null || !(request.arg instanceof Intent)) {
114 Log.w(this, "Invalid new incoming call request");
115 break;
116 }
117 CallReceiver.processIncomingCallIntent((Intent) request.arg);
118 break;
119 }
120
121 if (result != null) {
122 request.result = result;
123 synchronized(request) {
124 request.notifyAll();
125 }
126 }
127 }
128 }
129 }
130
131 private static final String TAG = TelecomService.class.getSimpleName();
132
133 private static final String SERVICE_NAME = "telecom";
134
135 private static final int MSG_SILENCE_RINGER = 1;
136 private static final int MSG_SHOW_CALL_SCREEN = 2;
137 private static final int MSG_END_CALL = 3;
138 private static final int MSG_ACCEPT_RINGING_CALL = 4;
139 private static final int MSG_CANCEL_MISSED_CALLS_NOTIFICATION = 5;
140 private static final int MSG_IS_TTY_SUPPORTED = 6;
141 private static final int MSG_GET_CURRENT_TTY_MODE = 7;
142 private static final int MSG_NEW_INCOMING_CALL = 8;
143
144 private final MainThreadHandler mMainThreadHandler = new MainThreadHandler();
145
146 private CallsManager mCallsManager;
147 private MissedCallNotifier mMissedCallNotifier;
148 private PhoneAccountRegistrar mPhoneAccountRegistrar;
149 private AppOpsManager mAppOpsManager;
150 private UserManager mUserManager;
151 private PackageManager mPackageManager;
152 private TelecomServiceImpl mServiceImpl;
153
154 @Override
155 public void onCreate() {
156 super.onCreate();
157
158 Log.d(this, "onCreate");
159 mContext = this;
160 mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
161 mServiceImpl = new TelecomServiceImpl();
162
163 TelecomGlobals globals = TelecomGlobals.getInstance();
164 globals.initialize(this);
165
166 mMissedCallNotifier = globals.getMissedCallNotifier();
167 mPhoneAccountRegistrar = globals.getPhoneAccountRegistrar();
168 mCallsManager = globals.getCallsManager();
169 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
170 mPackageManager = mContext.getPackageManager();
171 }
172
173 @Override
174 public IBinder onBind(Intent intent) {
175 Log.d(this, "onBind");
176 return mServiceImpl;
177 }
178
179 /**
180 * Implementation of the ITelecomService interface.
181 * TODO: Reorganize this inner class to top of file.
182 */
183 class TelecomServiceImpl extends ITelecomService.Stub {
184 @Override
185 public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
Santos Cordonb19ef4f2014-12-02 13:19:00 -0800186 enforceReadPermission();
187 long token = Binder.clearCallingIdentity();
Santos Cordonacfebb62014-12-02 03:37:03 -0800188 try {
189 PhoneAccountHandle defaultOutgoingPhoneAccount =
190 mPhoneAccountRegistrar.getDefaultOutgoingPhoneAccount(uriScheme);
191 // Make sure that the calling user can see this phone account.
192 if (defaultOutgoingPhoneAccount != null
193 && !isVisibleToCaller(defaultOutgoingPhoneAccount)) {
194 Log.w(this, "No account found for the calling user");
195 return null;
196 }
197 return defaultOutgoingPhoneAccount;
198 } catch (Exception e) {
199 Log.e(this, e, "getDefaultOutgoingPhoneAccount");
200 throw e;
Santos Cordonb19ef4f2014-12-02 13:19:00 -0800201 } finally {
202 Binder.restoreCallingIdentity(token);
Santos Cordonacfebb62014-12-02 03:37:03 -0800203 }
204 }
205
206 @Override
207 public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() {
208 try {
209 PhoneAccountHandle userSelectedOutgoingPhoneAccount =
210 mPhoneAccountRegistrar.getUserSelectedOutgoingPhoneAccount();
211 // Make sure that the calling user can see this phone account.
212 if (!isVisibleToCaller(userSelectedOutgoingPhoneAccount)) {
213 Log.w(this, "No account found for the calling user");
214 return null;
215 }
216 return userSelectedOutgoingPhoneAccount;
217 } catch (Exception e) {
218 Log.e(this, e, "getUserSelectedOutgoingPhoneAccount");
219 throw e;
220 }
221 }
222
223 @Override
224 public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
225 enforceModifyPermission();
226
227 try {
228 mPhoneAccountRegistrar.setUserSelectedOutgoingPhoneAccount(accountHandle);
229 } catch (Exception e) {
230 Log.e(this, e, "setUserSelectedOutgoingPhoneAccount");
231 throw e;
232 }
233 }
234
235 @Override
236 public List<PhoneAccountHandle> getCallCapablePhoneAccounts() {
Santos Cordonb19ef4f2014-12-02 13:19:00 -0800237 enforceReadPermission();
238 long token = Binder.clearCallingIdentity();
Santos Cordonacfebb62014-12-02 03:37:03 -0800239 try {
240 return filterForAccountsVisibleToCaller(
241 mPhoneAccountRegistrar.getCallCapablePhoneAccounts());
242 } catch (Exception e) {
243 Log.e(this, e, "getCallCapablePhoneAccounts");
244 throw e;
Santos Cordonb19ef4f2014-12-02 13:19:00 -0800245 } finally {
246 Binder.restoreCallingIdentity(token);
Santos Cordonacfebb62014-12-02 03:37:03 -0800247 }
248 }
249
250 @Override
251 public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) {
Santos Cordonb19ef4f2014-12-02 13:19:00 -0800252 enforceReadPermission();
253 long token = Binder.clearCallingIdentity();
Santos Cordonacfebb62014-12-02 03:37:03 -0800254 try {
255 return filterForAccountsVisibleToCaller(
256 mPhoneAccountRegistrar.getCallCapablePhoneAccounts(uriScheme));
257 } catch (Exception e) {
258 Log.e(this, e, "getPhoneAccountsSupportingScheme %s", uriScheme);
259 throw e;
Santos Cordonb19ef4f2014-12-02 13:19:00 -0800260 } finally {
261 Binder.restoreCallingIdentity(token);
Santos Cordonacfebb62014-12-02 03:37:03 -0800262 }
263 }
264
265 @Override
266 public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName) {
267 try {
268 return filterForAccountsVisibleToCaller(
269 mPhoneAccountRegistrar.getPhoneAccountsForPackage(packageName));
270 } catch (Exception e) {
271 Log.e(this, e, "getPhoneAccountsForPackage %s", packageName);
272 throw e;
273 }
274 }
275
276 @Override
277 public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle) {
278 try {
279 if (!isVisibleToCaller(accountHandle)) {
280 Log.w(this, "%s is not visible for the calling user", accountHandle);
281 return null;
282 }
283 return mPhoneAccountRegistrar.getPhoneAccountInternal(accountHandle);
284 } catch (Exception e) {
285 Log.e(this, e, "getPhoneAccount %s", accountHandle);
286 throw e;
287 }
288 }
289
290 @Override
291 public int getAllPhoneAccountsCount() {
292 try {
293 // This list is pre-filtered for the calling user.
294 return getAllPhoneAccounts().size();
295 } catch (Exception e) {
296 Log.e(this, e, "getAllPhoneAccountsCount");
297 throw e;
298 }
299 }
300
301 @Override
302 public List<PhoneAccount> getAllPhoneAccounts() {
303 try {
304 List<PhoneAccount> allPhoneAccounts = mPhoneAccountRegistrar.getAllPhoneAccounts();
305 List<PhoneAccount> profilePhoneAccounts = new ArrayList<>(allPhoneAccounts.size());
306 for (PhoneAccount phoneAccount : profilePhoneAccounts) {
307 if (isVisibleToCaller(phoneAccount)) {
308 profilePhoneAccounts.add(phoneAccount);
309 }
310 }
311 return profilePhoneAccounts;
312 } catch (Exception e) {
313 Log.e(this, e, "getAllPhoneAccounts");
314 throw e;
315 }
316 }
317
318 @Override
319 public List<PhoneAccountHandle> getAllPhoneAccountHandles() {
320 try {
321 return filterForAccountsVisibleToCaller(
322 mPhoneAccountRegistrar.getAllPhoneAccountHandles());
323 } catch (Exception e) {
324 Log.e(this, e, "getAllPhoneAccounts");
325 throw e;
326 }
327 }
328
329 @Override
330 public PhoneAccountHandle getSimCallManager() {
331 try {
332 PhoneAccountHandle accountHandle = mPhoneAccountRegistrar.getSimCallManager();
333 if (!isVisibleToCaller(accountHandle)) {
334 Log.w(this, "%s is not visible for the calling user", accountHandle);
335 return null;
336 }
337 return accountHandle;
338 } catch (Exception e) {
339 Log.e(this, e, "getSimCallManager");
340 throw e;
341 }
342 }
343
344 @Override
345 public void setSimCallManager(PhoneAccountHandle accountHandle) {
346 enforceModifyPermission();
347
348 try {
349 mPhoneAccountRegistrar.setSimCallManager(accountHandle);
350 } catch (Exception e) {
351 Log.e(this, e, "setSimCallManager");
352 throw e;
353 }
354 }
355
356 @Override
357 public List<PhoneAccountHandle> getSimCallManagers() {
Santos Cordonb19ef4f2014-12-02 13:19:00 -0800358 enforceReadPermission();
359 long token = Binder.clearCallingIdentity();
Santos Cordonacfebb62014-12-02 03:37:03 -0800360 try {
361 return filterForAccountsVisibleToCaller(
362 mPhoneAccountRegistrar.getConnectionManagerPhoneAccounts());
363 } catch (Exception e) {
364 Log.e(this, e, "getSimCallManagers");
365 throw e;
Santos Cordonb19ef4f2014-12-02 13:19:00 -0800366 } finally {
367 Binder.restoreCallingIdentity(token);
Santos Cordonacfebb62014-12-02 03:37:03 -0800368 }
369 }
370
371 @Override
372 public void registerPhoneAccount(PhoneAccount account) {
373 try {
374 enforcePhoneAccountModificationForPackage(
375 account.getAccountHandle().getComponentName().getPackageName());
376 if (account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)) {
377 enforceRegisterCallProviderPermission();
378 }
379 if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
380 enforceRegisterSimSubscriptionPermission();
381 }
382 if (account.hasCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
383 enforceRegisterConnectionManagerPermission();
384 }
385 if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
386 enforceRegisterMultiUser();
387 }
388 enforceUserHandleMatchesCaller(account.getAccountHandle());
389
390 mPhoneAccountRegistrar.registerPhoneAccount(account);
391 } catch (Exception e) {
392 Log.e(this, e, "registerPhoneAccount %s", account);
393 throw e;
394 }
395 }
396
397 @Override
398 public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
399 try {
400 enforcePhoneAccountModificationForPackage(
401 accountHandle.getComponentName().getPackageName());
402 enforceUserHandleMatchesCaller(accountHandle);
403 mPhoneAccountRegistrar.unregisterPhoneAccount(accountHandle);
404 } catch (Exception e) {
405 Log.e(this, e, "unregisterPhoneAccount %s", accountHandle);
406 throw e;
407 }
408 }
409
410 @Override
411 public void clearAccounts(String packageName) {
412 try {
413 enforcePhoneAccountModificationForPackage(packageName);
414 mPhoneAccountRegistrar.clearAccounts(packageName, Binder.getCallingUserHandle());
415 } catch (Exception e) {
416 Log.e(this, e, "clearAccounts %s", packageName);
417 throw e;
418 }
419 }
420
421 /**
422 * @see android.telecom.TelecomManager#isVoiceMailNumber
423 */
424 @Override
425 public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
426 enforceReadPermissionOrDefaultDialer();
427 try {
428 if (!isVisibleToCaller(accountHandle)) {
429 Log.w(this, "%s is not visible for the calling user", accountHandle);
430 return false;
431 }
432 return mPhoneAccountRegistrar.isVoiceMailNumber(accountHandle, number);
433 } catch (Exception e) {
434 Log.e(this, e, "getSubscriptionIdForPhoneAccount");
435 throw e;
436 }
437 }
438
439 /**
440 * @see android.telecom.TelecomManager#hasVoiceMailNumber
441 */
442 @Override
443 public boolean hasVoiceMailNumber(PhoneAccountHandle accountHandle) {
444 enforceReadPermissionOrDefaultDialer();
445 try {
446 if (!isVisibleToCaller(accountHandle)) {
447 Log.w(this, "%s is not visible for the calling user", accountHandle);
448 return false;
449 }
450
Nancy Chen3e672732015-01-24 23:29:22 -0800451 int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
Santos Cordonacfebb62014-12-02 03:37:03 -0800452 return !TextUtils.isEmpty(getTelephonyManager().getVoiceMailNumber(subId));
453 } catch (Exception e) {
454 Log.e(this, e, "getSubscriptionIdForPhoneAccount");
455 throw e;
456 }
457 }
458
459 /**
Nancy Chen3e672732015-01-24 23:29:22 -0800460 * @see android.telecom.TelecomManager#getLine1Number
461 */
462 @Override
463 public String getLine1Number(PhoneAccountHandle accountHandle) {
464 enforceReadPermissionOrDefaultDialer();
465 try {
466 if (!isVisibleToCaller(accountHandle)) {
467 Log.w(this, "%s is not visible for the calling user", accountHandle);
468 return null;
469 }
470 int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
471 return getTelephonyManager().getLine1NumberForSubscriber(subId);
472 } catch (Exception e) {
473 Log.e(this, e, "getSubscriptionIdForPhoneAccount");
474 throw e;
475 }
476 }
477
478 /**
Santos Cordonacfebb62014-12-02 03:37:03 -0800479 * @see android.telecom.TelecomManager#silenceRinger
480 */
481 @Override
482 public void silenceRinger() {
483 Log.d(this, "silenceRinger");
484 enforceModifyPermission();
485 sendRequestAsync(MSG_SILENCE_RINGER, 0);
486 }
487
488 /**
489 * @see android.telecom.TelecomManager#getDefaultPhoneApp
490 */
491 @Override
492 public ComponentName getDefaultPhoneApp() {
493 Resources resources = mContext.getResources();
494 return new ComponentName(
495 resources.getString(R.string.ui_default_package),
496 resources.getString(R.string.dialer_default_class));
497 }
498
499 /**
500 * @see android.telecom.TelecomManager#isInCall
501 */
502 @Override
503 public boolean isInCall() {
504 enforceReadPermission();
505 // Do not use sendRequest() with this method since it could cause a deadlock with
506 // audio service, which we call into from the main thread: AudioManager.setMode().
507 final int callState = mCallsManager.getCallState();
508 return callState == TelephonyManager.CALL_STATE_OFFHOOK
509 || callState == TelephonyManager.CALL_STATE_RINGING;
510 }
511
512 /**
513 * @see android.telecom.TelecomManager#isRinging
514 */
515 @Override
516 public boolean isRinging() {
517 enforceReadPermission();
518 return mCallsManager.getCallState() == TelephonyManager.CALL_STATE_RINGING;
519 }
520
521 /**
522 * @see TelecomManager#getCallState
523 */
524 @Override
525 public int getCallState() {
526 return mCallsManager.getCallState();
527 }
528
529 /**
530 * @see android.telecom.TelecomManager#endCall
531 */
532 @Override
533 public boolean endCall() {
534 enforceModifyPermission();
535 return (boolean) sendRequest(MSG_END_CALL);
536 }
537
538 /**
539 * @see android.telecom.TelecomManager#acceptRingingCall
540 */
541 @Override
542 public void acceptRingingCall() {
543 enforceModifyPermission();
544 sendRequestAsync(MSG_ACCEPT_RINGING_CALL, 0);
545 }
546
547 /**
548 * @see android.telecom.TelecomManager#showInCallScreen
549 */
550 @Override
551 public void showInCallScreen(boolean showDialpad) {
552 enforceReadPermissionOrDefaultDialer();
553 sendRequestAsync(MSG_SHOW_CALL_SCREEN, showDialpad ? 1 : 0);
554 }
555
556 /**
557 * @see android.telecom.TelecomManager#cancelMissedCallsNotification
558 */
559 @Override
560 public void cancelMissedCallsNotification() {
561 enforceModifyPermissionOrDefaultDialer();
562 sendRequestAsync(MSG_CANCEL_MISSED_CALLS_NOTIFICATION, 0);
563 }
564
565 /**
566 * @see android.telecom.TelecomManager#handleMmi
567 */
568 @Override
569 public boolean handlePinMmi(String dialString) {
570 enforceModifyPermissionOrDefaultDialer();
571
572 // Switch identity so that TelephonyManager checks Telecom's permissions instead.
573 long token = Binder.clearCallingIdentity();
574 boolean retval = false;
575 try {
576 retval = getTelephonyManager().handlePinMmi(dialString);
577 } finally {
578 Binder.restoreCallingIdentity(token);
579 }
580
581 return retval;
582 }
583
584 /**
585 * @see android.telecom.TelecomManager#handleMmi
586 */
587 @Override
588 public boolean handlePinMmiForPhoneAccount(PhoneAccountHandle accountHandle,
589 String dialString) {
590 enforceModifyPermissionOrDefaultDialer();
591
592 if (!isVisibleToCaller(accountHandle)) {
593 Log.w(this, "%s is not visible for the calling user", accountHandle);
594 return false;
595 }
596
597 // Switch identity so that TelephonyManager checks Telecom's permissions instead.
598 long token = Binder.clearCallingIdentity();
599 boolean retval = false;
600 try {
601 int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
602 retval = getTelephonyManager().handlePinMmiForSubscriber(subId, dialString);
603 } finally {
604 Binder.restoreCallingIdentity(token);
605 }
606
607 return retval;
608 }
609
610 /**
611 * @see android.telecom.TelecomManager#getAdnUriForPhoneAccount
612 */
613 @Override
614 public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle) {
615 enforceModifyPermissionOrDefaultDialer();
616
617 if (!isVisibleToCaller(accountHandle)) {
618 Log.w(this, "%s is not visible for the calling user", accountHandle);
619 return null;
620 }
621
622 // Switch identity so that TelephonyManager checks Telecom's permissions instead.
623 long token = Binder.clearCallingIdentity();
624 String retval = "content://icc/adn/";
625 try {
Sridhar Dubbaka533199a2015-03-20 17:25:01 +0530626 int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
Santos Cordonacfebb62014-12-02 03:37:03 -0800627 retval = retval + "subId/" + subId;
628 } finally {
629 Binder.restoreCallingIdentity(token);
630 }
631
632 return Uri.parse(retval);
633 }
634
635 /**
636 * @see android.telecom.TelecomManager#isTtySupported
637 */
638 @Override
639 public boolean isTtySupported() {
640 enforceReadPermission();
641 return (boolean) sendRequest(MSG_IS_TTY_SUPPORTED);
642 }
643
644 /**
645 * @see android.telecom.TelecomManager#getCurrentTtyMode
646 */
647 @Override
648 public int getCurrentTtyMode() {
649 enforceReadPermission();
650 return (int) sendRequest(MSG_GET_CURRENT_TTY_MODE);
651 }
652
653 /**
654 * @see android.telecom.TelecomManager#addNewIncomingCall
655 */
656 @Override
657 public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
658 Log.i(this, "Adding new incoming call with phoneAccountHandle %s", phoneAccountHandle);
659 if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) {
660 mAppOpsManager.checkPackage(
661 Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName());
662
663 // Make sure it doesn't cross the UserHandle boundary
664 enforceUserHandleMatchesCaller(phoneAccountHandle);
665
666 Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
667 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
668 intent.putExtra(CallReceiver.KEY_IS_INCOMING_CALL, true);
669 if (extras != null) {
670 intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
671 }
672 sendRequestAsync(MSG_NEW_INCOMING_CALL, 0, intent);
673 } else {
674 Log.w(this, "Null phoneAccountHandle. Ignoring request to add new incoming call");
675 }
676 }
677
678 /**
679 * @see android.telecom.TelecomManager#addNewUnknownCall
680 */
681 @Override
682 public void addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
683 if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null &&
684 TelephonyUtil.isPstnComponentName(phoneAccountHandle.getComponentName())) {
685 mAppOpsManager.checkPackage(
686 Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName());
687
688 // Make sure it doesn't cross the UserHandle boundary
689 enforceUserHandleMatchesCaller(phoneAccountHandle);
690
691 Intent intent = new Intent(TelecomManager.ACTION_NEW_UNKNOWN_CALL);
692 intent.setClass(mContext, CallReceiver.class);
693 intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
694 intent.putExtras(extras);
695 intent.putExtra(CallReceiver.KEY_IS_UNKNOWN_CALL, true);
696 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
697 mContext.sendBroadcastAsUser(intent, phoneAccountHandle.getUserHandle());
698 } else {
699 Log.i(this, "Null phoneAccountHandle or not initiated by Telephony. Ignoring request"
700 + " to add new unknown call.");
701 }
702 }
Sukanya Rajkhowa39267f62015-02-24 18:39:54 -0800703
704 @Override
Muhammed Siju5445bbc2015-03-18 17:01:08 +0530705 public int getActiveSubscription() {
706 enforceReadPermission();
707 String activeSub = mCallsManager.getActiveSubscription();
708 return (activeSub == null) ? SubscriptionManager.INVALID_SUBSCRIPTION_ID :
709 Integer.parseInt(activeSub);
710 }
Sukanya Rajkhowa39267f62015-02-24 18:39:54 -0800711
712 @Override
Muhammed Siju5445bbc2015-03-18 17:01:08 +0530713 public void switchToOtherActiveSub(int subId) {
714 enforceModifyPermission();
715 String activeSub = (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID)
716 ? null : String.valueOf(subId);
717 mCallsManager.switchToOtherActiveSub(activeSub, false);
718 }
Tyler Gunn93085be2014-12-17 17:10:28 -0800719
720 /**
721 * Dumps the current state of the TelecomService. Used when generating problem reports.
722 *
723 * @param fd The file descriptor.
724 * @param writer The print writer to dump the state to.
725 * @param args Optional dump arguments.
726 */
727 @Override
728 protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
729 if (mContext.checkCallingOrSelfPermission(
730 android.Manifest.permission.DUMP)
731 != PackageManager.PERMISSION_GRANTED) {
732 writer.println("Permission Denial: can't dump TelecomService " +
733 "from from pid=" + Binder.getCallingPid() + ", uid=" +
734 Binder.getCallingUid());
735 return;
736 }
737
738 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
739 if (mCallsManager != null) {
740 pw.println("mCallsManager: ");
741 pw.increaseIndent();
742 mCallsManager.dump(pw);
743 pw.decreaseIndent();
744
745 pw.println("mPhoneAccountRegistrar: ");
746 pw.increaseIndent();
747 mPhoneAccountRegistrar.dump(pw);
748 pw.decreaseIndent();
749 }
750 }
Santos Cordonacfebb62014-12-02 03:37:03 -0800751 }
752
753 //
754 // Supporting methods for the ITelecomService interface implementation.
755 //
756
757 private boolean isVisibleToCaller(PhoneAccountHandle accountHandle) {
758 if (accountHandle == null) {
759 return false;
760 }
761
762 return isVisibleToCaller(mPhoneAccountRegistrar.getPhoneAccountInternal(accountHandle));
763 }
764
765 private boolean isVisibleToCaller(PhoneAccount account) {
766 if (account == null) {
767 return false;
768 }
769
770 // If this PhoneAccount has CAPABILITY_MULTI_USER, it should be visible to all users and
771 // all profiles. Only Telephony and SIP accounts should have this capability.
772 if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
773 return true;
774 }
775
776 UserHandle phoneAccountUserHandle = account.getAccountHandle().getUserHandle();
777 if (phoneAccountUserHandle == null) {
778 return false;
779 }
780
781 List<UserHandle> profileUserHandles;
782 if (isCallerSystemApp()) {
783 // If the caller lives in /system/priv-app, it can see PhoneAccounts for all of the
784 // *profiles* that the calling user owns, but not for any other *users*.
785 profileUserHandles = mUserManager.getUserProfiles();
786 } else {
787 // Otherwise, it has to be owned by the current caller's profile.
788 profileUserHandles = new ArrayList<>(1);
789 profileUserHandles.add(Binder.getCallingUserHandle());
790 }
791
792 return profileUserHandles.contains(phoneAccountUserHandle);
793 }
794
795 /**
796 * Given a list of {@link PhoneAccountHandle}s, filter them to the ones that the calling
797 * user can see.
798 *
799 * @param phoneAccountHandles Unfiltered list of account handles.
800 *
801 * @return {@link PhoneAccountHandle}s visible to the calling user and its profiles.
802 */
803 private List<PhoneAccountHandle> filterForAccountsVisibleToCaller(
804 List<PhoneAccountHandle> phoneAccountHandles) {
805 List<PhoneAccountHandle> profilePhoneAccountHandles =
806 new ArrayList<>(phoneAccountHandles.size());
807 for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) {
808 if (isVisibleToCaller(phoneAccountHandle)) {
809 profilePhoneAccountHandles.add(phoneAccountHandle);
810 }
811 }
812 return profilePhoneAccountHandles;
813 }
814
815 private boolean isCallerSystemApp() {
816 int uid = Binder.getCallingUid();
817 String[] packages = mPackageManager.getPackagesForUid(uid);
818 for (String packageName : packages) {
819 if (isPackageSystemApp(packageName)) {
820 return true;
821 }
822 }
823 return false;
824 }
825
826 private boolean isPackageSystemApp(String packageName) {
827 try {
828 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(packageName,
829 PackageManager.GET_META_DATA);
830 if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
831 return true;
832 }
833 } catch (PackageManager.NameNotFoundException e) {
834 }
835 return false;
836 }
837
838 private void acceptRingingCallInternal() {
839 Call call = mCallsManager.getFirstCallWithState(CallState.RINGING);
840 if (call != null) {
841 call.answer(call.getVideoState());
842 }
843 }
844
845 private boolean endCallInternal() {
846 // Always operate on the foreground call if one exists, otherwise get the first call in
847 // priority order by call-state.
848 Call call = mCallsManager.getForegroundCall();
849 if (call == null) {
850 call = mCallsManager.getFirstCallWithState(
851 CallState.ACTIVE,
852 CallState.DIALING,
853 CallState.RINGING,
854 CallState.ON_HOLD);
855 }
856
857 if (call != null) {
858 if (call.getState() == CallState.RINGING) {
859 call.reject(false /* rejectWithMessage */, null);
860 } else {
861 call.disconnect();
862 }
863 return true;
864 }
865
866 return false;
867 }
868
869 private void enforcePhoneAccountModificationForPackage(String packageName) {
870 // TODO: Use a new telecomm permission for this instead of reusing modify.
871
872 int result = mContext.checkCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
873
874 // Callers with MODIFY_PHONE_STATE can use the PhoneAccount mechanism to implement
875 // built-in behavior even when PhoneAccounts are not exposed as a third-part API. They
876 // may also modify PhoneAccounts on behalf of any 'packageName'.
877
878 if (result != PackageManager.PERMISSION_GRANTED) {
879 // Other callers are only allowed to modify PhoneAccounts if the relevant system
880 // feature is enabled ...
881 enforceConnectionServiceFeature();
882 // ... and the PhoneAccounts they refer to are for their own package.
883 enforceCallingPackage(packageName);
884 }
885 }
886
887 private void enforceReadPermissionOrDefaultDialer() {
888 if (!isDefaultDialerCalling()) {
889 enforceReadPermission();
890 }
891 }
892
893 private void enforceModifyPermissionOrDefaultDialer() {
894 if (!isDefaultDialerCalling()) {
895 enforceModifyPermission();
896 }
897 }
898
899 private void enforceCallingPackage(String packageName) {
900 mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
901 }
902
903 private void enforceConnectionServiceFeature() {
904 enforceFeature(PackageManager.FEATURE_CONNECTION_SERVICE);
905 }
906
907 private void enforceRegisterCallProviderPermission() {
908 enforcePermission(android.Manifest.permission.REGISTER_CALL_PROVIDER);
909 }
910
911 private void enforceRegisterSimSubscriptionPermission() {
912 enforcePermission(android.Manifest.permission.REGISTER_SIM_SUBSCRIPTION);
913 }
914
915 private void enforceRegisterConnectionManagerPermission() {
916 enforcePermission(android.Manifest.permission.REGISTER_CONNECTION_MANAGER);
917 }
918
919 private void enforceReadPermission() {
920 enforcePermission(Manifest.permission.READ_PHONE_STATE);
921 }
922
923 private void enforceModifyPermission() {
924 enforcePermission(Manifest.permission.MODIFY_PHONE_STATE);
925 }
926
927 private void enforcePermission(String permission) {
928 mContext.enforceCallingOrSelfPermission(permission, null);
929 }
930
931 private void enforceRegisterMultiUser() {
932 if (!isCallerSystemApp()) {
933 throw new SecurityException("CAPABILITY_MULTI_USER is only available to system apps.");
934 }
935 }
936
937 private void enforceUserHandleMatchesCaller(PhoneAccountHandle accountHandle) {
938 if (!Binder.getCallingUserHandle().equals(accountHandle.getUserHandle())) {
939 throw new SecurityException("Calling UserHandle does not match PhoneAccountHandle's");
940 }
941 }
942
943 private void enforceFeature(String feature) {
944 PackageManager pm = mContext.getPackageManager();
945 if (!pm.hasSystemFeature(feature)) {
946 throw new UnsupportedOperationException(
947 "System does not support feature " + feature);
948 }
949 }
950
951 private boolean isDefaultDialerCalling() {
952 ComponentName defaultDialerComponent = getDefaultPhoneAppInternal();
953 if (defaultDialerComponent != null) {
954 try {
955 mAppOpsManager.checkPackage(
956 Binder.getCallingUid(), defaultDialerComponent.getPackageName());
957 return true;
958 } catch (SecurityException e) {
959 Log.e(TAG, e, "Could not get default dialer.");
960 }
961 }
962 return false;
963 }
964
965 private ComponentName getDefaultPhoneAppInternal() {
966 Resources resources = mContext.getResources();
967 return new ComponentName(
968 resources.getString(R.string.ui_default_package),
969 resources.getString(R.string.dialer_default_class));
970 }
971
972 private TelephonyManager getTelephonyManager() {
973 return (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
974 }
975
976 private MainThreadRequest sendRequestAsync(int command, int arg1) {
977 return sendRequestAsync(command, arg1, null);
978 }
979
980 private MainThreadRequest sendRequestAsync(int command, int arg1, Object arg) {
981 MainThreadRequest request = new MainThreadRequest();
982 request.arg = arg;
983 mMainThreadHandler.obtainMessage(command, arg1, 0, request).sendToTarget();
984 return request;
985 }
986
987 /**
988 * Posts the specified command to be executed on the main thread, waits for the request to
989 * complete, and returns the result.
990 */
991 private Object sendRequest(int command) {
992 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
993 MainThreadRequest request = new MainThreadRequest();
994 mMainThreadHandler.handleMessage(mMainThreadHandler.obtainMessage(command, request));
995 return request.result;
996 } else {
997 MainThreadRequest request = sendRequestAsync(command, 0);
998
999 // Wait for the request to complete
1000 synchronized (request) {
1001 while (request.result == null) {
1002 try {
1003 request.wait();
1004 } catch (InterruptedException e) {
1005 // Do nothing, go back and wait until the request is complete
1006 }
1007 }
1008 }
1009 return request.result;
1010 }
1011 }
Santos Cordonacfebb62014-12-02 03:37:03 -08001012}