1 /* 2 * Copyright (C) 2006 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.internal.telephony; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 import android.os.Build; 21 22 import com.android.ims.internal.ConferenceParticipant; 23 import com.android.telephony.Rlog; 24 25 import java.util.ArrayList; 26 import java.util.List; 27 import java.util.stream.Collectors; 28 29 /** 30 * {@hide} 31 */ 32 public abstract class Call { 33 protected final String LOG_TAG = "Call"; 34 35 @UnsupportedAppUsage Call()36 public Call() { 37 } 38 39 /* Enums */ 40 @UnsupportedAppUsage(implicitMember = "values()[Lcom/android/internal/telephony/Call$State;") 41 public enum State { 42 @UnsupportedAppUsage IDLE, 43 ACTIVE, 44 @UnsupportedAppUsage HOLDING, 45 @UnsupportedAppUsage DIALING, 46 @UnsupportedAppUsage ALERTING, 47 @UnsupportedAppUsage INCOMING, 48 @UnsupportedAppUsage WAITING, 49 @UnsupportedAppUsage DISCONNECTED, 50 @UnsupportedAppUsage DISCONNECTING; 51 52 @UnsupportedAppUsage isAlive()53 public boolean isAlive() { 54 return !(this == IDLE || this == DISCONNECTED || this == DISCONNECTING); 55 } 56 57 @UnsupportedAppUsage isRinging()58 public boolean isRinging() { 59 return this == INCOMING || this == WAITING; 60 } 61 isDialing()62 public boolean isDialing() { 63 return this == DIALING || this == ALERTING; 64 } 65 } 66 67 public static State stateFromDCState(DriverCall.State dcState)68 stateFromDCState (DriverCall.State dcState) { 69 switch (dcState) { 70 case ACTIVE: return State.ACTIVE; 71 case HOLDING: return State.HOLDING; 72 case DIALING: return State.DIALING; 73 case ALERTING: return State.ALERTING; 74 case INCOMING: return State.INCOMING; 75 case WAITING: return State.WAITING; 76 default: throw new RuntimeException ("illegal call state:" + dcState); 77 } 78 } 79 80 public enum SrvccState { 81 NONE, STARTED, COMPLETED, FAILED, CANCELED; 82 } 83 84 /* Instance Variables */ 85 86 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 87 public State mState = State.IDLE; 88 89 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 90 public ArrayList<Connection> mConnections = new ArrayList<>(); 91 92 private Object mLock = new Object(); 93 94 /* Instance Methods */ 95 96 /** Do not modify the List result!!! This list is not yours to keep 97 * It will change across event loop iterations top 98 */ 99 100 @UnsupportedAppUsage getConnections()101 public ArrayList<Connection> getConnections() { 102 synchronized (mLock) { 103 return (ArrayList<Connection>) mConnections.clone(); 104 } 105 } 106 107 /** 108 * Get mConnections field from another Call instance. 109 * @param other 110 */ copyConnectionFrom(Call other)111 public void copyConnectionFrom(Call other) { 112 mConnections = other.getConnections(); 113 } 114 115 /** 116 * Get connections count of this instance. 117 * @return the count to return 118 */ getConnectionsCount()119 public int getConnectionsCount() { 120 synchronized (mLock) { 121 return mConnections.size(); 122 } 123 } 124 125 /** 126 * @return returns a summary of the connections held in this call. 127 */ getConnectionSummary()128 public String getConnectionSummary() { 129 synchronized (mLock) { 130 return mConnections.stream() 131 .map(c -> c.getTelecomCallId() + "/objId:" + System.identityHashCode(c)) 132 .collect(Collectors.joining(", ")); 133 } 134 } 135 136 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getPhone()137 public abstract Phone getPhone(); 138 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isMultiparty()139 public abstract boolean isMultiparty(); 140 @UnsupportedAppUsage hangup()141 public abstract void hangup() throws CallStateException; 142 hangup(@ndroid.telecom.Call.RejectReason int rejectReason)143 public abstract void hangup(@android.telecom.Call.RejectReason int rejectReason) 144 throws CallStateException; 145 146 /** 147 * hasConnection 148 * 149 * @param c a Connection object 150 * @return true if the call contains the connection object passed in 151 */ hasConnection(Connection c)152 public boolean hasConnection(Connection c) { 153 return c.getCall() == this; 154 } 155 156 /** 157 * hasConnections 158 * @return true if the call contains one or more connections 159 */ hasConnections()160 public boolean hasConnections() { 161 List<Connection> connections = getConnections(); 162 163 if (connections == null) { 164 return false; 165 } 166 167 return connections.size() > 0; 168 } 169 170 /** 171 * removeConnection 172 * 173 * @param conn the connection to be removed 174 */ removeConnection(Connection conn)175 public void removeConnection(Connection conn) { 176 synchronized (mLock) { 177 mConnections.remove(conn); 178 } 179 } 180 181 /** 182 * addConnection 183 * 184 * @param conn the connection to be added 185 */ addConnection(Connection conn)186 public void addConnection(Connection conn) { 187 synchronized (mLock) { 188 mConnections.add(conn); 189 } 190 } 191 192 /** 193 * clearConnection 194 */ clearConnections()195 public void clearConnections() { 196 synchronized (mLock) { 197 mConnections.clear(); 198 } 199 } 200 201 /** 202 * getState 203 * @return state of class call 204 */ 205 @UnsupportedAppUsage getState()206 public State getState() { 207 return mState; 208 } 209 210 /** 211 * getConferenceParticipants 212 * @return List of conference participants. 213 */ getConferenceParticipants()214 public List<ConferenceParticipant> getConferenceParticipants() { 215 return null; 216 } 217 218 /** 219 * isIdle 220 * 221 * FIXME rename 222 * @return true if the call contains only disconnected connections (if any) 223 */ 224 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isIdle()225 public boolean isIdle() { 226 return !getState().isAlive(); 227 } 228 229 /** 230 * Returns the Connection associated with this Call that was created 231 * first, or null if there are no Connections in this Call 232 */ 233 @UnsupportedAppUsage 234 public Connection getEarliestConnection()235 getEarliestConnection() { 236 List<Connection> l; 237 long time = Long.MAX_VALUE; 238 Connection c; 239 Connection earliest = null; 240 241 l = getConnections(); 242 243 if (l.size() == 0) { 244 return null; 245 } 246 247 for (int i = 0, s = l.size() ; i < s ; i++) { 248 c = l.get(i); 249 long t; 250 251 t = c.getCreateTime(); 252 253 if (t < time) { 254 earliest = c; 255 time = t; 256 } 257 } 258 259 return earliest; 260 } 261 262 public long getEarliestCreateTime()263 getEarliestCreateTime() { 264 List<Connection> l; 265 long time = Long.MAX_VALUE; 266 267 l = getConnections(); 268 269 if (l.size() == 0) { 270 return 0; 271 } 272 273 for (int i = 0, s = l.size() ; i < s ; i++) { 274 Connection c = l.get(i); 275 long t; 276 277 t = c.getCreateTime(); 278 279 time = t < time ? t : time; 280 } 281 282 return time; 283 } 284 285 public long 286 getEarliestConnectTime() { 287 long time = Long.MAX_VALUE; 288 List<Connection> l = getConnections(); 289 290 if (l.size() == 0) { 291 return 0; 292 } 293 294 for (int i = 0, s = l.size() ; i < s ; i++) { 295 Connection c = l.get(i); 296 long t; 297 298 t = c.getConnectTime(); 299 300 time = t < time ? t : time; 301 } 302 303 return time; 304 } 305 306 307 public boolean 308 isDialingOrAlerting() { 309 return getState().isDialing(); 310 } 311 312 public boolean 313 isRinging() { 314 return getState().isRinging(); 315 } 316 317 /** 318 * Returns the Connection associated with this Call that was created 319 * last, or null if there are no Connections in this Call 320 */ 321 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 322 public Connection 323 getLatestConnection() { 324 List<Connection> l = getConnections(); 325 if (l.size() == 0) { 326 return null; 327 } 328 329 long time = 0; 330 Connection latest = null; 331 for (int i = 0, s = l.size() ; i < s ; i++) { 332 Connection c = l.get(i); 333 long t = c.getCreateTime(); 334 335 if (t > time) { 336 latest = c; 337 time = t; 338 } 339 } 340 341 return latest; 342 } 343 344 /** 345 * Hangup call if it is alive 346 */ 347 public void hangupIfAlive() { 348 if (getState().isAlive()) { 349 try { 350 hangup(); 351 } catch (CallStateException ex) { 352 Rlog.w(LOG_TAG, " hangupIfActive: caught " + ex); 353 } 354 } 355 } 356 357 /** 358 * Called when it's time to clean up disconnected Connection objects 359 */ 360 public void clearDisconnected() { 361 for (Connection conn : getConnections()) { 362 if (conn.getState() == State.DISCONNECTED) { 363 removeConnection(conn); 364 } 365 } 366 367 if (getConnectionsCount() == 0) { 368 setState(State.IDLE); 369 } 370 } 371 372 protected void setState(State newState) { 373 mState = newState; 374 } 375 } 376