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
17package android.telecom;
18
19import android.os.Parcel;
20import android.os.Parcelable;
21import android.media.ToneGenerator;
22import android.text.TextUtils;
23
24import java.util.Objects;
25
26/**
27 * Describes the cause of a disconnected call. This always includes a code describing the generic
28 * cause of the disconnect. Optionally, it may include a label and/or description to display to the
29 * user. It is the responsibility of the {@link ConnectionService} to provide localized versions of
30 * the label and description. It also may contain a reason for the disconnect, which is intended for
31 * logging and not for display to the user.
32 */
33public final class DisconnectCause implements Parcelable {
34
35    /** Disconnected because of an unknown or unspecified reason. */
36    public static final int UNKNOWN = 0;
37    /** Disconnected because there was an error, such as a problem with the network. */
38    public static final int ERROR = 1;
39    /** Disconnected because of a local user-initiated action, such as hanging up. */
40    public static final int LOCAL = 2;
41    /**
42     * Disconnected because of a remote user-initiated action, such as the other party hanging up
43     * up.
44     */
45    public static final int REMOTE = 3;
46    /** Disconnected because it has been canceled. */
47    public static final int CANCELED = 4;
48    /** Disconnected because there was no response to an incoming call. */
49    public static final int MISSED = 5;
50    /** Disconnected because the user rejected an incoming call. */
51    public static final int REJECTED = 6;
52    /** Disconnected because the other party was busy. */
53    public static final int BUSY = 7;
54    /**
55     * Disconnected because of a restriction on placing the call, such as dialing in airplane
56     * mode.
57     */
58    public static final int RESTRICTED = 8;
59    /** Disconnected for reason not described by other disconnect codes. */
60    public static final int OTHER = 9;
61    /**
62     * Disconnected because the connection manager did not support the call. The call will be tried
63     * again without a connection manager. See {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}.
64     */
65    public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10;
66
67    /**
68     * Disconnected because the user did not locally answer the incoming call, but it was answered
69     * on another device where the call was ringing.
70     */
71    public static final int ANSWERED_ELSEWHERE = 11;
72
73    /**
74     * Disconnected because the call was pulled from the current device to another device.
75     */
76    public static final int CALL_PULLED = 12;
77
78    /**
79     * Reason code (returned via {@link #getReason()}) which indicates that a call could not be
80     * completed because the cellular radio is off or out of service, the device is connected to
81     * a wifi network, but the user has not enabled wifi calling.
82     * @hide
83     */
84    public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF";
85
86    private int mDisconnectCode;
87    private CharSequence mDisconnectLabel;
88    private CharSequence mDisconnectDescription;
89    private String mDisconnectReason;
90    private int mToneToPlay;
91
92    /**
93     * Creates a new DisconnectCause.
94     *
95     * @param code The code for the disconnect cause.
96     */
97    public DisconnectCause(int code) {
98        this(code, null, null, null, ToneGenerator.TONE_UNKNOWN);
99    }
100
101    /**
102     * Creates a new DisconnectCause.
103     *
104     * @param code The code for the disconnect cause.
105     * @param reason The reason for the disconnect.
106     */
107    public DisconnectCause(int code, String reason) {
108        this(code, null, null, reason, ToneGenerator.TONE_UNKNOWN);
109    }
110
111    /**
112     * Creates a new DisconnectCause.
113     *
114     * @param code The code for the disconnect cause.
115     * @param label The localized label to show to the user to explain the disconnect.
116     * @param description The localized description to show to the user to explain the disconnect.
117     * @param reason The reason for the disconnect.
118     */
119    public DisconnectCause(int code, CharSequence label, CharSequence description, String reason) {
120        this(code, label, description, reason, ToneGenerator.TONE_UNKNOWN);
121    }
122
123    /**
124     * Creates a new DisconnectCause.
125     *
126     * @param code The code for the disconnect cause.
127     * @param label The localized label to show to the user to explain the disconnect.
128     * @param description The localized description to show to the user to explain the disconnect.
129     * @param reason The reason for the disconnect.
130     * @param toneToPlay The tone to play on disconnect, as defined in {@link ToneGenerator}.
131     */
132    public DisconnectCause(int code, CharSequence label, CharSequence description, String reason,
133            int toneToPlay) {
134        mDisconnectCode = code;
135        mDisconnectLabel = label;
136        mDisconnectDescription = description;
137        mDisconnectReason = reason;
138        mToneToPlay = toneToPlay;
139    }
140
141    /**
142     * Returns the code for the reason for this disconnect.
143     *
144     * @return The disconnect code.
145     */
146    public int getCode() {
147        return mDisconnectCode;
148    }
149
150    /**
151     * Returns a short label which explains the reason for the disconnect cause and is for display
152     * in the user interface. If not null, it is expected that the In-Call UI should display this
153     * text where it would normally display the call state ("Dialing", "Disconnected") and is
154     * therefore expected to be relatively small. The {@link ConnectionService } is responsible for
155     * providing and localizing this label. If there is no string provided, returns null.
156     *
157     * @return The disconnect label.
158     */
159    public CharSequence getLabel() {
160        return mDisconnectLabel;
161    }
162
163    /**
164     * Returns a description which explains the reason for the disconnect cause and is for display
165     * in the user interface. This optional text is generally a longer and more descriptive version
166     * of {@link #getLabel}, however it can exist even if {@link #getLabel} is empty. The In-Call UI
167     * should display this relatively prominently; the traditional implementation displays this as
168     * an alert dialog. The {@link ConnectionService} is responsible for providing and localizing
169     * this message. If there is no string provided, returns null.
170     *
171     * @return The disconnect description.
172     */
173    public CharSequence getDescription() {
174        return mDisconnectDescription;
175    }
176
177    /**
178     * Returns an explanation of the reason for the disconnect. This is not intended for display to
179     * the user and is used mainly for logging.
180     *
181     * @return The disconnect reason.
182     */
183    public String getReason() {
184        return mDisconnectReason;
185    }
186
187    /**
188     * Returns the tone to play when disconnected.
189     *
190     * @return the tone as defined in {@link ToneGenerator} to play when disconnected.
191     */
192    public int getTone() {
193        return mToneToPlay;
194    }
195
196    public static final Creator<DisconnectCause> CREATOR = new Creator<DisconnectCause>() {
197        @Override
198        public DisconnectCause createFromParcel(Parcel source) {
199            int code = source.readInt();
200            CharSequence label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
201            CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
202            String reason = source.readString();
203            int tone = source.readInt();
204            return new DisconnectCause(code, label, description, reason, tone);
205        }
206
207        @Override
208        public DisconnectCause[] newArray(int size) {
209            return new DisconnectCause[size];
210        }
211    };
212
213    @Override
214    public void writeToParcel(Parcel destination, int flags) {
215        destination.writeInt(mDisconnectCode);
216        TextUtils.writeToParcel(mDisconnectLabel, destination, flags);
217        TextUtils.writeToParcel(mDisconnectDescription, destination, flags);
218        destination.writeString(mDisconnectReason);
219        destination.writeInt(mToneToPlay);
220    }
221
222    @Override
223    public int describeContents() {
224        return 0;
225    }
226
227    @Override
228    public int hashCode() {
229        return Objects.hashCode(mDisconnectCode)
230                + Objects.hashCode(mDisconnectLabel)
231                + Objects.hashCode(mDisconnectDescription)
232                + Objects.hashCode(mDisconnectReason)
233                + Objects.hashCode(mToneToPlay);
234    }
235
236    @Override
237    public boolean equals(Object o) {
238        if (o instanceof DisconnectCause) {
239            DisconnectCause d = (DisconnectCause) o;
240            return Objects.equals(mDisconnectCode, d.getCode())
241                    && Objects.equals(mDisconnectLabel, d.getLabel())
242                    && Objects.equals(mDisconnectDescription, d.getDescription())
243                    && Objects.equals(mDisconnectReason, d.getReason())
244                    && Objects.equals(mToneToPlay, d.getTone());
245        }
246        return false;
247    }
248
249    @Override
250    public String toString() {
251        String code = "";
252        switch (mDisconnectCode) {
253            case UNKNOWN:
254                code = "UNKNOWN";
255                break;
256            case ERROR:
257                code = "ERROR";
258                break;
259            case LOCAL:
260                code = "LOCAL";
261                break;
262            case REMOTE:
263                code = "REMOTE";
264                break;
265            case CANCELED:
266                code = "CANCELED";
267                break;
268            case MISSED:
269                code = "MISSED";
270                break;
271            case REJECTED:
272                code = "REJECTED";
273                break;
274            case BUSY:
275                code = "BUSY";
276                break;
277            case RESTRICTED:
278                code = "RESTRICTED";
279                break;
280            case OTHER:
281                code = "OTHER";
282                break;
283            case CONNECTION_MANAGER_NOT_SUPPORTED:
284                code = "CONNECTION_MANAGER_NOT_SUPPORTED";
285                break;
286            case CALL_PULLED:
287                code = "CALL_PULLED";
288                break;
289            case ANSWERED_ELSEWHERE:
290                code = "ANSWERED_ELSEWHERE";
291                break;
292            default:
293                code = "invalid code: " + mDisconnectCode;
294                break;
295        }
296        String label = mDisconnectLabel == null ? "" : mDisconnectLabel.toString();
297        String description = mDisconnectDescription == null
298                ? "" : mDisconnectDescription.toString();
299        String reason = mDisconnectReason == null ? "" : mDisconnectReason;
300        return "DisconnectCause [ Code: (" + code + ")"
301                + " Label: (" + label + ")"
302                + " Description: (" + description + ")"
303                + " Reason: (" + reason + ")"
304                + " Tone: (" + mToneToPlay + ") ]";
305    }
306}
307