TelecomServiceImpl.java revision 1c5926fc5f3c828c5b16c25a5154e5a0306ea3e7
1/* 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.app.AppOpsManager; 21import android.content.ComponentName; 22import android.content.Context; 23import android.content.Intent; 24import android.content.pm.PackageManager; 25import android.content.res.Resources; 26import android.os.Binder; 27import android.os.Bundle; 28import android.os.Handler; 29import android.os.IBinder; 30import android.os.Looper; 31import android.os.Message; 32import android.os.ServiceManager; 33import android.os.UserHandle; 34import android.telecom.CallState; 35import android.telecom.PhoneAccount; 36import android.telecom.PhoneAccountHandle; 37import android.telecom.TelecomManager; 38import android.telephony.TelephonyManager; 39 40// TODO: Needed for move to system service: import com.android.internal.R; 41import com.android.internal.telecom.ITelecomService; 42import com.android.internal.util.IndentingPrintWriter; 43 44import java.io.FileDescriptor; 45import java.io.PrintWriter; 46import java.util.List; 47 48/** 49 * Implementation of the ITelecom interface. 50 */ 51public class TelecomServiceImpl extends ITelecomService.Stub { 52 private static final String REGISTER_PROVIDER_OR_SUBSCRIPTION = 53 "com.android.server.telecom.permission.REGISTER_PROVIDER_OR_SUBSCRIPTION"; 54 55 /** The context. */ 56 private Context mContext; 57 58 /** ${inheritDoc} */ 59 @Override 60 public IBinder asBinder() { 61 return super.asBinder(); 62 } 63 64 /** 65 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the 66 * request after sending. The main thread will notify the request when it is complete. 67 */ 68 private static final class MainThreadRequest { 69 /** The result of the request that is run on the main thread */ 70 public Object result; 71 } 72 73 /** 74 * A handler that processes messages on the main thread in the phone process. Since many 75 * of the Phone calls are not thread safe this is needed to shuttle the requests from the 76 * inbound binder threads to the main thread in the phone process. 77 */ 78 private final class MainThreadHandler extends Handler { 79 @Override 80 public void handleMessage(Message msg) { 81 if (msg.obj instanceof MainThreadRequest) { 82 MainThreadRequest request = (MainThreadRequest) msg.obj; 83 Object result = null; 84 switch (msg.what) { 85 case MSG_SILENCE_RINGER: 86 mCallsManager.getRinger().silence(); 87 break; 88 case MSG_SHOW_CALL_SCREEN: 89 mCallsManager.getInCallController().bringToForeground(msg.arg1 == 1); 90 break; 91 case MSG_END_CALL: 92 result = endCallInternal(); 93 break; 94 case MSG_ACCEPT_RINGING_CALL: 95 acceptRingingCallInternal(); 96 break; 97 case MSG_CANCEL_MISSED_CALLS_NOTIFICATION: 98 mMissedCallNotifier.clearMissedCalls(); 99 break; 100 case MSG_IS_TTY_SUPPORTED: 101 result = mCallsManager.isTtySupported(); 102 break; 103 case MSG_GET_CURRENT_TTY_MODE: 104 result = mCallsManager.getCurrentTtyMode(); 105 break; 106 } 107 108 if (result != null) { 109 request.result = result; 110 synchronized(request) { 111 request.notifyAll(); 112 } 113 } 114 } 115 } 116 } 117 118 /** Private constructor; @see init() */ 119 private static final String TAG = TelecomServiceImpl.class.getSimpleName(); 120 121 private static final String SERVICE_NAME = "telecom"; 122 123 private static final int MSG_SILENCE_RINGER = 1; 124 private static final int MSG_SHOW_CALL_SCREEN = 2; 125 private static final int MSG_END_CALL = 3; 126 private static final int MSG_ACCEPT_RINGING_CALL = 4; 127 private static final int MSG_CANCEL_MISSED_CALLS_NOTIFICATION = 5; 128 private static final int MSG_IS_TTY_SUPPORTED = 6; 129 private static final int MSG_GET_CURRENT_TTY_MODE = 7; 130 131 /** The singleton instance. */ 132 private static TelecomServiceImpl sInstance; 133 134 private final MainThreadHandler mMainThreadHandler = new MainThreadHandler(); 135 private final CallsManager mCallsManager; 136 private final MissedCallNotifier mMissedCallNotifier; 137 private final PhoneAccountRegistrar mPhoneAccountRegistrar; 138 private final AppOpsManager mAppOpsManager; 139 140 public TelecomServiceImpl( 141 MissedCallNotifier missedCallNotifier, PhoneAccountRegistrar phoneAccountRegistrar, 142 CallsManager callsManager, Context context) { 143 mMissedCallNotifier = missedCallNotifier; 144 mPhoneAccountRegistrar = phoneAccountRegistrar; 145 mCallsManager = callsManager; 146 mContext = context; 147 mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 148 } 149 150 // 151 // Implementation of the ITelecomService interface. 152 // 153 154 @Override 155 public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) { 156 try { 157 return mPhoneAccountRegistrar.getDefaultOutgoingPhoneAccount(uriScheme); 158 } catch (Exception e) { 159 Log.e(this, e, "getDefaultOutgoingPhoneAccount"); 160 throw e; 161 } 162 } 163 164 @Override 165 public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() { 166 try { 167 return mPhoneAccountRegistrar.getUserSelectedOutgoingPhoneAccount(); 168 } catch (Exception e) { 169 Log.e(this, e, "getUserSelectedOutgoingPhoneAccount"); 170 throw e; 171 } 172 } 173 174 @Override 175 public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) { 176 enforceModifyPermission(); 177 178 try { 179 mPhoneAccountRegistrar.setUserSelectedOutgoingPhoneAccount(accountHandle); 180 } catch (Exception e) { 181 Log.e(this, e, "setUserSelectedOutgoingPhoneAccount"); 182 throw e; 183 } 184 } 185 186 @Override 187 public List<PhoneAccountHandle> getCallCapablePhoneAccounts() { 188 try { 189 return mPhoneAccountRegistrar.getCallCapablePhoneAccounts(); 190 } catch (Exception e) { 191 Log.e(this, e, "getCallCapablePhoneAccounts"); 192 throw e; 193 } 194 } 195 196 @Override 197 public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) { 198 try { 199 return mPhoneAccountRegistrar.getCallCapablePhoneAccounts(uriScheme); 200 } catch (Exception e) { 201 Log.e(this, e, "getPhoneAccountsSupportingScheme"); 202 throw e; 203 } 204 } 205 206 @Override 207 public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName) { 208 try { 209 return mPhoneAccountRegistrar.getPhoneAccountsForPackage(packageName); 210 } catch (Exception e) { 211 Log.e(this, e, "getPhoneAccountsForPackage"); 212 throw e; 213 } 214 } 215 216 @Override 217 public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle) { 218 try { 219 return mPhoneAccountRegistrar.getPhoneAccount(accountHandle); 220 } catch (Exception e) { 221 Log.e(this, e, "getPhoneAccount %s", accountHandle); 222 throw e; 223 } 224 } 225 226 @Override 227 public int getAllPhoneAccountsCount() { 228 try { 229 return mPhoneAccountRegistrar.getAllPhoneAccountsCount(); 230 } catch (Exception e) { 231 Log.e(this, e, "getAllPhoneAccountsCount"); 232 throw e; 233 } 234 } 235 236 @Override 237 public List<PhoneAccount> getAllPhoneAccounts() { 238 try { 239 return mPhoneAccountRegistrar.getAllPhoneAccounts(); 240 } catch (Exception e) { 241 Log.e(this, e, "getAllPhoneAccounts"); 242 throw e; 243 } 244 } 245 246 @Override 247 public List<PhoneAccountHandle> getAllPhoneAccountHandles() { 248 try { 249 return mPhoneAccountRegistrar.getAllPhoneAccountHandles(); 250 } catch (Exception e) { 251 Log.e(this, e, "getAllPhoneAccounts"); 252 throw e; 253 } 254 } 255 256 @Override 257 public PhoneAccountHandle getSimCallManager() { 258 try { 259 return mPhoneAccountRegistrar.getSimCallManager(); 260 } catch (Exception e) { 261 Log.e(this, e, "getSimCallManager"); 262 throw e; 263 } 264 } 265 266 @Override 267 public void setSimCallManager(PhoneAccountHandle accountHandle) { 268 enforceModifyPermission(); 269 270 try { 271 mPhoneAccountRegistrar.setSimCallManager(accountHandle); 272 } catch (Exception e) { 273 Log.e(this, e, "setSimCallManager"); 274 throw e; 275 } 276 } 277 278 @Override 279 public List<PhoneAccountHandle> getSimCallManagers() { 280 try { 281 return mPhoneAccountRegistrar.getConnectionManagerPhoneAccounts(); 282 } catch (Exception e) { 283 Log.e(this, e, "getSimCallManagers"); 284 throw e; 285 } 286 } 287 288 @Override 289 public void registerPhoneAccount(PhoneAccount account) { 290 try { 291 enforcePhoneAccountModificationForPackage( 292 account.getAccountHandle().getComponentName().getPackageName()); 293 if (account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) || 294 account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { 295 enforceRegisterProviderOrSubscriptionPermission(); 296 } 297 298 mPhoneAccountRegistrar.registerPhoneAccount(account); 299 } catch (Exception e) { 300 Log.e(this, e, "registerPhoneAccount %s", account); 301 throw e; 302 } 303 } 304 305 @Override 306 public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) { 307 try { 308 enforcePhoneAccountModificationForPackage( 309 accountHandle.getComponentName().getPackageName()); 310 mPhoneAccountRegistrar.unregisterPhoneAccount(accountHandle); 311 } catch (Exception e) { 312 Log.e(this, e, "unregisterPhoneAccount %s", accountHandle); 313 throw e; 314 } 315 } 316 317 @Override 318 public void clearAccounts(String packageName) { 319 try { 320 enforcePhoneAccountModificationForPackage(packageName); 321 mPhoneAccountRegistrar.clearAccounts(packageName); 322 } catch (Exception e) { 323 Log.e(this, e, "clearAccounts %s", packageName); 324 throw e; 325 } 326 } 327 328 /** 329 * @see android.telecom.TelecomManager#silenceRinger 330 */ 331 @Override 332 public void silenceRinger() { 333 Log.d(this, "silenceRinger"); 334 enforceModifyPermission(); 335 sendRequestAsync(MSG_SILENCE_RINGER, 0); 336 } 337 338 /** 339 * @see android.telecom.TelecomManager#getDefaultPhoneApp 340 */ 341 @Override 342 public ComponentName getDefaultPhoneApp() { 343 Resources resources = mContext.getResources(); 344 return new ComponentName( 345 resources.getString(R.string.ui_default_package), 346 resources.getString(R.string.dialer_default_class)); 347 } 348 349 /** 350 * @see android.telecom.TelecomManager#isInCall 351 */ 352 @Override 353 public boolean isInCall() { 354 enforceReadPermission(); 355 // Do not use sendRequest() with this method since it could cause a deadlock with 356 // audio service, which we call into from the main thread: AudioManager.setMode(). 357 final int callState = mCallsManager.getCallState(); 358 return callState == TelephonyManager.CALL_STATE_OFFHOOK 359 || callState == TelephonyManager.CALL_STATE_RINGING; 360 } 361 362 /** 363 * @see android.telecom.TelecomManager#isRinging 364 */ 365 @Override 366 public boolean isRinging() { 367 enforceReadPermission(); 368 return mCallsManager.getCallState() == TelephonyManager.CALL_STATE_RINGING; 369 } 370 371 /** 372 * @see TelecomManager#getCallState 373 */ 374 @Override 375 public int getCallState() { 376 return mCallsManager.getCallState(); 377 } 378 379 /** 380 * @see android.telecom.TelecomManager#endCall 381 */ 382 @Override 383 public boolean endCall() { 384 enforceModifyPermission(); 385 return (boolean) sendRequest(MSG_END_CALL); 386 } 387 388 /** 389 * @see android.telecom.TelecomManager#acceptRingingCall 390 */ 391 @Override 392 public void acceptRingingCall() { 393 enforceModifyPermission(); 394 sendRequestAsync(MSG_ACCEPT_RINGING_CALL, 0); 395 } 396 397 /** 398 * @see android.telecom.TelecomManager#showInCallScreen 399 */ 400 @Override 401 public void showInCallScreen(boolean showDialpad) { 402 enforceReadPermissionOrDefaultDialer(); 403 sendRequestAsync(MSG_SHOW_CALL_SCREEN, showDialpad ? 1 : 0); 404 } 405 406 /** 407 * @see android.telecom.TelecomManager#cancelMissedCallsNotification 408 */ 409 @Override 410 public void cancelMissedCallsNotification() { 411 enforceModifyPermissionOrDefaultDialer(); 412 sendRequestAsync(MSG_CANCEL_MISSED_CALLS_NOTIFICATION, 0); 413 } 414 415 /** 416 * @see android.telecom.TelecomManager#handleMmi 417 */ 418 @Override 419 public boolean handlePinMmi(String dialString) { 420 enforceModifyPermissionOrDefaultDialer(); 421 422 // Switch identity so that TelephonyManager checks Telecom's permissions instead. 423 long token = Binder.clearCallingIdentity(); 424 boolean retval = getTelephonyManager().handlePinMmi(dialString); 425 Binder.restoreCallingIdentity(token); 426 427 return retval; 428 } 429 430 /** 431 * @see android.telecom.TelecomManager#isTtySupported 432 */ 433 @Override 434 public boolean isTtySupported() { 435 enforceReadPermission(); 436 return (boolean) sendRequest(MSG_IS_TTY_SUPPORTED); 437 } 438 439 /** 440 * @see android.telecom.TelecomManager#getCurrentTtyMode 441 */ 442 @Override 443 public int getCurrentTtyMode() { 444 enforceReadPermission(); 445 return (int) sendRequest(MSG_GET_CURRENT_TTY_MODE); 446 } 447 448 /** 449 * @see android.telecom.TelecomManager#addNewIncomingCall 450 */ 451 @Override 452 public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) { 453 if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) { 454 mAppOpsManager.checkPackage( 455 Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName()); 456 457 Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL); 458 intent.setPackage(mContext.getPackageName()); 459 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 460 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle); 461 if (extras != null) { 462 intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras); 463 } 464 465 long token = Binder.clearCallingIdentity(); 466 mContext.startActivityAsUser(intent, UserHandle.CURRENT); 467 Binder.restoreCallingIdentity(token); 468 } 469 } 470 471 // 472 // Supporting methods for the ITelecomService interface implementation. 473 // 474 475 private void acceptRingingCallInternal() { 476 Call call = mCallsManager.getFirstCallWithState(CallState.RINGING); 477 if (call != null) { 478 call.answer(call.getVideoState()); 479 } 480 } 481 482 private boolean endCallInternal() { 483 // Always operate on the foreground call if one exists, otherwise get the first call in 484 // priority order by call-state. 485 Call call = mCallsManager.getForegroundCall(); 486 if (call == null) { 487 call = mCallsManager.getFirstCallWithState( 488 CallState.ACTIVE, 489 CallState.DIALING, 490 CallState.RINGING, 491 CallState.ON_HOLD); 492 } 493 494 if (call != null) { 495 if (call.getState() == CallState.RINGING) { 496 call.reject(false /* rejectWithMessage */, null); 497 } else { 498 call.disconnect(); 499 } 500 return true; 501 } 502 503 return false; 504 } 505 506 private void enforcePhoneAccountModificationForPackage(String packageName) { 507 // TODO: Use a new telecomm permission for this instead of reusing modify. 508 509 int result = mContext.checkCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); 510 511 // Callers with MODIFY_PHONE_STATE can use the PhoneAccount mechanism to implement 512 // built-in behavior even when PhoneAccounts are not exposed as a third-part API. They 513 // may also modify PhoneAccounts on behalf of any 'packageName'. 514 515 if (result != PackageManager.PERMISSION_GRANTED) { 516 // Other callers are only allowed to modify PhoneAccounts if the relevant system 517 // feature is enabled ... 518 enforceConnectionServiceFeature(); 519 // ... and the PhoneAccounts they refer to are for their own package. 520 enforceCallingPackage(packageName); 521 } 522 } 523 524 private void enforceReadPermissionOrDefaultDialer() { 525 if (!isDefaultDialerCalling()) { 526 enforceReadPermission(); 527 } 528 } 529 530 private void enforceModifyPermissionOrDefaultDialer() { 531 if (!isDefaultDialerCalling()) { 532 enforceModifyPermission(); 533 } 534 } 535 536 private void enforceCallingPackage(String packageName) { 537 mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName); 538 } 539 540 private void enforceConnectionServiceFeature() { 541 enforceFeature(PackageManager.FEATURE_CONNECTION_SERVICE); 542 } 543 544 private void enforceRegisterProviderOrSubscriptionPermission() { 545 enforcePermission(REGISTER_PROVIDER_OR_SUBSCRIPTION); 546 } 547 548 private void enforceReadPermission() { 549 enforcePermission(Manifest.permission.READ_PHONE_STATE); 550 } 551 552 private void enforceModifyPermission() { 553 enforcePermission(Manifest.permission.MODIFY_PHONE_STATE); 554 } 555 556 private void enforcePermission(String permission) { 557 mContext.enforceCallingOrSelfPermission(permission, null); 558 } 559 560 private void enforceFeature(String feature) { 561 PackageManager pm = mContext.getPackageManager(); 562 if (!pm.hasSystemFeature(feature)) { 563 throw new UnsupportedOperationException( 564 "System does not support feature " + feature); 565 } 566 } 567 568 private boolean isDefaultDialerCalling() { 569 ComponentName defaultDialerComponent = getDefaultPhoneApp(); 570 if (defaultDialerComponent != null) { 571 try { 572 mAppOpsManager.checkPackage( 573 Binder.getCallingUid(), defaultDialerComponent.getPackageName()); 574 return true; 575 } catch (SecurityException e) { 576 Log.e(TAG, e, "Could not get default dialer."); 577 } 578 } 579 return false; 580 } 581 582 private TelephonyManager getTelephonyManager() { 583 return (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE); 584 } 585 586 private MainThreadRequest sendRequestAsync(int command, int arg1) { 587 MainThreadRequest request = new MainThreadRequest(); 588 mMainThreadHandler.obtainMessage(command, arg1, 0, request).sendToTarget(); 589 return request; 590 } 591 592 /** 593 * Posts the specified command to be executed on the main thread, waits for the request to 594 * complete, and returns the result. 595 */ 596 private Object sendRequest(int command) { 597 if (Looper.myLooper() == mMainThreadHandler.getLooper()) { 598 MainThreadRequest request = new MainThreadRequest(); 599 mMainThreadHandler.handleMessage(mMainThreadHandler.obtainMessage(command, request)); 600 return request.result; 601 } else { 602 MainThreadRequest request = sendRequestAsync(command, 0); 603 604 // Wait for the request to complete 605 synchronized (request) { 606 while (request.result == null) { 607 try { 608 request.wait(); 609 } catch (InterruptedException e) { 610 // Do nothing, go back and wait until the request is complete 611 } 612 } 613 } 614 return request.result; 615 } 616 } 617 618 @Override 619 protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) { 620 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 621 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 622 if (mCallsManager != null) { 623 pw.println("mCallsManager: "); 624 pw.increaseIndent(); 625 mCallsManager.dump(pw); 626 pw.decreaseIndent(); 627 } 628 } 629} 630