1 /*
2  * Copyright 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 
17 package com.android.tv.common.util;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.media.tv.TvInputInfo;
22 import android.os.Build;
23 import android.util.ArraySet;
24 import android.util.Log;
25 import com.android.tv.common.CommonConstants;
26 import com.android.tv.common.actions.InputSetupActionUtils;
27 import java.io.File;
28 import java.text.SimpleDateFormat;
29 import java.util.Date;
30 import java.util.Locale;
31 import java.util.Set;
32 
33 /** Util class for common use in TV app and inputs. */
34 @SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
35 public final class CommonUtils {
36     private static final String TAG = "CommonUtils";
37     private static final ThreadLocal<SimpleDateFormat> ISO_8601 =
38             new ThreadLocal() {
39                 private final SimpleDateFormat value =
40                         new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
41 
42                 @Override
43                 protected SimpleDateFormat initialValue() {
44                     return value;
45                 }
46             };
47     // Hardcoded list for known bundled inputs not written by OEM/SOCs.
48     // Bundled (system) inputs not in the list will get the high priority
49     // so they and their channels come first in the UI.
50     private static final Set<String> BUNDLED_PACKAGE_SET = new ArraySet<>();
51 
52     static {
53         BUNDLED_PACKAGE_SET.add("com.android.tv");
54 // AOSP_Comment_Out         BUNDLED_PACKAGE_SET.add(CommonConstants.BASE_PACKAGE);
55     }
56 
57     private static Boolean sRunningInTest;
58 
CommonUtils()59     private CommonUtils() {}
60 
61     /**
62      * Returns an intent to start the setup activity for the TV input using {@link
63      * InputSetupActionUtils#INTENT_ACTION_INPUT_SETUP}.
64      */
createSetupIntent(Intent originalSetupIntent, String inputId)65     public static Intent createSetupIntent(Intent originalSetupIntent, String inputId) {
66         if (originalSetupIntent == null) {
67             return null;
68         }
69         Intent setupIntent = new Intent(originalSetupIntent);
70         if (!InputSetupActionUtils.hasInputSetupAction(originalSetupIntent)) {
71             Intent intentContainer = new Intent(InputSetupActionUtils.INTENT_ACTION_INPUT_SETUP);
72             intentContainer.putExtra(InputSetupActionUtils.EXTRA_SETUP_INTENT, originalSetupIntent);
73             intentContainer.putExtra(InputSetupActionUtils.EXTRA_INPUT_ID, inputId);
74             setupIntent = intentContainer;
75         }
76         return setupIntent;
77     }
78 
79     /**
80      * Returns an intent to start the setup activity for this TV input using {@link
81      * InputSetupActionUtils#INTENT_ACTION_INPUT_SETUP}.
82      */
createSetupIntent(TvInputInfo input)83     public static Intent createSetupIntent(TvInputInfo input) {
84         return createSetupIntent(input.createSetupIntent(), input.getId());
85     }
86 
87     /**
88      * Checks if this application is running in tests.
89      *
90      * <p>{@link android.app.ActivityManager#isRunningInTestHarness} doesn't return {@code true} for
91      * the usual devices even the application is running in tests. We need to figure it out by
92      * checking whether the class in tv-tests-common module can be loaded or not.
93      */
isRunningInTest()94     public static synchronized boolean isRunningInTest() {
95         if (sRunningInTest == null) {
96             try {
97                 Class.forName("com.android.tv.testing.utils.Utils");
98                 Log.i(
99                         TAG,
100                         "Assumed to be running in a test because"
101                                 + " com.android.tv.testing.utils.Utils is found");
102                 sRunningInTest = true;
103             } catch (ClassNotFoundException e) {
104                 sRunningInTest = false;
105             }
106         }
107         return sRunningInTest;
108     }
109 
110     /** Checks whether a given package is in our bundled package set. */
isInBundledPackageSet(String packageName)111     public static boolean isInBundledPackageSet(String packageName) {
112         return BUNDLED_PACKAGE_SET.contains(packageName);
113     }
114 
115     /** Checks whether a given input is a bundled input. */
isBundledInput(String inputId)116     public static boolean isBundledInput(String inputId) {
117         for (String prefix : BUNDLED_PACKAGE_SET) {
118             if (inputId.startsWith(prefix + "/")) {
119                 return true;
120             }
121         }
122         return false;
123     }
124 
125     /** Returns true if the application is packaged with TV app. */
isPackagedWithLiveChannels(Context context)126     public static boolean isPackagedWithLiveChannels(Context context) {
127         return (CommonConstants.BASE_PACKAGE.equals(context.getPackageName()));
128     }
129 
130     /** Converts time in milliseconds to a ISO 8061 string. */
toIsoDateTimeString(long timeMillis)131     public static String toIsoDateTimeString(long timeMillis) {
132         return ISO_8601.get().format(new Date(timeMillis));
133     }
134 
135     /**
136      * Deletes a file or a directory.
137      *
138      * @return <code>true</code> if and only if the file or directory is successfully deleted;
139      *     <code>false</code> otherwise
140      */
deleteDirOrFile(File fileOrDirectory)141     public static boolean deleteDirOrFile(File fileOrDirectory) {
142         if (fileOrDirectory.isDirectory()) {
143             File[] files = fileOrDirectory.listFiles();
144             if (files != null) {
145                 for (File child : files) {
146                     deleteDirOrFile(child);
147                 }
148             }
149         }
150         // If earlier deletes failed this will also
151         return fileOrDirectory.delete();
152     }
153 
isRoboTest()154     public static boolean isRoboTest() {
155         return "robolectric".equals(Build.FINGERPRINT);
156     }
157 }
158