17c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn/*
27c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn * Copyright (C) 2014 The Android Open Source Project
37c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn *
47c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn * Licensed under the Apache License, Version 2.0 (the "License");
57c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn * you may not use this file except in compliance with the License.
67c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn * You may obtain a copy of the License at
77c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn *
87c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn *      http://www.apache.org/licenses/LICENSE-2.0
97c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn *
107c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn * Unless required by applicable law or agreed to in writing, software
117c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn * distributed under the License is distributed on an "AS IS" BASIS,
127c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn * See the License for the specific language governing permissions and
147c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn * limitations under the License
157c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn */
167c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
17ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunnpackage android.telecom;
187c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
1948d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunnimport android.annotation.IntDef;
207c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunnimport android.os.Parcel;
217c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunnimport android.os.Parcelable;
227c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
2348d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunnimport java.lang.annotation.Retention;
2448d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunnimport java.lang.annotation.RetentionPolicy;
2548d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn
267c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn/**
277c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn * Represents attributes of video calls.
287c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn */
29b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awadpublic class VideoProfile implements Parcelable {
3048d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn
3148d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    /** @hide */
3248d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    @Retention(RetentionPolicy.SOURCE)
3348d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    @IntDef({QUALITY_UNKNOWN, QUALITY_HIGH, QUALITY_MEDIUM, QUALITY_LOW, QUALITY_DEFAULT})
3448d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    public @interface VideoQuality {}
3548d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn
367c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    /**
3707366813cdf3768dcd69a1f744023747564d654aRekha Kumar     * "Unknown" video quality.
3807366813cdf3768dcd69a1f744023747564d654aRekha Kumar     * @hide
3907366813cdf3768dcd69a1f744023747564d654aRekha Kumar     */
4007366813cdf3768dcd69a1f744023747564d654aRekha Kumar    public static final int QUALITY_UNKNOWN = 0;
4107366813cdf3768dcd69a1f744023747564d654aRekha Kumar    /**
427c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * "High" video quality.
437c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     */
447c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    public static final int QUALITY_HIGH = 1;
457c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
467c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    /**
477c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * "Medium" video quality.
487c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     */
497c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    public static final int QUALITY_MEDIUM = 2;
507c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
517c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    /**
527c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * "Low" video quality.
537c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     */
547c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    public static final int QUALITY_LOW = 3;
557c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
567c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    /**
577c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * Use default video quality.
587c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     */
597c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    public static final int QUALITY_DEFAULT = 4;
607c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
6148d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    /** @hide */
6248d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    @Retention(RetentionPolicy.SOURCE)
6348d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    @IntDef(
6448d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn            flag = true,
6548d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn            value = {STATE_AUDIO_ONLY, STATE_TX_ENABLED, STATE_RX_ENABLED, STATE_BIDIRECTIONAL,
6648d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn                    STATE_PAUSED})
6748d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    public @interface VideoState {}
6848d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn
6932f24731604fd81289a39619bbc925b65184b505Yorke Lee    /**
70bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * Used when answering or dialing a call to indicate that the call does not have a video
71bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * component.
72bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * <p>
73bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * Should <b>not</b> be used in comparison checks to determine if a video state represents an
74bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * audio-only call.
75bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * <p>
76bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * The following, for example, is not the correct way to check if a call is audio-only:
77bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * <pre>
78bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * {@code
79bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * // This is the incorrect way to check for an audio-only call.
80bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * if (videoState == VideoProfile.STATE_AUDIO_ONLY) {
81bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     *      // Handle audio-only call.
82bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * }
83bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * }
84bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * </pre>
85bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * <p>
86bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * Instead, use the {@link VideoProfile#isAudioOnly(int)} helper function to check if a
87bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * video state represents an audio-only call:
88bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * <pre>
89bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * {@code
90bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * // This is the correct way to check for an audio-only call.
91bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * if (VideoProfile.isAudioOnly(videoState)) {
92bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     *      // Handle audio-only call.
93bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * }
94bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * }
95bc6f12ee42f810a68ef4d1e9185d42cd10124d9aTyler Gunn     * </pre>
9632f24731604fd81289a39619bbc925b65184b505Yorke Lee     */
9732f24731604fd81289a39619bbc925b65184b505Yorke Lee    public static final int STATE_AUDIO_ONLY = 0x0;
9832f24731604fd81289a39619bbc925b65184b505Yorke Lee
9932f24731604fd81289a39619bbc925b65184b505Yorke Lee    /**
10032f24731604fd81289a39619bbc925b65184b505Yorke Lee     * Video transmission is enabled.
10132f24731604fd81289a39619bbc925b65184b505Yorke Lee     */
10232f24731604fd81289a39619bbc925b65184b505Yorke Lee    public static final int STATE_TX_ENABLED = 0x1;
10332f24731604fd81289a39619bbc925b65184b505Yorke Lee
10432f24731604fd81289a39619bbc925b65184b505Yorke Lee    /**
10532f24731604fd81289a39619bbc925b65184b505Yorke Lee     * Video reception is enabled.
10632f24731604fd81289a39619bbc925b65184b505Yorke Lee     */
10732f24731604fd81289a39619bbc925b65184b505Yorke Lee    public static final int STATE_RX_ENABLED = 0x2;
10832f24731604fd81289a39619bbc925b65184b505Yorke Lee
10932f24731604fd81289a39619bbc925b65184b505Yorke Lee    /**
11032f24731604fd81289a39619bbc925b65184b505Yorke Lee     * Video signal is bi-directional.
11132f24731604fd81289a39619bbc925b65184b505Yorke Lee     */
11232f24731604fd81289a39619bbc925b65184b505Yorke Lee    public static final int STATE_BIDIRECTIONAL = STATE_TX_ENABLED | STATE_RX_ENABLED;
11332f24731604fd81289a39619bbc925b65184b505Yorke Lee
11432f24731604fd81289a39619bbc925b65184b505Yorke Lee    /**
11532f24731604fd81289a39619bbc925b65184b505Yorke Lee     * Video is paused.
11632f24731604fd81289a39619bbc925b65184b505Yorke Lee     */
11732f24731604fd81289a39619bbc925b65184b505Yorke Lee    public static final int STATE_PAUSED = 0x4;
11832f24731604fd81289a39619bbc925b65184b505Yorke Lee
1197c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    private final int mVideoState;
1207c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
1217c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    private final int mQuality;
1227c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
1237c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    /**
124b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad     * Creates an instance of the VideoProfile
1257c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     *
1267c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * @param videoState The video state.
127055e5a227bf9924fb8278e14ffc08a4054ba8f95Andrew Lee     */
12848d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    public VideoProfile(@VideoState int videoState) {
129055e5a227bf9924fb8278e14ffc08a4054ba8f95Andrew Lee        this(videoState, QUALITY_DEFAULT);
130055e5a227bf9924fb8278e14ffc08a4054ba8f95Andrew Lee    }
131055e5a227bf9924fb8278e14ffc08a4054ba8f95Andrew Lee
132055e5a227bf9924fb8278e14ffc08a4054ba8f95Andrew Lee    /**
133b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad     * Creates an instance of the VideoProfile
134055e5a227bf9924fb8278e14ffc08a4054ba8f95Andrew Lee     *
135055e5a227bf9924fb8278e14ffc08a4054ba8f95Andrew Lee     * @param videoState The video state.
1367c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * @param quality The video quality.
1377c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     */
13848d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    public VideoProfile(@VideoState int videoState, @VideoQuality int quality) {
1397c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn        mVideoState = videoState;
1407c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn        mQuality = quality;
1417c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    }
1427c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
1437c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    /**
14448332d622b138aeb3a198efe29bb3d4705411f62Andrew Lee     * The video state of the call.
14532f24731604fd81289a39619bbc925b65184b505Yorke Lee     * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
14632f24731604fd81289a39619bbc925b65184b505Yorke Lee     * {@link VideoProfile#STATE_BIDIRECTIONAL},
14732f24731604fd81289a39619bbc925b65184b505Yorke Lee     * {@link VideoProfile#STATE_TX_ENABLED},
14832f24731604fd81289a39619bbc925b65184b505Yorke Lee     * {@link VideoProfile#STATE_RX_ENABLED},
14932f24731604fd81289a39619bbc925b65184b505Yorke Lee     * {@link VideoProfile#STATE_PAUSED}.
1507c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     */
15148d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    @VideoState
1527c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    public int getVideoState() {
1537c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn        return mVideoState;
1547c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    }
1557c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
1567c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    /**
1577c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * The desired video quality for the call.
158b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad     * Valid values: {@link VideoProfile#QUALITY_HIGH}, {@link VideoProfile#QUALITY_MEDIUM},
159b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad     * {@link VideoProfile#QUALITY_LOW}, {@link VideoProfile#QUALITY_DEFAULT}.
1607c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     */
16148d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    @VideoQuality
1627c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    public int getQuality() {
1637c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn        return mQuality;
1647c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    }
1657c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
1667c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    /**
167b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad     * Responsible for creating VideoProfile objects from deserialized Parcels.
1687c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     **/
169b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad    public static final Parcelable.Creator<VideoProfile> CREATOR =
170b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad            new Parcelable.Creator<VideoProfile> () {
1717c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn                /**
1727c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn                 * Creates a MediaProfile instances from a parcel.
1737c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn                 *
1747c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn                 * @param source The parcel.
1757c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn                 * @return The MediaProfile.
1767c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn                 */
1777c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn                @Override
178b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad                public VideoProfile createFromParcel(Parcel source) {
1797c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn                    int state = source.readInt();
1807c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn                    int quality = source.readInt();
1817c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
182b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad                    ClassLoader classLoader = VideoProfile.class.getClassLoader();
183b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad                    return new VideoProfile(state, quality);
1847c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn                }
1857c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
1867c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn                @Override
187b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad                public VideoProfile[] newArray(int size) {
188b19a0bcdd8a5020c61a0d697f600fdc943c86f59Ihab Awad                    return new VideoProfile[size];
1897c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn                }
1907c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn            };
1917c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
1927c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    /**
1937c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * Describe the kinds of special objects contained in this Parcelable's
1947c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * marshalled representation.
1957c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     *
1967c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * @return a bitmask indicating the set of special object types marshalled
1977c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * by the Parcelable.
1987c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     */
1997c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    @Override
2007c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    public int describeContents() {
2017c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn        return 0;
2027c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    }
2037c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn
2047c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    /**
2057c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * Flatten this object in to a Parcel.
2067c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     *
2077c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * @param dest  The Parcel in which the object should be written.
2087c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     * @param flags Additional flags about how the object should be written.
2097c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
2107c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn     */
2117c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    @Override
2127c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    public void writeToParcel(Parcel dest, int flags) {
2137c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn        dest.writeInt(mVideoState);
2147c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn        dest.writeInt(mQuality);
2157c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn    }
21648332d622b138aeb3a198efe29bb3d4705411f62Andrew Lee
217bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn    @Override
218bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn    public String toString() {
219bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn        StringBuilder sb = new StringBuilder();
220bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn        sb.append("[VideoProfile videoState = ");
22187b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn        sb.append(videoStateToString(mVideoState));
222bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn        sb.append(" videoQuality = ");
223bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn        sb.append(mQuality);
224bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn        sb.append("]");
225bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn        return sb.toString();
226bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn    }
227bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn
22848332d622b138aeb3a198efe29bb3d4705411f62Andrew Lee    /**
22987b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * Generates a string representation of a video state.
23087b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     *
23187b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @param videoState The video state.
23287b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @return String representation of the video state.
23387b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     */
23448d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    public static String videoStateToString(@VideoState int videoState) {
23587b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn        StringBuilder sb = new StringBuilder();
23687b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn        sb.append("Audio");
23748332d622b138aeb3a198efe29bb3d4705411f62Andrew Lee
23887b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn        if (isAudioOnly(videoState)) {
23987b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn            sb.append(" Only");
24087b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn        } else {
24187b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn            if (isTransmissionEnabled(videoState)) {
24287b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn                sb.append(" Tx");
24387b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn            }
24407366813cdf3768dcd69a1f744023747564d654aRekha Kumar
24587b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn            if (isReceptionEnabled(videoState)) {
24687b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn                sb.append(" Rx");
24787b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn            }
24848332d622b138aeb3a198efe29bb3d4705411f62Andrew Lee
24987b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn            if (isPaused(videoState)) {
25087b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn                sb.append(" Pause");
25187b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn            }
25248332d622b138aeb3a198efe29bb3d4705411f62Andrew Lee        }
25348332d622b138aeb3a198efe29bb3d4705411f62Andrew Lee
25487b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn        return sb.toString();
25587b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    }
25648332d622b138aeb3a198efe29bb3d4705411f62Andrew Lee
25787b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    /**
25887b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * Indicates whether the video state is audio only.
25987b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     *
26087b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @param videoState The video state.
26187b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @return {@code True} if the video state is audio only, {@code false} otherwise.
26287b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     */
26348d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    public static boolean isAudioOnly(@VideoState int videoState) {
26487b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn        return !hasState(videoState, VideoProfile.STATE_TX_ENABLED)
26587b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn                && !hasState(videoState, VideoProfile.STATE_RX_ENABLED);
26687b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    }
26748332d622b138aeb3a198efe29bb3d4705411f62Andrew Lee
26887b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    /**
26987b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * Indicates whether video transmission or reception is enabled for a video state.
27087b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     *
27187b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @param videoState The video state.
27287b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @return {@code True} if video transmission or reception is enabled, {@code false} otherwise.
27387b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     */
27448d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    public static boolean isVideo(@VideoState int videoState) {
27587b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn        return hasState(videoState, VideoProfile.STATE_TX_ENABLED)
27687b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn                || hasState(videoState, VideoProfile.STATE_RX_ENABLED)
27787b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn                || hasState(videoState, VideoProfile.STATE_BIDIRECTIONAL);
27887b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    }
279bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn
28087b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    /**
28187b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * Indicates whether the video state has video transmission enabled.
28287b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     *
28387b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @param videoState The video state.
28487b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @return {@code True} if video transmission is enabled, {@code false} otherwise.
28587b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     */
28648d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    public static boolean isTransmissionEnabled(@VideoState int videoState) {
28787b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn        return hasState(videoState, VideoProfile.STATE_TX_ENABLED);
28887b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    }
289bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn
29087b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    /**
29187b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * Indicates whether the video state has video reception enabled.
29287b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     *
29387b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @param videoState The video state.
29487b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @return {@code True} if video reception is enabled, {@code false} otherwise.
29587b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     */
29648d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    public static boolean isReceptionEnabled(@VideoState int videoState) {
29787b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn        return hasState(videoState, VideoProfile.STATE_RX_ENABLED);
29887b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    }
299bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn
30087b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    /**
30187b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * Indicates whether the video state is bi-directional.
30287b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     *
30387b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @param videoState The video state.
30487b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @return {@code True} if the video is bi-directional, {@code false} otherwise.
30587b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     */
30648d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    public static boolean isBidirectional(@VideoState int videoState) {
30787b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn        return hasState(videoState, VideoProfile.STATE_BIDIRECTIONAL);
30887b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    }
309bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn
31087b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    /**
31187b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * Indicates whether the video state is paused.
31287b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     *
31387b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @param videoState The video state.
31487b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @return {@code True} if the video is paused, {@code false} otherwise.
31587b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     */
31648d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    public static boolean isPaused(@VideoState int videoState) {
31787b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn        return hasState(videoState, VideoProfile.STATE_PAUSED);
31887b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    }
319bde0b1e4c8672133e346d964f946d435da8f4d22Tyler Gunn
32087b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn    /**
32187b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * Indicates if a specified state is set in a videoState bit-mask.
32287b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     *
32387b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @param videoState The video state bit-mask.
32487b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @param state The state to check.
32587b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     * @return {@code True} if the state is set.
32687b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn     */
32748d021026a13fa1e1c892de281b55c3c9c2b5754Tyler Gunn    private static boolean hasState(@VideoState int videoState, @VideoState int state) {
32887b73f370e2b8a76b0540580f43edba6ec21c6cfTyler Gunn        return (videoState & state) == state;
32948332d622b138aeb3a198efe29bb3d4705411f62Andrew Lee    }
330400470fab932fe3374149ab89386e460ea161002Yorke Lee
331400470fab932fe3374149ab89386e460ea161002Yorke Lee    /**
332400470fab932fe3374149ab89386e460ea161002Yorke Lee     * Represents the camera capabilities important to a Video Telephony provider.
333400470fab932fe3374149ab89386e460ea161002Yorke Lee     */
334400470fab932fe3374149ab89386e460ea161002Yorke Lee    public static final class CameraCapabilities implements Parcelable {
335400470fab932fe3374149ab89386e460ea161002Yorke Lee
336400470fab932fe3374149ab89386e460ea161002Yorke Lee        /**
337400470fab932fe3374149ab89386e460ea161002Yorke Lee         * The width of the camera video in pixels.
338400470fab932fe3374149ab89386e460ea161002Yorke Lee         */
339400470fab932fe3374149ab89386e460ea161002Yorke Lee        private final int mWidth;
340400470fab932fe3374149ab89386e460ea161002Yorke Lee
341400470fab932fe3374149ab89386e460ea161002Yorke Lee        /**
342400470fab932fe3374149ab89386e460ea161002Yorke Lee         * The height of the camera video in pixels.
343400470fab932fe3374149ab89386e460ea161002Yorke Lee         */
344400470fab932fe3374149ab89386e460ea161002Yorke Lee        private final int mHeight;
345400470fab932fe3374149ab89386e460ea161002Yorke Lee
346400470fab932fe3374149ab89386e460ea161002Yorke Lee        /**
347400470fab932fe3374149ab89386e460ea161002Yorke Lee         * Whether the camera supports zoom.
348400470fab932fe3374149ab89386e460ea161002Yorke Lee         */
349400470fab932fe3374149ab89386e460ea161002Yorke Lee        private final boolean mZoomSupported;
350400470fab932fe3374149ab89386e460ea161002Yorke Lee
351400470fab932fe3374149ab89386e460ea161002Yorke Lee        /**
352400470fab932fe3374149ab89386e460ea161002Yorke Lee         * The maximum zoom supported by the camera.
353400470fab932fe3374149ab89386e460ea161002Yorke Lee         */
354400470fab932fe3374149ab89386e460ea161002Yorke Lee        private final float mMaxZoom;
355400470fab932fe3374149ab89386e460ea161002Yorke Lee
356400470fab932fe3374149ab89386e460ea161002Yorke Lee        /**
357400470fab932fe3374149ab89386e460ea161002Yorke Lee         * Create a call camera capabilities instance.
358400470fab932fe3374149ab89386e460ea161002Yorke Lee         *
359400470fab932fe3374149ab89386e460ea161002Yorke Lee         * @param width The width of the camera video (in pixels).
360400470fab932fe3374149ab89386e460ea161002Yorke Lee         * @param height The height of the camera video (in pixels).
361400470fab932fe3374149ab89386e460ea161002Yorke Lee         */
362400470fab932fe3374149ab89386e460ea161002Yorke Lee        public CameraCapabilities(int width, int height) {
363400470fab932fe3374149ab89386e460ea161002Yorke Lee            this(width, height, false, 1.0f);
364400470fab932fe3374149ab89386e460ea161002Yorke Lee        }
365400470fab932fe3374149ab89386e460ea161002Yorke Lee
366400470fab932fe3374149ab89386e460ea161002Yorke Lee        /**
367400470fab932fe3374149ab89386e460ea161002Yorke Lee         * Create a call camera capabilities instance that optionally
368400470fab932fe3374149ab89386e460ea161002Yorke Lee         * supports zoom.
369400470fab932fe3374149ab89386e460ea161002Yorke Lee         *
370400470fab932fe3374149ab89386e460ea161002Yorke Lee         * @param width The width of the camera video (in pixels).
371400470fab932fe3374149ab89386e460ea161002Yorke Lee         * @param height The height of the camera video (in pixels).
372400470fab932fe3374149ab89386e460ea161002Yorke Lee         * @param zoomSupported True when camera supports zoom.
373400470fab932fe3374149ab89386e460ea161002Yorke Lee         * @param maxZoom Maximum zoom supported by camera.
374400470fab932fe3374149ab89386e460ea161002Yorke Lee         * @hide
375400470fab932fe3374149ab89386e460ea161002Yorke Lee         */
376400470fab932fe3374149ab89386e460ea161002Yorke Lee        public CameraCapabilities(int width, int height, boolean zoomSupported, float maxZoom) {
377400470fab932fe3374149ab89386e460ea161002Yorke Lee            mWidth = width;
378400470fab932fe3374149ab89386e460ea161002Yorke Lee            mHeight = height;
379400470fab932fe3374149ab89386e460ea161002Yorke Lee            mZoomSupported = zoomSupported;
380400470fab932fe3374149ab89386e460ea161002Yorke Lee            mMaxZoom = maxZoom;
381400470fab932fe3374149ab89386e460ea161002Yorke Lee        }
382400470fab932fe3374149ab89386e460ea161002Yorke Lee
383400470fab932fe3374149ab89386e460ea161002Yorke Lee        /**
384400470fab932fe3374149ab89386e460ea161002Yorke Lee         * Responsible for creating CallCameraCapabilities objects from deserialized Parcels.
385400470fab932fe3374149ab89386e460ea161002Yorke Lee         **/
386400470fab932fe3374149ab89386e460ea161002Yorke Lee        public static final Parcelable.Creator<CameraCapabilities> CREATOR =
387400470fab932fe3374149ab89386e460ea161002Yorke Lee                new Parcelable.Creator<CameraCapabilities> () {
388400470fab932fe3374149ab89386e460ea161002Yorke Lee                    /**
389400470fab932fe3374149ab89386e460ea161002Yorke Lee                     * Creates a CallCameraCapabilities instances from a parcel.
390400470fab932fe3374149ab89386e460ea161002Yorke Lee                     *
391400470fab932fe3374149ab89386e460ea161002Yorke Lee                     * @param source The parcel.
392400470fab932fe3374149ab89386e460ea161002Yorke Lee                     * @return The CallCameraCapabilities.
393400470fab932fe3374149ab89386e460ea161002Yorke Lee                     */
394400470fab932fe3374149ab89386e460ea161002Yorke Lee                    @Override
395400470fab932fe3374149ab89386e460ea161002Yorke Lee                    public CameraCapabilities createFromParcel(Parcel source) {
396400470fab932fe3374149ab89386e460ea161002Yorke Lee                        int width = source.readInt();
397400470fab932fe3374149ab89386e460ea161002Yorke Lee                        int height = source.readInt();
398400470fab932fe3374149ab89386e460ea161002Yorke Lee                        boolean supportsZoom = source.readByte() != 0;
399400470fab932fe3374149ab89386e460ea161002Yorke Lee                        float maxZoom = source.readFloat();
400400470fab932fe3374149ab89386e460ea161002Yorke Lee
401400470fab932fe3374149ab89386e460ea161002Yorke Lee                        return new CameraCapabilities(width, height, supportsZoom, maxZoom);
402400470fab932fe3374149ab89386e460ea161002Yorke Lee                    }
403400470fab932fe3374149ab89386e460ea161002Yorke Lee
404400470fab932fe3374149ab89386e460ea161002Yorke Lee                    @Override
405400470fab932fe3374149ab89386e460ea161002Yorke Lee                    public CameraCapabilities[] newArray(int size) {
406400470fab932fe3374149ab89386e460ea161002Yorke Lee                        return new CameraCapabilities[size];
407400470fab932fe3374149ab89386e460ea161002Yorke Lee                    }
408400470fab932fe3374149ab89386e460ea161002Yorke Lee                };
409400470fab932fe3374149ab89386e460ea161002Yorke Lee
410400470fab932fe3374149ab89386e460ea161002Yorke Lee        /**
411400470fab932fe3374149ab89386e460ea161002Yorke Lee         * Describe the kinds of special objects contained in this Parcelable's
412400470fab932fe3374149ab89386e460ea161002Yorke Lee         * marshalled representation.
413400470fab932fe3374149ab89386e460ea161002Yorke Lee         *
414400470fab932fe3374149ab89386e460ea161002Yorke Lee         * @return a bitmask indicating the set of special object types marshalled
415400470fab932fe3374149ab89386e460ea161002Yorke Lee         * by the Parcelable.
416400470fab932fe3374149ab89386e460ea161002Yorke Lee         */
417400470fab932fe3374149ab89386e460ea161002Yorke Lee        @Override
418400470fab932fe3374149ab89386e460ea161002Yorke Lee        public int describeContents() {
419400470fab932fe3374149ab89386e460ea161002Yorke Lee            return 0;
420400470fab932fe3374149ab89386e460ea161002Yorke Lee        }
421400470fab932fe3374149ab89386e460ea161002Yorke Lee
422400470fab932fe3374149ab89386e460ea161002Yorke Lee        /**
423400470fab932fe3374149ab89386e460ea161002Yorke Lee         * Flatten this object in to a Parcel.
424400470fab932fe3374149ab89386e460ea161002Yorke Lee         *
425400470fab932fe3374149ab89386e460ea161002Yorke Lee         * @param dest  The Parcel in which the object should be written.
426400470fab932fe3374149ab89386e460ea161002Yorke Lee         * @param flags Additional flags about how the object should be written.
427400470fab932fe3374149ab89386e460ea161002Yorke Lee         *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
428400470fab932fe3374149ab89386e460ea161002Yorke Lee         */
429400470fab932fe3374149ab89386e460ea161002Yorke Lee        @Override
430400470fab932fe3374149ab89386e460ea161002Yorke Lee        public void writeToParcel(Parcel dest, int flags) {
431400470fab932fe3374149ab89386e460ea161002Yorke Lee            dest.writeInt(getWidth());
432400470fab932fe3374149ab89386e460ea161002Yorke Lee            dest.writeInt(getHeight());
433400470fab932fe3374149ab89386e460ea161002Yorke Lee            dest.writeByte((byte) (isZoomSupported() ? 1 : 0));
434400470fab932fe3374149ab89386e460ea161002Yorke Lee            dest.writeFloat(getMaxZoom());
435400470fab932fe3374149ab89386e460ea161002Yorke Lee        }
436400470fab932fe3374149ab89386e460ea161002Yorke Lee
437400470fab932fe3374149ab89386e460ea161002Yorke Lee        /**
438400470fab932fe3374149ab89386e460ea161002Yorke Lee         * The width of the camera video in pixels.
439400470fab932fe3374149ab89386e460ea161002Yorke Lee         */
440400470fab932fe3374149ab89386e460ea161002Yorke Lee        public int getWidth() {
441400470fab932fe3374149ab89386e460ea161002Yorke Lee            return mWidth;
442400470fab932fe3374149ab89386e460ea161002Yorke Lee        }
443400470fab932fe3374149ab89386e460ea161002Yorke Lee
444400470fab932fe3374149ab89386e460ea161002Yorke Lee        /**
445400470fab932fe3374149ab89386e460ea161002Yorke Lee         * The height of the camera video in pixels.
446400470fab932fe3374149ab89386e460ea161002Yorke Lee         */
447400470fab932fe3374149ab89386e460ea161002Yorke Lee        public int getHeight() {
448400470fab932fe3374149ab89386e460ea161002Yorke Lee            return mHeight;
449400470fab932fe3374149ab89386e460ea161002Yorke Lee        }
450400470fab932fe3374149ab89386e460ea161002Yorke Lee
451400470fab932fe3374149ab89386e460ea161002Yorke Lee        /**
452400470fab932fe3374149ab89386e460ea161002Yorke Lee         * Whether the camera supports zoom.
453400470fab932fe3374149ab89386e460ea161002Yorke Lee         * @hide
454400470fab932fe3374149ab89386e460ea161002Yorke Lee         */
455400470fab932fe3374149ab89386e460ea161002Yorke Lee        public boolean isZoomSupported() {
456400470fab932fe3374149ab89386e460ea161002Yorke Lee            return mZoomSupported;
457400470fab932fe3374149ab89386e460ea161002Yorke Lee        }
458400470fab932fe3374149ab89386e460ea161002Yorke Lee
459400470fab932fe3374149ab89386e460ea161002Yorke Lee        /**
460400470fab932fe3374149ab89386e460ea161002Yorke Lee         * The maximum zoom supported by the camera.
461400470fab932fe3374149ab89386e460ea161002Yorke Lee         * @hide
462400470fab932fe3374149ab89386e460ea161002Yorke Lee         */
463400470fab932fe3374149ab89386e460ea161002Yorke Lee        public float getMaxZoom() {
464400470fab932fe3374149ab89386e460ea161002Yorke Lee            return mMaxZoom;
465400470fab932fe3374149ab89386e460ea161002Yorke Lee        }
466400470fab932fe3374149ab89386e460ea161002Yorke Lee    }
467400470fab932fe3374149ab89386e460ea161002Yorke Lee
4687c668b921b62e07833c2b8384b33e6ab9c5a0929Tyler Gunn}
469