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.content.pm.PackageManager; 20 import android.telecom.Log; 21 import android.telephony.PhoneNumberUtils; 22 import android.telephony.SubscriptionInfo; 23 import android.telephony.SubscriptionManager; 24 import android.telephony.TelephonyManager; 25 import android.telephony.TelephonyRegistryManager; 26 import android.telephony.emergency.EmergencyNumber; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 30 import java.util.List; 31 import java.util.Objects; 32 import java.util.Optional; 33 34 /** 35 * Send a {@link TelephonyManager#ACTION_PHONE_STATE_CHANGED} broadcast when the call state 36 * changes. 37 */ 38 public final class PhoneStateBroadcaster extends CallsManagerListenerBase { 39 40 private final CallsManager mCallsManager; 41 private final TelephonyRegistryManager mRegistry; 42 private int mCurrentState = TelephonyManager.CALL_STATE_IDLE; 43 PhoneStateBroadcaster(CallsManager callsManager)44 public PhoneStateBroadcaster(CallsManager callsManager) { 45 mCallsManager = callsManager; 46 mRegistry = callsManager.getContext().getSystemService(TelephonyRegistryManager.class); 47 if (mRegistry == null) { 48 Log.w(this, "TelephonyRegistry is null"); 49 } 50 } 51 52 @Override onCallStateChanged(Call call, int oldState, int newState)53 public void onCallStateChanged(Call call, int oldState, int newState) { 54 if (call.isExternalCall()) { 55 return; 56 } 57 updateStates(call); 58 } 59 60 @Override onCallAdded(Call call)61 public void onCallAdded(Call call) { 62 if (call.isExternalCall()) { 63 return; 64 } 65 updateStates(call); 66 67 if (call.isEmergencyCall() && !call.isIncoming()) { 68 sendOutgoingEmergencyCallEvent(call); 69 } 70 } 71 72 @Override onCallRemoved(Call call)73 public void onCallRemoved(Call call) { 74 if (call.isExternalCall()) { 75 return; 76 } 77 updateStates(call); 78 } 79 80 /** 81 * Handles changes to a call's external property. If the call becomes external, we end up 82 * updating the call state to idle. If the call becomes non-external, then the call state can 83 * update to off hook. 84 * 85 * @param call The call. 86 * @param isExternalCall {@code True} if the call is external, {@code false} otherwise. 87 */ 88 @Override onExternalCallChanged(Call call, boolean isExternalCall)89 public void onExternalCallChanged(Call call, boolean isExternalCall) { 90 updateStates(call); 91 } 92 updateStates(Call call)93 private void updateStates(Call call) { 94 // Recalculate the current phone state based on the consolidated state of the remaining 95 // calls in the call list. 96 // Note: CallsManager#hasRingingCall() and CallsManager#getFirstCallWithState(..) do not 97 // consider external calls, so an external call is going to cause the state to be idle. 98 int callState = TelephonyManager.CALL_STATE_IDLE; 99 if (mCallsManager.hasRingingOrSimulatedRingingCall()) { 100 callState = TelephonyManager.CALL_STATE_RINGING; 101 } else if (mCallsManager.getFirstCallWithState(CallState.DIALING, CallState.PULLING, 102 CallState.ACTIVE, CallState.ON_HOLD) != null) { 103 callState = TelephonyManager.CALL_STATE_OFFHOOK; 104 } 105 sendPhoneStateChangedBroadcast(call, callState); 106 } 107 getCallState()108 int getCallState() { 109 return mCurrentState; 110 } 111 sendPhoneStateChangedBroadcast(Call call, int phoneState)112 private void sendPhoneStateChangedBroadcast(Call call, int phoneState) { 113 if (phoneState == mCurrentState) { 114 return; 115 } 116 117 mCurrentState = phoneState; 118 119 String callHandle = null; 120 // Only report phone numbers in phone state broadcast for regular mobile calls; do not 121 // include numbers from 3rd party apps. 122 if (!call.isSelfManaged() && call.getHandle() != null) { 123 callHandle = call.getHandle().getSchemeSpecificPart(); 124 } 125 126 if (mRegistry != null) { 127 mRegistry.notifyCallStateChangedForAllSubscriptions(phoneState, callHandle); 128 Log.i(this, "Broadcasted state change: %s", mCurrentState); 129 } 130 } 131 sendOutgoingEmergencyCallEvent(Call call)132 private void sendOutgoingEmergencyCallEvent(Call call) { 133 TelephonyManager tm = mCallsManager.getContext().getSystemService(TelephonyManager.class); 134 String strippedNumber = 135 PhoneNumberUtils.stripSeparators(call.getHandle().getSchemeSpecificPart()); 136 Optional<EmergencyNumber> emergencyNumber; 137 try { 138 emergencyNumber = tm.getEmergencyNumberList().values().stream() 139 .flatMap(List::stream) 140 .filter(numberObj -> Objects.equals(numberObj.getNumber(), strippedNumber)) 141 .findFirst(); 142 } catch (UnsupportedOperationException ignored) { 143 emergencyNumber = Optional.empty(); 144 } catch (IllegalStateException ie) { 145 emergencyNumber = Optional.empty(); 146 } catch (RuntimeException r) { 147 emergencyNumber = Optional.empty(); 148 } 149 150 if (emergencyNumber.isPresent()) { 151 int subscriptionId; 152 int simSlotIndex; 153 try { 154 subscriptionId = tm.getSubscriptionId(call.getTargetPhoneAccount()); 155 SubscriptionManager subscriptionManager = 156 mCallsManager.getContext().getSystemService(SubscriptionManager.class); 157 simSlotIndex = SubscriptionManager.DEFAULT_PHONE_INDEX; 158 if (subscriptionManager != null) { 159 SubscriptionInfo subInfo = 160 subscriptionManager.getActiveSubscriptionInfo(subscriptionId); 161 if (subInfo != null) { 162 simSlotIndex = subInfo.getSimSlotIndex(); 163 } 164 } 165 } catch (UnsupportedOperationException ignored) { 166 subscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 167 simSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX; 168 } 169 170 mRegistry.notifyOutgoingEmergencyCall( 171 simSlotIndex, subscriptionId, emergencyNumber.get()); 172 } 173 } 174 } 175