TvApplication.java revision 3a72b93e554bd22a5c64e71a6956d9604ce05108
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.app.Activity; 20import android.app.Application; 21import android.content.ComponentName; 22import android.content.Context; 23import android.content.Intent; 24import android.content.pm.PackageInfo; 25import android.content.pm.PackageManager; 26import android.media.tv.TvInputInfo; 27import android.media.tv.TvInputManager; 28import android.media.tv.TvInputManager.TvInputCallback; 29import android.os.Bundle; 30import android.os.StrictMode; 31import android.support.annotation.NonNull; 32import android.support.annotation.Nullable; 33import android.support.annotation.UiThread; 34import android.util.Log; 35import android.view.KeyEvent; 36 37import com.android.tv.analytics.Analytics; 38import com.android.tv.analytics.StubAnalytics; 39import com.android.tv.analytics.StubAnalytics; 40import com.android.tv.analytics.Tracker; 41import com.android.tv.common.BuildConfig; 42import com.android.tv.common.SharedPreferencesUtils; 43import com.android.tv.common.TvCommonUtils; 44import com.android.tv.common.feature.CommonFeatures; 45import com.android.tv.common.ui.setup.animation.SetupAnimationHelper; 46import com.android.tv.data.ChannelDataManager; 47import com.android.tv.data.ProgramDataManager; 48import com.android.tv.dvr.DvrDataManager; 49import com.android.tv.dvr.DvrDataManagerImpl; 50import com.android.tv.dvr.DvrDataManagerInMemoryImpl; 51import com.android.tv.dvr.DvrManager; 52import com.android.tv.dvr.DvrRecordingService; 53import com.android.tv.dvr.DvrSessionManager; 54import com.android.tv.util.SetupUtils; 55import com.android.tv.util.SystemProperties; 56import com.android.tv.util.TvInputManagerHelper; 57import com.android.tv.util.Utils; 58 59import java.util.List; 60 61public class TvApplication extends Application implements ApplicationSingletons { 62 private static final String TAG = "TvApplication"; 63 private static final boolean DEBUG = false; 64 65 /** 66 * Returns the @{@link ApplicationSingletons} using the application context. 67 */ 68 public static ApplicationSingletons getSingletons(Context context) { 69 return (ApplicationSingletons) context.getApplicationContext(); 70 } 71 private String mVersionName = ""; 72 73 private final MainActivityWrapper mMainActivityWrapper = new MainActivityWrapper(); 74 75 private SelectInputActivity mSelectInputActivity; 76 private Analytics mAnalytics; 77 private Tracker mTracker; 78 private TvInputManagerHelper mTvInputManagerHelper; 79 private ChannelDataManager mChannelDataManager; 80 private ProgramDataManager mProgramDataManager; 81 private DvrManager mDvrManager; 82 private DvrDataManager mDvrDataManager; 83 @Nullable 84 private DvrSessionManager mDvrSessionManager; 85 86 @Override 87 public void onCreate() { 88 super.onCreate(); 89 SharedPreferencesUtils.initialize(this); 90 try { 91 PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0); 92 mVersionName = pInfo.versionName; 93 } catch (PackageManager.NameNotFoundException e) { 94 Log.w(TAG, "Unable to find package '" + getPackageName() + "'.", e); 95 mVersionName = ""; 96 } 97 Log.i(TAG, "Starting Live TV " + getVersionName()); 98 // Only set StrictMode for ENG builds because the build server only produces userdebug 99 // builds. 100 if (BuildConfig.ENG && SystemProperties.ALLOW_STRICT_MODE.getValue()) { 101 StrictMode.setThreadPolicy( 102 new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); 103 StrictMode.VmPolicy.Builder vmPolicyBuilder = new StrictMode.VmPolicy.Builder() 104 .detectAll().penaltyLog(); 105 if (BuildConfig.ENG && SystemProperties.ALLOW_DEATH_PENALTY.getValue() && 106 !TvCommonUtils.isRunningInTest()) { 107 // TODO turn on death penalty for tests when they stop leaking MainActivity 108 } 109 StrictMode.setVmPolicy(vmPolicyBuilder.build()); 110 } 111 if (BuildConfig.ENG && !SystemProperties.ALLOW_ANALYTICS_IN_ENG.getValue()) { 112 mAnalytics = StubAnalytics.getInstance(this); 113 } else { 114 mAnalytics = StubAnalytics.getInstance(this); 115 } 116 mTracker = mAnalytics.getDefaultTracker(); 117 mTvInputManagerHelper = new TvInputManagerHelper(this); 118 mTvInputManagerHelper.start(); 119 mTvInputManagerHelper.addCallback(new TvInputCallback() { 120 @Override 121 public void onInputAdded(String inputId) { 122 handleInputCountChanged(); 123 } 124 125 @Override 126 public void onInputRemoved(String inputId) { 127 handleInputCountChanged(); 128 } 129 }); 130 if (CommonFeatures.DVR.isEnabled(this)) { 131 mDvrManager = new DvrManager(this); 132 //NOTE: DvrRecordingService just keeps running. 133 DvrRecordingService.startService(this); 134 } 135 // In SetupFragment, transitions are set in the constructor. Because the fragment can be 136 // created in Activity.onCreate() by the framework, SetupAnimationHelper should be 137 // initialized here before Activity.onCreate() is called. 138 SetupAnimationHelper.initialize(this); 139 if (DEBUG) Log.i(TAG, "Started Live TV " + mVersionName); 140 } 141 142 /** 143 * Returns the {@link DvrManager}. 144 */ 145 @Override 146 public DvrManager getDvrManager() { 147 return mDvrManager; 148 } 149 150 @Override 151 public DvrSessionManager getDvrSessionManger() { 152 if (mDvrSessionManager == null) { 153 mDvrSessionManager = new DvrSessionManager(this); 154 } 155 return mDvrSessionManager; 156 } 157 158 /** 159 * Returns the {@link Analytics}. 160 */ 161 @Override 162 public Analytics getAnalytics() { 163 return mAnalytics; 164 } 165 166 /** 167 * Returns the default tracker. 168 */ 169 @Override 170 public Tracker getTracker() { 171 return mTracker; 172 } 173 174 175 /** 176 * Returns {@link ChannelDataManager}. 177 */ 178 @Override 179 public ChannelDataManager getChannelDataManager() { 180 if (mChannelDataManager == null) { 181 mChannelDataManager = new ChannelDataManager(this, mTvInputManagerHelper); 182 mChannelDataManager.start(); 183 } 184 return mChannelDataManager; 185 } 186 187 /** 188 * Returns {@link ProgramDataManager}. 189 */ 190 @Override 191 public ProgramDataManager getProgramDataManager() { 192 if (mProgramDataManager == null) { 193 mProgramDataManager = new ProgramDataManager(this); 194 mProgramDataManager.start(); 195 } 196 return mProgramDataManager; 197 } 198 199 /** 200 * Returns {@link DvrDataManager}. 201 */ 202 @Override 203 public DvrDataManager getDvrDataManager() { 204 if (mDvrDataManager == null) { 205 if(SystemProperties.USE_IN_MEMORY_DVR_DB.getValue()){ 206 mDvrDataManager = new DvrDataManagerInMemoryImpl(this); 207 } else { 208 DvrDataManagerImpl dvrDataManager = new DvrDataManagerImpl(this); 209 mDvrDataManager = dvrDataManager; 210 dvrDataManager.start(); 211 } 212 } 213 return mDvrDataManager; 214 } 215 216 /** 217 * Returns {@link TvInputManagerHelper}. 218 */ 219 @Override 220 public TvInputManagerHelper getTvInputManagerHelper() { 221 return mTvInputManagerHelper; 222 } 223 224 /** 225 * Returns the main activity information. 226 */ 227 @Override 228 public MainActivityWrapper getMainActivityWrapper() { 229 return mMainActivityWrapper; 230 } 231 232 /** 233 * SelectInputActivity is set in {@link SelectInputActivity#onCreate} and cleared in 234 * {@link SelectInputActivity#onDestroy}. 235 */ 236 public void setSelectInputActivity(SelectInputActivity activity) { 237 mSelectInputActivity = activity; 238 } 239 240 /** 241 * Handles the global key KEYCODE_TV. 242 */ 243 public void handleTvKey() { 244 if (!mMainActivityWrapper.isResumed()) { 245 startMainActivity(null); 246 } 247 } 248 249 /** 250 * Handles the global key KEYCODE_TV_INPUT. 251 */ 252 public void handleTvInputKey() { 253 TvInputManager tvInputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE); 254 List<TvInputInfo> tvInputs = tvInputManager.getTvInputList(); 255 int inputCount = 0; 256 boolean hasTunerInput = false; 257 for (TvInputInfo input : tvInputs) { 258 if (input.isPassthroughInput()) { 259 ++inputCount; 260 } else if (!hasTunerInput) { 261 hasTunerInput = true; 262 ++inputCount; 263 } 264 } 265 if (inputCount < 2) { 266 return; 267 } 268 Activity activityToHandle = mMainActivityWrapper.isResumed() 269 ? mMainActivityWrapper.getMainActivity() : mSelectInputActivity; 270 if (activityToHandle != null) { 271 // If startActivity is called, MainActivity.onPause is unnecessarily called. To 272 // prevent it, MainActivity.dispatchKeyEvent is directly called. 273 activityToHandle.dispatchKeyEvent( 274 new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_TV_INPUT)); 275 activityToHandle.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, 276 KeyEvent.KEYCODE_TV_INPUT)); 277 } else if (mMainActivityWrapper.isStarted()) { 278 Bundle extras = new Bundle(); 279 extras.putString(Utils.EXTRA_KEY_ACTION, Utils.EXTRA_ACTION_SHOW_TV_INPUT); 280 startMainActivity(extras); 281 } else { 282 startActivity(new Intent(this, SelectInputActivity.class).setFlags( 283 Intent.FLAG_ACTIVITY_NEW_TASK)); 284 } 285 } 286 287 private void startMainActivity(Bundle extras) { 288 // The use of FLAG_ACTIVITY_NEW_TASK enables arbitrary applications to access the intent 289 // sent to the root activity. Having said that, we should be fine here since such an intent 290 // does not carry any important user data. 291 Intent intent = new Intent(this, MainActivity.class) 292 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 293 if (extras != null) { 294 intent.putExtras(extras); 295 } 296 startActivity(intent); 297 } 298 299 /** 300 * Returns the version name of the live channels. 301 * 302 * @see PackageInfo#versionName 303 */ 304 public String getVersionName() { 305 return mVersionName; 306 } 307 308 /** 309 * Checks the input counts and enable/disable TvActivity. Also updates the input list in 310 * {@link SetupUtils}. 311 */ 312 public void handleInputCountChanged() { 313 TvInputManager inputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE); 314 boolean enable = false; 315 if (Features.UNHIDE.isEnabled(TvApplication.this)) { 316 enable = true; 317 } else { 318 List<TvInputInfo> inputs = inputManager.getTvInputList(); 319 // Enable the TvActivity only if there is at least one tuner type input. 320 for (TvInputInfo input : inputs) { 321 if (input.getType() == TvInputInfo.TYPE_TUNER) { 322 enable = true; 323 break; 324 } 325 } 326 if (DEBUG) Log.d(TAG, "Enable MainActivity: " + enable); 327 } 328 PackageManager packageManager = getPackageManager(); 329 ComponentName name = new ComponentName(this, TvActivity.class); 330 int newState = enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 331 PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 332 if (packageManager.getComponentEnabledSetting(name) != newState) { 333 packageManager.setComponentEnabledSetting(name, newState, 0); 334 } 335 SetupUtils.getInstance(TvApplication.this).onInputListUpdated(inputManager); 336 } 337} 338