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