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 17 package com.android.server.telecom; 18 19 import android.os.RemoteException; 20 import android.os.ServiceManager; 21 import android.telecom.Log; 22 import android.telephony.TelephonyManager; 23 24 import com.android.internal.telephony.ITelephonyRegistry; 25 26 /** 27 * Send a {@link TelephonyManager#ACTION_PHONE_STATE_CHANGED} broadcast when the call state 28 * changes. 29 */ 30 final class PhoneStateBroadcaster extends CallsManagerListenerBase { 31 32 private final CallsManager mCallsManager; 33 private final ITelephonyRegistry mRegistry; 34 private int mCurrentState = TelephonyManager.CALL_STATE_IDLE; 35 36 public PhoneStateBroadcaster(CallsManager callsManager) { 37 mCallsManager = callsManager; 38 mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( 39 "telephony.registry")); 40 if (mRegistry == null) { 41 Log.w(this, "TelephonyRegistry is null"); 42 } 43 } 44 45 @Override 46 public void onCallStateChanged(Call call, int oldState, int newState) { 47 if (call.isExternalCall()) { 48 return; 49 } 50 updateStates(call); 51 } 52 53 @Override 54 public void onCallAdded(Call call) { 55 if (call.isExternalCall()) { 56 return; 57 } 58 updateStates(call); 59 } 60 61 @Override 62 public void onCallRemoved(Call call) { 63 if (call.isExternalCall()) { 64 return; 65 } 66 updateStates(call); 67 } 68 69 /** 70 * Handles changes to a call's external property. If the call becomes external, we end up 71 * updating the call state to idle. If the call becomes non-external, then the call state can 72 * update to off hook. 73 * 74 * @param call The call. 75 * @param isExternalCall {@code True} if the call is external, {@code false} otherwise. 76 */ 77 @Override 78 public void onExternalCallChanged(Call call, boolean isExternalCall) { 79 updateStates(call); 80 } 81 82 private void updateStates(Call call) { 83 // Recalculate the current phone state based on the consolidated state of the remaining 84 // calls in the call list. 85 // Note: CallsManager#hasRingingCall() and CallsManager#getFirstCallWithState(..) do not 86 // consider external calls, so an external call is going to cause the state to be idle. 87 int callState = TelephonyManager.CALL_STATE_IDLE; 88 if (mCallsManager.hasRingingCall()) { 89 callState = TelephonyManager.CALL_STATE_RINGING; 90 } else if (mCallsManager.getFirstCallWithState(CallState.DIALING, CallState.PULLING, 91 CallState.ACTIVE, CallState.ON_HOLD) != null) { 92 callState = TelephonyManager.CALL_STATE_OFFHOOK; 93 } 94 sendPhoneStateChangedBroadcast(call, callState); 95 } 96 97 int getCallState() { 98 return mCurrentState; 99 } 100 101 private void sendPhoneStateChangedBroadcast(Call call, int phoneState) { 102 if (phoneState == mCurrentState) { 103 return; 104 } 105 106 mCurrentState = phoneState; 107 108 String callHandle = null; 109 if (call.getHandle() != null) { 110 callHandle = call.getHandle().getSchemeSpecificPart(); 111 } 112 113 try { 114 if (mRegistry != null) { 115 mRegistry.notifyCallState(phoneState, callHandle); 116 Log.i(this, "Broadcasted state change: %s", mCurrentState); 117 } 118 } catch (RemoteException e) { 119 Log.w(this, "RemoteException when notifying TelephonyRegistry of call state change."); 120 } 121 } 122 } 123