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.telecom;
18 
19 import android.os.Parcel;
20 import android.os.Parcelable;
21 import android.media.ToneGenerator;
22 import android.text.TextUtils;
23 
24 import 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  */
33 public 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      */
DisconnectCause(int code)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      */
DisconnectCause(int code, String reason)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      */
DisconnectCause(int code, CharSequence label, CharSequence description, String reason)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      */
DisconnectCause(int code, CharSequence label, CharSequence description, String reason, int toneToPlay)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      */
getCode()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      */
getLabel()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      */
getDescription()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      */
getReason()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      */
getTone()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
writeToParcel(Parcel destination, int flags)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
describeContents()204     public int describeContents() {
205         return 0;
206     }
207 
208     @Override
hashCode()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
equals(Object o)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
toString()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