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.annotation.FloatRange;
20 import android.annotation.IntDef;
21 import android.annotation.IntRange;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 
28 /**
29  * Represents attributes of video calls.
30  */
31 public class VideoProfile implements Parcelable {
32 
33     /** @hide */
34     @Retention(RetentionPolicy.SOURCE)
35     @IntDef({QUALITY_UNKNOWN, QUALITY_HIGH, QUALITY_MEDIUM, QUALITY_LOW, QUALITY_DEFAULT})
36     public @interface VideoQuality {}
37 
38     /**
39      * "Unknown" video quality.
40      * @hide
41      */
42     public static final int QUALITY_UNKNOWN = 0;
43     /**
44      * "High" video quality.
45      */
46     public static final int QUALITY_HIGH = 1;
47 
48     /**
49      * "Medium" video quality.
50      */
51     public static final int QUALITY_MEDIUM = 2;
52 
53     /**
54      * "Low" video quality.
55      */
56     public static final int QUALITY_LOW = 3;
57 
58     /**
59      * Use default video quality.
60      */
61     public static final int QUALITY_DEFAULT = 4;
62 
63     /** @hide */
64     @Retention(RetentionPolicy.SOURCE)
65     @IntDef(
66             flag = true,
67             prefix = { "STATE_" },
68             value = {STATE_AUDIO_ONLY, STATE_TX_ENABLED, STATE_RX_ENABLED, STATE_BIDIRECTIONAL,
69                     STATE_PAUSED})
70     public @interface VideoState {}
71 
72     /**
73      * Used when answering or dialing a call to indicate that the call does not have a video
74      * component.
75      * <p>
76      * Should <b>not</b> be used in comparison checks to determine if a video state represents an
77      * audio-only call.
78      * <p>
79      * The following, for example, is not the correct way to check if a call is audio-only:
80      * <pre>
81      * {@code
82      * // This is the incorrect way to check for an audio-only call.
83      * if (videoState == VideoProfile.STATE_AUDIO_ONLY) {
84      *      // Handle audio-only call.
85      * }
86      * }
87      * </pre>
88      * <p>
89      * Instead, use the {@link VideoProfile#isAudioOnly(int)} helper function to check if a
90      * video state represents an audio-only call:
91      * <pre>
92      * {@code
93      * // This is the correct way to check for an audio-only call.
94      * if (VideoProfile.isAudioOnly(videoState)) {
95      *      // Handle audio-only call.
96      * }
97      * }
98      * </pre>
99      */
100     public static final int STATE_AUDIO_ONLY = 0x0;
101 
102     /**
103      * Video transmission is enabled.
104      */
105     public static final int STATE_TX_ENABLED = 0x1;
106 
107     /**
108      * Video reception is enabled.
109      */
110     public static final int STATE_RX_ENABLED = 0x2;
111 
112     /**
113      * Video signal is bi-directional.
114      */
115     public static final int STATE_BIDIRECTIONAL = STATE_TX_ENABLED | STATE_RX_ENABLED;
116 
117     /**
118      * Video is paused.
119      */
120     public static final int STATE_PAUSED = 0x4;
121 
122     private final int mVideoState;
123 
124     private final int mQuality;
125 
126     /**
127      * Creates an instance of the VideoProfile
128      *
129      * @param videoState The video state.
130      */
VideoProfile(@ideoState int videoState)131     public VideoProfile(@VideoState int videoState) {
132         this(videoState, QUALITY_DEFAULT);
133     }
134 
135     /**
136      * Creates an instance of the VideoProfile
137      *
138      * @param videoState The video state.
139      * @param quality The video quality.
140      */
VideoProfile(@ideoState int videoState, @VideoQuality int quality)141     public VideoProfile(@VideoState int videoState, @VideoQuality int quality) {
142         mVideoState = videoState;
143         mQuality = quality;
144     }
145 
146     /**
147      * The video state of the call.
148      * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
149      * {@link VideoProfile#STATE_BIDIRECTIONAL},
150      * {@link VideoProfile#STATE_TX_ENABLED},
151      * {@link VideoProfile#STATE_RX_ENABLED},
152      * {@link VideoProfile#STATE_PAUSED}.
153      */
154     @VideoState
getVideoState()155     public int getVideoState() {
156         return mVideoState;
157     }
158 
159     /**
160      * The desired video quality for the call.
161      * Valid values: {@link VideoProfile#QUALITY_HIGH}, {@link VideoProfile#QUALITY_MEDIUM},
162      * {@link VideoProfile#QUALITY_LOW}, {@link VideoProfile#QUALITY_DEFAULT}.
163      */
164     @VideoQuality
getQuality()165     public int getQuality() {
166         return mQuality;
167     }
168 
169     /**
170      * Responsible for creating VideoProfile objects from deserialized Parcels.
171      **/
172     public static final @android.annotation.NonNull Parcelable.Creator<VideoProfile> CREATOR =
173             new Parcelable.Creator<VideoProfile> () {
174                 /**
175                  * Creates a MediaProfile instances from a parcel.
176                  *
177                  * @param source The parcel.
178                  * @return The MediaProfile.
179                  */
180                 @Override
181                 public VideoProfile createFromParcel(Parcel source) {
182                     int state = source.readInt();
183                     int quality = source.readInt();
184 
185                     ClassLoader classLoader = VideoProfile.class.getClassLoader();
186                     return new VideoProfile(state, quality);
187                 }
188 
189                 @Override
190                 public VideoProfile[] newArray(int size) {
191                     return new VideoProfile[size];
192                 }
193             };
194 
195     /**
196      * Describe the kinds of special objects contained in this Parcelable's
197      * marshalled representation.
198      *
199      * @return a bitmask indicating the set of special object types marshalled
200      * by the Parcelable.
201      */
202     @Override
describeContents()203     public int describeContents() {
204         return 0;
205     }
206 
207     /**
208      * Flatten this object in to a Parcel.
209      *
210      * @param dest  The Parcel in which the object should be written.
211      * @param flags Additional flags about how the object should be written.
212      *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
213      */
214     @Override
writeToParcel(Parcel dest, int flags)215     public void writeToParcel(Parcel dest, int flags) {
216         dest.writeInt(mVideoState);
217         dest.writeInt(mQuality);
218     }
219 
220     @Override
toString()221     public String toString() {
222         StringBuilder sb = new StringBuilder();
223         sb.append("[VideoProfile videoState = ");
224         sb.append(videoStateToString(mVideoState));
225         sb.append(" videoQuality = ");
226         sb.append(mQuality);
227         sb.append("]");
228         return sb.toString();
229     }
230 
231     /**
232      * Generates a string representation of a video state.
233      *
234      * @param videoState The video state.
235      * @return String representation of the video state.
236      */
videoStateToString(@ideoState int videoState)237     public static String videoStateToString(@VideoState int videoState) {
238         StringBuilder sb = new StringBuilder();
239         sb.append("Audio");
240 
241         if (videoState == STATE_AUDIO_ONLY) {
242             sb.append(" Only");
243         } else {
244             if (isTransmissionEnabled(videoState)) {
245                 sb.append(" Tx");
246             }
247 
248             if (isReceptionEnabled(videoState)) {
249                 sb.append(" Rx");
250             }
251 
252             if (isPaused(videoState)) {
253                 sb.append(" Pause");
254             }
255         }
256 
257         return sb.toString();
258     }
259 
260     /**
261      * Indicates whether the video state is audio only.
262      * <p>
263      * Note: Considers only whether either both the {@link #STATE_RX_ENABLED} or
264      * {@link #STATE_TX_ENABLED} bits are off, but not {@link #STATE_PAUSED}.
265      *
266      * @param videoState The video state.
267      * @return {@code True} if the video state is audio only, {@code false} otherwise.
268      */
isAudioOnly(@ideoState int videoState)269     public static boolean isAudioOnly(@VideoState int videoState) {
270         return !hasState(videoState, VideoProfile.STATE_TX_ENABLED)
271                 && !hasState(videoState, VideoProfile.STATE_RX_ENABLED);
272     }
273 
274     /**
275      * Indicates whether video transmission or reception is enabled for a video state.
276      *
277      * @param videoState The video state.
278      * @return {@code True} if video transmission or reception is enabled, {@code false} otherwise.
279      */
isVideo(@ideoState int videoState)280     public static boolean isVideo(@VideoState int videoState) {
281         return hasState(videoState, VideoProfile.STATE_TX_ENABLED)
282                 || hasState(videoState, VideoProfile.STATE_RX_ENABLED)
283                 || hasState(videoState, VideoProfile.STATE_BIDIRECTIONAL);
284     }
285 
286     /**
287      * Indicates whether the video state has video transmission enabled.
288      *
289      * @param videoState The video state.
290      * @return {@code True} if video transmission is enabled, {@code false} otherwise.
291      */
isTransmissionEnabled(@ideoState int videoState)292     public static boolean isTransmissionEnabled(@VideoState int videoState) {
293         return hasState(videoState, VideoProfile.STATE_TX_ENABLED);
294     }
295 
296     /**
297      * Indicates whether the video state has video reception enabled.
298      *
299      * @param videoState The video state.
300      * @return {@code True} if video reception is enabled, {@code false} otherwise.
301      */
isReceptionEnabled(@ideoState int videoState)302     public static boolean isReceptionEnabled(@VideoState int videoState) {
303         return hasState(videoState, VideoProfile.STATE_RX_ENABLED);
304     }
305 
306     /**
307      * Indicates whether the video state is bi-directional.
308      *
309      * @param videoState The video state.
310      * @return {@code True} if the video is bi-directional, {@code false} otherwise.
311      */
isBidirectional(@ideoState int videoState)312     public static boolean isBidirectional(@VideoState int videoState) {
313         return hasState(videoState, VideoProfile.STATE_BIDIRECTIONAL);
314     }
315 
316     /**
317      * Indicates whether the video state is paused.
318      *
319      * @param videoState The video state.
320      * @return {@code True} if the video is paused, {@code false} otherwise.
321      */
isPaused(@ideoState int videoState)322     public static boolean isPaused(@VideoState int videoState) {
323         return hasState(videoState, VideoProfile.STATE_PAUSED);
324     }
325 
326     /**
327      * Indicates if a specified state is set in a videoState bit-mask.
328      *
329      * @param videoState The video state bit-mask.
330      * @param state The state to check.
331      * @return {@code True} if the state is set.
332      */
hasState(@ideoState int videoState, @VideoState int state)333     private static boolean hasState(@VideoState int videoState, @VideoState int state) {
334         return (videoState & state) == state;
335     }
336 
337     /**
338      * Represents the camera capabilities important to a Video Telephony provider.
339      */
340     public static final class CameraCapabilities implements Parcelable {
341 
342         /**
343          * The width of the camera video in pixels.
344          */
345         private final int mWidth;
346 
347         /**
348          * The height of the camera video in pixels.
349          */
350         private final int mHeight;
351 
352         /**
353          * Whether the camera supports zoom.
354          */
355         private final boolean mZoomSupported;
356 
357         /**
358          * The maximum zoom supported by the camera.
359          */
360         private final float mMaxZoom;
361 
362         /**
363          * Create a call camera capabilities instance.
364          *
365          * @param width The width of the camera video (in pixels).
366          * @param height The height of the camera video (in pixels).
367          */
CameraCapabilities(@ntRangefrom = 0) int width, @IntRange(from = 0) int height)368         public CameraCapabilities(@IntRange(from = 0) int width, @IntRange(from = 0) int height) {
369             this(width, height, false, 1.0f);
370         }
371 
372         /**
373          * Create a call camera capabilities instance that optionally supports zoom.
374          *
375          * @param width The width of the camera video (in pixels).
376          * @param height The height of the camera video (in pixels).
377          * @param zoomSupported True when camera supports zoom.
378          * @param maxZoom Maximum zoom supported by camera.
379          */
CameraCapabilities(@ntRangefrom = 0) int width, @IntRange(from = 0) int height, boolean zoomSupported, @FloatRange(from = 1.0f) float maxZoom)380         public CameraCapabilities(@IntRange(from = 0) int width,  @IntRange(from = 0) int height,
381                                    boolean zoomSupported,  @FloatRange(from = 1.0f) float maxZoom) {
382             mWidth = width;
383             mHeight = height;
384             mZoomSupported = zoomSupported;
385             mMaxZoom = maxZoom;
386         }
387 
388         /**
389          * Responsible for creating CallCameraCapabilities objects from deserialized Parcels.
390          **/
391         public static final @android.annotation.NonNull Parcelable.Creator<CameraCapabilities> CREATOR =
392                 new Parcelable.Creator<CameraCapabilities> () {
393                     /**
394                      * Creates a CallCameraCapabilities instances from a parcel.
395                      *
396                      * @param source The parcel.
397                      * @return The CallCameraCapabilities.
398                      */
399                     @Override
400                     public CameraCapabilities createFromParcel(Parcel source) {
401                         int width = source.readInt();
402                         int height = source.readInt();
403                         boolean supportsZoom = source.readByte() != 0;
404                         float maxZoom = source.readFloat();
405 
406                         return new CameraCapabilities(width, height, supportsZoom, maxZoom);
407                     }
408 
409                     @Override
410                     public CameraCapabilities[] newArray(int size) {
411                         return new CameraCapabilities[size];
412                     }
413                 };
414 
415         /**
416          * Describe the kinds of special objects contained in this Parcelable's
417          * marshalled representation.
418          *
419          * @return a bitmask indicating the set of special object types marshalled
420          * by the Parcelable.
421          */
422         @Override
describeContents()423         public int describeContents() {
424             return 0;
425         }
426 
427         /**
428          * Flatten this object in to a Parcel.
429          *
430          * @param dest  The Parcel in which the object should be written.
431          * @param flags Additional flags about how the object should be written.
432          *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
433          */
434         @Override
writeToParcel(Parcel dest, int flags)435         public void writeToParcel(Parcel dest, int flags) {
436             dest.writeInt(getWidth());
437             dest.writeInt(getHeight());
438             dest.writeByte((byte) (isZoomSupported() ? 1 : 0));
439             dest.writeFloat(getMaxZoom());
440         }
441 
442         /**
443          * The width of the camera video in pixels.
444          */
getWidth()445         public int getWidth() {
446             return mWidth;
447         }
448 
449         /**
450          * The height of the camera video in pixels.
451          */
getHeight()452         public int getHeight() {
453             return mHeight;
454         }
455 
456         /**
457          * Returns {@code true} is zoom is supported, {@code false} otherwise.
458          */
isZoomSupported()459         public boolean isZoomSupported() {
460             return mZoomSupported;
461         }
462 
463         /**
464          * Returns the maximum zoom supported by the camera.
465          */
getMaxZoom()466         public float getMaxZoom() {
467             return mMaxZoom;
468         }
469     }
470 
471 }
472