1 /*
2  * Copyright (C) 2014 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 android.bluetooth;
18 
19 import android.annotation.NonNull;
20 import android.compat.annotation.UnsupportedAppUsage;
21 import android.content.AttributionSource;
22 import android.os.Build;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 import android.os.SystemClock;
26 
27 import java.util.UUID;
28 
29 /**
30  * This class represents a single call, its state and properties. It implements {@link Parcelable}
31  * for inter-process message passing.
32  *
33  * @hide
34  */
35 public final class BluetoothHeadsetClientCall implements Parcelable, Attributable {
36 
37     /* Call state */
38     /** Call is active. */
39     public static final int CALL_STATE_ACTIVE = 0;
40 
41     /** Call is in held state. */
42     public static final int CALL_STATE_HELD = 1;
43 
44     /** Outgoing call that is being dialed right now. */
45     public static final int CALL_STATE_DIALING = 2;
46 
47     /** Outgoing call that remote party has already been alerted about. */
48     public static final int CALL_STATE_ALERTING = 3;
49 
50     /** Incoming call that can be accepted or rejected. */
51     public static final int CALL_STATE_INCOMING = 4;
52 
53     /** Waiting call state when there is already an active call. */
54     public static final int CALL_STATE_WAITING = 5;
55 
56     /**
57      * Call that has been held by response and hold (see Bluetooth specification for further
58      * references).
59      */
60     public static final int CALL_STATE_HELD_BY_RESPONSE_AND_HOLD = 6;
61 
62     /** Call that has been already terminated and should not be referenced as a valid call. */
63     public static final int CALL_STATE_TERMINATED = 7;
64 
65     private final BluetoothDevice mDevice;
66     private final int mId;
67     private int mState;
68     private String mNumber;
69     private boolean mMultiParty;
70     private final boolean mOutgoing;
71     private final UUID mUUID;
72     private final long mCreationElapsedMilli;
73     private final boolean mInBandRing;
74 
75     /** Creates BluetoothHeadsetClientCall instance. */
BluetoothHeadsetClientCall( BluetoothDevice device, int id, int state, String number, boolean multiParty, boolean outgoing, boolean inBandRing)76     public BluetoothHeadsetClientCall(
77             BluetoothDevice device,
78             int id,
79             int state,
80             String number,
81             boolean multiParty,
82             boolean outgoing,
83             boolean inBandRing) {
84         this(device, id, UUID.randomUUID(), state, number, multiParty, outgoing, inBandRing);
85     }
86 
BluetoothHeadsetClientCall( BluetoothDevice device, int id, UUID uuid, int state, String number, boolean multiParty, boolean outgoing, boolean inBandRing)87     public BluetoothHeadsetClientCall(
88             BluetoothDevice device,
89             int id,
90             UUID uuid,
91             int state,
92             String number,
93             boolean multiParty,
94             boolean outgoing,
95             boolean inBandRing) {
96         mDevice = device;
97         mId = id;
98         mUUID = uuid;
99         mState = state;
100         mNumber = number != null ? number : "";
101         mMultiParty = multiParty;
102         mOutgoing = outgoing;
103         mInBandRing = inBandRing;
104         mCreationElapsedMilli = SystemClock.elapsedRealtime();
105     }
106 
107     /** @hide */
setAttributionSource(@onNull AttributionSource attributionSource)108     public void setAttributionSource(@NonNull AttributionSource attributionSource) {
109         Attributable.setAttributionSource(mDevice, attributionSource);
110     }
111 
112     /**
113      * Sets call's state.
114      *
115      * <p>Note: This is an internal function and shouldn't be exposed
116      *
117      * @param state new call state.
118      */
setState(int state)119     public void setState(int state) {
120         mState = state;
121     }
122 
123     /**
124      * Sets call's number.
125      *
126      * <p>Note: This is an internal function and shouldn't be exposed
127      *
128      * @param number String representing phone number.
129      */
setNumber(String number)130     public void setNumber(String number) {
131         mNumber = number;
132     }
133 
134     /**
135      * Sets this call as multi party call.
136      *
137      * <p>Note: This is an internal function and shouldn't be exposed
138      *
139      * @param multiParty if <code>true</code> sets this call as a part of multi party conference.
140      */
setMultiParty(boolean multiParty)141     public void setMultiParty(boolean multiParty) {
142         mMultiParty = multiParty;
143     }
144 
145     /**
146      * Gets call's device.
147      *
148      * @return call device.
149      */
getDevice()150     public BluetoothDevice getDevice() {
151         return mDevice;
152     }
153 
154     /**
155      * Gets call's Id.
156      *
157      * @return call id.
158      */
159     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getId()160     public int getId() {
161         return mId;
162     }
163 
164     /**
165      * Gets call's UUID.
166      *
167      * @return call uuid
168      * @hide
169      */
getUUID()170     public UUID getUUID() {
171         return mUUID;
172     }
173 
174     /**
175      * Gets call's current state.
176      *
177      * @return state of this particular phone call.
178      */
179     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getState()180     public int getState() {
181         return mState;
182     }
183 
184     /**
185      * Gets call's number.
186      *
187      * @return string representing phone number.
188      */
189     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getNumber()190     public String getNumber() {
191         return mNumber;
192     }
193 
194     /**
195      * Gets call's creation time in millis since epoch.
196      *
197      * @return long representing the creation time.
198      */
getCreationElapsedMilli()199     public long getCreationElapsedMilli() {
200         return mCreationElapsedMilli;
201     }
202 
203     /**
204      * Checks if call is an active call in a conference mode (aka multi party).
205      *
206      * @return <code>true</code> if call is a multi party call, <code>false</code> otherwise.
207      */
208     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isMultiParty()209     public boolean isMultiParty() {
210         return mMultiParty;
211     }
212 
213     /**
214      * Checks if this call is an outgoing call.
215      *
216      * @return <code>true</code> if its outgoing call, <code>false</code> otherwise.
217      */
218     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isOutgoing()219     public boolean isOutgoing() {
220         return mOutgoing;
221     }
222 
223     /**
224      * Checks if the ringtone will be generated by the connected phone
225      *
226      * @return <code>true</code> if in band ring is enabled, <code>false</code> otherwise.
227      */
isInBandRing()228     public boolean isInBandRing() {
229         return mInBandRing;
230     }
231 
232     @Override
toString()233     public String toString() {
234         return toString(false);
235     }
236 
237     /**
238      * Generate a log string for this call
239      *
240      * @param loggable whether device address should be logged
241      * @return log string
242      */
toString(boolean loggable)243     public String toString(boolean loggable) {
244         StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mDevice: ");
245         builder.append(loggable ? mDevice : mDevice.hashCode());
246         builder.append(", mId: ");
247         builder.append(mId);
248         builder.append(", mUUID: ");
249         builder.append(mUUID);
250         builder.append(", mState: ");
251         switch (mState) {
252             case CALL_STATE_ACTIVE:
253                 builder.append("ACTIVE");
254                 break;
255             case CALL_STATE_HELD:
256                 builder.append("HELD");
257                 break;
258             case CALL_STATE_DIALING:
259                 builder.append("DIALING");
260                 break;
261             case CALL_STATE_ALERTING:
262                 builder.append("ALERTING");
263                 break;
264             case CALL_STATE_INCOMING:
265                 builder.append("INCOMING");
266                 break;
267             case CALL_STATE_WAITING:
268                 builder.append("WAITING");
269                 break;
270             case CALL_STATE_HELD_BY_RESPONSE_AND_HOLD:
271                 builder.append("HELD_BY_RESPONSE_AND_HOLD");
272                 break;
273             case CALL_STATE_TERMINATED:
274                 builder.append("TERMINATED");
275                 break;
276             default:
277                 builder.append(mState);
278                 break;
279         }
280         builder.append(", mNumber: ");
281         builder.append(loggable ? mNumber : mNumber.hashCode());
282         builder.append(", mMultiParty: ");
283         builder.append(mMultiParty);
284         builder.append(", mOutgoing: ");
285         builder.append(mOutgoing);
286         builder.append(", mInBandRing: ");
287         builder.append(mInBandRing);
288         builder.append("}");
289         return builder.toString();
290     }
291 
292     /** {@link Parcelable.Creator} interface implementation. */
293     public static final @NonNull Creator<BluetoothHeadsetClientCall> CREATOR =
294             new Creator<>() {
295                 @Override
296                 public BluetoothHeadsetClientCall createFromParcel(Parcel in) {
297                     return new BluetoothHeadsetClientCall(
298                             (BluetoothDevice) in.readParcelable(null),
299                             in.readInt(),
300                             UUID.fromString(in.readString()),
301                             in.readInt(),
302                             in.readString(),
303                             in.readInt() == 1,
304                             in.readInt() == 1,
305                             in.readInt() == 1);
306                 }
307 
308                 @Override
309                 public BluetoothHeadsetClientCall[] newArray(int size) {
310                     return new BluetoothHeadsetClientCall[size];
311                 }
312             };
313 
314     @Override
writeToParcel(Parcel out, int flags)315     public void writeToParcel(Parcel out, int flags) {
316         out.writeParcelable(mDevice, 0);
317         out.writeInt(mId);
318         out.writeString(mUUID.toString());
319         out.writeInt(mState);
320         out.writeString(mNumber);
321         out.writeInt(mMultiParty ? 1 : 0);
322         out.writeInt(mOutgoing ? 1 : 0);
323         out.writeInt(mInBandRing ? 1 : 0);
324     }
325 
326     @Override
describeContents()327     public int describeContents() {
328         return 0;
329     }
330 }
331