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