1 /* 2 * Copyright (C) 2019 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.services.telephony; 18 19 import android.annotation.NonNull; 20 import android.os.Bundle; 21 import android.telecom.Conference; 22 import android.telecom.Connection; 23 import android.telecom.PhoneAccountHandle; 24 import android.telecom.TelecomManager; 25 import android.telephony.ServiceState; 26 27 import java.util.Collections; 28 import java.util.Iterator; 29 import java.util.Set; 30 import java.util.concurrent.ConcurrentHashMap; 31 32 /** 33 * Base class for the various Telephony {@link Conference} implementations ({@link CdmaConference}, 34 * {@link TelephonyConference}, and {@link ImsConference}). Adds some common listener code which 35 * all of these conferences use. 36 */ 37 public class TelephonyConferenceBase extends Conference { 38 private static final String TAG = "TelephonyConferenceBase"; 39 40 /** 41 * Listener for conference events. 42 */ 43 public abstract static class TelephonyConferenceListener { 44 /** 45 * Listener called when a connection is added or removed from a conference. 46 * @param connection The connection. 47 */ onConferenceMembershipChanged(Connection connection)48 public void onConferenceMembershipChanged(Connection connection) {} 49 50 /** 51 * Listener called when there conference call state changes. 52 * @param conference The conference. 53 * @param oldState previous state of conference call. 54 * @param newState new state of conference call. 55 */ onStateChanged(Conference conference, int oldState, int newState)56 public void onStateChanged(Conference conference, int oldState, int newState) {} 57 58 /** 59 * Listener called when a conference is destroyed. 60 * @param conference The conference. 61 */ onDestroyed(Conference conference)62 public void onDestroyed(Conference conference) {} 63 } 64 65 private final Set<TelephonyConferenceListener> mListeners = Collections.newSetFromMap( 66 new ConcurrentHashMap<>(8, 0.9f, 1)); 67 68 /** 69 * Adds a listener to this conference. 70 * @param listener The listener. 71 */ addTelephonyConferenceListener(@onNull TelephonyConferenceListener listener)72 public void addTelephonyConferenceListener(@NonNull TelephonyConferenceListener listener) { 73 mListeners.add(listener); 74 } 75 76 /** 77 * Removes a listener from this conference. 78 * @param listener The listener. 79 */ removeTelephonyConferenceListener(@onNull TelephonyConferenceListener listener)80 public void removeTelephonyConferenceListener(@NonNull TelephonyConferenceListener listener) { 81 mListeners.remove(listener); 82 } 83 84 /** 85 * Constructs a new Conference with a mandatory {@link PhoneAccountHandle} 86 * 87 * @param phoneAccount The {@code PhoneAccountHandle} associated with the conference. 88 */ TelephonyConferenceBase(PhoneAccountHandle phoneAccount)89 public TelephonyConferenceBase(PhoneAccountHandle phoneAccount) { 90 super(phoneAccount); 91 } 92 93 /** 94 * Adds a connection to this {@link Conference}. 95 * <p> 96 * Should be used in place of {@link Conference#addConnection(Connection)} to ensure 97 * {@link TelephonyConferenceListener}s are informed of the change. 98 * 99 * @param connection The connection. 100 */ addTelephonyConnection(@onNull Connection connection)101 public void addTelephonyConnection(@NonNull Connection connection) { 102 addConnection(connection); 103 notifyConferenceMembershipChanged(connection); 104 } 105 106 /** 107 * Removes a {@link Connection} from this {@link Conference}. 108 * <p> 109 * Should be used instead of {@link Conference#removeConnection(Connection)} to ensure 110 * {@link TelephonyConferenceListener}s are notified of the change. 111 * 112 * @param connection The connection. 113 */ removeTelephonyConnection(@onNull Connection connection)114 public void removeTelephonyConnection(@NonNull Connection connection) { 115 removeConnection(connection); 116 notifyConferenceMembershipChanged(connection); 117 } 118 119 /** 120 * Destroys the current {@link Conference} and notifies {@link TelephonyConferenceListener}s of 121 * the change to conference membership. 122 * <p> 123 * Should be used instead of {@link Conference#destroy()} to ensure telephony listeners are 124 * notified. 125 */ destroyTelephonyConference()126 public void destroyTelephonyConference() { 127 // Conference#removeConnection modifies the list of participants, so we need to use an 128 // iterator here to ensure all participants are removed. 129 // Technically Conference#destroy does this, but we want to notify listeners of the state 130 // change so we'll do it here first. 131 Iterator<Connection> connectionIterator = getConnections().iterator(); 132 while (connectionIterator.hasNext()) { 133 removeTelephonyConnection(connectionIterator.next()); 134 } 135 destroy(); 136 notifyDestroyed(); 137 } 138 139 /** 140 * Sets state to be on hold. 141 */ setConferenceOnHold()142 public final void setConferenceOnHold() { 143 int oldState = getState(); 144 if (oldState == Connection.STATE_HOLDING) { 145 return; 146 } 147 setOnHold(); 148 notifyStateChanged(oldState, getState()); 149 } 150 151 /** 152 * Sets state to be dialing. 153 */ setConferenceOnDialing()154 public final void setConferenceOnDialing() { 155 int oldState = getState(); 156 if (oldState == Connection.STATE_DIALING) { 157 return; 158 } 159 setDialing(); 160 notifyStateChanged(oldState, getState()); 161 } 162 163 /** 164 * Sets state to be ringing. 165 */ setConferenceOnRinging()166 public final void setConferenceOnRinging() { 167 int oldState = getState(); 168 if (oldState == Connection.STATE_RINGING) { 169 return; 170 } 171 setRinging(); 172 notifyStateChanged(oldState, getState()); 173 } 174 175 /** 176 * Sets state to be active. 177 */ setConferenceOnActive()178 public final void setConferenceOnActive() { 179 int oldState = getState(); 180 if (oldState == Connection.STATE_ACTIVE) { 181 return; 182 } 183 setActive(); 184 notifyStateChanged(oldState, getState()); 185 } 186 187 /** 188 * Updates RIL voice radio technology used for current conference after its creation. 189 */ updateCallRadioTechAfterCreation()190 public void updateCallRadioTechAfterCreation() { 191 final Connection primaryConnection = getPrimaryConnection(); 192 if (primaryConnection != null && primaryConnection instanceof TelephonyConnection) { 193 TelephonyConnection telephonyConnection = (TelephonyConnection) primaryConnection; 194 Bundle newExtras = new Bundle(); 195 newExtras.putInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE, 196 ServiceState.rilRadioTechnologyToNetworkType( 197 telephonyConnection.getCallRadioTech())); 198 putExtras(newExtras); 199 } else { 200 Log.w(TAG, "No primary connection found while updateCallRadioTechAfterCreation"); 201 } 202 } 203 204 /** 205 * Removes the specified capability from the set of capabilities of this {@code Conference}. 206 * 207 * @param capability The capability to remove from the set. 208 */ removeCapability(int capability)209 public void removeCapability(int capability) { 210 int newCapabilities = getConnectionCapabilities(); 211 newCapabilities &= ~capability; 212 213 setConnectionCapabilities(newCapabilities); 214 } 215 216 /** 217 * Adds the specified capability to the set of capabilities of this {@code Conference}. 218 * 219 * @param capability The capability to add to the set. 220 */ addCapability(int capability)221 public void addCapability(int capability) { 222 int newCapabilities = getConnectionCapabilities(); 223 newCapabilities |= capability; 224 225 setConnectionCapabilities(newCapabilities); 226 } 227 228 /** 229 * Notifies {@link TelephonyConferenceListener}s of a connection being added or removed from 230 * the conference. 231 * @param connection The conference. 232 */ notifyConferenceMembershipChanged(@onNull Connection connection)233 private void notifyConferenceMembershipChanged(@NonNull Connection connection) { 234 for (TelephonyConferenceListener listener : mListeners) { 235 listener.onConferenceMembershipChanged(connection); 236 } 237 } 238 239 /** 240 * Notifies {@link TelephonyConferenceListener}s of a conference being destroyed 241 */ notifyDestroyed()242 private void notifyDestroyed() { 243 for (TelephonyConferenceListener listener : mListeners) { 244 listener.onDestroyed(this); 245 } 246 } 247 notifyStateChanged(int oldState, int newState)248 private void notifyStateChanged(int oldState, int newState) { 249 if (oldState != newState) { 250 for (TelephonyConferenceListener listener : mListeners) { 251 listener.onStateChanged(this, oldState, newState); 252 } 253 } 254 } 255 } 256