aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tv/TvApplication.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/tv/TvApplication.java')
-rw-r--r--src/com/android/tv/TvApplication.java162
1 files changed, 141 insertions, 21 deletions
diff --git a/src/com/android/tv/TvApplication.java b/src/com/android/tv/TvApplication.java
index 0e18a259..0c7c0fd1 100644
--- a/src/com/android/tv/TvApplication.java
+++ b/src/com/android/tv/TvApplication.java
@@ -22,16 +22,20 @@ import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.media.tv.TvContract;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
import android.media.tv.TvInputManager.TvInputCallback;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
@@ -49,19 +53,30 @@ import com.android.tv.common.ui.setup.animation.SetupAnimationHelper;
import com.android.tv.config.DefaultConfigManager;
import com.android.tv.config.RemoteConfig;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.PreviewDataManager;
import com.android.tv.data.ProgramDataManager;
+import com.android.tv.data.epg.EpgFetcher;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrDataManagerImpl;
import com.android.tv.dvr.DvrManager;
-import com.android.tv.dvr.DvrRecordingService;
import com.android.tv.dvr.DvrScheduleManager;
import com.android.tv.dvr.DvrStorageStatusManager;
import com.android.tv.dvr.DvrWatchedPositionManager;
+import com.android.tv.dvr.recorder.RecordingScheduler;
+import com.android.tv.perf.EventNames;
+import com.android.tv.perf.PerformanceMonitor;
+import com.android.tv.perf.StubPerformanceMonitor;
+import com.android.tv.perf.TimerEvent;
+import com.android.tv.recommendation.ChannelPreviewUpdater;
+import com.android.tv.recommendation.RecordedProgramPreviewUpdater;
+import com.android.tv.tuner.TunerInputController;
import com.android.tv.tuner.TunerPreferences;
import com.android.tv.tuner.tvinput.TunerTvInputService;
import com.android.tv.tuner.util.TunerInputInfoUtils;
import com.android.tv.util.AccountHelper;
import com.android.tv.util.Clock;
+import com.android.tv.util.Debug;
+import com.android.tv.util.PermissionUtils;
import com.android.tv.util.SetupUtils;
import com.android.tv.util.SystemProperties;
import com.android.tv.util.TvInputManagerHelper;
@@ -72,17 +87,25 @@ import java.util.List;
public class TvApplication extends Application implements ApplicationSingletons {
private static final String TAG = "TvApplication";
private static final boolean DEBUG = false;
- private RemoteConfig mRemoteConfig;
+ private static final TimerEvent sAppStartTimer = StubPerformanceMonitor.startBootstrapTimer();
+
+ /**
+ * An instance of {@link ApplicationSingletons}. Note that this can be set directly only for the
+ * test purpose.
+ */
+ @VisibleForTesting
+ public static ApplicationSingletons sAppSingletons;
/**
* Broadcast Action: The user has updated LC to a new version that supports tuner input.
- * {@link TunerInputController} will recevice this intent to check the existence of tuner
- * input when the new version is first launched.
+ * {@link com.android.tv.tuner.TunerInputController} will recevice this intent to check
+ * the existence of tuner input when the new version is first launched.
*/
public static final String ACTION_APPLICATION_FIRST_LAUNCHED =
"com.android.tv.action.APPLICATION_FIRST_LAUNCHED";
private static final String PREFERENCE_IS_FIRST_LAUNCH = "is_first_launch";
+ private RemoteConfig mRemoteConfig;
private String mVersionName = "";
private final MainActivityWrapper mMainActivityWrapper = new MainActivityWrapper();
@@ -92,21 +115,30 @@ public class TvApplication extends Application implements ApplicationSingletons
private Tracker mTracker;
private TvInputManagerHelper mTvInputManagerHelper;
private ChannelDataManager mChannelDataManager;
- private ProgramDataManager mProgramDataManager;
+ private volatile ProgramDataManager mProgramDataManager;
+ private PreviewDataManager mPreviewDataManager;
private DvrManager mDvrManager;
private DvrScheduleManager mDvrScheduleManager;
private DvrDataManager mDvrDataManager;
private DvrStorageStatusManager mDvrStorageStatusManager;
private DvrWatchedPositionManager mDvrWatchedPositionManager;
+ private RecordingScheduler mRecordingScheduler;
@Nullable
private InputSessionManager mInputSessionManager;
private AccountHelper mAccountHelper;
// When this variable is null, we don't know in which process TvApplication runs.
private Boolean mRunningInMainProcess;
+ private PerformanceMonitor mPerformanceMonitor;
@Override
public void onCreate() {
super.onCreate();
+ if (!PermissionUtils.hasInternet(this)) {
+ // When an isolated process starts, just skip all the initialization.
+ return;
+ }
+ Debug.getTimer(Debug.TAG_START_UP_TIMER).start();
+ Debug.getTimer(Debug.TAG_START_UP_TIMER).log("Start TvApplication.onCreate");
SharedPreferencesUtils.initialize(this, new Runnable() {
@Override
public void run() {
@@ -127,18 +159,15 @@ public class TvApplication extends Application implements ApplicationSingletons
}
Log.i(TAG, "Starting Live TV " + getVersionName());
-
// Only set StrictMode for ENG builds because the build server only produces userdebug
// builds.
if (BuildConfig.ENG && SystemProperties.ALLOW_STRICT_MODE.getValue()) {
StrictMode.ThreadPolicy.Builder threadPolicyBuilder =
new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog();
StrictMode.VmPolicy.Builder vmPolicyBuilder =
- new StrictMode.VmPolicy.Builder().detectAll().penaltyLog();
+ new StrictMode.VmPolicy.Builder().detectAll().penaltyDeath();
if (!TvCommonUtils.isRunningInTest()) {
threadPolicyBuilder.penaltyDialog();
- // Turn off death penalty for tests b/23355898
- vmPolicyBuilder.penaltyDeath();
}
StrictMode.setThreadPolicy(threadPolicyBuilder.build());
StrictMode.setVmPolicy(vmPolicyBuilder.build());
@@ -149,13 +178,16 @@ public class TvApplication extends Application implements ApplicationSingletons
mAnalytics = StubAnalytics.getInstance(this);
}
mTracker = mAnalytics.getDefaultTracker();
- mTvInputManagerHelper = new TvInputManagerHelper(this);
- mTvInputManagerHelper.start();
+ getTvInputManagerHelper();
// In SetupFragment, transitions are set in the constructor. Because the fragment can be
// created in Activity.onCreate() by the framework, SetupAnimationHelper should be
// initialized here before Activity.onCreate() is called.
SetupAnimationHelper.initialize(this);
+
+
Log.i(TAG, "Started Live TV " + mVersionName);
+ Debug.getTimer(Debug.TAG_START_UP_TIMER).log("finish TvApplication.onCreate");
+ getPerformanceMonitor().stopTimer(sAppStartTimer, EventNames.APPLICATION_ONCREATE);
}
private void setCurrentRunningProcess(boolean isMainProcess) {
@@ -163,12 +195,22 @@ public class TvApplication extends Application implements ApplicationSingletons
SoftPreconditions.checkState(isMainProcess == mRunningInMainProcess);
return;
}
+ Debug.getTimer(Debug.TAG_START_UP_TIMER).log(
+ "start TvApplication.setCurrentRunningProcess");
mRunningInMainProcess = isMainProcess;
if (CommonFeatures.DVR.isEnabled(this)) {
mDvrStorageStatusManager = new DvrStorageStatusManager(this, mRunningInMainProcess);
}
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ // Fetch remote config
+ getRemoteConfig().fetch(null);
+ return null;
+ }
+ }.execute();
if (mRunningInMainProcess) {
- mTvInputManagerHelper.addCallback(new TvInputCallback() {
+ getTvInputManagerHelper().addCallback(new TvInputCallback() {
@Override
public void onInputAdded(String inputId) {
if (Features.TUNER.isEnabled(TvApplication.this) && TextUtils.equals(inputId,
@@ -186,15 +228,22 @@ public class TvApplication extends Application implements ApplicationSingletons
if (Features.TUNER.isEnabled(this)) {
// If the tuner input service is added before the app is started, we need to
// handle it here.
- TunerInputInfoUtils.updateTunerInputInfo(this);
+ TunerInputInfoUtils.updateTunerInputInfo(TvApplication.this);
}
if (CommonFeatures.DVR.isEnabled(this)) {
mDvrScheduleManager = new DvrScheduleManager(this);
mDvrManager = new DvrManager(this);
- //NOTE: DvrRecordingService just keeps running.
- DvrRecordingService.startService(this);
+ mRecordingScheduler = RecordingScheduler.createScheduler(this);
+ }
+ EpgFetcher.getInstance(this).startRoutineService();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ ChannelPreviewUpdater.getInstance(this).startRoutineService();
+ RecordedProgramPreviewUpdater.getInstance(this)
+ .updatePreviewDataForRecordedPrograms();
}
}
+ Debug.getTimer(Debug.TAG_START_UP_TIMER).log(
+ "finish TvApplication.setCurrentRunningProcess");
}
private void checkTunerServiceOnFirstLaunch() {
@@ -203,7 +252,7 @@ public class TvApplication extends Application implements ApplicationSingletons
boolean isFirstLaunch = sharedPreferences.getBoolean(PREFERENCE_IS_FIRST_LAUNCH, true);
if (isFirstLaunch) {
if (DEBUG) Log.d(TAG, "Congratulations, it's the first launch!");
- sendBroadcast(new Intent(ACTION_APPLICATION_FIRST_LAUNCHED));
+ TunerInputController.onCheckingUsbTunerStatus(this, ACTION_APPLICATION_FIRST_LAUNCHED);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(PREFERENCE_IS_FIRST_LAUNCH, false);
editor.apply();
@@ -227,6 +276,15 @@ public class TvApplication extends Application implements ApplicationSingletons
}
/**
+ * Returns the {@link RecordingScheduler}.
+ */
+ @Override
+ @Nullable
+ public RecordingScheduler getRecordingScheduler() {
+ return mRecordingScheduler;
+ }
+
+ /**
* Returns the {@link DvrWatchedPositionManager}.
*/
@Override
@@ -268,24 +326,55 @@ public class TvApplication extends Application implements ApplicationSingletons
@Override
public ChannelDataManager getChannelDataManager() {
if (mChannelDataManager == null) {
- mChannelDataManager = new ChannelDataManager(this, mTvInputManagerHelper);
+ mChannelDataManager = new ChannelDataManager(this, getTvInputManagerHelper());
mChannelDataManager.start();
}
return mChannelDataManager;
}
+ @Override
+ public boolean isChannelDataManagerLoadFinished() {
+ return mChannelDataManager != null && mChannelDataManager.isDbLoadFinished();
+ }
+
/**
* Returns {@link ProgramDataManager}.
*/
@Override
public ProgramDataManager getProgramDataManager() {
- if (mProgramDataManager == null) {
- mProgramDataManager = new ProgramDataManager(this);
- mProgramDataManager.start();
+ if (mProgramDataManager != null) {
+ return mProgramDataManager;
}
+ Utils.runInMainThreadAndWait(new Runnable() {
+ @Override
+ public void run() {
+ if (mProgramDataManager == null) {
+ mProgramDataManager = new ProgramDataManager(TvApplication.this);
+ mProgramDataManager.start();
+ }
+ }
+ });
return mProgramDataManager;
}
+ @Override
+ public boolean isProgramDataManagerCurrentProgramsLoadFinished() {
+ return mProgramDataManager != null && mProgramDataManager.isCurrentProgramsLoadFinished();
+ }
+
+ /**
+ * Returns {@link PreviewDataManager}.
+ */
+ @TargetApi(Build.VERSION_CODES.O)
+ @Override
+ public PreviewDataManager getPreviewDataManager() {
+ if (mPreviewDataManager == null) {
+ mPreviewDataManager = new PreviewDataManager(this);
+ mPreviewDataManager.start();
+ }
+ return mPreviewDataManager;
+ }
+
/**
* Returns {@link DvrDataManager}.
*/
@@ -314,6 +403,10 @@ public class TvApplication extends Application implements ApplicationSingletons
*/
@Override
public TvInputManagerHelper getTvInputManagerHelper() {
+ if (mTvInputManagerHelper == null) {
+ mTvInputManagerHelper = new TvInputManagerHelper(this);
+ mTvInputManagerHelper.start();
+ }
return mTvInputManagerHelper;
}
@@ -345,6 +438,19 @@ public class TvApplication extends Application implements ApplicationSingletons
return mRemoteConfig;
}
+ @Override
+ public boolean isRunningInMainProcess() {
+ return mRunningInMainProcess != null && mRunningInMainProcess;
+ }
+
+ @Override
+ public PerformanceMonitor getPerformanceMonitor() {
+ if (mPerformanceMonitor == null) {
+ mPerformanceMonitor = StubPerformanceMonitor.initialize(this);
+ }
+ return mPerformanceMonitor;
+ }
+
/**
* SelectInputActivity is set in {@link SelectInputActivity#onCreate} and cleared in
* {@link SelectInputActivity#onDestroy}.
@@ -353,6 +459,14 @@ public class TvApplication extends Application implements ApplicationSingletons
mSelectInputActivity = activity;
}
+ public void handleGuideKey() {
+ if (!mMainActivityWrapper.isResumed()) {
+ startActivity(new Intent(Intent.ACTION_VIEW, TvContract.Programs.CONTENT_URI));
+ } else {
+ mMainActivityWrapper.getMainActivity().getOverlayManager().toggleProgramGuide();
+ }
+ }
+
/**
* Handles the global key KEYCODE_TV.
*/
@@ -471,6 +585,7 @@ public class TvApplication extends Application implements ApplicationSingletons
if (packageManager.getComponentEnabledSetting(name) != newState) {
packageManager.setComponentEnabledSetting(name, newState,
dontKillApp ? PackageManager.DONT_KILL_APP : 0);
+ Log.i(TAG, (enable ? "Un-hide" : "Hide") + " Live TV.");
}
SetupUtils.getInstance(TvApplication.this).onInputListUpdated(inputManager);
}
@@ -479,7 +594,11 @@ public class TvApplication extends Application implements ApplicationSingletons
* Returns the @{@link ApplicationSingletons} using the application context.
*/
public static ApplicationSingletons getSingletons(Context context) {
- return (ApplicationSingletons) context.getApplicationContext();
+ // No need to be "synchronized" because this doesn't create any instance.
+ if (sAppSingletons == null) {
+ sAppSingletons = (ApplicationSingletons) context.getApplicationContext();
+ }
+ return sAppSingletons;
}
/**
@@ -491,6 +610,7 @@ public class TvApplication extends Application implements ApplicationSingletons
* specific initializations.
*/
public static void setCurrentRunningProcess(Context context, boolean isMainProcess) {
+ // TODO(b/63064354) TvApplication should not have to know if it is "the main process"
if (context.getApplicationContext() instanceof TvApplication) {
TvApplication tvApplication = (TvApplication) context.getApplicationContext();
tvApplication.setCurrentRunningProcess(isMainProcess);