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    private int mDisconnectCode;
68    private CharSequence mDisconnectLabel;
69    private CharSequence mDisconnectDescription;
70    private String mDisconnectReason;
71    private int mToneToPlay;
72
73    /**
74     * Creates a new DisconnectCause.
75     *
76     * @param code The code for the disconnect cause.
77     */
78    public DisconnectCause(int code) {
79        this(code, null, null, null, ToneGenerator.TONE_UNKNOWN);
80    }
81
82    /**
83     * Creates a new DisconnectCause.
84     *
85     * @param code The code for the disconnect cause.
86     * @param reason The reason for the disconnect.
87     */
88    public DisconnectCause(int code, String reason) {
89        this(code, null, null, reason, ToneGenerator.TONE_UNKNOWN);
90    }
91
92    /**
93     * Creates a new DisconnectCause.
94     *
95     * @param label The localized label to show to the user to explain the disconnect.
96     * @param code The code for the disconnect cause.
97     * @param description The localized description to show to the user to explain the disconnect.
98     * @param reason The reason for the disconnect.
99     */
100    public DisconnectCause(int code, CharSequence label, CharSequence description, String reason) {
101        this(code, label, description, reason, ToneGenerator.TONE_UNKNOWN);
102    }
103
104    /**
105     * Creates a new DisconnectCause.
106     *
107     * @param code The code for the disconnect cause.
108     * @param label The localized label to show to the user to explain the disconnect.
109     * @param description The localized description to show to the user to explain the disconnect.
110     * @param reason The reason for the disconnect.
111     * @param toneToPlay The tone to play on disconnect, as defined in {@link ToneGenerator}.
112     */
113    public DisconnectCause(int code, CharSequence label, CharSequence description, String reason,
114            int toneToPlay) {
115        mDisconnectCode = code;
116        mDisconnectLabel = label;
117        mDisconnectDescription = description;
118        mDisconnectReason = reason;
119        mToneToPlay = toneToPlay;
120    }
121
122    /**
123     * Returns the code for the reason for this disconnect.
124     *
125     * @return The disconnect code.
126     */
127    public int getCode() {
128        return mDisconnectCode;
129    }
130
131    /**
132     * Returns a short label which explains the reason for the disconnect cause and is for display
133     * in the user interface. If not null, it is expected that the In-Call UI should display this
134     * text where it would normally display the call state ("Dialing", "Disconnected") and is
135     * therefore expected to be relatively small. The {@link ConnectionService } is responsible for
136     * providing and localizing this label. If there is no string provided, returns null.
137     *
138     * @return The disconnect label.
139     */
140    public CharSequence getLabel() {
141        return mDisconnectLabel;
142    }
143
144    /**
145     * Returns a description which explains the reason for the disconnect cause and is for display
146     * in the user interface. This optional text is generally a longer and more descriptive version
147     * of {@link #getLabel}, however it can exist even if {@link #getLabel} is empty. The In-Call UI
148     * should display this relatively prominently; the traditional implementation displays this as
149     * an alert dialog. The {@link ConnectionService} is responsible for providing and localizing
150     * this message. If there is no string provided, returns null.
151     *
152     * @return The disconnect description.
153     */
154    public CharSequence getDescription() {
155        return mDisconnectDescription;
156    }
157
158    /**
159     * Returns an explanation of the reason for the disconnect. This is not intended for display to
160     * the user and is used mainly for logging.
161     *
162     * @return The disconnect reason.
163     */
164    public String getReason() {
165        return mDisconnectReason;
166    }
167
168    /**
169     * Returns the tone to play when disconnected.
170     *
171     * @return the tone as defined in {@link ToneGenerator} to play when disconnected.
172     */
173    public int getTone() {
174        return mToneToPlay;
175    }
176
177    public static final Creator<DisconnectCause> CREATOR = new Creator<DisconnectCause>() {
178        @Override
179        public DisconnectCause createFromParcel(Parcel source) {
180            int code = source.readInt();
181            CharSequence label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
182            CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
183            String reason = source.readString();
184            int tone = source.readInt();
185            return new DisconnectCause(code, label, description, reason, tone);
186        }
187
188        @Override
189        public DisconnectCause[] newArray(int size) {
190            return new DisconnectCause[size];
191        }
192    };
193
194    @Override
195    public void writeToParcel(Parcel destination, int flags) {
196        destination.writeInt(mDisconnectCode);
197        TextUtils.writeToParcel(mDisconnectLabel, destination, flags);
198        TextUtils.writeToParcel(mDisconnectDescription, destination, flags);
199        destination.writeString(mDisconnectReason);
200        destination.writeInt(mToneToPlay);
201    }
202
203    @Override
204    public int describeContents() {
205        return 0;
206    }
207
208    @Override
209    public int hashCode() {
210        return Objects.hashCode(mDisconnectCode)
211                + Objects.hashCode(mDisconnectLabel)
212                + Objects.hashCode(mDisconnectDescription)
213                + Objects.hashCode(mDisconnectReason)
214                + Objects.hashCode(mToneToPlay);
215    }
216
217    @Override
218    public boolean equals(Object o) {
219        if (o instanceof DisconnectCause) {
220            DisconnectCause d = (DisconnectCause) o;
221            return Objects.equals(mDisconnectCode, d.getCode())
222                    && Objects.equals(mDisconnectLabel, d.getLabel())
223                    && Objects.equals(mDisconnectDescription, d.getDescription())
224                    && Objects.equals(mDisconnectReason, d.getReason())
225                    && Objects.equals(mToneToPlay, d.getTone());
226        }
227        return false;
228    }
229
230    @Override
231    public String toString() {
232        String code = "";
233        switch (mDisconnectCode) {
234            case UNKNOWN:
235                code = "UNKNOWN";
236                break;
237            case ERROR:
238                code = "ERROR";
239                break;
240            case LOCAL:
241                code = "LOCAL";
242                break;
243            case REMOTE:
244                code = "REMOTE";
245                break;
246            case CANCELED:
247                code = "CANCELED";
248                break;
249            case MISSED:
250                code = "MISSED";
251                break;
252            case REJECTED:
253                code = "REJECTED";
254                break;
255            case BUSY:
256                code = "BUSY";
257                break;
258            case RESTRICTED:
259                code = "RESTRICTED";
260                break;
261            case OTHER:
262                code = "OTHER";
263                break;
264            case CONNECTION_MANAGER_NOT_SUPPORTED:
265                code = "CONNECTION_MANAGER_NOT_SUPPORTED";
266                break;
267            default:
268                code = "invalid code: " + mDisconnectCode;
269                break;
270        }
271        String label = mDisconnectLabel == null ? "" : mDisconnectLabel.toString();
272        String description = mDisconnectDescription == null
273                ? "" : mDisconnectDescription.toString();
274        String reason = mDisconnectReason == null ? "" : mDisconnectReason;
275        return "DisconnectCause [ Code: (" + code + ")"
276                + " Label: (" + label + ")"
277                + " Description: (" + description + ")"
278                + " Reason: (" + reason + ")"
279                + " Tone: (" + mToneToPlay + ") ]";
280    }
281}
282