• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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