• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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