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