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 17 package com.android.tv; 18 19 import android.annotation.TargetApi; 20 import android.app.Activity; 21 import android.app.Application; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.SharedPreferences; 27 import android.content.pm.PackageInfo; 28 import android.content.pm.PackageManager; 29 import android.media.tv.TvContract; 30 import android.media.tv.TvInputInfo; 31 import android.media.tv.TvInputManager; 32 import android.media.tv.TvInputManager.TvInputCallback; 33 import android.os.AsyncTask; 34 import android.os.Build; 35 import android.os.Bundle; 36 import android.os.StrictMode; 37 import android.support.annotation.Nullable; 38 import android.support.annotation.VisibleForTesting; 39 import android.text.TextUtils; 40 import android.util.Log; 41 import android.view.KeyEvent; 42 43 import com.android.tv.analytics.Analytics; 44 import com.android.tv.analytics.StubAnalytics; 45 import com.android.tv.analytics.StubAnalytics; 46 import com.android.tv.analytics.Tracker; 47 import com.android.tv.common.BuildConfig; 48 import com.android.tv.common.SharedPreferencesUtils; 49 import com.android.tv.common.SoftPreconditions; 50 import com.android.tv.common.TvCommonUtils; 51 import com.android.tv.common.feature.CommonFeatures; 52 import com.android.tv.common.ui.setup.animation.SetupAnimationHelper; 53 import com.android.tv.config.DefaultConfigManager; 54 import com.android.tv.config.RemoteConfig; 55 import com.android.tv.data.ChannelDataManager; 56 import com.android.tv.data.PreviewDataManager; 57 import com.android.tv.data.ProgramDataManager; 58 import com.android.tv.data.epg.EpgFetcher; 59 import com.android.tv.dvr.DvrDataManager; 60 import com.android.tv.dvr.DvrDataManagerImpl; 61 import com.android.tv.dvr.DvrManager; 62 import com.android.tv.dvr.DvrScheduleManager; 63 import com.android.tv.dvr.DvrStorageStatusManager; 64 import com.android.tv.dvr.DvrWatchedPositionManager; 65 import com.android.tv.dvr.recorder.RecordingScheduler; 66 import com.android.tv.perf.EventNames; 67 import com.android.tv.perf.PerformanceMonitor; 68 import com.android.tv.perf.StubPerformanceMonitor; 69 import com.android.tv.perf.TimerEvent; 70 import com.android.tv.recommendation.ChannelPreviewUpdater; 71 import com.android.tv.recommendation.RecordedProgramPreviewUpdater; 72 import com.android.tv.tuner.TunerInputController; 73 import com.android.tv.tuner.TunerPreferences; 74 import com.android.tv.tuner.tvinput.TunerTvInputService; 75 import com.android.tv.tuner.util.TunerInputInfoUtils; 76 import com.android.tv.util.AccountHelper; 77 import com.android.tv.util.Clock; 78 import com.android.tv.util.Debug; 79 import com.android.tv.util.PermissionUtils; 80 import com.android.tv.util.SetupUtils; 81 import com.android.tv.util.SystemProperties; 82 import com.android.tv.util.TvInputManagerHelper; 83 import com.android.tv.util.Utils; 84 85 import java.util.List; 86 87 public class TvApplication extends Application implements ApplicationSingletons { 88 private static final String TAG = "TvApplication"; 89 private static final boolean DEBUG = false; 90 private static final TimerEvent sAppStartTimer = StubPerformanceMonitor.startBootstrapTimer(); 91 92 /** 93 * An instance of {@link ApplicationSingletons}. Note that this can be set directly only for the 94 * test purpose. 95 */ 96 @VisibleForTesting 97 public static ApplicationSingletons sAppSingletons; 98 99 /** 100 * Broadcast Action: The user has updated LC to a new version that supports tuner input. 101 * {@link com.android.tv.tuner.TunerInputController} will recevice this intent to check 102 * the existence of tuner input when the new version is first launched. 103 */ 104 public static final String ACTION_APPLICATION_FIRST_LAUNCHED = 105 "com.android.tv.action.APPLICATION_FIRST_LAUNCHED"; 106 private static final String PREFERENCE_IS_FIRST_LAUNCH = "is_first_launch"; 107 108 private RemoteConfig mRemoteConfig; 109 private String mVersionName = ""; 110 111 private final MainActivityWrapper mMainActivityWrapper = new MainActivityWrapper(); 112 113 private SelectInputActivity mSelectInputActivity; 114 private Analytics mAnalytics; 115 private Tracker mTracker; 116 private TvInputManagerHelper mTvInputManagerHelper; 117 private ChannelDataManager mChannelDataManager; 118 private volatile ProgramDataManager mProgramDataManager; 119 private PreviewDataManager mPreviewDataManager; 120 private DvrManager mDvrManager; 121 private DvrScheduleManager mDvrScheduleManager; 122 private DvrDataManager mDvrDataManager; 123 private DvrStorageStatusManager mDvrStorageStatusManager; 124 private DvrWatchedPositionManager mDvrWatchedPositionManager; 125 private RecordingScheduler mRecordingScheduler; 126 @Nullable 127 private InputSessionManager mInputSessionManager; 128 private AccountHelper mAccountHelper; 129 // When this variable is null, we don't know in which process TvApplication runs. 130 private Boolean mRunningInMainProcess; 131 private PerformanceMonitor mPerformanceMonitor; 132 133 @Override onCreate()134 public void onCreate() { 135 super.onCreate(); 136 if (!PermissionUtils.hasInternet(this)) { 137 // When an isolated process starts, just skip all the initialization. 138 return; 139 } 140 Debug.getTimer(Debug.TAG_START_UP_TIMER).start(); 141 Debug.getTimer(Debug.TAG_START_UP_TIMER).log("Start TvApplication.onCreate"); 142 SharedPreferencesUtils.initialize(this, new Runnable() { 143 @Override 144 public void run() { 145 if (mRunningInMainProcess != null && mRunningInMainProcess) { 146 checkTunerServiceOnFirstLaunch(); 147 } 148 } 149 }); 150 // TunerPreferences is used to enable/disable the tuner input even when TUNER feature is 151 // disabled. 152 TunerPreferences.initialize(this); 153 try { 154 PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0); 155 mVersionName = pInfo.versionName; 156 } catch (PackageManager.NameNotFoundException e) { 157 Log.w(TAG, "Unable to find package '" + getPackageName() + "'.", e); 158 mVersionName = ""; 159 } 160 Log.i(TAG, "Starting Live TV " + getVersionName()); 161 162 // Only set StrictMode for ENG builds because the build server only produces userdebug 163 // builds. 164 if (BuildConfig.ENG && SystemProperties.ALLOW_STRICT_MODE.getValue()) { 165 StrictMode.ThreadPolicy.Builder threadPolicyBuilder = 166 new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog(); 167 StrictMode.VmPolicy.Builder vmPolicyBuilder = 168 new StrictMode.VmPolicy.Builder().detectAll().penaltyDeath(); 169 if (!TvCommonUtils.isRunningInTest()) { 170 threadPolicyBuilder.penaltyDialog(); 171 } 172 StrictMode.setThreadPolicy(threadPolicyBuilder.build()); 173 StrictMode.setVmPolicy(vmPolicyBuilder.build()); 174 } 175 if (BuildConfig.ENG && !SystemProperties.ALLOW_ANALYTICS_IN_ENG.getValue()) { 176 mAnalytics = StubAnalytics.getInstance(this); 177 } else { 178 mAnalytics = StubAnalytics.getInstance(this); 179 } 180 mTracker = mAnalytics.getDefaultTracker(); 181 getTvInputManagerHelper(); 182 // In SetupFragment, transitions are set in the constructor. Because the fragment can be 183 // created in Activity.onCreate() by the framework, SetupAnimationHelper should be 184 // initialized here before Activity.onCreate() is called. 185 SetupAnimationHelper.initialize(this); 186 187 188 Log.i(TAG, "Started Live TV " + mVersionName); 189 Debug.getTimer(Debug.TAG_START_UP_TIMER).log("finish TvApplication.onCreate"); 190 getPerformanceMonitor().stopTimer(sAppStartTimer, EventNames.APPLICATION_ONCREATE); 191 } 192 setCurrentRunningProcess(boolean isMainProcess)193 private void setCurrentRunningProcess(boolean isMainProcess) { 194 if (mRunningInMainProcess != null) { 195 SoftPreconditions.checkState(isMainProcess == mRunningInMainProcess); 196 return; 197 } 198 Debug.getTimer(Debug.TAG_START_UP_TIMER).log( 199 "start TvApplication.setCurrentRunningProcess"); 200 mRunningInMainProcess = isMainProcess; 201 if (CommonFeatures.DVR.isEnabled(this)) { 202 mDvrStorageStatusManager = new DvrStorageStatusManager(this, mRunningInMainProcess); 203 } 204 new AsyncTask<Void, Void, Void>() { 205 @Override 206 protected Void doInBackground(Void... params) { 207 // Fetch remote config 208 getRemoteConfig().fetch(null); 209 return null; 210 } 211 }.execute(); 212 if (mRunningInMainProcess) { 213 getTvInputManagerHelper().addCallback(new TvInputCallback() { 214 @Override 215 public void onInputAdded(String inputId) { 216 if (Features.TUNER.isEnabled(TvApplication.this) && TextUtils.equals(inputId, 217 TunerTvInputService.getInputId(TvApplication.this))) { 218 TunerInputInfoUtils.updateTunerInputInfo(TvApplication.this); 219 } 220 handleInputCountChanged(); 221 } 222 223 @Override 224 public void onInputRemoved(String inputId) { 225 handleInputCountChanged(); 226 } 227 }); 228 if (Features.TUNER.isEnabled(this)) { 229 // If the tuner input service is added before the app is started, we need to 230 // handle it here. 231 TunerInputInfoUtils.updateTunerInputInfo(TvApplication.this); 232 } 233 if (CommonFeatures.DVR.isEnabled(this)) { 234 mDvrScheduleManager = new DvrScheduleManager(this); 235 mDvrManager = new DvrManager(this); 236 mRecordingScheduler = RecordingScheduler.createScheduler(this); 237 } 238 EpgFetcher.getInstance(this).startRoutineService(); 239 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 240 ChannelPreviewUpdater.getInstance(this).startRoutineService(); 241 RecordedProgramPreviewUpdater.getInstance(this) 242 .updatePreviewDataForRecordedPrograms(); 243 } 244 } 245 Debug.getTimer(Debug.TAG_START_UP_TIMER).log( 246 "finish TvApplication.setCurrentRunningProcess"); 247 } 248 checkTunerServiceOnFirstLaunch()249 private void checkTunerServiceOnFirstLaunch() { 250 SharedPreferences sharedPreferences = this.getSharedPreferences( 251 SharedPreferencesUtils.SHARED_PREF_FEATURES, Context.MODE_PRIVATE); 252 boolean isFirstLaunch = sharedPreferences.getBoolean(PREFERENCE_IS_FIRST_LAUNCH, true); 253 if (isFirstLaunch) { 254 if (DEBUG) Log.d(TAG, "Congratulations, it's the first launch!"); 255 TunerInputController.onCheckingUsbTunerStatus(this, ACTION_APPLICATION_FIRST_LAUNCHED); 256 SharedPreferences.Editor editor = sharedPreferences.edit(); 257 editor.putBoolean(PREFERENCE_IS_FIRST_LAUNCH, false); 258 editor.apply(); 259 } 260 } 261 262 /** 263 * Returns the {@link DvrManager}. 264 */ 265 @Override getDvrManager()266 public DvrManager getDvrManager() { 267 return mDvrManager; 268 } 269 270 /** 271 * Returns the {@link DvrScheduleManager}. 272 */ 273 @Override getDvrScheduleManager()274 public DvrScheduleManager getDvrScheduleManager() { 275 return mDvrScheduleManager; 276 } 277 278 /** 279 * Returns the {@link RecordingScheduler}. 280 */ 281 @Override 282 @Nullable getRecordingScheduler()283 public RecordingScheduler getRecordingScheduler() { 284 return mRecordingScheduler; 285 } 286 287 /** 288 * Returns the {@link DvrWatchedPositionManager}. 289 */ 290 @Override getDvrWatchedPositionManager()291 public DvrWatchedPositionManager getDvrWatchedPositionManager() { 292 if (mDvrWatchedPositionManager == null) { 293 mDvrWatchedPositionManager = new DvrWatchedPositionManager(this); 294 } 295 return mDvrWatchedPositionManager; 296 } 297 298 @Override 299 @TargetApi(Build.VERSION_CODES.N) getInputSessionManager()300 public InputSessionManager getInputSessionManager() { 301 if (mInputSessionManager == null) { 302 mInputSessionManager = new InputSessionManager(this); 303 } 304 return mInputSessionManager; 305 } 306 307 /** 308 * Returns the {@link Analytics}. 309 */ 310 @Override getAnalytics()311 public Analytics getAnalytics() { 312 return mAnalytics; 313 } 314 315 /** 316 * Returns the default tracker. 317 */ 318 @Override getTracker()319 public Tracker getTracker() { 320 return mTracker; 321 } 322 323 /** 324 * Returns {@link ChannelDataManager}. 325 */ 326 @Override getChannelDataManager()327 public ChannelDataManager getChannelDataManager() { 328 if (mChannelDataManager == null) { 329 mChannelDataManager = new ChannelDataManager(this, getTvInputManagerHelper()); 330 mChannelDataManager.start(); 331 } 332 return mChannelDataManager; 333 } 334 335 @Override isChannelDataManagerLoadFinished()336 public boolean isChannelDataManagerLoadFinished() { 337 return mChannelDataManager != null && mChannelDataManager.isDbLoadFinished(); 338 } 339 340 /** 341 * Returns {@link ProgramDataManager}. 342 */ 343 @Override getProgramDataManager()344 public ProgramDataManager getProgramDataManager() { 345 if (mProgramDataManager != null) { 346 return mProgramDataManager; 347 } 348 Utils.runInMainThreadAndWait(new Runnable() { 349 @Override 350 public void run() { 351 if (mProgramDataManager == null) { 352 mProgramDataManager = new ProgramDataManager(TvApplication.this); 353 mProgramDataManager.start(); 354 } 355 } 356 }); 357 return mProgramDataManager; 358 } 359 360 @Override isProgramDataManagerCurrentProgramsLoadFinished()361 public boolean isProgramDataManagerCurrentProgramsLoadFinished() { 362 return mProgramDataManager != null && mProgramDataManager.isCurrentProgramsLoadFinished(); 363 } 364 365 /** 366 * Returns {@link PreviewDataManager}. 367 */ 368 @TargetApi(Build.VERSION_CODES.O) 369 @Override getPreviewDataManager()370 public PreviewDataManager getPreviewDataManager() { 371 if (mPreviewDataManager == null) { 372 mPreviewDataManager = new PreviewDataManager(this); 373 mPreviewDataManager.start(); 374 } 375 return mPreviewDataManager; 376 } 377 378 /** 379 * Returns {@link DvrDataManager}. 380 */ 381 @TargetApi(Build.VERSION_CODES.N) 382 @Override getDvrDataManager()383 public DvrDataManager getDvrDataManager() { 384 if (mDvrDataManager == null) { 385 DvrDataManagerImpl dvrDataManager = new DvrDataManagerImpl(this, Clock.SYSTEM); 386 mDvrDataManager = dvrDataManager; 387 dvrDataManager.start(); 388 } 389 return mDvrDataManager; 390 } 391 392 /** 393 * Returns {@link DvrStorageStatusManager}. 394 */ 395 @TargetApi(Build.VERSION_CODES.N) 396 @Override getDvrStorageStatusManager()397 public DvrStorageStatusManager getDvrStorageStatusManager() { 398 return mDvrStorageStatusManager; 399 } 400 401 /** 402 * Returns {@link TvInputManagerHelper}. 403 */ 404 @Override getTvInputManagerHelper()405 public TvInputManagerHelper getTvInputManagerHelper() { 406 if (mTvInputManagerHelper == null) { 407 mTvInputManagerHelper = new TvInputManagerHelper(this); 408 mTvInputManagerHelper.start(); 409 } 410 return mTvInputManagerHelper; 411 } 412 413 /** 414 * Returns the main activity information. 415 */ 416 @Override getMainActivityWrapper()417 public MainActivityWrapper getMainActivityWrapper() { 418 return mMainActivityWrapper; 419 } 420 421 /** 422 * Returns the {@link AccountHelper}. 423 */ 424 @Override getAccountHelper()425 public AccountHelper getAccountHelper() { 426 if (mAccountHelper == null) { 427 mAccountHelper = new AccountHelper(getApplicationContext()); 428 } 429 return mAccountHelper; 430 } 431 432 @Override getRemoteConfig()433 public RemoteConfig getRemoteConfig() { 434 if (mRemoteConfig == null) { 435 // No need to synchronize this, it does not hurt to create two and throw one away. 436 mRemoteConfig = DefaultConfigManager.createInstance(this).getRemoteConfig(); 437 } 438 return mRemoteConfig; 439 } 440 441 @Override isRunningInMainProcess()442 public boolean isRunningInMainProcess() { 443 return mRunningInMainProcess != null && mRunningInMainProcess; 444 } 445 446 @Override getPerformanceMonitor()447 public PerformanceMonitor getPerformanceMonitor() { 448 if (mPerformanceMonitor == null) { 449 mPerformanceMonitor = StubPerformanceMonitor.initialize(this); 450 } 451 return mPerformanceMonitor; 452 } 453 454 /** 455 * SelectInputActivity is set in {@link SelectInputActivity#onCreate} and cleared in 456 * {@link SelectInputActivity#onDestroy}. 457 */ setSelectInputActivity(SelectInputActivity activity)458 public void setSelectInputActivity(SelectInputActivity activity) { 459 mSelectInputActivity = activity; 460 } 461 handleGuideKey()462 public void handleGuideKey() { 463 if (!mMainActivityWrapper.isResumed()) { 464 startActivity(new Intent(Intent.ACTION_VIEW, TvContract.Programs.CONTENT_URI)); 465 } else { 466 mMainActivityWrapper.getMainActivity().getOverlayManager().toggleProgramGuide(); 467 } 468 } 469 470 /** 471 * Handles the global key KEYCODE_TV. 472 */ handleTvKey()473 public void handleTvKey() { 474 if (!mMainActivityWrapper.isResumed()) { 475 startMainActivity(null); 476 } 477 } 478 479 /** 480 * Handles the global key KEYCODE_TV_INPUT. 481 */ handleTvInputKey()482 public void handleTvInputKey() { 483 TvInputManager tvInputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE); 484 List<TvInputInfo> tvInputs = tvInputManager.getTvInputList(); 485 int inputCount = 0; 486 boolean hasTunerInput = false; 487 for (TvInputInfo input : tvInputs) { 488 if (input.isPassthroughInput()) { 489 if (!input.isHidden(this)) { 490 ++inputCount; 491 } 492 } else if (!hasTunerInput) { 493 hasTunerInput = true; 494 ++inputCount; 495 } 496 } 497 if (inputCount < 2) { 498 return; 499 } 500 Activity activityToHandle = mMainActivityWrapper.isResumed() 501 ? mMainActivityWrapper.getMainActivity() : mSelectInputActivity; 502 if (activityToHandle != null) { 503 // If startActivity is called, MainActivity.onPause is unnecessarily called. To 504 // prevent it, MainActivity.dispatchKeyEvent is directly called. 505 activityToHandle.dispatchKeyEvent( 506 new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_TV_INPUT)); 507 activityToHandle.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, 508 KeyEvent.KEYCODE_TV_INPUT)); 509 } else if (mMainActivityWrapper.isStarted()) { 510 Bundle extras = new Bundle(); 511 extras.putString(Utils.EXTRA_KEY_ACTION, Utils.EXTRA_ACTION_SHOW_TV_INPUT); 512 startMainActivity(extras); 513 } else { 514 startActivity(new Intent(this, SelectInputActivity.class).setFlags( 515 Intent.FLAG_ACTIVITY_NEW_TASK)); 516 } 517 } 518 startMainActivity(Bundle extras)519 private void startMainActivity(Bundle extras) { 520 // The use of FLAG_ACTIVITY_NEW_TASK enables arbitrary applications to access the intent 521 // sent to the root activity. Having said that, we should be fine here since such an intent 522 // does not carry any important user data. 523 Intent intent = new Intent(this, MainActivity.class) 524 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 525 if (extras != null) { 526 intent.putExtras(extras); 527 } 528 startActivity(intent); 529 } 530 531 /** 532 * Returns the version name of the live channels. 533 * 534 * @see PackageInfo#versionName 535 */ getVersionName()536 public String getVersionName() { 537 return mVersionName; 538 } 539 540 /** 541 * Checks the input counts and enable/disable TvActivity. Also updates the input list in 542 * {@link SetupUtils}. 543 */ handleInputCountChanged()544 public void handleInputCountChanged() { 545 handleInputCountChanged(false, false, false); 546 } 547 548 /** 549 * Checks the input counts and enable/disable TvActivity. Also updates the input list in 550 * {@link SetupUtils}. 551 * 552 * @param calledByTunerServiceChanged true if it is called when TunerTvInputService 553 * is enabled or disabled. 554 * @param tunerServiceEnabled it's available only when calledByTunerServiceChanged is true. 555 * @param dontKillApp when TvActivity is enabled or disabled by this method, the app restarts 556 * by default. But, if dontKillApp is true, the app won't restart. 557 */ handleInputCountChanged(boolean calledByTunerServiceChanged, boolean tunerServiceEnabled, boolean dontKillApp)558 public void handleInputCountChanged(boolean calledByTunerServiceChanged, 559 boolean tunerServiceEnabled, boolean dontKillApp) { 560 TvInputManager inputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE); 561 boolean enable = (calledByTunerServiceChanged && tunerServiceEnabled) 562 || Features.UNHIDE.isEnabled(TvApplication.this); 563 if (!enable) { 564 List<TvInputInfo> inputs = inputManager.getTvInputList(); 565 boolean skipTunerInputCheck = false; 566 // Enable the TvActivity only if there is at least one tuner type input. 567 if (!skipTunerInputCheck) { 568 for (TvInputInfo input : inputs) { 569 if (calledByTunerServiceChanged && !tunerServiceEnabled 570 && TunerTvInputService.getInputId(this).equals(input.getId())) { 571 continue; 572 } 573 if (input.getType() == TvInputInfo.TYPE_TUNER) { 574 enable = true; 575 break; 576 } 577 } 578 } 579 if (DEBUG) Log.d(TAG, "Enable MainActivity: " + enable); 580 } 581 PackageManager packageManager = getPackageManager(); 582 ComponentName name = new ComponentName(this, TvActivity.class); 583 int newState = enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 584 PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 585 if (packageManager.getComponentEnabledSetting(name) != newState) { 586 packageManager.setComponentEnabledSetting(name, newState, 587 dontKillApp ? PackageManager.DONT_KILL_APP : 0); 588 Log.i(TAG, (enable ? "Un-hide" : "Hide") + " Live TV."); 589 } 590 SetupUtils.getInstance(TvApplication.this).onInputListUpdated(inputManager); 591 } 592 593 /** 594 * Returns the @{@link ApplicationSingletons} using the application context. 595 */ getSingletons(Context context)596 public static ApplicationSingletons getSingletons(Context context) { 597 // No need to be "synchronized" because this doesn't create any instance. 598 if (sAppSingletons == null) { 599 sAppSingletons = (ApplicationSingletons) context.getApplicationContext(); 600 } 601 return sAppSingletons; 602 } 603 604 /** 605 * Sets true, if TvApplication is running on the main process. If TvApplication runs on 606 * tuner process or other process, it sets false. 607 * 608 * Note: it should be called at the beginning of Service.onCreate Activity.onCreate, or 609 * BroadcastReceiver.onCreate. When it is firstly called after launch, it runs process 610 * specific initializations. 611 */ setCurrentRunningProcess(Context context, boolean isMainProcess)612 public static void setCurrentRunningProcess(Context context, boolean isMainProcess) { 613 // TODO(b/63064354) TvApplication should not have to know if it is "the main process" 614 if (context.getApplicationContext() instanceof TvApplication) { 615 TvApplication tvApplication = (TvApplication) context.getApplicationContext(); 616 tvApplication.setCurrentRunningProcess(isMainProcess); 617 } else { 618 // Application context can be MockTvApplication. 619 Log.w(TAG, "It is not a context of TvApplication"); 620 } 621 } 622 } 623