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 (videoState == STATE_AUDIO_ONLY) {
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     * <p>
260     * Note: Considers only whether either both the {@link #STATE_RX_ENABLED} or
261     * {@link #STATE_TX_ENABLED} bits are off, but not {@link #STATE_PAUSED}.
262     *
263     * @param videoState The video state.
264     * @return {@code True} if the video state is audio only, {@code false} otherwise.
265     */
266    public static boolean isAudioOnly(@VideoState int videoState) {
267        return !hasState(videoState, VideoProfile.STATE_TX_ENABLED)
268                && !hasState(videoState, VideoProfile.STATE_RX_ENABLED);
269    }
270
271    /**
272     * Indicates whether video transmission or reception is enabled for a video state.
273     *
274     * @param videoState The video state.
275     * @return {@code True} if video transmission or reception is enabled, {@code false} otherwise.
276     */
277    public static boolean isVideo(@VideoState int videoState) {
278        return hasState(videoState, VideoProfile.STATE_TX_ENABLED)
279                || hasState(videoState, VideoProfile.STATE_RX_ENABLED)
280                || hasState(videoState, VideoProfile.STATE_BIDIRECTIONAL);
281    }
282
283    /**
284     * Indicates whether the video state has video transmission enabled.
285     *
286     * @param videoState The video state.
287     * @return {@code True} if video transmission is enabled, {@code false} otherwise.
288     */
289    public static boolean isTransmissionEnabled(@VideoState int videoState) {
290        return hasState(videoState, VideoProfile.STATE_TX_ENABLED);
291    }
292
293    /**
294     * Indicates whether the video state has video reception enabled.
295     *
296     * @param videoState The video state.
297     * @return {@code True} if video reception is enabled, {@code false} otherwise.
298     */
299    public static boolean isReceptionEnabled(@VideoState int videoState) {
300        return hasState(videoState, VideoProfile.STATE_RX_ENABLED);
301    }
302
303    /**
304     * Indicates whether the video state is bi-directional.
305     *
306     * @param videoState The video state.
307     * @return {@code True} if the video is bi-directional, {@code false} otherwise.
308     */
309    public static boolean isBidirectional(@VideoState int videoState) {
310        return hasState(videoState, VideoProfile.STATE_BIDIRECTIONAL);
311    }
312
313    /**
314     * Indicates whether the video state is paused.
315     *
316     * @param videoState The video state.
317     * @return {@code True} if the video is paused, {@code false} otherwise.
318     */
319    public static boolean isPaused(@VideoState int videoState) {
320        return hasState(videoState, VideoProfile.STATE_PAUSED);
321    }
322
323    /**
324     * Indicates if a specified state is set in a videoState bit-mask.
325     *
326     * @param videoState The video state bit-mask.
327     * @param state The state to check.
328     * @return {@code True} if the state is set.
329     */
330    private static boolean hasState(@VideoState int videoState, @VideoState int state) {
331        return (videoState & state) == state;
332    }
333
334    /**
335     * Represents the camera capabilities important to a Video Telephony provider.
336     */
337    public static final class CameraCapabilities implements Parcelable {
338
339        /**
340         * The width of the camera video in pixels.
341         */
342        private final int mWidth;
343
344        /**
345         * The height of the camera video in pixels.
346         */
347        private final int mHeight;
348
349        /**
350         * Whether the camera supports zoom.
351         */
352        private final boolean mZoomSupported;
353
354        /**
355         * The maximum zoom supported by the camera.
356         */
357        private final float mMaxZoom;
358
359        /**
360         * Create a call camera capabilities instance.
361         *
362         * @param width The width of the camera video (in pixels).
363         * @param height The height of the camera video (in pixels).
364         */
365        public CameraCapabilities(int width, int height) {
366            this(width, height, false, 1.0f);
367        }
368
369        /**
370         * Create a call camera capabilities instance that optionally
371         * supports zoom.
372         *
373         * @param width The width of the camera video (in pixels).
374         * @param height The height of the camera video (in pixels).
375         * @param zoomSupported True when camera supports zoom.
376         * @param maxZoom Maximum zoom supported by camera.
377         * @hide
378         */
379        public CameraCapabilities(int width, int height, boolean zoomSupported, float maxZoom) {
380            mWidth = width;
381            mHeight = height;
382            mZoomSupported = zoomSupported;
383            mMaxZoom = maxZoom;
384        }
385
386        /**
387         * Responsible for creating CallCameraCapabilities objects from deserialized Parcels.
388         **/
389        public static final Parcelable.Creator<CameraCapabilities> CREATOR =
390                new Parcelable.Creator<CameraCapabilities> () {
391                    /**
392                     * Creates a CallCameraCapabilities instances from a parcel.
393                     *
394                     * @param source The parcel.
395                     * @return The CallCameraCapabilities.
396                     */
397                    @Override
398                    public CameraCapabilities createFromParcel(Parcel source) {
399                        int width = source.readInt();
400                        int height = source.readInt();
401                        boolean supportsZoom = source.readByte() != 0;
402                        float maxZoom = source.readFloat();
403
404                        return new CameraCapabilities(width, height, supportsZoom, maxZoom);
405                    }
406
407                    @Override
408                    public CameraCapabilities[] newArray(int size) {
409                        return new CameraCapabilities[size];
410                    }
411                };
412
413        /**
414         * Describe the kinds of special objects contained in this Parcelable's
415         * marshalled representation.
416         *
417         * @return a bitmask indicating the set of special object types marshalled
418         * by the Parcelable.
419         */
420        @Override
421        public int describeContents() {
422            return 0;
423        }
424
425        /**
426         * Flatten this object in to a Parcel.
427         *
428         * @param dest  The Parcel in which the object should be written.
429         * @param flags Additional flags about how the object should be written.
430         *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
431         */
432        @Override
433        public void writeToParcel(Parcel dest, int flags) {
434            dest.writeInt(getWidth());
435            dest.writeInt(getHeight());
436            dest.writeByte((byte) (isZoomSupported() ? 1 : 0));
437            dest.writeFloat(getMaxZoom());
438        }
439
440        /**
441         * The width of the camera video in pixels.
442         */
443        public int getWidth() {
444            return mWidth;
445        }
446
447        /**
448         * The height of the camera video in pixels.
449         */
450        public int getHeight() {
451            return mHeight;
452        }
453
454        /**
455         * Whether the camera supports zoom.
456         * @hide
457         */
458        public boolean isZoomSupported() {
459            return mZoomSupported;
460        }
461
462        /**
463         * The maximum zoom supported by the camera.
464         * @hide
465         */
466        public float getMaxZoom() {
467            return mMaxZoom;
468        }
469    }
470
471}
472