1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.tv;
18
19import android.content.Context;
20import android.content.pm.PackageManager;
21import android.os.Build;
22import android.support.annotation.VisibleForTesting;
23import android.text.TextUtils;
24import android.util.Log;
25
26import com.android.tv.common.feature.Feature;
27import com.android.tv.common.feature.GServiceFeature;
28import com.android.tv.common.feature.PropertyFeature;
29import com.android.tv.config.RemoteConfig;
30import com.android.tv.experiments.Experiments;
31import com.android.tv.util.LocationUtils;
32import com.android.tv.util.PermissionUtils;
33import com.android.tv.util.Utils;
34
35import java.util.Locale;
36
37import static com.android.tv.common.feature.EngOnlyFeature.ENG_ONLY_FEATURE;
38import static com.android.tv.common.feature.FeatureUtils.AND;
39import static com.android.tv.common.feature.FeatureUtils.OFF;
40import static com.android.tv.common.feature.FeatureUtils.ON;
41import static com.android.tv.common.feature.FeatureUtils.OR;
42
43/**
44 * List of {@link Feature} for the Live TV App.
45 *
46 * <p>Remove the {@code Feature} once it is launched.
47 */
48public final class Features {
49    private static final String TAG = "Features";
50    private static final boolean DEBUG = false;
51
52    /**
53     * UI for opting in to analytics.
54     *
55     * <p>Do not turn this on until the splash screen asking existing users to opt-in is launched.
56     * See <a href="http://b/20228119">b/20228119</a>
57     */
58    public static final Feature ANALYTICS_OPT_IN = ENG_ONLY_FEATURE;
59
60    /**
61     * Analytics that include sensitive information such as channel or program identifiers.
62     *
63     * <p>See <a href="http://b/22062676">b/22062676</a>
64     */
65    public static final Feature ANALYTICS_V2 = AND(ON, ANALYTICS_OPT_IN);
66
67    public static final Feature EPG_SEARCH =
68            new PropertyFeature("feature_tv_use_epg_search", false);
69
70    public static final Feature TUNER =
71            new Feature() {
72                @Override
73                public boolean isEnabled(Context context) {
74
75                    if (Utils.isDeveloper()) {
76                        // we enable tuner for developers to test tuner in any platform.
77                        return true;
78                    }
79
80                    // This is special handling just for USB Tuner.
81                    // It does not require any N API's but relies on a improvements in N for AC3 support
82                    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
83                }
84            };
85
86    /**
87     * Use network tuner if it is available and there is no other tuner types.
88     */
89    public static final Feature NETWORK_TUNER =
90            new Feature() {
91                @Override
92                public boolean isEnabled(Context context) {
93                    if (!TUNER.isEnabled(context)) {
94                        return false;
95                    }
96                    if (Utils.isDeveloper()) {
97                        // Network tuner will be enabled for developers.
98                        return true;
99                    }
100                    return Locale.US.getCountry().equalsIgnoreCase(
101                            LocationUtils.getCurrentCountry(context));
102                }
103            };
104
105    private static final String GSERVICE_KEY_UNHIDE = "live_channels_unhide";
106    /**
107     * A flag which indicates that LC app is unhidden even when there is no input.
108     */
109    public static final Feature UNHIDE =
110            OR(new GServiceFeature(GSERVICE_KEY_UNHIDE, false), new Feature() {
111                @Override
112                public boolean isEnabled(Context context) {
113                    // If LC app runs as non-system app, we unhide the app.
114                    return !PermissionUtils.hasAccessAllEpg(context);
115                }
116            });
117
118    public static final Feature PICTURE_IN_PICTURE =
119            new Feature() {
120                private Boolean mEnabled;
121
122                @Override
123                public boolean isEnabled(Context context) {
124                    if (mEnabled == null) {
125                        mEnabled =
126                                Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
127                                        && context.getPackageManager()
128                                                .hasSystemFeature(
129                                                        PackageManager.FEATURE_PICTURE_IN_PICTURE);
130                    }
131                    return mEnabled;
132                }
133            };
134
135    /** Use AC3 software decode. */
136    public static final Feature AC3_SOFTWARE_DECODE =
137            new Feature() {
138                private final String[] SUPPORTED_REGIONS = {};
139
140                private Boolean mEnabled;
141
142                @Override
143                public boolean isEnabled(Context context) {
144                    if (mEnabled == null) {
145                        if (mEnabled == null) {
146                            // We will not cache the result of fallback solution.
147                            String country = LocationUtils.getCurrentCountry(context);
148                            for (int i = 0; i < SUPPORTED_REGIONS.length; ++i) {
149                                if (SUPPORTED_REGIONS[i].equalsIgnoreCase(country)) {
150                                    return true;
151                                }
152                            }
153                            if (DEBUG) Log.d(TAG, "AC3 flag false after country check");
154                            return false;
155                        }
156                    }
157                    if (DEBUG) Log.d(TAG, "AC3 flag " + mEnabled);
158                    return mEnabled;
159                }
160            };
161
162    /** Show postal code fragment before channel scan. */
163    public static final Feature ENABLE_CLOUD_EPG_REGION =
164            new Feature() {
165                private final String[] SUPPORTED_REGIONS = {
166                };
167
168
169                @Override
170                public boolean isEnabled(Context context) {
171                    if (!Experiments.CLOUD_EPG.get()) {
172                        if (DEBUG) Log.d(TAG, "Experiments.CLOUD_EPG is false");
173                        return false;
174                    }
175                    String country = LocationUtils.getCurrentCountry(context);
176                    for (int i = 0; i < SUPPORTED_REGIONS.length; i++) {
177                        if (SUPPORTED_REGIONS[i].equalsIgnoreCase(country)) {
178                            return true;
179                        }
180                    }
181                    if (DEBUG) Log.d(TAG, "EPG flag false after country check");
182                    return false;
183                }
184            };
185
186    /** Enable a conflict dialog between currently watched channel and upcoming recording. */
187    public static final Feature SHOW_UPCOMING_CONFLICT_DIALOG = OFF;
188
189    /**
190     * Use input blacklist to disable partner's tuner input.
191     */
192    public static final Feature USE_PARTNER_INPUT_BLACKLIST = ON;
193
194    /**
195     * Enable Dvb parsers and listeners.
196     */
197    public static final Feature ENABLE_FILE_DVB = OFF;
198
199    @VisibleForTesting
200    public static final Feature TEST_FEATURE = new PropertyFeature("test_feature", false);
201
202    private Features() {
203    }
204}
205