13f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho/*
2816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Copyright (C) 2015 The Android Open Source Project
33f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho *
43f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho * Licensed under the Apache License, Version 2.0 (the "License");
53f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho * you may not use this file except in compliance with the License.
63f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho * You may obtain a copy of the License at
73f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho *
83f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho *      http://www.apache.org/licenses/LICENSE-2.0
93f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho *
103f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho * Unless required by applicable law or agreed to in writing, software
113f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho * distributed under the License is distributed on an "AS IS" BASIS,
123f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho * See the License for the specific language governing permissions and
143f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho * limitations under the License.
153f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho */
163f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
17d422754c0cc8475d6e2c8c079ed2ee2e96213edbChulwoo Leepackage com.android.tv.data;
183f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
19ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.annotation.SuppressLint;
204d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Leeimport android.content.Context;
21816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.content.Intent;
22816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.content.pm.PackageManager;
23624e1a7dc4e4d7aafefdeeaaa07f1849eb1a2c3fSungsoo Limimport android.database.Cursor;
249035590d94d136a020e499ce720b9d2cf1f6f45cJae Seoimport android.media.tv.TvContract;
25816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.media.tv.TvInputInfo;
26816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.net.Uri;
2707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.os.Build;
287d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport android.support.annotation.Nullable;
29816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.support.annotation.UiThread;
30816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.support.annotation.VisibleForTesting;
31816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.text.TextUtils;
324d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Leeimport android.util.Log;
334d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee
34ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport com.android.tv.common.CollectionUtils;
35816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.common.TvCommonConstants;
36816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.util.ImageLoader;
37816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.util.TvInputManagerHelper;
38816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.util.Utils;
39816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
40816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.net.URISyntaxException;
41816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.Comparator;
42816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.HashMap;
43816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.Map;
44816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.Objects;
453f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
463f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho/**
473f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho * A convenience class to create and insert channel entries into the database.
483f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho */
493f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Chopublic final class Channel {
504d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee    private static final String TAG = "Channel";
514d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee
523f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    public static final long INVALID_ID = -1;
53816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static final int LOAD_IMAGE_TYPE_CHANNEL_LOGO = 1;
54816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static final int LOAD_IMAGE_TYPE_APP_LINK_ICON = 2;
55816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static final int LOAD_IMAGE_TYPE_APP_LINK_POSTER_ART = 3;
56816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
57816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
58816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * When a TIS doesn't provide any information about app link, and it doesn't have a leanback
59816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * launch intent, there will be no app link card for the TIS.
60816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
61816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static final int APP_LINK_TYPE_NONE = -1;
62816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
63816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * When a TIS provide a specific app link information, the app link card will be
64816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * {@code APP_LINK_TYPE_CHANNEL} which contains all the provided information.
65816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
66816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static final int APP_LINK_TYPE_CHANNEL = 1;
67816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
68816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * When a TIS doesn't provide a specific app link information, but the app has a leanback launch
69816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * intent, the app link card will be {@code APP_LINK_TYPE_APP} which launches the application.
70816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
71816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static final int APP_LINK_TYPE_APP = 2;
72816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
73816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int APP_LINK_TYPE_NOT_SET = 0;
74816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final String INVALID_PACKAGE_NAME = "packageName";
75816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
76816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final String[] PROJECTION_BASE = {
7748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            // Columns must match what is read in Channel.fromCursor()
7848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            TvContract.Channels._ID,
7948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            TvContract.Channels.COLUMN_PACKAGE_NAME,
8048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            TvContract.Channels.COLUMN_INPUT_ID,
8148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            TvContract.Channels.COLUMN_TYPE,
8248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            TvContract.Channels.COLUMN_DISPLAY_NUMBER,
8348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            TvContract.Channels.COLUMN_DISPLAY_NAME,
8448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            TvContract.Channels.COLUMN_DESCRIPTION,
8548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            TvContract.Channels.COLUMN_VIDEO_FORMAT,
8648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            TvContract.Channels.COLUMN_BROWSABLE,
8748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            TvContract.Channels.COLUMN_LOCKED,
88816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    };
89816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
90816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    // Additional fields added in MNC.
91ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    @SuppressLint("InlinedApi")
92816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final String[] PROJECTION_ADDED_IN_MNC = {
93816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            // Columns should match what is read in Channel.fromCursor()
94816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            TvContract.Channels.COLUMN_APP_LINK_TEXT,
95816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            TvContract.Channels.COLUMN_APP_LINK_COLOR,
96816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            TvContract.Channels.COLUMN_APP_LINK_ICON_URI,
97816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            TvContract.Channels.COLUMN_APP_LINK_POSTER_ART_URI,
98816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            TvContract.Channels.COLUMN_APP_LINK_INTENT_URI,
99816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    };
100816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
101816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static final String[] PROJECTION = createProjection();
102816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
103816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static String[] createProjection() {
104ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
105ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            return CollectionUtils.concatAll(PROJECTION_BASE, PROJECTION_ADDED_IN_MNC);
106816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        } else {
107816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return PROJECTION_BASE;
108816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
109816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
1103f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
11107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko    /**
11207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko     * Creates {@code Channel} object from cursor.
11307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko     *
11407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko     * <p>The query that created the cursor MUST use {@link #PROJECTION}
11507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko     *
11607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko     */
11707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko    public static Channel fromCursor(Cursor cursor) {
11807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        // Columns read must match the order of {@link #PROJECTION}
11907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        Channel channel = new Channel();
12007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        int index = 0;
12107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        channel.mId = cursor.getLong(index++);
12207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        channel.mPackageName = Utils.intern(cursor.getString(index++));
12307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        channel.mInputId = Utils.intern(cursor.getString(index++));
12407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        channel.mType = Utils.intern(cursor.getString(index++));
12507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        channel.mDisplayNumber = cursor.getString(index++);
12607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        channel.mDisplayName = cursor.getString(index++);
12707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        channel.mDescription = cursor.getString(index++);
12807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        channel.mVideoFormat = Utils.intern(cursor.getString(index++));
12907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        channel.mBrowsable = cursor.getInt(index++) == 1;
13007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        channel.mLocked = cursor.getInt(index++) == 1;
131ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
13207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            channel.mAppLinkText = cursor.getString(index++);
13307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            channel.mAppLinkColor = cursor.getInt(index++);
13407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            channel.mAppLinkIconUri = cursor.getString(index++);
13507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            channel.mAppLinkPosterArtUri = cursor.getString(index++);
13607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            channel.mAppLinkIntentUri = cursor.getString(index++);
13707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        }
13807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        return channel;
13907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko    }
14007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko
1411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    /**
1421abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * Creates a {@link Channel} object from the DVR database.
1431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     */
1441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public static Channel fromDvrCursor(Cursor c) {
1451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        Channel channel = new Channel();
1461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        int index = -1;
1471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        channel.mDvrId = c.getLong(++index);
1481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        return channel;
1491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
1501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1513f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    /** ID of this channel. Matches to BaseColumns._ID. */
1523f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    private long mId;
1533f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
154816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private String mPackageName;
1555e91a958ffdfcae33dd0614fe683b64535d76e03Chulwoo Lee    private String mInputId;
156816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private String mType;
1573f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    private String mDisplayNumber;
1583f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    private String mDisplayName;
1593f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    private String mDescription;
160816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private String mVideoFormat;
161816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private boolean mBrowsable;
162816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private boolean mLocked;
163816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private boolean mIsPassthrough;
164816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private String mAppLinkText;
165816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private int mAppLinkColor;
166816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private String mAppLinkIconUri;
167816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private String mAppLinkPosterArtUri;
168816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private String mAppLinkIntentUri;
169816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private Intent mAppLinkIntent;
170816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private int mAppLinkType;
171816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
1721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private long mDvrId;
1731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    /**
1751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * TODO(DVR): Need to fill the following data.
1761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     */
1771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private boolean mRecordable;
1781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1793f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    private Channel() {
1803f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        // Do nothing.
1813f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
1823f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
1833f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    public long getId() {
1843f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        return mId;
1853f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
1863f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
187816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public Uri getUri() {
188816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (isPassthrough()) {
189816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return TvContract.buildChannelUriForPassthroughInput(mInputId);
190816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        } else {
191816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return TvContract.buildChannelUri(mId);
192816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
1933f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
1943f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
195816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public String getPackageName() {
196816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mPackageName;
1973f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
1983f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
199816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public String getInputId() {
200816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mInputId;
2013f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
2023f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
203816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public String getType() {
204816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mType;
2053f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
2063f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
2073f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    public String getDisplayNumber() {
2083f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        return mDisplayNumber;
2093f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
2103f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
2117d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko    @Nullable
2123f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    public String getDisplayName() {
2133f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        return mDisplayName;
2143f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
2153f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
21607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko    @VisibleForTesting
2173f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    public String getDescription() {
2183f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        return mDescription;
2193f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
2203f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
221816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public String getVideoFormat() {
222816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mVideoFormat;
223816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
224816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
225816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public boolean isPassthrough() {
226816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mIsPassthrough;
227816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
228816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
229816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public String getAppLinkText() {
230816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mAppLinkText;
231816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
232816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
233816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public int getAppLinkColor() {
234816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mAppLinkColor;
235816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
236816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
237816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public String getAppLinkIconUri() {
238816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mAppLinkIconUri;
239816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
240816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
241816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public String getAppLinkPosterArtUri() {
242816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mAppLinkPosterArtUri;
243816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
244816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
245816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public String getAppLinkIntentUri() {
246816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mAppLinkIntentUri;
247816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
248816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
249816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
2501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * Returns an ID in DVR database.
2511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     */
2521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public long getDvrId() {
2531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        return mDvrId;
2541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
2551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    /**
25748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho     * Checks whether this channel is physical tuner channel or not.
25848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho     */
25948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho    public boolean isPhysicalTunerChannel() {
26048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        return !TextUtils.isEmpty(mType) && !TvContract.Channels.TYPE_OTHER.equals(mType);
26148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho    }
26248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho
26348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho    /**
264816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Checks if two channels equal by checking ids.
265816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
266816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    @Override
267816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public boolean equals(Object o) {
268816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (!(o instanceof Channel)) {
269816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return false;
270816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
271816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        Channel other = (Channel) o;
272816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        // All pass-through TV channels have INVALID_ID value for mId.
273816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mId == other.mId && TextUtils.equals(mInputId, other.mInputId)
274816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && mIsPassthrough == other.mIsPassthrough;
275816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
276816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
277816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    @Override
278816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public int hashCode() {
279816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return Objects.hash(mId, mInputId, mIsPassthrough);
280816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
281816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
2827ebbe134810d0461f031b0b57ea2752ec188ab42Jaekyun Seok    public boolean isBrowsable() {
283816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mBrowsable;
2847ebbe134810d0461f031b0b57ea2752ec188ab42Jaekyun Seok    }
2857ebbe134810d0461f031b0b57ea2752ec188ab42Jaekyun Seok
286816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public boolean isLocked() {
287816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mLocked;
2883f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
2893f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
2903f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    public void setBrowsable(boolean browsable) {
291816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mBrowsable = browsable;
2923f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
2933f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
294816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public void setLocked(boolean locked) {
295816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mLocked = locked;
2963f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
2973f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
298816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
299816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Check whether {@code other} has same read-only channel info as this. But, it cannot check two
300816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * channels have same logos. It also excludes browsable and locked, because two fields are
301816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * changed by TV app.
302816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
303816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public boolean hasSameReadOnlyInfo(Channel other) {
304816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return other != null
305816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && Objects.equals(mId, other.mId)
306816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && Objects.equals(mPackageName, other.mPackageName)
307816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && Objects.equals(mInputId, other.mInputId)
308816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && Objects.equals(mType, other.mType)
309816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && Objects.equals(mDisplayNumber, other.mDisplayNumber)
310816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && Objects.equals(mDisplayName, other.mDisplayName)
311816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && Objects.equals(mDescription, other.mDescription)
312816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && Objects.equals(mVideoFormat, other.mVideoFormat)
313816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && mIsPassthrough == other.mIsPassthrough
314816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && Objects.equals(mAppLinkText, other.mAppLinkText)
315816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && mAppLinkColor == other.mAppLinkColor
316816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && Objects.equals(mAppLinkIconUri, other.mAppLinkIconUri)
317816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && Objects.equals(mAppLinkPosterArtUri, other.mAppLinkPosterArtUri)
318816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && Objects.equals(mAppLinkIntentUri, other.mAppLinkIntentUri);
3193f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
3203f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
3213f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    @Override
3223f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    public String toString() {
323816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return "Channel{"
324816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + "id=" + mId
325816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ", packageName=" + mPackageName
326816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ", inputId=" + mInputId
327816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ", type=" + mType
328816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ", displayNumber=" + mDisplayNumber
329816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ", displayName=" + mDisplayName
330816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ", description=" + mDescription
331816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ", videoFormat=" + mVideoFormat
332816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ", isPassthrough=" + mIsPassthrough
333816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ", browsable=" + mBrowsable
334816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ", locked=" + mLocked
335816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ", appLinkText=" + mAppLinkText + "}";
336816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
337816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
338816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    void copyFrom(Channel other) {
3393f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        if (this == other) {
3403f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            return;
3413f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
3423f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        mId = other.mId;
343816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mPackageName = other.mPackageName;
3445e91a958ffdfcae33dd0614fe683b64535d76e03Chulwoo Lee        mInputId = other.mInputId;
3453f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        mType = other.mType;
3463f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        mDisplayNumber = other.mDisplayNumber;
3473f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        mDisplayName = other.mDisplayName;
3483f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        mDescription = other.mDescription;
349816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mVideoFormat = other.mVideoFormat;
350816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mIsPassthrough = other.mIsPassthrough;
351816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mBrowsable = other.mBrowsable;
352816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mLocked = other.mLocked;
353816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mAppLinkText = other.mAppLinkText;
354816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mAppLinkColor = other.mAppLinkColor;
355816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mAppLinkIconUri = other.mAppLinkIconUri;
356816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mAppLinkPosterArtUri = other.mAppLinkPosterArtUri;
357816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mAppLinkIntentUri = other.mAppLinkIntentUri;
358816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mAppLinkIntent = other.mAppLinkIntent;
359816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mAppLinkType = other.mAppLinkType;
360816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
361816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
362816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
363816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Creates a channel for a passthrough TV input.
364816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
365816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static Channel createPassthroughChannel(Uri uri) {
366816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (!TvContract.isChannelUriForPassthroughInput(uri)) {
367816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            throw new IllegalArgumentException("URI is not a passthrough channel URI");
368816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
369816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        String inputId = uri.getPathSegments().get(1);
370816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return createPassthroughChannel(inputId);
371816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
372816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
373816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
374816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Creates a channel for a passthrough TV input with {@code inputId}.
375816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
376816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static Channel createPassthroughChannel(String inputId) {
377816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return new Builder()
378816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                .setInputId(inputId)
379816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                .setPassthrough(true)
380816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                .build();
3813f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
3823f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
383816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
384816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Checks whether the channel is valid or not.
385816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
386816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static boolean isValid(Channel channel) {
387816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return channel != null && (channel.mId != INVALID_ID || channel.mIsPassthrough);
388816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
389816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
390816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
391816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Builder class for {@code Channel}.
392816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Suppress using this outside of ChannelDataManager
393816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * so Channels could be managed by ChannelDataManager.
394816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
3953f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    public static final class Builder {
3963f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        private final Channel mChannel;
3973f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
3983f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        public Builder() {
3993f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            mChannel = new Channel();
4003f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            // Fill initial data.
4013f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            mChannel.mId = INVALID_ID;
402816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mPackageName = INVALID_PACKAGE_NAME;
4035e91a958ffdfcae33dd0614fe683b64535d76e03Chulwoo Lee            mChannel.mInputId = "inputId";
404816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mType = "type";
4053f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            mChannel.mDisplayNumber = "0";
4063f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            mChannel.mDisplayName = "name";
4073f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            mChannel.mDescription = "description";
408816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mBrowsable = true;
409816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mLocked = false;
410816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mIsPassthrough = false;
4113f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
4123f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
4133f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        public Builder(Channel other) {
4143f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            mChannel = new Channel();
4153f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            mChannel.copyFrom(other);
4163f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
4173f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
418816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        @VisibleForTesting
4193f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        public Builder setId(long id) {
4203f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            mChannel.mId = id;
4213f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            return this;
4223f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
4233f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
424816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        @VisibleForTesting
425816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public Builder setPackageName(String packageName) {
426816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mPackageName = packageName;
4273f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            return this;
4283f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
4293f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
430816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public Builder setInputId(String inputId) {
431816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mInputId = inputId;
4323f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            return this;
4333f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
4343f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
435816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public Builder setType(String type) {
436816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mType = type;
4373f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            return this;
4383f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
4393f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
440816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        @VisibleForTesting
4413f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        public Builder setDisplayNumber(String displayNumber) {
4423f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            mChannel.mDisplayNumber = displayNumber;
4433f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            return this;
4443f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
4453f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
446816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        @VisibleForTesting
4473f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        public Builder setDisplayName(String displayName) {
4483f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            mChannel.mDisplayName = displayName;
4493f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            return this;
4503f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
4513f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
45207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        @VisibleForTesting
4533f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        public Builder setDescription(String description) {
4543f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            mChannel.mDescription = description;
4553f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            return this;
4563f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
4573f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
458816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public Builder setVideoFormat(String videoFormat) {
459816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mVideoFormat = videoFormat;
460816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return this;
461816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
462816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
4633f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        public Builder setBrowsable(boolean browsable) {
464816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mBrowsable = browsable;
465816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return this;
466816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
467816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
468816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public Builder setLocked(boolean locked) {
469816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mLocked = locked;
470816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return this;
471816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
472816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
473816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public Builder setPassthrough(boolean isPassthrough) {
474816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mIsPassthrough = isPassthrough;
475816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return this;
476816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
477816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
478816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        @VisibleForTesting
479816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public Builder setAppLinkText(String appLinkText) {
480816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mAppLinkText = appLinkText;
4813f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            return this;
4823f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
4833f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
484816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public Builder setAppLinkColor(int appLinkColor) {
485816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mAppLinkColor = appLinkColor;
486816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return this;
487816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
488816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
489816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public Builder setAppLinkIconUri(String appLinkIconUri) {
490816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mAppLinkIconUri = appLinkIconUri;
491816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return this;
492816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
493816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
494816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public Builder setAppLinkPosterArtUri(String appLinkPosterArtUri) {
495816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mAppLinkPosterArtUri = appLinkPosterArtUri;
496816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return this;
497816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
498816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
499816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        @VisibleForTesting
500816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public Builder setAppLinkIntentUri(String appLinkIntentUri) {
501816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mChannel.mAppLinkIntentUri = appLinkIntentUri;
5023f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            return this;
5033f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
5043f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
5053f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        public Channel build() {
506816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            Channel channel = new Channel();
507816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            channel.copyFrom(mChannel);
508816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return channel;
5093f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
5103f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
5114d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee
512816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
513816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Prefetches the images for this channel.
514816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
515816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public void prefetchImage(Context context, int type, int maxWidth, int maxHeight) {
516816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        String uriString = getImageUriString(type);
517816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (!TextUtils.isEmpty(uriString)) {
518816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            ImageLoader.prefetchBitmap(context, uriString, maxWidth, maxHeight);
519816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
5204d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee    }
5214d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee
522816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
523816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Loads the bitmap of this channel and returns it via {@code callback}.
524816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * The loaded bitmap will be cached and resized with given params.
525816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * <p>
526816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Note that it may directly call {@code callback} if the bitmap is already loaded.
527816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     *
528816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * @param context A context.
529816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * @param type The type of bitmap which will be loaded. It should be one of follows:
530816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     *        {@link #LOAD_IMAGE_TYPE_CHANNEL_LOGO}, {@link #LOAD_IMAGE_TYPE_APP_LINK_ICON}, or
531816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     *        {@link #LOAD_IMAGE_TYPE_APP_LINK_POSTER_ART}.
532816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * @param maxWidth The max width of the loaded bitmap.
533816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * @param maxHeight The max height of the loaded bitmap.
534816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * @param callback A callback which will be called after the loading finished.
535816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
536816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    @UiThread
537816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public void loadBitmap(Context context, final int type, int maxWidth, int maxHeight,
538ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            ImageLoader.ImageLoaderCallback callback) {
539816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        String uriString = getImageUriString(type);
540ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        ImageLoader.loadBitmap(context, uriString, maxWidth, maxHeight, callback);
5414d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee    }
5424d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee
543816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
544816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Returns the type of app link for this channel.
545816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * It returns {@link #APP_LINK_TYPE_CHANNEL} if the channel has a non null app link text and
546816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * a valid app link intent, it returns {@link #APP_LINK_TYPE_APP} if the input service which
547816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * holds the channel has leanback launch intent, and it returns {@link #APP_LINK_TYPE_NONE}
548816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * otherwise.
549816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
550816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public int getAppLinkType(Context context) {
551816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (mAppLinkType == APP_LINK_TYPE_NOT_SET) {
552816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            initAppLinkTypeAndIntent(context);
553816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
554816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mAppLinkType;
5555e0399e9eb876608689dfe2187de3b50a4a6145eChulwoo Lee    }
5565e0399e9eb876608689dfe2187de3b50a4a6145eChulwoo Lee
557816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
558816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Returns the app link intent for this channel.
559816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * If the type of app link is {@link #APP_LINK_TYPE_NONE}, it returns {@code null}.
560816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
561816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public Intent getAppLinkIntent(Context context) {
562816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (mAppLinkType == APP_LINK_TYPE_NOT_SET) {
563816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            initAppLinkTypeAndIntent(context);
5644d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee        }
565816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return mAppLinkIntent;
5664d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee    }
5674d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee
568816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private void initAppLinkTypeAndIntent(Context context) {
569816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mAppLinkType = APP_LINK_TYPE_NONE;
570816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mAppLinkIntent = null;
571816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        PackageManager pm = context.getPackageManager();
572816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (!TextUtils.isEmpty(mAppLinkText) && !TextUtils.isEmpty(mAppLinkIntentUri)) {
573816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            try {
57407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko                Intent intent = Intent.parseUri(mAppLinkIntentUri, Intent.URI_INTENT_SCHEME);
575816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                if (intent.resolveActivityInfo(pm, 0) != null) {
576816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    mAppLinkIntent = intent;
577816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    mAppLinkIntent.putExtra(TvCommonConstants.EXTRA_APP_LINK_CHANNEL_URI,
578816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                            getUri().toString());
579816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    mAppLinkType = APP_LINK_TYPE_CHANNEL;
580816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    return;
581816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                }
582816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            } catch (URISyntaxException e) {
5831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                Log.w(TAG, "Unable to set app link for " + mAppLinkIntentUri, e);
584816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                // Do nothing.
585816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            }
586816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
587816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (mPackageName.equals(context.getApplicationContext().getPackageName())) {
588816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return;
5894d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee        }
590816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        mAppLinkIntent = pm.getLeanbackLaunchIntentForPackage(mPackageName);
591816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (mAppLinkIntent != null) {
592816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mAppLinkIntent.putExtra(TvCommonConstants.EXTRA_APP_LINK_CHANNEL_URI,
593816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    getUri().toString());
594816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mAppLinkType = APP_LINK_TYPE_APP;
595816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
596816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
5974d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee
598816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private String getImageUriString(int type) {
599816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        switch (type) {
600816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            case LOAD_IMAGE_TYPE_CHANNEL_LOGO:
601816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return TvContract.buildChannelLogoUri(mId).toString();
602816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            case LOAD_IMAGE_TYPE_APP_LINK_ICON:
603816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return mAppLinkIconUri;
604816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            case LOAD_IMAGE_TYPE_APP_LINK_POSTER_ART:
605816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return mAppLinkPosterArtUri;
6064d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee        }
607816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return null;
6084d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee    }
6094d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee
610816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static class DefaultComparator implements Comparator<Channel> {
611816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        private final Context mContext;
612816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        private final TvInputManagerHelper mInputManager;
613816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        private final Map<String, String> mInputIdToLabelMap = new HashMap<>();
614816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        private boolean mDetectDuplicatesEnabled;
6154d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee
616816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public DefaultComparator(Context context, TvInputManagerHelper inputManager) {
6174d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee            mContext = context;
618816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mInputManager = inputManager;
619816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
620816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
621816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public void setDetectDuplicatesEnabled(boolean detectDuplicatesEnabled) {
622816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            mDetectDuplicatesEnabled = detectDuplicatesEnabled;
6234d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee        }
6244d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee
6254d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee        @Override
626816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        public int compare(Channel lhs, Channel rhs) {
62707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            if (lhs == rhs) {
62807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko                return 0;
62907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            }
63007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            // Put channels from OEM/SOC inputs first.
63107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            boolean lhsIsPartner = mInputManager.isPartnerInput(lhs.getInputId());
63207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            boolean rhsIsPartner = mInputManager.isPartnerInput(rhs.getInputId());
63307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            if (lhsIsPartner != rhsIsPartner) {
63407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko                return lhsIsPartner ? -1 : 1;
63507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            }
63607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            // Compare the input labels.
63707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            String lhsLabel = getInputLabelForChannel(lhs);
63807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            String rhsLabel = getInputLabelForChannel(rhs);
63907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            int result = lhsLabel == null ? (rhsLabel == null ? 0 : 1) : rhsLabel == null ? -1
64007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko                    : lhsLabel.compareTo(rhsLabel);
64107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            if (result != 0) {
64207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko                return result;
64307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            }
64407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            // Compare the input IDs. The input IDs cannot be null.
64507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            result = lhs.getInputId().compareTo(rhs.getInputId());
64607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            if (result != 0) {
64707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko                return result;
64807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            }
64907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            // Compare the channel numbers if both channels belong to the same input.
65007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            result = ChannelNumber.compare(lhs.getDisplayNumber(), rhs.getDisplayNumber());
65107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            if (mDetectDuplicatesEnabled && result == 0) {
65207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko                Log.w(TAG, "Duplicate channels detected! - \""
65307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko                        + lhs.getDisplayNumber() + " " + lhs.getDisplayName() + "\" and \""
65407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko                        + rhs.getDisplayNumber() + " " + rhs.getDisplayName() + "\"");
6554d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee            }
65607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko            return result;
6574d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee        }
6584d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee
659816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        @VisibleForTesting
660816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        String getInputLabelForChannel(Channel channel) {
661816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            String label = mInputIdToLabelMap.get(channel.getInputId());
662816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            if (label == null) {
663816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                TvInputInfo info = mInputManager.getTvInputInfo(channel.getInputId());
664816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                if (info != null) {
665816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    label = Utils.loadLabel(mContext, info);
666816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    if (label != null) {
667816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                        mInputIdToLabelMap.put(channel.getInputId(), label);
668816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    }
669816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                }
6704d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee            }
671816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return label;
6724d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee        }
6734d7677b4cc5ccf7c4f88d32f81417dcfc8155c04Ji-Hwan Lee    }
6743f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho}
675