1 /* 2 * Copyright (C) 2017 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.dialer.simulator.impl; 18 19 import android.support.annotation.NonNull; 20 import android.telecom.CallAudioState; 21 import android.telecom.Conference; 22 import android.telecom.Connection; 23 import android.telecom.PhoneAccountHandle; 24 import com.android.dialer.common.Assert; 25 import com.android.dialer.common.LogUtil; 26 import com.android.dialer.simulator.Simulator; 27 import com.android.dialer.simulator.Simulator.Event; 28 import java.util.ArrayList; 29 import java.util.List; 30 31 /** 32 * Represents a conference call. When a user merges two phone calls we create an instance of this 33 * conference object and add it to the connection service. All operations such as hold and DTMF are 34 * then performed on this object. 35 */ 36 public final class SimulatorConference extends Conference implements SimulatorConnection.Listener { 37 static final int PROPERTY_GENERIC_CONFERENCE = 1 << 1; 38 39 private final List<Listener> listeners = new ArrayList<>(); 40 private final List<Event> events = new ArrayList<>(); 41 private final int conferenceType; 42 SimulatorConference( PhoneAccountHandle handle, @Simulator.ConferenceType int conferenceType)43 private SimulatorConference( 44 PhoneAccountHandle handle, @Simulator.ConferenceType int conferenceType) { 45 super(handle); 46 this.conferenceType = conferenceType; 47 setActive(); 48 } 49 newGsmConference(PhoneAccountHandle handle)50 static SimulatorConference newGsmConference(PhoneAccountHandle handle) { 51 SimulatorConference simulatorConference = 52 new SimulatorConference(handle, Simulator.CONFERENCE_TYPE_GSM); 53 simulatorConference.setConnectionCapabilities( 54 Connection.CAPABILITY_MUTE 55 | Connection.CAPABILITY_SUPPORT_HOLD 56 | Connection.CAPABILITY_HOLD 57 | Connection.CAPABILITY_MANAGE_CONFERENCE); 58 return simulatorConference; 59 } 60 newVoLteConference(PhoneAccountHandle handle)61 static SimulatorConference newVoLteConference(PhoneAccountHandle handle) { 62 SimulatorConference simulatorConference = 63 new SimulatorConference(handle, Simulator.CONFERENCE_TYPE_VOLTE); 64 simulatorConference.setConnectionCapabilities( 65 Connection.CAPABILITY_MUTE 66 | Connection.CAPABILITY_SUPPORT_HOLD 67 | Connection.CAPABILITY_HOLD 68 | Connection.CAPABILITY_MANAGE_CONFERENCE); 69 return simulatorConference; 70 } 71 addListener(@onNull Listener listener)72 public void addListener(@NonNull Listener listener) { 73 listeners.add(Assert.isNotNull(listener)); 74 } 75 removeListener(@onNull Listener listener)76 public void removeListener(@NonNull Listener listener) { 77 listeners.remove(Assert.isNotNull(listener)); 78 } 79 80 @NonNull getEvents()81 public List<Event> getEvents() { 82 return events; 83 } 84 85 @Override onCallAudioStateChanged(CallAudioState state)86 public void onCallAudioStateChanged(CallAudioState state) { 87 LogUtil.enterBlock("SimulatorConference.onCallAudioStateChanged"); 88 onEvent(new Event(Event.CALL_AUDIO_STATE_CHANGED)); 89 } 90 91 @Override onConnectionAdded(Connection connection)92 public void onConnectionAdded(Connection connection) { 93 LogUtil.enterBlock("SimulatorConference.onConnectionAdded"); 94 onEvent( 95 new Event( 96 Event.CONNECTION_ADDED, SimulatorSimCallManager.getConnectionTag(connection), null)); 97 ((SimulatorConnection) connection).addListener(this); 98 } 99 100 @Override onDisconnect()101 public void onDisconnect() { 102 LogUtil.enterBlock("SimulatorConference.onDisconnect"); 103 onEvent(new Event(Event.DISCONNECT)); 104 } 105 106 @Override onHold()107 public void onHold() { 108 LogUtil.enterBlock("SimulatorConference.onHold"); 109 onEvent(new Event(Event.HOLD)); 110 } 111 112 @Override onMerge(Connection connection)113 public void onMerge(Connection connection) { 114 LogUtil.i("SimulatorConference.onMerge", "connection: " + connection); 115 onEvent(new Event(Event.MERGE, SimulatorSimCallManager.getConnectionTag(connection), null)); 116 } 117 118 @Override onMerge()119 public void onMerge() { 120 LogUtil.enterBlock("SimulatorConference.onMerge"); 121 onEvent(new Event(Event.MERGE)); 122 } 123 124 @Override onPlayDtmfTone(char c)125 public void onPlayDtmfTone(char c) { 126 LogUtil.enterBlock("SimulatorConference.onPlayDtmfTone"); 127 onEvent(new Event(Event.DTMF, Character.toString(c), null)); 128 } 129 130 @Override onSeparate(Connection connection)131 public void onSeparate(Connection connection) { 132 LogUtil.i("SimulatorConference.onSeparate", "connection: " + connection); 133 onEvent(new Event(Event.SEPARATE, SimulatorSimCallManager.getConnectionTag(connection), null)); 134 // if there is only 1 connection in a gsm conference, destroy the conference. 135 if (conferenceType == Simulator.CONFERENCE_TYPE_GSM && getConnections().size() == 1) { 136 removeConnection(getConnections().get(0)); 137 destroy(); 138 } 139 } 140 141 @Override onSwap()142 public void onSwap() { 143 LogUtil.enterBlock("SimulatorConference.onSwap"); 144 onEvent(new Event(Event.SWAP)); 145 } 146 147 @Override onUnhold()148 public void onUnhold() { 149 LogUtil.enterBlock("SimulatorConference.onUnhold"); 150 onEvent(new Event(Event.UNHOLD)); 151 } 152 153 @Override onEvent(@onNull SimulatorConnection connection, @NonNull Event event)154 public void onEvent(@NonNull SimulatorConnection connection, @NonNull Event event) { 155 if (conferenceType == Simulator.CONFERENCE_TYPE_GSM) { 156 onGsmEvent(connection, event); 157 } 158 } 159 onGsmEvent(@onNull SimulatorConnection connection, @NonNull Event event)160 private void onGsmEvent(@NonNull SimulatorConnection connection, @NonNull Event event) { 161 if (event.type == Event.STATE_CHANGE 162 && Connection.stateToString(Connection.STATE_DISCONNECTED).equals(event.data2)) { 163 removeConnection(connection); 164 connection.removeListener(this); 165 if (getConnections().size() <= 1) { 166 // When only one connection exists, it's not conference call anymore 167 setDisconnected(connection.getDisconnectCause()); 168 destroy(); 169 } 170 } 171 } 172 onEvent(@onNull Event event)173 void onEvent(@NonNull Event event) { 174 events.add(Assert.isNotNull(event)); 175 for (Listener listener : new ArrayList<>(listeners)) { 176 listener.onEvent(this, event); 177 } 178 } 179 180 /** Callback for when a new event arrives. */ 181 public interface Listener { onEvent(@onNull SimulatorConference conference, @NonNull Event event)182 void onEvent(@NonNull SimulatorConference conference, @NonNull Event event); 183 } 184 } 185