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.util;
183f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
19816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.annotation.SuppressLint;
207d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport android.content.ComponentName;
21816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.content.ContentResolver;
228f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seoimport android.content.ContentValues;
233f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Choimport android.content.Context;
24c0dbe65141bbf5abe42f77ccda21f9bc44f69b48Youngsang Choimport android.content.Intent;
255980d6736ab06e8c15eebb151a3b0c8d943b37b8Jae Seoimport android.content.pm.PackageManager;
267d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport android.content.res.ColorStateList;
2748dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.content.res.Configuration;
287d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport android.content.res.Resources;
297d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport android.content.res.Resources.Theme;
303f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Choimport android.database.Cursor;
319035590d94d136a020e499ce720b9d2cf1f6f45cJae Seoimport android.media.tv.TvContract;
32816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.media.tv.TvContract.Channels;
339035590d94d136a020e499ce720b9d2cf1f6f45cJae Seoimport android.media.tv.TvInputInfo;
34816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.media.tv.TvTrackInfo;
353f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Choimport android.net.Uri;
367d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport android.os.Build;
374ffb471c39be6b915ad2396887fab450dc262600Youngsang Choimport android.preference.PreferenceManager;
38816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.support.annotation.Nullable;
39816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.support.annotation.VisibleForTesting;
4007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.support.annotation.WorkerThread;
414ffb471c39be6b915ad2396887fab450dc262600Youngsang Choimport android.text.TextUtils;
42816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.text.format.DateUtils;
43816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.util.Log;
44816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.View;
4548dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.widget.Toast;
463f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
47816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.R;
487d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport com.android.tv.TvApplication;
49d422754c0cc8475d6e2c8c079ed2ee2e96213edbChulwoo Leeimport com.android.tv.data.Channel;
50d422754c0cc8475d6e2c8c079ed2ee2e96213edbChulwoo Leeimport com.android.tv.data.Program;
5121abb13274f379e69c3c86d51e493122cccca345Dongwon Kangimport com.android.tv.data.StreamInfo;
52ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
531abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.text.SimpleDateFormat;
54816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.ArrayList;
55816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.Calendar;
567d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport java.util.Collection;
57816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.Date;
58816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.HashSet;
59c0dbe65141bbf5abe42f77ccda21f9bc44f69b48Youngsang Choimport java.util.List;
60816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.Locale;
61816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.Set;
62816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.TimeZone;
63816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.concurrent.TimeUnit;
64c0dbe65141bbf5abe42f77ccda21f9bc44f69b48Youngsang Cho
653f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho/**
663f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho * A class that includes convenience methods for accessing TvProvider database.
673f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho */
68fd85048121f09be7722700cdc78e463e93f6cc5bYoungsang Chopublic class Utils {
69816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final String TAG = "Utils";
70816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final boolean DEBUG = false;
71816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private static final SimpleDateFormat ISO_8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
74816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static final String EXTRA_KEY_KEYCODE = "keycode";
75816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static final String EXTRA_KEY_ACTION = "action";
76816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static final String EXTRA_ACTION_SHOW_TV_INPUT ="show_tv_input";
77816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static final String EXTRA_KEY_FROM_LAUNCHER = "from_launcher";
78ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    public static final String EXTRA_KEY_RECORDING_URI = "recording_uri";
79816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
80816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    // Query parameter in the intent of starting MainActivity.
81816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static final String PARAM_SOURCE = "source";
824ffb471c39be6b915ad2396887fab450dc262600Youngsang Cho
83816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final String PATH_CHANNEL = "channel";
84816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final String PATH_PROGRAM = "program";
858f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo
86816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final String PREF_KEY_LAST_WATCHED_CHANNEL_ID = "last_watched_channel_id";
87816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final String PREF_KEY_LAST_WATCHED_CHANNEL_ID_FOR_INPUT =
88816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            "last_watched_channel_id_for_input_";
89816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final String PREF_KEY_LAST_WATCHED_CHANNEL_URI = "last_watched_channel_uri";
90816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
91816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int VIDEO_SD_WIDTH = 704;
92816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int VIDEO_SD_HEIGHT = 480;
93816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int VIDEO_HD_WIDTH = 1280;
94816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int VIDEO_HD_HEIGHT = 720;
95816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int VIDEO_FULL_HD_WIDTH = 1920;
96816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int VIDEO_FULL_HD_HEIGHT = 1080;
97816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int VIDEO_ULTRA_HD_WIDTH = 2048;
98816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int VIDEO_ULTRA_HD_HEIGHT = 1536;
99816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
100816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int AUDIO_CHANNEL_NONE = 0;
101816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int AUDIO_CHANNEL_MONO = 1;
102816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int AUDIO_CHANNEL_STEREO = 2;
103816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int AUDIO_CHANNEL_SURROUND_6 = 6;
104816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static final int AUDIO_CHANNEL_SURROUND_8 = 8;
10521abb13274f379e69c3c86d51e493122cccca345Dongwon Kang
106e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim    private enum AspectRatio {
107e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        ASPECT_RATIO_4_3(4, 3),
108e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        ASPECT_RATIO_16_9(16, 9),
109e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        ASPECT_RATIO_21_9(21, 9);
110e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim
111e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        final int width;
112e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        final int height;
113e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim
114e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        AspectRatio(int width, int height) {
115e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim            this.width = width;
116e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim            this.height = height;
117e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        }
118e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim
1198f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo        @Override
120816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        @SuppressLint("DefaultLocale")
121e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        public String toString() {
122e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim            return String.format("%d:%d", width, height);
123e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        }
124e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim    }
125e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim
126816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private Utils() {
127900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    }
128900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
129816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static String buildSelectionForIds(String idName, List<Long> ids) {
130816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        StringBuilder sb = new StringBuilder();
131816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        sb.append(idName).append(" in (")
132816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                .append(ids.get(0));
133816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        for (int i = 1; i < ids.size(); ++i) {
134816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            sb.append(",").append(ids.get(i));
1353f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
136816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        sb.append(")");
137816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return sb.toString();
1383f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
1393f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
14007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko    @WorkerThread
141816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static String getInputIdForChannel(Context context, long channelId) {
142816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (channelId == Channel.INVALID_ID) {
1433f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho            return null;
1443f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
145816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        Uri channelUri = TvContract.buildChannelUri(channelId);
146816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        String[] projection = {TvContract.Channels.COLUMN_INPUT_ID};
147816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        try (Cursor cursor = context.getContentResolver()
148816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                .query(channelUri, projection, null, null, null)) {
1495e91a958ffdfcae33dd0614fe683b64535d76e03Chulwoo Lee            if (cursor != null && cursor.moveToNext()) {
150816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return Utils.intern(cursor.getString(0));
1515e91a958ffdfcae33dd0614fe683b64535d76e03Chulwoo Lee            }
1523f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho        }
1535e91a958ffdfcae33dd0614fe683b64535d76e03Chulwoo Lee        return null;
1543f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
1553f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
156816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static void setLastWatchedChannel(Context context, Channel channel) {
157816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (channel == null) {
158816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            Log.e(TAG, "setLastWatchedChannel: channel cannot be null");
159816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return;
1604ffb471c39be6b915ad2396887fab450dc262600Youngsang Cho        }
161dbe4746286fb0dcdf24a89fb4a08b620c5e71b05Jaekyun Seok        PreferenceManager.getDefaultSharedPreferences(context).edit()
162816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                .putString(PREF_KEY_LAST_WATCHED_CHANNEL_URI, channel.getUri().toString()).apply();
163816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (!channel.isPassthrough()) {
164816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            long channelId = channel.getId();
165816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            if (channel.getId() < 0) {
166816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                throw new IllegalArgumentException("channelId should be equal to or larger than 0");
167816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            }
168816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            PreferenceManager.getDefaultSharedPreferences(context).edit()
169816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    .putLong(PREF_KEY_LAST_WATCHED_CHANNEL_ID, channelId).apply();
170816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            PreferenceManager.getDefaultSharedPreferences(context).edit()
171816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    .putLong(PREF_KEY_LAST_WATCHED_CHANNEL_ID_FOR_INPUT + channel.getInputId(),
172816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                            channelId).apply();
173816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
1744ffb471c39be6b915ad2396887fab450dc262600Youngsang Cho    }
1754ffb471c39be6b915ad2396887fab450dc262600Youngsang Cho
176900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    public static long getLastWatchedChannelId(Context context) {
177816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return PreferenceManager.getDefaultSharedPreferences(context)
178816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                .getLong(PREF_KEY_LAST_WATCHED_CHANNEL_ID, Channel.INVALID_ID);
1794ffb471c39be6b915ad2396887fab450dc262600Youngsang Cho    }
1804ffb471c39be6b915ad2396887fab450dc262600Youngsang Cho
181816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static long getLastWatchedChannelIdForInput(Context context, String inputId) {
182816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return PreferenceManager.getDefaultSharedPreferences(context)
183816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                .getLong(PREF_KEY_LAST_WATCHED_CHANNEL_ID_FOR_INPUT + inputId, Channel.INVALID_ID);
1843f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho    }
1853f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho
186816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static String getLastWatchedChannelUri(Context context) {
18756008ca02c3d40e73fe6229b9eb95277d5c57129Youngsang Cho        return PreferenceManager.getDefaultSharedPreferences(context)
188816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                .getString(PREF_KEY_LAST_WATCHED_CHANNEL_URI, null);
18956008ca02c3d40e73fe6229b9eb95277d5c57129Youngsang Cho    }
19056008ca02c3d40e73fe6229b9eb95277d5c57129Youngsang Cho
191816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
192816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Returns {@code true}, if {@code uri} specifies an input, which is usually generated
193816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * from {@link TvContract#buildChannelsUriForInput}.
194816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
195816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static boolean isChannelUriForInput(Uri uri) {
196816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return isTvUri(uri) && PATH_CHANNEL.equals(uri.getPathSegments().get(0))
197816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && !TextUtils.isEmpty(uri.getQueryParameter("input"));
198dbe4746286fb0dcdf24a89fb4a08b620c5e71b05Jaekyun Seok    }
199dbe4746286fb0dcdf24a89fb4a08b620c5e71b05Jaekyun Seok
200816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
201816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Returns {@code true}, if {@code uri} is a channel URI for a specific channel. It is copied
202816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * from the hidden method TvContract.isChannelUri.
203816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
204816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static boolean isChannelUriForOneChannel(Uri uri) {
205816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return isChannelUriForTunerInput(uri) || TvContract.isChannelUriForPassthroughInput(uri);
206816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
207816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
208816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
209816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Returns {@code true}, if {@code uri} is a channel URI for a tuner input. It is copied from
210816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * the hidden method TvContract.isChannelUriForTunerInput.
211816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
212816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static boolean isChannelUriForTunerInput(Uri uri) {
213816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_CHANNEL);
214816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
215816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
216816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static boolean isTvUri(Uri uri) {
217816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return uri != null && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
218816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                && TvContract.AUTHORITY.equals(uri.getAuthority());
219816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
220816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
221816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    private static boolean isTwoSegmentUriStartingWith(Uri uri, String pathSegment) {
222816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        List<String> pathSegments = uri.getPathSegments();
223816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return pathSegments.size() == 2 && pathSegment.equals(pathSegments.get(0));
224816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
225816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
226816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
227816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Returns {@code true}, if {@code uri} is a programs URI.
228816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
229816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static boolean isProgramsUri(Uri uri) {
230816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return isTvUri(uri) && PATH_PROGRAM.equals(uri.getPathSegments().get(0));
231816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
232816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
233816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
234816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Gets the info of the program on particular time.
235816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
23607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko    @WorkerThread
237816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static Program getProgramAt(Context context, long channelId, long timeMs) {
2388f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo        if (channelId == Channel.INVALID_ID) {
239816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            Log.e(TAG, "getCurrentProgramAt - channelId is invalid");
240816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return null;
2418f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo        }
242816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (context.getMainLooper().getThread().equals(Thread.currentThread())) {
243816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            String message = "getCurrentProgramAt called on main thread";
244816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            if (DEBUG) {
245816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                // Generating a stack trace can be expensive, only do it in debug mode.
246816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                Log.w(TAG, message, new IllegalStateException(message));
247816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            } else {
248816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                Log.w(TAG, message);
2498f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo            }
250816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
251816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        Uri uri = TvContract.buildProgramsUriForChannel(TvContract.buildChannelUri(channelId),
252816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                timeMs, timeMs);
253816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        try (Cursor cursor = context.getContentResolver().query(uri, Program.PROJECTION,
254816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                null, null, null)) {
255816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            if (cursor != null && cursor.moveToNext()) {
256816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return Program.fromCursor(cursor);
2578f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo            }
2588f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo        }
259816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return null;
260816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
2618f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo
262816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
263816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Gets the info of the current program.
264816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
26507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko    @WorkerThread
266816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static Program getCurrentProgram(Context context, long channelId) {
267816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return getProgramAt(context, channelId, System.currentTimeMillis());
2688f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo    }
2698f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo
270816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
271816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Returns duration string according to the date & time format.
272816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * If {@code startUtcMillis} and {@code endUtcMills} are equal,
273816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * formatted time will be returned instead.
274816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     *
275816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * @param startUtcMillis start of duration in millis. Should be less than {code endUtcMillis}.
276816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * @param endUtcMillis end of duration in millis. Should be larger than {@code startUtcMillis}.
277816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * @param useShortFormat {@code true} if abbreviation is needed to save space.
278816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     *                       In that case, date will be omitted if duration starts from today
279816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     *                       and is less than a day. If it's necessary,
280816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     *                       {@link DateUtils#FORMAT_NUMERIC_DATE} is used otherwise.
281816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
282816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static String getDurationString(
283816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            Context context, long startUtcMillis, long endUtcMillis, boolean useShortFormat) {
28407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        return getDurationString(context, System.currentTimeMillis(), startUtcMillis, endUtcMillis,
28507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko                useShortFormat, 0);
286058dc361839df5a41093a4e671466c1977b59fa6Jaekyun Seok    }
287058dc361839df5a41093a4e671466c1977b59fa6Jaekyun Seok
288816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    @VisibleForTesting
289816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    static String getDurationString(Context context, long baseMillis,
290816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            long startUtcMillis, long endUtcMillis, boolean useShortFormat, int flag) {
291816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        flag |= DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_SHOW_TIME
292816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                | ((useShortFormat) ? DateUtils.FORMAT_NUMERIC_DATE : 0);
293816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (!isInGivenDay(baseMillis, startUtcMillis)) {
294816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            flag |= DateUtils.FORMAT_SHOW_DATE;
295816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
296816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (startUtcMillis != endUtcMillis && useShortFormat) {
297816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            // Do special handling for 12:00 AM when checking if it's in the given day.
298816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            // If it's start, it's considered as beginning of the day. (e.g. 12:00 AM - 12:30 AM)
299816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            // If it's end, it's considered as end of the day (e.g. 11:00 PM - 12:00 AM)
300816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            if (!isInGivenDay(startUtcMillis, endUtcMillis - 1)
301816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    && endUtcMillis - startUtcMillis < TimeUnit.HOURS.toMillis(11)) {
302816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                // Do not show date for short format.
303816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                // Extracting a day is needed because {@link DateUtils@formatDateRange}
304816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                // adds date if the duration covers multiple days.
305816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return DateUtils.formatDateRange(context,
306816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                        startUtcMillis, endUtcMillis - TimeUnit.DAYS.toMillis(1), flag);
307fe6c711c0321ced102e962c790c8dbc5db9c3257Jaekyun Seok            }
308fe6c711c0321ced102e962c790c8dbc5db9c3257Jaekyun Seok        }
309816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return DateUtils.formatDateRange(context, startUtcMillis, endUtcMillis, flag);
310fe6c711c0321ced102e962c790c8dbc5db9c3257Jaekyun Seok    }
311fe6c711c0321ced102e962c790c8dbc5db9c3257Jaekyun Seok
312816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    @VisibleForTesting
313816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static boolean isInGivenDay(long dayToMatchInMillis, long subjectTimeInMillis) {
314816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        final long DAY_IN_MS = TimeUnit.DAYS.toMillis(1);
315816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        TimeZone timeZone = Calendar.getInstance().getTimeZone();
316816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        long offset = timeZone.getRawOffset();
317816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (timeZone.inDaylightTime(new Date(dayToMatchInMillis))) {
318816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            offset += timeZone.getDSTSavings();
319816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
320816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return Utils.floorTime(dayToMatchInMillis + offset, DAY_IN_MS)
321816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                == Utils.floorTime(subjectTimeInMillis + offset, DAY_IN_MS);
322c0dbe65141bbf5abe42f77ccda21f9bc44f69b48Youngsang Cho    }
323c0dbe65141bbf5abe42f77ccda21f9bc44f69b48Youngsang Cho
324e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim    public static String getAspectRatioString(int width, int height) {
325e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        if (width == 0 || height == 0) {
326e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim            return "";
327e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        }
328e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim
329e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        for (AspectRatio ratio: AspectRatio.values()) {
330e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim            if (Math.abs((float) ratio.height / ratio.width - (float) height / width) < 0.05f) {
331e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim                return ratio.toString();
332e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim            }
333e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        }
334e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim        return "";
335e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim    }
336e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim
33748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho    public static String getAspectRatioString(float videoDisplayAspectRatio) {
33848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        if (videoDisplayAspectRatio <= 0) {
33948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            return "";
34048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        }
34148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho
34248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        for (AspectRatio ratio : AspectRatio.values()) {
34348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            if (Math.abs((float) ratio.width / ratio.height - videoDisplayAspectRatio) < 0.05f) {
34448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                return ratio.toString();
34548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            }
34648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        }
34748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        return "";
34848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho    }
34948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho
35021abb13274f379e69c3c86d51e493122cccca345Dongwon Kang    public static int getVideoDefinitionLevelFromSize(int width, int height) {
35121abb13274f379e69c3c86d51e493122cccca345Dongwon Kang        if (width >= VIDEO_ULTRA_HD_WIDTH && height >= VIDEO_ULTRA_HD_HEIGHT) {
35221abb13274f379e69c3c86d51e493122cccca345Dongwon Kang            return StreamInfo.VIDEO_DEFINITION_LEVEL_ULTRA_HD;
35321abb13274f379e69c3c86d51e493122cccca345Dongwon Kang        } else if (width >= VIDEO_FULL_HD_WIDTH && height >= VIDEO_FULL_HD_HEIGHT) {
35421abb13274f379e69c3c86d51e493122cccca345Dongwon Kang            return StreamInfo.VIDEO_DEFINITION_LEVEL_FULL_HD;
35521abb13274f379e69c3c86d51e493122cccca345Dongwon Kang        } else if (width >= VIDEO_HD_WIDTH && height >= VIDEO_HD_HEIGHT) {
35621abb13274f379e69c3c86d51e493122cccca345Dongwon Kang            return StreamInfo.VIDEO_DEFINITION_LEVEL_HD;
35721abb13274f379e69c3c86d51e493122cccca345Dongwon Kang        } else if (width >= VIDEO_SD_WIDTH && height >= VIDEO_SD_HEIGHT) {
35821abb13274f379e69c3c86d51e493122cccca345Dongwon Kang            return StreamInfo.VIDEO_DEFINITION_LEVEL_SD;
35921abb13274f379e69c3c86d51e493122cccca345Dongwon Kang        }
36021abb13274f379e69c3c86d51e493122cccca345Dongwon Kang        return StreamInfo.VIDEO_DEFINITION_LEVEL_UNKNOWN;
36121abb13274f379e69c3c86d51e493122cccca345Dongwon Kang    }
36221abb13274f379e69c3c86d51e493122cccca345Dongwon Kang
363816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static String getVideoDefinitionLevelString(Context context, int videoFormat) {
36421abb13274f379e69c3c86d51e493122cccca345Dongwon Kang        switch (videoFormat) {
36521abb13274f379e69c3c86d51e493122cccca345Dongwon Kang            case StreamInfo.VIDEO_DEFINITION_LEVEL_ULTRA_HD:
366816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return context.getResources().getString(
367816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                        R.string.video_definition_level_ultra_hd);
36821abb13274f379e69c3c86d51e493122cccca345Dongwon Kang            case StreamInfo.VIDEO_DEFINITION_LEVEL_FULL_HD:
369816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return context.getResources().getString(
370816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                        R.string.video_definition_level_full_hd);
37121abb13274f379e69c3c86d51e493122cccca345Dongwon Kang            case StreamInfo.VIDEO_DEFINITION_LEVEL_HD:
372816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return context.getResources().getString(R.string.video_definition_level_hd);
37321abb13274f379e69c3c86d51e493122cccca345Dongwon Kang            case StreamInfo.VIDEO_DEFINITION_LEVEL_SD:
374816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return context.getResources().getString(R.string.video_definition_level_sd);
37521abb13274f379e69c3c86d51e493122cccca345Dongwon Kang        }
37621abb13274f379e69c3c86d51e493122cccca345Dongwon Kang        return "";
37721abb13274f379e69c3c86d51e493122cccca345Dongwon Kang    }
37821abb13274f379e69c3c86d51e493122cccca345Dongwon Kang
379816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static String getAudioChannelString(Context context, int channelCount) {
380e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang        switch (channelCount) {
381e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang            case 1:
382816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return context.getResources().getString(R.string.audio_channel_mono);
383e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang            case 2:
384816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return context.getResources().getString(R.string.audio_channel_stereo);
385e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang            case 6:
386816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return context.getResources().getString(R.string.audio_channel_5_1);
387f8367f0d7dc6abc4876b52e04e2530c06464698eDongwon Kang            case 8:
388816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return context.getResources().getString(R.string.audio_channel_7_1);
389e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang        }
390e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang        return "";
391e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang    }
392e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang
393816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static boolean needToShowSampleRate(Context context, List<TvTrackInfo> tracks) {
394816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        Set<String> multiAudioStrings = new HashSet<>();
395816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        for (TvTrackInfo track : tracks) {
396816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            String multiAudioString = getMultiAudioString(context, track, false);
397816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            if (multiAudioStrings.contains(multiAudioString)) {
398816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                return true;
399816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            }
400816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            multiAudioStrings.add(multiAudioString);
401816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
402816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return false;
403816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
404816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
405816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static String getMultiAudioString(Context context, TvTrackInfo track,
406816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            boolean showSampleRate) {
407816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (track.getType() != TvTrackInfo.TYPE_AUDIO) {
408816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            throw new IllegalArgumentException("Not an audio track: " + track);
409816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
410816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        String language = context.getString(R.string.default_language);
4111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        if (!TextUtils.isEmpty(track.getLanguage())) {
412816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            language = new Locale(track.getLanguage()).getDisplayName();
4137d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko        } else {
4147d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko            Log.d(TAG, "No language information found for the audio track: " + track);
415816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
416816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
417816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        StringBuilder metadata = new StringBuilder();
418816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        switch (track.getAudioChannelCount()) {
419816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            case AUDIO_CHANNEL_NONE:
420816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                break;
421816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            case AUDIO_CHANNEL_MONO:
422816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                metadata.append(context.getString(R.string.multi_audio_channel_mono));
423816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                break;
424816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            case AUDIO_CHANNEL_STEREO:
425816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                metadata.append(context.getString(R.string.multi_audio_channel_stereo));
426816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                break;
427816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            case AUDIO_CHANNEL_SURROUND_6:
428816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                metadata.append(context.getString(R.string.multi_audio_channel_surround_6));
429816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                break;
430816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            case AUDIO_CHANNEL_SURROUND_8:
431816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                metadata.append(context.getString(R.string.multi_audio_channel_surround_8));
432816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                break;
433816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            default:
4347d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko                if (track.getAudioChannelCount() > 0) {
4357d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko                    metadata.append(context.getString(R.string.multi_audio_channel_suffix,
4367d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko                            track.getAudioChannelCount()));
4377d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko                } else {
4387d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko                    Log.d(TAG, "Invalid audio channel count (" + track.getAudioChannelCount()
4397d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko                            + ") found for the audio track: " + track);
4407d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko                }
441816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                break;
442816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
443816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (showSampleRate) {
444816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            int sampleRate = track.getAudioSampleRate();
445816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            if (sampleRate > 0) {
446816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                if (metadata.length() > 0) {
447816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    metadata.append(", ");
448816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                }
449816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                int integerPart = sampleRate / 1000;
450816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                int tenths = (sampleRate % 1000) / 100;
451816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                metadata.append(integerPart);
452816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                if (tenths != 0) {
453816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    metadata.append(".");
454816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    metadata.append(tenths);
455816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                }
456816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                metadata.append("kHz");
457816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            }
458816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
459816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
460816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (metadata.length() == 0) {
461816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return language;
462816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
463816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return context.getString(R.string.multi_audio_display_string_with_channel, language,
464816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                metadata.toString());
465816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
466816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
467816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static boolean isEqualLanguage(String lang1, String lang2) {
468816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (lang1 == null) {
469816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return lang2 == null;
470816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        } else if (lang2 == null) {
471816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return false;
472816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        }
473816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        try {
474816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            return TextUtils.equals(
475816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                    new Locale(lang1).getISO3Language(), new Locale(lang2).getISO3Language());
476816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        } catch (Exception ignored) {
477c0dbe65141bbf5abe42f77ccda21f9bc44f69b48Youngsang Cho        }
478816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return false;
479816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
480c0dbe65141bbf5abe42f77ccda21f9bc44f69b48Youngsang Cho
481816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static boolean isIntentAvailable(Context context, Intent intent) {
482816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko       return context.getPackageManager().queryIntentActivities(
483816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko               intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
484816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
485816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
486816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
487816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Returns the label for a given input. Returns the custom label, if any.
488816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
489816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static String loadLabel(Context context, TvInputInfo input) {
490816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (input == null) {
491c0dbe65141bbf5abe42f77ccda21f9bc44f69b48Youngsang Cho            return null;
492c0dbe65141bbf5abe42f77ccda21f9bc44f69b48Youngsang Cho        }
493816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        CharSequence customLabel = input.loadCustomLabel(context);
494816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        String label = (customLabel == null) ? null : customLabel.toString();
495816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        if (TextUtils.isEmpty(label)) {
496816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko            label = input.loadLabel(context).toString();
497c0dbe65141bbf5abe42f77ccda21f9bc44f69b48Youngsang Cho        }
498816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return label;
499816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
500816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
501816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
502816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Enable all channels synchronously.
503816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
50407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko    @WorkerThread
505816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static void enableAllChannels(Context context) {
506816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        ContentValues values = new ContentValues();
507816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        values.put(Channels.COLUMN_BROWSABLE, 1);
508816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        context.getContentResolver().update(Channels.CONTENT_URI, values, null, null);
509816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
510816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
511816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
512816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Converts time in milliseconds to a String.
513816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
514816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static String toTimeString(long timeMillis) {
515816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return new Date(timeMillis).toString();
516816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
517816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
518816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
5191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     * Converts time in milliseconds to a ISO 8061 string.
5201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     */
5211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public static String toIsoDateTimeString(long timeMillis) {
5221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        return ISO_8601.format(new Date(timeMillis));
5231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
5241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
5251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    /**
526816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Returns a {@link String} object which contains the layout information of the {@code view}.
527816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
528816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static String toRectString(View view) {
529816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return "{"
530816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + "l=" + view.getLeft()
531816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ",r=" + view.getRight()
532816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ",t=" + view.getTop()
533816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ",b=" + view.getBottom()
534816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ",w=" + view.getWidth()
535816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko                + ",h=" + view.getHeight() + "}";
536816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
537816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
538816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
539816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Floors time to the given {@code timeUnit}. For example, if time is 5:32:11 and timeUnit is
540816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * one hour (60 * 60 * 1000), then the output will be 5:00:00.
541816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
542816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static long floorTime(long timeMs, long timeUnit) {
543816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return timeMs - (timeMs % timeUnit);
544816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    }
545816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko
546816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
547816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Ceils time to the given {@code timeUnit}. For example, if time is 5:32:11 and timeUnit is
548816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * one hour (60 * 60 * 1000), then the output will be 6:00:00.
549816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
550816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static long ceilTime(long timeMs, long timeUnit) {
551816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return timeMs + timeUnit - (timeMs % timeUnit);
552c0dbe65141bbf5abe42f77ccda21f9bc44f69b48Youngsang Cho    }
553c0dbe65141bbf5abe42f77ccda21f9bc44f69b48Youngsang Cho
554816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    /**
555816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     * Returns an {@link String#intern() interned} string or null if the input is null.
556816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko     */
557816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    @Nullable
558816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko    public static String intern(@Nullable String string) {
559816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko        return string == null ? null : string.intern();
5604ffb471c39be6b915ad2396887fab450dc262600Youngsang Cho    }
56107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko
56207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko    /**
5637d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * Check if the index is valid for the collection,
5647d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * @param collection the collection
5657d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * @param index the index position to test
5667d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * @return index >= 0 && index < collection.size().
5677d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     */
5687d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko    public static boolean isIndexValid(@Nullable Collection<?> collection, int index) {
5697d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko        return collection == null ? false : index >= 0 && index < collection.size();
5707d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko    }
5717d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko
5727d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko    /**
5737d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * Returns a color integer associated with a particular resource ID.
57407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko     *
5757d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * @see #getColor(android.content.res.Resources,int,Theme)
57607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko     */
5777d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko    public static int getColor(Resources res, int id) {
5787d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko        return getColor(res, id, null);
5797d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko    }
5807d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko
5817d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko    /**
5827d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * Returns a color integer associated with a particular resource ID.
5837d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     *
5847d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * <p>In M version, {@link android.content.res.Resources#getColor(int)} was deprecated and
5857d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * {@link android.content.res.Resources#getColor(int,Theme)} was newly added.
5867d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     *
5877d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * @see android.content.res.Resources#getColor(int)
5887d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     */
5897d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko    public static int getColor(Resources res, int id, @Nullable Theme theme) {
5907d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
5917d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko            return res.getColor(id, theme);
59207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        } else {
5937d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko            return res.getColor(id);
59407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        }
59507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko    }
59607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko
59707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko    /**
5987d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * Returns a color state list associated with a particular resource ID.
5997d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     *
6007d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * @see #getColorStateList(android.content.res.Resources,int,Theme)
6017d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     */
6027d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko    public static ColorStateList getColorStateList(Resources res, int id) {
6037d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko        return getColorStateList(res, id, null);
6047d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko    }
6057d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko
6067d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko    /**
6077d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * Returns a color state list associated with a particular resource ID.
6087d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     *
6097d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * <p>In M version, {@link android.content.res.Resources#getColorStateList(int)} was deprecated
6107d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * and {@link android.content.res.Resources#getColorStateList(int,Theme)} was newly added.
61107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko     *
6127d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko     * @see android.content.res.Resources#getColorStateList(int)
61307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko     */
6147d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko    public static ColorStateList getColorStateList(Resources res, int id, @Nullable Theme theme) {
6157d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
6167d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko            return res.getColorStateList(id, theme);
61707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko        } else {
6187d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko            return res.getColorStateList(id);
6197d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko        }
6207d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko    }
6217d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko
6221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    /**
62348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho     * Returns a localized version of the text resource specified by resourceId.
6241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     */
62548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho    public static CharSequence getTextForLocale(Context context, Locale locale, int resourceId) {
62648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        if (locale.equals(context.getResources().getConfiguration().locale)) {
62748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            return context.getText(resourceId);
6281abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
62948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        Configuration config = new Configuration(context.getResources().getConfiguration());
63048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        config.setLocale(locale);
63148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        return context.createConfigurationContext(config).getText(resourceId);
6321abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
6331abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
6341abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    /**
63548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho     * Returns the internal TV inputs.
6361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     */
63748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho    public static List<TvInputInfo> getInternalTvInputs(Context context, boolean tunerInputOnly) {
63848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        List<TvInputInfo> inputs = new ArrayList<>();
63948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        String contextPackageName = context.getPackageName();
64048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        for (TvInputInfo input : TvApplication.getSingletons(context).getTvInputManagerHelper()
64148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                .getTvInputInfos(true, tunerInputOnly)) {
64248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            if (contextPackageName.equals(ComponentName.unflattenFromString(input.getId())
64348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                    .getPackageName())) {
64448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                inputs.add(input);
64548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho            }
6461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
64748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        return inputs;
6481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
6497d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko
65048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho    /**
65148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho     * Checks whether the input is internal or not.
65248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho     */
65348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho    public static boolean isInternalTvInput(Context context, String inputId) {
65448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        return context.getPackageName().equals(ComponentName.unflattenFromString(inputId)
65548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                .getPackageName());
65648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho    }
6573a72b93e554bd22a5c64e71a6956d9604ce05108Youngsang Cho
65848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho    /**
65948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho     * Shows a toast message to notice that the current feature is a developer feature.
66048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho     */
66148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho    public static void showToastMessageForDeveloperFeature(Context context) {
66248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho        Toast.makeText(context, "This feature is for developer preview.", Toast.LENGTH_SHORT)
66348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho                .show();
66407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko    }
6653f07ce6c09b77e0c9224a16a4c73c8750ff8a07bYoungsang Cho}
666