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