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