diff options
Diffstat (limited to 'src/com/android')
130 files changed, 1174 insertions, 630 deletions
diff --git a/src/com/android/tv/LauncherActivity.java b/src/com/android/tv/LauncherActivity.java index 679d612d..ccc5600a 100644 --- a/src/com/android/tv/LauncherActivity.java +++ b/src/com/android/tv/LauncherActivity.java @@ -27,10 +27,10 @@ import android.util.Log; * An activity to launch a new activity. * * <p>In the case when {@link MainActivity} starts a new activity using {@link - * Activity#startActivity} or {@link Activity#startActivityForResult}, Live TV app is - * terminated if the new activity crashes. That's because the {@link android.app.ActivityManager} - * terminates the activity which is just below the crashed activity in the activity stack. To avoid - * this, we need to locate an additional activity between these activities in the activity stack. + * Activity#startActivity} or {@link Activity#startActivityForResult}, TV app is terminated if the + * new activity crashes. That's because the {@link android.app.ActivityManager} terminates the + * activity which is just below the crashed activity in the activity stack. To avoid this, we need + * to locate an additional activity between these activities in the activity stack. */ public class LauncherActivity extends Activity { private static final String TAG = "LauncherActivity"; diff --git a/src/com/android/tv/MainActivity.java b/src/com/android/tv/MainActivity.java index 8718cac8..a018c930 100644 --- a/src/com/android/tv/MainActivity.java +++ b/src/com/android/tv/MainActivity.java @@ -44,6 +44,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.PowerManager; +import android.provider.BaseColumns; import android.provider.Settings; import android.support.annotation.IntDef; import android.support.annotation.NonNull; @@ -110,7 +111,7 @@ import com.android.tv.menu.Menu; import com.android.tv.onboarding.OnboardingActivity; import com.android.tv.parental.ContentRatingsManager; import com.android.tv.parental.ParentalControlSettings; -import com.android.tv.perf.PerformanceMonitorManagerFactory; +import com.android.tv.perf.StartupMeasureFactory; import com.android.tv.receiver.AudioCapabilitiesReceiver; import com.android.tv.recommendation.ChannelPreviewUpdater; import com.android.tv.recommendation.NotificationService; @@ -135,6 +136,7 @@ import com.android.tv.ui.sidepanel.MultiAudioFragment; import com.android.tv.ui.sidepanel.SettingsFragment; import com.android.tv.ui.sidepanel.SideFragment; import com.android.tv.ui.sidepanel.parentalcontrols.ParentalControlsFragment; +import com.android.tv.ui.sidepanel.parentalcontrols.RatingsFragment; import com.android.tv.util.AsyncDbTask; import com.android.tv.util.AsyncDbTask.DbExecutor; import com.android.tv.util.CaptionSettings; @@ -148,11 +150,12 @@ import com.android.tv.util.Utils; import com.android.tv.util.ViewCache; import com.android.tv.util.account.AccountHelper; import com.android.tv.util.images.ImageCache; - import com.google.common.base.Optional; import dagger.android.AndroidInjection; import dagger.android.ContributesAndroidInjector; import com.android.tv.common.flags.BackendKnobsFlags; +import com.android.tv.common.flags.LegacyFlags; +import com.android.tv.common.flags.StartupFlags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayDeque; @@ -166,7 +169,7 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Provider; -/** The main activity for the Live TV app. */ +/** The main activity for the TV app. */ public class MainActivity extends Activity implements OnActionClickListener, OnPinCheckedListener, @@ -258,7 +261,7 @@ public class MainActivity extends Activity private static final long START_UP_TIMER_RESET_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(3); { - PerformanceMonitorManagerFactory.create().getStartupMeasure().onActivityInit(); + StartupMeasureFactory.create().onActivityInit(); } private final MySingletonsImpl mMySingletons = new MySingletonsImpl(); @@ -278,8 +281,11 @@ public class MainActivity extends Activity private DvrManager mDvrManager; private ConflictChecker mDvrConflictChecker; @Inject BackendKnobsFlags mBackendKnobs; + @Inject LegacyFlags mLegacyFlags; + @Inject StartupFlags mStartupFlags; @Inject SetupUtils mSetupUtils; @Inject Optional<BuiltInTunerManager> mOptionalBuiltInTunerManager; + @Inject AccountHelper mAccountHelper; @VisibleForTesting protected TunableTvView mTvView; private View mContentView; @@ -477,7 +483,6 @@ public class MainActivity extends Activity AndroidInjection.inject(this); mAccessibilityManager = (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE); - TvSingletons tvSingletons = TvSingletons.getSingletons(this); DurationTimer startUpDebugTimer = Debug.getTimer(Debug.TAG_START_UP_TIMER); if (!startUpDebugTimer.isStarted() || startUpDebugTimer.getDuration() > START_UP_TIMER_RESET_THRESHOLD_MS) { @@ -496,6 +501,7 @@ public class MainActivity extends Activity finishAndRemoveTask(); return; } + mAccountHelper.init(); TvSingletons tvApplication = (TvSingletons) getApplication(); // In API 23, TvContract.isChannelUriForPassthroughInput is hidden. @@ -514,8 +520,8 @@ public class MainActivity extends Activity return; } setContentView(R.layout.activity_tv); - mTvView = (TunableTvView) findViewById(R.id.main_tunable_tv_view); - mTvView.initialize(mProgramDataManager, mTvInputManagerHelper); + mTvView = findViewById(R.id.main_tunable_tv_view); + mTvView.initialize(mProgramDataManager, mTvInputManagerHelper, mLegacyFlags); mTvView.setOnUnhandledInputEventListener( new OnUnhandledInputEventListener() { @Override @@ -545,6 +551,7 @@ public class MainActivity extends Activity String inputId = Utils.getLastWatchedTunerInputId(this); if (!isPassthroughInput && inputId != null + && !mStartupFlags.warmupInputidBlacklist().getElementList().contains(inputId) && channelId != Channel.INVALID_ID) { mTvView.warmUpInput(inputId, TvContract.buildChannelUri(channelId)); } @@ -612,13 +619,10 @@ public class MainActivity extends Activity } mTvViewUiManager = new TvViewUiManager( - this, - mTvView, - (FrameLayout) findViewById(android.R.id.content), - mTvOptionsManager); + this, mTvView, findViewById(android.R.id.content), mTvOptionsManager); mContentView = findViewById(android.R.id.content); - ViewGroup sceneContainer = (ViewGroup) findViewById(R.id.scene_container); + ViewGroup sceneContainer = findViewById(R.id.scene_container); ChannelBannerView channelBannerView = (ChannelBannerView) getLayoutInflater().inflate(R.layout.channel_banner, sceneContainer, false); @@ -681,7 +685,8 @@ public class MainActivity extends Activity inputBannerView, selectInputView, sceneContainer, - mSearchFragment); + mSearchFragment, + mLegacyFlags); mAccessibilityManager.addAccessibilityStateChangeListener(mOverlayManager); mAudioManagerHelper = new AudioManagerHelper(this, mTvView); @@ -740,7 +745,7 @@ public class MainActivity extends Activity mChannelDataManager.reload(); mProgramDataManager.reload(); - // Restart live channels. + // Restart TV app. Intent intent = getIntent(); finish(); startActivity(intent); @@ -1125,8 +1130,8 @@ public class MainActivity extends Activity Toast.makeText(this, R.string.msg_no_setup_activity, Toast.LENGTH_SHORT).show(); return; } - // Even though other app can handle the intent, the setup launched by Live channels - // should go through Live channels SetupPassthroughActivity. + // Even though other app can handle the intent, the setup launched by TV app + // should go through TV app SetupPassthroughActivity. intent.setComponent(new ComponentName(this, SetupPassthroughActivity.class)); try { // Now we know that the user intends to set up this input. Grant permission for writing @@ -1532,7 +1537,7 @@ public class MainActivity extends Activity String inputId = mInitChannelUri.getQueryParameter("input"); long channelId = Utils.getLastWatchedChannelIdForInput(this, inputId); if (channelId == Channel.INVALID_ID) { - String[] projection = {Channels._ID}; + String[] projection = {BaseColumns._ID}; long time = System.currentTimeMillis(); try (Cursor cursor = getContentResolver().query(uri, projection, null, null, null)) { @@ -2821,10 +2826,10 @@ public class MainActivity extends Activity Debug.getTimer(Debug.TAG_START_UP_TIMER).log("MainActivity.MyOnTuneListener.onTune"); mChannel = channel; mWasUnderShrunkenTvView = wasUnderShrunkenTvView; - - if (mBackendKnobs.enablePartialProgramFetch()) { + if (mBackendKnobs.enablePartialProgramFetch() + || mBackendKnobs.fetchProgramsAsNeeded()) { // Fetch complete projection of tuned channel. - mProgramDataManager.prefetchChannel(channel.getId()); + mProgramDataManager.onChannelTuned(channel.getId()); } } @@ -2980,5 +2985,11 @@ public class MainActivity extends Activity public abstract static class Module { @ContributesAndroidInjector abstract MainActivity contributesMainActivityActivityInjector(); + + @ContributesAndroidInjector + abstract DeveloperOptionFragment contributesDeveloperOptionFragment(); + + @ContributesAndroidInjector + abstract RatingsFragment contributesRatingsFragment(); } } diff --git a/src/com/android/tv/SetupPassthroughActivity.java b/src/com/android/tv/SetupPassthroughActivity.java index 5185b122..95fd93d5 100644 --- a/src/com/android/tv/SetupPassthroughActivity.java +++ b/src/com/android/tv/SetupPassthroughActivity.java @@ -37,7 +37,10 @@ import com.android.tv.util.SetupUtils; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; import com.google.android.tv.partner.support.EpgContract; +import dagger.android.AndroidInjection; +import dagger.android.ContributesAndroidInjector; import java.util.concurrent.TimeUnit; +import javax.inject.Inject; /** * An activity to launch a TV input setup activity. @@ -55,18 +58,19 @@ public class SetupPassthroughActivity extends Activity { private TvInputInfo mTvInputInfo; private Intent mActivityAfterCompletion; private boolean mEpgFetcherDuringScan; - private EpgInputWhiteList mEpgInputWhiteList; + @Inject EpgInputWhiteList mEpgInputWhiteList; + @Inject TvInputManagerHelper mInputManager; + @Inject SetupUtils mSetupUtils; + @Inject ChannelDataManager mChannelDataManager; @Override public void onCreate(Bundle savedInstanceState) { if (DEBUG) Log.d(TAG, "onCreate"); + AndroidInjection.inject(this); super.onCreate(savedInstanceState); - TvSingletons tvSingletons = TvSingletons.getSingletons(this); - TvInputManagerHelper inputManager = tvSingletons.getTvInputManagerHelper(); Intent intent = getIntent(); String inputId = intent.getStringExtra(InputSetupActionUtils.EXTRA_INPUT_ID); - mTvInputInfo = inputManager.getTvInputInfo(inputId); - mEpgInputWhiteList = new EpgInputWhiteList(tvSingletons.getCloudEpgFlags()); + mTvInputInfo = mInputManager.getTvInputInfo(inputId); mActivityAfterCompletion = InputSetupActionUtils.getExtraActivityAfter(intent); boolean needToFetchEpg = mTvInputInfo != null && Utils.isInternalTvInput(this, mTvInputInfo.getId()); @@ -114,7 +118,7 @@ public class SetupPassthroughActivity extends Activity { } if (needToFetchEpg) { if (sScanTimeoutMonitor == null) { - sScanTimeoutMonitor = new ScanTimeoutMonitor(this); + sScanTimeoutMonitor = new ScanTimeoutMonitor(this, mChannelDataManager); } sScanTimeoutMonitor.startMonitoring(); TvSingletons.getSingletons(this).getEpgFetcher().onChannelScanStarted(); @@ -142,6 +146,16 @@ public class SetupPassthroughActivity extends Activity { finish(); return; } + if (TvFeatures.CLOUD_EPG_FOR_3RD_PARTY.isEnabled(this) + && data != null + && data.getBooleanExtra(EpgContract.EXTRA_USE_CLOUD_EPG, false)) { + if (DEBUG) Log.d(TAG, "extra " + data.getExtras()); + String inputId = data.getStringExtra(TvInputInfo.EXTRA_INPUT_ID); + if (mEpgInputWhiteList.isInputWhiteListed(inputId)) { + epgFetcher.fetchImmediately(); + } + } + if (mTvInputInfo == null) { Log.w( TAG, @@ -152,21 +166,19 @@ public class SetupPassthroughActivity extends Activity { finish(); return; } - TvSingletons.getSingletons(this) - .getSetupUtils() - .onTvInputSetupFinished( - mTvInputInfo.getId(), - () -> { - if (mActivityAfterCompletion != null) { - try { - startActivity(mActivityAfterCompletion); - } catch (ActivityNotFoundException e) { - Log.w(TAG, "Activity launch failed", e); - } - } - setResult(resultCode, data); - finish(); - }); + mSetupUtils.onTvInputSetupFinished( + mTvInputInfo.getId(), + () -> { + if (mActivityAfterCompletion != null) { + try { + startActivity(mActivityAfterCompletion); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "Activity launch failed", e); + } + } + setResult(resultCode, data); + finish(); + }); } /** @@ -207,9 +219,9 @@ public class SetupPassthroughActivity extends Activity { }; private boolean mStarted; - private ScanTimeoutMonitor(Context context) { + private ScanTimeoutMonitor(Context context, ChannelDataManager mChannelDataManager) { mContext = context.getApplicationContext(); - mChannelDataManager = TvSingletons.getSingletons(context).getChannelDataManager(); + this.mChannelDataManager = mChannelDataManager; } private void startMonitoring() { @@ -240,4 +252,11 @@ public class SetupPassthroughActivity extends Activity { TvSingletons.getSingletons(mContext).getEpgFetcher().onChannelScanFinished(); } } + + /** Exports {@link MainActivity} for Dagger codegen to create the appropriate injector. */ + @dagger.Module + public abstract static class Module { + @ContributesAndroidInjector + abstract SetupPassthroughActivity contributesSetupPassthroughActivity(); + } } diff --git a/src/com/android/tv/TimeShiftManager.java b/src/com/android/tv/TimeShiftManager.java index 779e8df6..c165af33 100644 --- a/src/com/android/tv/TimeShiftManager.java +++ b/src/com/android/tv/TimeShiftManager.java @@ -50,7 +50,7 @@ import java.util.Queue; import java.util.concurrent.TimeUnit; /** - * A class which manages the time shift feature in Live TV. It consists of two parts. {@link + * A class which manages the time shift feature in TV app. It consists of two parts. {@link * PlayController} controls the playback such as play/pause, rewind and fast-forward using {@link * TunableTvView} which communicates with TvInputService through {@link * android.media.tv.TvInputService.Session}. {@link ProgramManager} loads programs of the current @@ -144,8 +144,8 @@ public class TimeShiftManager { DISABLE_ACTION_THRESHOLD + 3 * REQUEST_CURRENT_POSITION_INTERVAL; /** * The current position sent from TIS can not be exactly the same as the current system time due - * to the elapsed time to pass the message from TIS to Live TV. So the boundary threshold - * is necessary. The same goes for the recording start time. It's the same {@link + * to the elapsed time to pass the message from TIS to TV app. So the boundary threshold is + * necessary. The same goes for the recording start time. It's the same {@link * #REQUEST_CURRENT_POSITION_INTERVAL}. */ private static final long RECORDING_BOUNDARY_THRESHOLD = REQUEST_CURRENT_POSITION_INTERVAL; diff --git a/src/com/android/tv/TvApplication.java b/src/com/android/tv/TvApplication.java index 5f25a24b..65a3d928 100644 --- a/src/com/android/tv/TvApplication.java +++ b/src/com/android/tv/TvApplication.java @@ -47,6 +47,7 @@ import com.android.tv.data.PreviewDataManager; import com.android.tv.data.ProgramDataManager; import com.android.tv.data.epg.EpgFetcher; import com.android.tv.data.epg.EpgFetcherImpl; +import com.android.tv.data.epg.EpgReader; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrDataManagerImpl; import com.android.tv.dvr.DvrManager; @@ -56,8 +57,9 @@ import com.android.tv.dvr.DvrWatchedPositionManager; import com.android.tv.dvr.recorder.RecordingScheduler; import com.android.tv.dvr.ui.browse.DvrBrowseActivity; import com.android.tv.features.TvFeatures; -import com.android.tv.perf.PerformanceMonitorManager; -import com.android.tv.perf.PerformanceMonitorManagerFactory; +import com.android.tv.perf.PerformanceMonitor; +import com.android.tv.perf.StartupMeasure; +import com.android.tv.perf.StartupMeasureFactory; import com.android.tv.recommendation.ChannelPreviewUpdater; import com.android.tv.recommendation.RecordedProgramPreviewUpdater; import com.android.tv.tunerinputcontroller.BuiltInTunerManager; @@ -68,25 +70,23 @@ import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; import com.google.common.base.Optional; import dagger.Lazy; +import com.android.tv.common.flags.CloudEpgFlags; +import com.android.tv.common.flags.LegacyFlags; import java.util.List; import java.util.concurrent.Executor; import javax.inject.Inject; /** - * Live TV application. + * TV application. * * <p>This includes all the Google specific hooks. */ public abstract class TvApplication extends BaseApplication implements TvSingletons, Starter { - protected static final PerformanceMonitorManager PERFORMANCE_MONITOR_MANAGER = - PerformanceMonitorManagerFactory.create(); + protected static final StartupMeasure STARTUP_MEASURE = StartupMeasureFactory.create(); private static final String TAG = "TvApplication"; private static final boolean DEBUG = false; - /** Namespace for LiveChannels configs. LiveChannels configs are kept in piper. */ - public static final String CONFIGNS_P4 = "configns:p4"; - /** * Broadcast Action: The user has updated LC to a new version that supports tuner input. {@link * TunerInputController} will receive this intent to check the existence of tuner input when the @@ -102,7 +102,7 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet private final MainActivityWrapper mMainActivityWrapper = new MainActivityWrapper(); private SelectInputActivity mSelectInputActivity; - private ChannelDataManager mChannelDataManager; + @Inject Lazy<ChannelDataManager> mChannelDataManager; private volatile ProgramDataManager mProgramDataManager; private PreviewDataManager mPreviewDataManager; private DvrManager mDvrManager; @@ -122,6 +122,11 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet @Inject Optional<BuiltInTunerManager> mOptionalBuiltInTunerManager; @Inject SetupUtils mSetupUtils; @Inject @DbExecutor Executor mDbExecutor; + @Inject Lazy<EpgReader> mEpgReader; + @Inject BuildType mBuildType; + @Inject CloudEpgFlags mCloudEpgFlags; + @Inject LegacyFlags mLegacyFlags; + @Inject PerformanceMonitor mPerformanceMonitor; @Override public void onCreate() { @@ -132,6 +137,8 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet throw new IllegalStateException(msg); } super.onCreate(); + mPerformanceMonitor.startMemoryMonitor(); + mPerformanceMonitor.startCrashMonitor(); SharedPreferencesUtils.initialize( this, () -> { @@ -146,16 +153,16 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet Log.w(TAG, "Unable to find package '" + getPackageName() + "'.", e); mVersionName = ""; } - Log.i(TAG, "Starting Live TV " + getVersionName()); + Log.i(TAG, "Starting TV app " + getVersionName()); // 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. - mEpgFetcher = EpgFetcherImpl.create(this); + mEpgFetcher = EpgFetcherImpl.create(this, mCloudEpgFlags, mLegacyFlags); SetupAnimationHelper.initialize(this); getTvInputManagerHelper(); - Log.i(TAG, "Started Live TV " + mVersionName); + Log.i(TAG, "Started TV app " + mVersionName); Debug.getTimer(Debug.TAG_START_UP_TIMER).log("finish TvApplication.onCreate"); } @@ -210,8 +217,10 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet mEpgFetcher.startRoutineService(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ChannelPreviewUpdater.getInstance(this).startRoutineService(); - RecordedProgramPreviewUpdater.getInstance(this) - .updatePreviewDataForRecordedPrograms(); + if (CommonFeatures.DVR.isEnabled(this)) { + RecordedProgramPreviewUpdater.getInstance(this) + .updatePreviewDataForRecordedPrograms(); + } } } Debug.getTimer(Debug.TAG_START_UP_TIMER).log("finish TvApplication.start"); @@ -286,16 +295,12 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet /** Returns {@link ChannelDataManager}. */ @Override public ChannelDataManager getChannelDataManager() { - if (mChannelDataManager == null) { - mChannelDataManager = new ChannelDataManager(this, getTvInputManagerHelper()); - mChannelDataManager.start(); - } - return mChannelDataManager; + return mChannelDataManager.get(); } @Override public boolean isChannelDataManagerLoadFinished() { - return mChannelDataManager != null && mChannelDataManager.isDbLoadFinished(); + return mChannelDataManager.get().isDbLoadFinished(); } /** Returns {@link ProgramDataManager}. */ @@ -351,6 +356,11 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet return mDvrStorageStatusManager; } + @Override + public PerformanceMonitor getPerformanceMonitor() { + return mPerformanceMonitor; + } + /** Returns the main activity information. */ @Override public MainActivityWrapper getMainActivityWrapper() { @@ -450,7 +460,7 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet } /** - * Returns the version name of the live channels. + * Returns the version name of the TV app. * * @see PackageInfo#versionName */ @@ -489,6 +499,37 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet Optional<String> optionalEmbeddedTunerInputId = mOptionalBuiltInTunerManager.transform( BuiltInTunerManager::getEmbeddedTunerInputId); + // If there is only play movies trailer input, we don't handle input count change. + final String playMoviesInputIdPrefix = "com.google.android.videos/"; + int tunerInputCount = 0; + boolean hasPlayMoviesInput = false; + for (TvInputInfo input : inputs) { + if (calledByTunerServiceChanged + && !tunerServiceEnabled + && optionalEmbeddedTunerInputId.isPresent() + && optionalEmbeddedTunerInputId.get().equals(input.getId())) { + continue; + } + if (input.getType() == TvInputInfo.TYPE_TUNER) { + if (DEBUG) Log.d(TAG, "Tuner input: " + input.getId()); + ++tunerInputCount; + if (input.getId().startsWith(playMoviesInputIdPrefix)) { + hasPlayMoviesInput = true; + } + } + } + if (DEBUG) { + Log.d( + TAG, + "Input count: " + + tunerInputCount + + " hasPlayMoviesChannel: " + + hasPlayMoviesInput); + } + if (tunerInputCount == 1 && hasPlayMoviesInput) { + if (DEBUG) Log.d(TAG, "There is only play movies input"); + skipTunerInputCheck = true; + } // Enable the TvActivity only if there is at least one tuner type input. if (!skipTunerInputCheck) { for (TvInputInfo input : inputs) { @@ -515,13 +556,24 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet if (packageManager.getComponentEnabledSetting(name) != newState) { packageManager.setComponentEnabledSetting( name, newState, dontKillApp ? PackageManager.DONT_KILL_APP : 0); - Log.i(TAG, (enable ? "Un-hide" : "Hide") + " Live TV."); + Log.i(TAG, (enable ? "Un-hide" : "Hide") + " TV app."); } mSetupUtils.onInputListUpdated(inputManager); } @Override + @DbExecutor public Executor getDbExecutor() { return mDbExecutor; } + + @Override + public Lazy<EpgReader> providesEpgReader() { + return mEpgReader; + } + + @Override + public BuildType getBuildType() { + return mBuildType; + } } diff --git a/src/com/android/tv/TvSingletons.java b/src/com/android/tv/TvSingletons.java index 20edf3d4..8f9fd25e 100644 --- a/src/com/android/tv/TvSingletons.java +++ b/src/com/android/tv/TvSingletons.java @@ -21,7 +21,6 @@ import com.android.tv.analytics.Analytics; import com.android.tv.analytics.Tracker; import com.android.tv.common.BaseApplication; import com.android.tv.common.BaseSingletons; -import com.android.tv.common.experiments.ExperimentLoader; import com.android.tv.common.flags.has.HasUiFlags; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.PreviewDataManager; @@ -38,9 +37,9 @@ import com.android.tv.tunerinputcontroller.HasBuiltInTunerManager; import com.android.tv.util.SetupUtils; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.account.AccountHelper; +import dagger.Lazy; import com.android.tv.common.flags.BackendKnobsFlags; import java.util.concurrent.Executor; -import javax.inject.Provider; /** Interface with getters for application scoped singletons. */ public interface TvSingletons extends BaseSingletons, HasBuiltInTunerManager, HasUiFlags { @@ -80,6 +79,8 @@ public interface TvSingletons extends BaseSingletons, HasBuiltInTunerManager, Ha PreviewDataManager getPreviewDataManager(); + /** @deprecated use injection instead. */ + @Deprecated DvrDataManager getDvrDataManager(); DvrScheduleManager getDvrScheduleManager(); @@ -88,6 +89,8 @@ public interface TvSingletons extends BaseSingletons, HasBuiltInTunerManager, Ha RecordingScheduler getRecordingScheduler(); + /** @deprecated use injection instead. */ + @Deprecated DvrWatchedPositionManager getDvrWatchedPositionManager(); InputSessionManager getInputSessionManager(); @@ -96,17 +99,21 @@ public interface TvSingletons extends BaseSingletons, HasBuiltInTunerManager, Ha MainActivityWrapper getMainActivityWrapper(); + /** @deprecated use injection instead. */ + @Deprecated AccountHelper getAccountHelper(); boolean isRunningInMainProcess(); + /** @deprecated use injection instead. */ + @Deprecated PerformanceMonitor getPerformanceMonitor(); /** @deprecated use injection instead. */ @Deprecated TvInputManagerHelper getTvInputManagerHelper(); - Provider<EpgReader> providesEpgReader(); + Lazy<EpgReader> providesEpgReader(); EpgFetcher getEpgFetcher(); @@ -114,8 +121,6 @@ public interface TvSingletons extends BaseSingletons, HasBuiltInTunerManager, Ha @Deprecated SetupUtils getSetupUtils(); - ExperimentLoader getExperimentLoader(); - /** @deprecated use injection instead. */ @Deprecated Executor getDbExecutor(); diff --git a/src/com/android/tv/app/LiveTvApplication.java b/src/com/android/tv/app/LiveTvApplication.java index 38e85e48..dcd4a66d 100644 --- a/src/com/android/tv/app/LiveTvApplication.java +++ b/src/com/android/tv/app/LiveTvApplication.java @@ -22,50 +22,35 @@ import com.android.tv.analytics.Analytics; import com.android.tv.analytics.StubAnalytics; import com.android.tv.analytics.Tracker; import com.android.tv.common.dagger.ApplicationModule; -import com.android.tv.common.experiments.ExperimentLoader; import com.android.tv.common.flags.impl.DefaultBackendKnobsFlags; import com.android.tv.common.flags.impl.DefaultCloudEpgFlags; import com.android.tv.common.flags.impl.DefaultConcurrentDvrPlaybackFlags; import com.android.tv.common.flags.impl.DefaultUiFlags; import com.android.tv.common.singletons.HasSingletons; -import com.android.tv.data.epg.EpgReader; -import com.android.tv.data.epg.StubEpgReader; import com.android.tv.modules.TvSingletonsModule; import com.android.tv.perf.PerformanceMonitor; -import com.android.tv.perf.PerformanceMonitorManagerFactory; import com.android.tv.tunerinputcontroller.BuiltInTunerManager; import com.android.tv.util.account.AccountHelper; -import com.android.tv.util.account.AccountHelperImpl; import com.google.common.base.Optional; import dagger.android.AndroidInjector; -import javax.inject.Provider; +import javax.inject.Inject; /** The top level application for Live TV. */ public class LiveTvApplication extends TvApplication implements HasSingletons<TvSingletons> { static { - PERFORMANCE_MONITOR_MANAGER.getStartupMeasure().onAppClassLoaded(); + STARTUP_MEASURE.onAppClassLoaded(); } - private final Provider<EpgReader> mEpgReaderProvider = - new Provider<EpgReader>() { - - @Override - public EpgReader get() { - return new StubEpgReader(LiveTvApplication.this); - } - }; - private final DefaultBackendKnobsFlags mBackendKnobsFlags = new DefaultBackendKnobsFlags(); private final DefaultCloudEpgFlags mCloudEpgFlags = new DefaultCloudEpgFlags(); private final DefaultUiFlags mUiFlags = new DefaultUiFlags(); private final DefaultConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags = new DefaultConcurrentDvrPlaybackFlags(); - private AccountHelper mAccountHelper; + @Inject AccountHelper mAccountHelper; private Analytics mAnalytics; private Tracker mTracker; - private ExperimentLoader mExperimentLoader; - private PerformanceMonitor mPerformanceMonitor; + @Inject PerformanceMonitor mPerformanceMonitor; @Override protected AndroidInjector<LiveTvApplication> applicationInjector() { @@ -78,38 +63,20 @@ public class LiveTvApplication extends TvApplication implements HasSingletons<Tv @Override public void onCreate() { super.onCreate(); - PERFORMANCE_MONITOR_MANAGER.getStartupMeasure().onAppCreate(this); + STARTUP_MEASURE.onAppCreate(this); } - /** Returns the {@link AccountHelperImpl}. */ @Override public AccountHelper getAccountHelper() { - if (mAccountHelper == null) { - mAccountHelper = new AccountHelperImpl(getApplicationContext()); - } return mAccountHelper; } @Override - public synchronized PerformanceMonitor getPerformanceMonitor() { - if (mPerformanceMonitor == null) { - mPerformanceMonitor = PerformanceMonitorManagerFactory.create().initialize(this); - } + public PerformanceMonitor getPerformanceMonitor() { return mPerformanceMonitor; } @Override - public Provider<EpgReader> providesEpgReader() { - return mEpgReaderProvider; - } - - @Override - public ExperimentLoader getExperimentLoader() { - mExperimentLoader = new ExperimentLoader(); - return mExperimentLoader; - } - - @Override public DefaultBackendKnobsFlags getBackendKnobs() { return mBackendKnobsFlags; } @@ -148,11 +115,6 @@ public class LiveTvApplication extends TvApplication implements HasSingletons<Tv } @Override - public BuildType getBuildType() { - return BuildType.AOSP; - } - - @Override public DefaultConcurrentDvrPlaybackFlags getConcurrentDvrPlaybackFlags() { return mConcurrentDvrPlaybackFlags; } diff --git a/src/com/android/tv/app/LiveTvModule.java b/src/com/android/tv/app/LiveTvModule.java index a28749bd..db631bc0 100644 --- a/src/com/android/tv/app/LiveTvModule.java +++ b/src/com/android/tv/app/LiveTvModule.java @@ -16,18 +16,49 @@ package com.android.tv.app; import com.android.tv.common.flags.impl.DefaultFlagsModule; +import com.android.tv.data.epg.EpgReader; +import com.android.tv.data.epg.StubEpgReader; import com.android.tv.modules.TvApplicationModule; +import com.android.tv.perf.PerformanceMonitor; +import com.android.tv.perf.stub.StubPerformanceMonitor; import com.android.tv.tunerinputcontroller.BuiltInTunerManager; +import com.android.tv.ui.sidepanel.DeveloperOptionFragment; +import com.android.tv.util.account.AccountHelper; +import com.android.tv.util.account.AccountHelperImpl; import com.google.common.base.Optional; import dagger.Module; import dagger.Provides; +import javax.inject.Singleton; /** Dagger module for {@link LiveTvApplication}. */ @Module(includes = {DefaultFlagsModule.class, TvApplicationModule.class}) class LiveTvModule { @Provides + static AccountHelper providesAccountHelper(AccountHelperImpl impl) { + return impl; + } + + @Provides + static Optional<DeveloperOptionFragment.AdditionalDeveloperItemsFactory> + providesAdditionalDeveloperItemsFactory() { + return Optional.absent(); + } + + @Provides Optional<BuiltInTunerManager> providesBuiltInTunerManager() { return Optional.absent(); } + + @Provides + @Singleton + PerformanceMonitor providesPerformanceMonitor() { + return new StubPerformanceMonitor(); + } + + @Provides + @Singleton + static EpgReader providesEpgReader(StubEpgReader impl) { + return impl; + } } diff --git a/src/com/android/tv/data/ChannelDataManager.java b/src/com/android/tv/data/ChannelDataManager.java index a5c786cf..67c32309 100644 --- a/src/com/android/tv/data/ChannelDataManager.java +++ b/src/com/android/tv/data/ChannelDataManager.java @@ -37,15 +37,18 @@ import android.support.annotation.VisibleForTesting; import android.util.ArraySet; import android.util.Log; import android.util.MutableInt; -import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.WeakHandler; +import com.android.tv.common.dagger.annotations.ApplicationContext; import com.android.tv.common.util.PermissionUtils; import com.android.tv.common.util.SharedPreferencesUtils; import com.android.tv.data.api.Channel; import com.android.tv.util.AsyncDbTask; +import com.android.tv.util.AsyncDbTask.DbExecutor; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; +import com.google.auto.factory.AutoFactory; +import com.google.auto.factory.Provided; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Collections; @@ -56,6 +59,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.Executor; +import javax.inject.Singleton; /** * The class to manage channel data. Basic features: reading channel list and each channel's current @@ -64,6 +68,8 @@ import java.util.concurrent.Executor; * methods are called in only the main thread. */ @AnyThread +@AutoFactory +@Singleton public class ChannelDataManager { private static final String TAG = "ChannelDataManager"; private static final boolean DEBUG = false; @@ -143,21 +149,11 @@ public class ChannelDataManager { }; @MainThread - public ChannelDataManager(Context context, TvInputManagerHelper inputManager) { - this( - context, - inputManager, - TvSingletons.getSingletons(context).getDbExecutor(), - context.getContentResolver()); - } - - @MainThread - @VisibleForTesting - ChannelDataManager( - Context context, - TvInputManagerHelper inputManager, - Executor executor, - ContentResolver contentResolver) { + public ChannelDataManager( + @Provided @ApplicationContext Context context, + @Provided TvInputManagerHelper inputManager, + @Provided @DbExecutor Executor executor, + @Provided ContentResolver contentResolver) { mContext = context; mInputManager = inputManager; mDbExecutor = executor; @@ -729,7 +725,7 @@ public class ChannelDataManager { /** * Updates a column {@code columnName} of DB table {@code uri} with the value {@code * columnValue}. The selective rows in the ID list {@code ids} will be updated. The DB - * operations will run on {@link TvSingletons#getDbExecutor()}. + * operations will run on @{@link DbExecutor}. */ private void updateOneColumnValue( final String columnName, final int columnValue, final List<Long> ids) { diff --git a/src/com/android/tv/data/PreviewDataManager.java b/src/com/android/tv/data/PreviewDataManager.java index 8616aeec..91aca09a 100644 --- a/src/com/android/tv/data/PreviewDataManager.java +++ b/src/com/android/tv/data/PreviewDataManager.java @@ -36,6 +36,7 @@ import androidx.tvprovider.media.tv.ChannelLogoUtils; import androidx.tvprovider.media.tv.PreviewProgram; import com.android.tv.R; import com.android.tv.common.util.PermissionUtils; +import com.android.tv.util.images.ImageLoader; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.HashMap; @@ -428,10 +429,14 @@ public class PreviewDataManager { continue; } try { + int aspectRatio = + ImageLoader.getAspectRatioFromPosterArtUri( + mContext, program.getPosterArtUri().toString()); Uri programUri = mContentResolver.insert( TvContract.PreviewPrograms.CONTENT_URI, - PreviewDataUtils.createPreviewProgramFromContent(program) + PreviewDataUtils.createPreviewProgramFromContent( + program, aspectRatio) .toContentValues()); if (programUri != null) { long previewProgramId = ContentUris.parseId(programUri); @@ -592,13 +597,14 @@ public class PreviewDataManager { /** Creates a preview program. */ public static PreviewProgram createPreviewProgramFromContent( - PreviewProgramContent program) { + PreviewProgramContent program, int aspectRatio) { PreviewProgram.Builder builder = new PreviewProgram.Builder(); builder.setChannelId(program.getPreviewChannelId()) .setType(program.getType()) .setLive(program.getLive()) .setTitle(program.getTitle()) .setDescription(program.getDescription()) + .setPosterArtAspectRatio(aspectRatio) .setPosterArtUri(program.getPosterArtUri()) .setIntentUri(program.getIntentUri()) .setPreviewVideoUri(program.getPreviewVideoUri()) diff --git a/src/com/android/tv/data/ProgramDataManager.java b/src/com/android/tv/data/ProgramDataManager.java index bd74cf34..8b38060a 100644 --- a/src/com/android/tv/data/ProgramDataManager.java +++ b/src/com/android/tv/data/ProgramDataManager.java @@ -76,6 +76,11 @@ public class ProgramDataManager implements MemoryManageable { private static final long CURRENT_PROGRAM_UPDATE_WAIT_MS = TimeUnit.SECONDS.toMillis(5); @VisibleForTesting static final long PROGRAM_GUIDE_SNAP_TIME_MS = TimeUnit.MINUTES.toMillis(30); + // Default fetch hours + private static final long FETCH_HOURS_MS = TimeUnit.HOURS.toMillis(24); + // Load data earlier for smooth scrolling. + private static final long BUFFER_HOURS_MS = TimeUnit.HOURS.toMillis(6); + // TODO: Use TvContract constants, once they become public. private static final String PARAM_START_TIME = "start_time"; private static final String PARAM_END_TIME = "end_time"; @@ -128,6 +133,11 @@ public class ProgramDataManager implements MemoryManageable { private boolean mPauseProgramUpdate = false; private final LruCache<Long, Program> mZeroLengthProgramCache = new LruCache<>(10); + // Current tuned channel. + private long mTunedChannelId; + // Hours of data to be fetched, it is updated during horizontal scroll. + // Note that it should never exceed programGuideMaxHours. + private long mMaxFetchHoursMs = FETCH_HOURS_MS; @MainThread public ProgramDataManager(Context context) { @@ -266,17 +276,79 @@ public class ProgramDataManager implements MemoryManageable { } } - public void prefetchChannel(long channelId) { - if (mCompleteInfoChannelIds.add(channelId)) { - long startTimeMs = - Utils.floorTime( - mClock.currentTimeMillis() - PROGRAM_GUIDE_SNAP_TIME_MS, - PROGRAM_GUIDE_SNAP_TIME_MS); - long endTimeMs = startTimeMs + TimeUnit.HOURS.toMillis(getFetchDuration()); - new SingleChannelPrefetchTask(channelId, startTimeMs, endTimeMs).executeOnDbThread(); + /** + * Prefetch program data if needed. + * + * @param channelId ID of the channel to prefetch + * @param selectedProgramIndex index of selected program. + */ + public void prefetchChannel(long channelId, int selectedProgramIndex) { + long startTimeMs = + Utils.floorTime( + mClock.currentTimeMillis() - PROGRAM_GUIDE_SNAP_TIME_MS, + PROGRAM_GUIDE_SNAP_TIME_MS); + + if (!mBackendKnobsFlags.fetchProgramsAsNeeded()) { + if (mCompleteInfoChannelIds.add(channelId)) { + long endTimeMs = startTimeMs + TimeUnit.HOURS.toMillis(getFetchDuration()); + mCompleteInfoChannelIds.clear(); + new SingleChannelPrefetchTask(channelId, startTimeMs, endTimeMs) + .executeOnDbThread(); + } + } else { + long programGuideMaxHoursMs = + TimeUnit.HOURS.toMillis(mBackendKnobsFlags.programGuideMaxHours()); + long endTimeMs = 0; + if (mMaxFetchHoursMs < programGuideMaxHoursMs + && isHorizontalLoadNeeded(startTimeMs, channelId, selectedProgramIndex)) { + // Horizontal scrolling needs to load data of further days. + mMaxFetchHoursMs = + Math.min(programGuideMaxHoursMs, mMaxFetchHoursMs + FETCH_HOURS_MS); + mCompleteInfoChannelIds.clear(); + } + // Load max hours complete data for first channel. + if (mCompleteInfoChannelIds.isEmpty()) { + endTimeMs = startTimeMs + programGuideMaxHoursMs; + } else if (!mCompleteInfoChannelIds.contains(channelId)) { + endTimeMs = startTimeMs + mMaxFetchHoursMs; + } + + if (endTimeMs > 0) { + mCompleteInfoChannelIds.add(channelId); + new SingleChannelPrefetchTask(channelId, startTimeMs, endTimeMs) + .executeOnDbThread(); + } } } + /** + * Check if enough data is present for horizontal scroll, otherwise prefetch programs. + * + * <p>If end time of current program is past {@code BUFFER_HOURS_MS} less than the fetched time + * we need to prefetch proceeding programs. + * + * @param startTimeMs Fetch start time, it is used to get fetch end time. + * @param channelId + * @param selectedProgramIndex + * @return {@code true} If data load is needed, else {@code false}. + */ + private boolean isHorizontalLoadNeeded( + long startTimeMs, long channelId, int selectedProgramIndex) { + long marginEndTime = startTimeMs + mMaxFetchHoursMs - BUFFER_HOURS_MS; + return (mChannelIdProgramCache.containsKey(channelId) + && mChannelIdProgramCache.get(channelId).size() > selectedProgramIndex + && mChannelIdProgramCache + .get(channelId) + .get(selectedProgramIndex) + .getEndTimeUtcMillis() + > marginEndTime); + } + + public void onChannelTuned(long channelId) { + mTunedChannelId = channelId; + prefetchChannel(channelId, 0); + } + /** A Callback interface to receive notification on program data retrieval from DB. */ public interface Callback { /** @@ -293,6 +365,12 @@ public class ProgramDataManager implements MemoryManageable { * @param channelId */ void onSingleChannelUpdated(long channelId); + + /** + * Called when we update program data during scrolling. Data is loaded from DB on request + * basis. It loads data based on horizontal scrolling as well. + */ + void onChannelUpdated(); } /** Adds the {@link Callback}. */ @@ -319,7 +397,7 @@ public class ProgramDataManager implements MemoryManageable { } else { mPrefetchEnabled = false; cancelPrefetchTask(); - mChannelIdProgramCache.clear(); + clearChannelInfoMap(); mHandler.removeMessages(MSG_UPDATE_PREFETCH_PROGRAM); } } @@ -548,6 +626,7 @@ public class ProgramDataManager implements MemoryManageable { String[] projection = mBackendKnobsFlags.enablePartialProgramFetch() + || mBackendKnobsFlags.fetchProgramsAsNeeded() ? Program.PARTIAL_PROJECTION : Program.PROJECTION; if (TvProviderUtils.checkSeriesIdColumn(mContext, Programs.CONTENT_URI)) { @@ -636,13 +715,19 @@ public class ProgramDataManager implements MemoryManageable { PROGRAM_GUIDE_SNAP_TIME_MS) - currentTime; // Issue second pre-fetch immediately after the first partial update - if (mChannelIdProgramCache.isEmpty()) { + if (!mBackendKnobsFlags.fetchProgramsAsNeeded() + && mChannelIdProgramCache.isEmpty()) { nextMessageDelayedTime = 0; } mChannelIdProgramCache = programs; - if (mBackendKnobsFlags.enablePartialProgramFetch()) { + if (mBackendKnobsFlags.enablePartialProgramFetch() + || mBackendKnobsFlags.fetchProgramsAsNeeded()) { // Since cache has partial data we need to reset the map of complete data. - mCompleteInfoChannelIds.clear(); + clearChannelInfoMap(); + // Get complete projection of tuned channel. + if (mBackendKnobsFlags.fetchProgramsAsNeeded()) { + prefetchChannel(mTunedChannelId, 0); + } } notifyProgramUpdated(); if (mFromEmptyCacheTimeEvent != null) { @@ -661,6 +746,11 @@ public class ProgramDataManager implements MemoryManageable { } } + private void clearChannelInfoMap() { + mCompleteInfoChannelIds.clear(); + mMaxFetchHoursMs = FETCH_HOURS_MS; + } + private long getFetchDuration() { if (mChannelIdProgramCache.isEmpty()) { return Math.max(1L, mBackendKnobsFlags.programGuideInitialFetchHours()); @@ -712,7 +802,11 @@ public class ProgramDataManager implements MemoryManageable { @Override protected void onPostExecute(ArrayList<Program> programs) { mChannelIdProgramCache.put(mChannelId, programs); - notifySingleChannelUpdated(mChannelId); + if (mBackendKnobsFlags.fetchProgramsAsNeeded()) { + notifyChannelUpdated(); + } else { + notifySingleChannelUpdated(mChannelId); + } } } @@ -728,6 +822,12 @@ public class ProgramDataManager implements MemoryManageable { } } + private void notifyChannelUpdated() { + for (Callback callback : mCallbacks) { + callback.onChannelUpdated(); + } + } + private class ProgramsUpdateTask extends AsyncDbTask.AsyncQueryTask<List<Program>> { public ProgramsUpdateTask(long time) { super( diff --git a/src/com/android/tv/data/epg/EpgFetcherImpl.java b/src/com/android/tv/data/epg/EpgFetcherImpl.java index b191421f..b40ce0d2 100644 --- a/src/com/android/tv/data/epg/EpgFetcherImpl.java +++ b/src/com/android/tv/data/epg/EpgFetcherImpl.java @@ -63,6 +63,8 @@ import com.google.android.tv.partner.support.EpgInput; import com.google.android.tv.partner.support.EpgInputs; import com.google.common.collect.ImmutableSet; import com.android.tv.common.flags.BackendKnobsFlags; +import com.android.tv.common.flags.CloudEpgFlags; +import com.android.tv.common.flags.LegacyFlags; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -130,15 +132,15 @@ public class EpgFetcherImpl implements EpgFetcher { private Clock mClock; - public static EpgFetcher create(Context context) { + public static EpgFetcher create( + Context context, CloudEpgFlags cloudEpgFlags, LegacyFlags legacyFlags) { context = context.getApplicationContext(); TvSingletons tvSingletons = TvSingletons.getSingletons(context); ChannelDataManager channelDataManager = tvSingletons.getChannelDataManager(); PerformanceMonitor performanceMonitor = tvSingletons.getPerformanceMonitor(); EpgReader epgReader = tvSingletons.providesEpgReader().get(); Clock clock = tvSingletons.getClock(); - EpgInputWhiteList epgInputWhiteList = - new EpgInputWhiteList(tvSingletons.getCloudEpgFlags()); + EpgInputWhiteList epgInputWhiteList = new EpgInputWhiteList(cloudEpgFlags, legacyFlags); BackendKnobsFlags backendKnobsFlags = tvSingletons.getBackendKnobs(); HasBuildType.BuildType buildType = tvSingletons.getBuildType(); return new EpgFetcherImpl( @@ -604,6 +606,7 @@ public class EpgFetcherImpl implements EpgFetcher { ? ((Integer) REASON_CLOUD_EPG_FAILURE) : anyCloudEpgSuccess ? null : builtInResult; } + clearUnusedLineups(null); return builtInResult; } finally { TrafficStats.setThreadStatsTag(oldTag); diff --git a/src/com/android/tv/data/epg/EpgInputWhiteList.java b/src/com/android/tv/data/epg/EpgInputWhiteList.java index 24b4fe3d..4a5f98bb 100644 --- a/src/com/android/tv/data/epg/EpgInputWhiteList.java +++ b/src/com/android/tv/data/epg/EpgInputWhiteList.java @@ -21,13 +21,14 @@ import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; import com.android.tv.common.BuildConfig; -import com.android.tv.common.experiments.Experiments; import com.android.tv.common.flags.CloudEpgFlags; +import com.android.tv.common.flags.LegacyFlags; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import javax.inject.Inject; /** Checks if a package or a input is white listed. */ public final class EpgInputWhiteList { @@ -36,6 +37,7 @@ public final class EpgInputWhiteList { private static final String QA_DEV_INPUTS = "com.example.partnersupportsampletvinput/.SampleTvInputService," + "com.android.tv.tuner.sample.dvb/.tvinput.SampleDvbTunerTvInputService"; + private final LegacyFlags mLegacyFlags; /** Returns the package portion of a inputId */ @Nullable @@ -43,10 +45,12 @@ public final class EpgInputWhiteList { return inputId == null ? null : inputId.substring(0, inputId.indexOf("/")); } - private final CloudEpgFlags cloudEpgFlags; + private final CloudEpgFlags mCloudEpgFlags; - public EpgInputWhiteList(CloudEpgFlags cloudEpgFlags) { - this.cloudEpgFlags = cloudEpgFlags; + @Inject + public EpgInputWhiteList(CloudEpgFlags cloudEpgFlags, LegacyFlags legacyFlags) { + mCloudEpgFlags = cloudEpgFlags; + mLegacyFlags = legacyFlags; } public boolean isInputWhiteListed(String inputId) { @@ -71,8 +75,8 @@ public final class EpgInputWhiteList { } private Set<String> getWhiteListedInputs() { - Set<String> result = toInputSet(cloudEpgFlags.thirdPartyEpgInputsCsv()); - if (BuildConfig.ENG || Experiments.ENABLE_QA_FEATURES.get()) { + Set<String> result = toInputSet(mCloudEpgFlags.thirdPartyEpgInputsCsv()); + if (BuildConfig.ENG || mLegacyFlags.enableQaFeatures()) { HashSet<String> moreInputs = new HashSet<>(toInputSet(QA_DEV_INPUTS)); if (result.isEmpty()) { result = moreInputs; diff --git a/src/com/android/tv/data/epg/StubEpgReader.java b/src/com/android/tv/data/epg/StubEpgReader.java index 3b001481..bb069dba 100644 --- a/src/com/android/tv/data/epg/StubEpgReader.java +++ b/src/com/android/tv/data/epg/StubEpgReader.java @@ -16,7 +16,6 @@ package com.android.tv.data.epg; -import android.content.Context; import android.support.annotation.NonNull; import com.android.tv.data.Lineup; import com.android.tv.data.Program; @@ -27,10 +26,12 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; +import javax.inject.Inject; /** A stub class to read EPG. */ public class StubEpgReader implements EpgReader { - public StubEpgReader(@SuppressWarnings("unused") Context context) {} + @Inject + public StubEpgReader() {} @Override public boolean isAvailable() { diff --git a/src/com/android/tv/dialog/PinDialogFragment.java b/src/com/android/tv/dialog/PinDialogFragment.java index 87308093..ad245fad 100644 --- a/src/com/android/tv/dialog/PinDialogFragment.java +++ b/src/com/android/tv/dialog/PinDialogFragment.java @@ -18,6 +18,7 @@ package com.android.tv.dialog; import android.app.ActivityManager; import android.app.Dialog; +import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.media.tv.TvContentRating; @@ -33,10 +34,14 @@ import android.view.ViewGroup.LayoutParams; import android.widget.TextView; import android.widget.Toast; import com.android.tv.R; -import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.dialog.picker.PinPicker; +import com.android.tv.dialog.picker.TvPinPicker; +import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.TvSettings; +import dagger.android.AndroidInjection; +import com.android.tv.common.flags.UiFlags; +import javax.inject.Inject; public class PinDialogFragment extends SafeDismissDialogFragment { private static final String TAG = "PinDialogFragment"; @@ -80,7 +85,9 @@ public class PinDialogFragment extends SafeDismissDialogFragment { private TextView mWrongPinView; private View mEnterPinView; private TextView mTitleView; + private PinPicker mPicker; + private TvPinPicker mTvPinPicker; private SharedPreferences mSharedPreferences; private String mPrevPin; private String mPin; @@ -88,6 +95,8 @@ public class PinDialogFragment extends SafeDismissDialogFragment { private int mWrongPinCount; private long mDisablePinUntil; private final Handler mHandler = new Handler(); + @Inject TvInputManagerHelper mTvInputManagerHelper; + @Inject UiFlags mUiFlags; public static PinDialogFragment create(int type) { return create(type, null); @@ -103,6 +112,12 @@ public class PinDialogFragment extends SafeDismissDialogFragment { } @Override + public void onAttach(Context context) { + AndroidInjection.inject(this); + super.onAttach(context); + } + + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mRequestType = getArguments().getInt(ARGS_TYPE, PIN_DIALOG_TYPE_ENTER_PIN); @@ -155,13 +170,26 @@ public class PinDialogFragment extends SafeDismissDialogFragment { mEnterPinView = v.findViewById(R.id.enter_pin); mTitleView = (TextView) mEnterPinView.findViewById(R.id.title); mPicker = v.findViewById(R.id.pin_picker); - mPicker.setOnClickListener( - view -> { - String pin = getPinInput(); - if (!TextUtils.isEmpty(pin)) { - done(pin); - } - }); + mTvPinPicker = v.findViewById(R.id.tv_pin_picker); + if (!mUiFlags.useLeanbackPinPicker()) { + mTvPinPicker.setVisibility(View.GONE); + mPicker.setOnClickListener( + view -> { + String pin = getPinInput(); + if (!TextUtils.isEmpty(pin)) { + done(pin); + } + }); + } else { + mPicker.setVisibility(View.GONE); + mTvPinPicker.setOnClickListener( + view -> { + String pin = getPinInput(); + if (!TextUtils.isEmpty(pin)) { + done(pin); + } + }); + } if (TextUtils.isEmpty(getPin())) { // If PIN isn't set, user should set a PIN. // Successfully setting a new set is considered as entering correct PIN. @@ -183,8 +211,7 @@ public class PinDialogFragment extends SafeDismissDialogFragment { mTitleView.setText( getString( R.string.pin_enter_unlock_dvr, - TvSingletons.getSingletons(getContext()) - .getTvInputManagerHelper() + mTvInputManagerHelper .getContentRatingsManager() .getDisplayNameForRating(tvContentRating))); } @@ -204,7 +231,11 @@ public class PinDialogFragment extends SafeDismissDialogFragment { if (mType != PIN_DIALOG_TYPE_NEW_PIN) { updateWrongPin(); } - mPicker.requestFocus(); + if (!mUiFlags.useLeanbackPinPicker()) { + mPicker.requestFocus(); + } else { + mTvPinPicker.requestFocus(); + } return v; } @@ -338,11 +369,15 @@ public class PinDialogFragment extends SafeDismissDialogFragment { } private String getPinInput() { - return mPicker.getPinInput(); + return (mUiFlags.useLeanbackPinPicker() ? mTvPinPicker.getPin() : mPicker.getPinInput()); } private void resetPinInput() { - mPicker.resetPinInput(); + if (!mUiFlags.useLeanbackPinPicker()) { + mPicker.resetPinInput(); + } else { + mTvPinPicker.resetPin(); + } } /** diff --git a/src/com/android/tv/dialog/picker/PinPicker.java b/src/com/android/tv/dialog/picker/PinPicker.java index f501dfd1..7af62585 100644 --- a/src/com/android/tv/dialog/picker/PinPicker.java +++ b/src/com/android/tv/dialog/picker/PinPicker.java @@ -15,15 +15,18 @@ */ package com.android.tv.dialog.picker; +import static android.content.Context.ACCESSIBILITY_SERVICE; + import android.content.Context; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; -import android.support.v17.leanback.widget.picker.Picker; -import android.support.v17.leanback.widget.picker.PickerColumn; +import androidx.leanback.widget.picker.Picker; +import androidx.leanback.widget.picker.PickerColumn; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityManager; import java.util.ArrayList; import java.util.List; @@ -33,6 +36,8 @@ public final class PinPicker extends Picker { private final List<PickerColumn> mPickers = new ArrayList<>(); private OnClickListener mOnClickListener; + private boolean mSkipPerformClick = true; + private boolean mIsAccessibilityEnabled = false; // the version of picker I link to does not have this constructor public PinPicker(Context context, AttributeSet attributeSet) { @@ -53,6 +58,9 @@ public final class PinPicker extends Picker { setColumns(mPickers); setActivated(true); setFocusable(true); + AccessibilityManager am = + (AccessibilityManager) context.getSystemService(ACCESSIBILITY_SERVICE); + mIsAccessibilityEnabled = am.isEnabled(); super.setOnClickListener(this::onClick); } @@ -76,6 +84,12 @@ public final class PinPicker extends Picker { private void onClick(View v) { int selectedColumn = getSelectedColumn(); + // (b/120096347) Skip first click when talkback is enabled + if (mSkipPerformClick && mIsAccessibilityEnabled) { + mSkipPerformClick = false; + /* Force focus to next value */ + setColumnValue(selectedColumn, 1, true); + } int nextColumn = selectedColumn + 1; // Only call the click listener if we are on the last column // Otherwise move to the next column diff --git a/src/com/android/tv/dialog/picker/TvPinPicker.java b/src/com/android/tv/dialog/picker/TvPinPicker.java new file mode 100644 index 00000000..064b7f02 --- /dev/null +++ b/src/com/android/tv/dialog/picker/TvPinPicker.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tv.dialog.picker; + +import static android.content.Context.ACCESSIBILITY_SERVICE; + +import android.content.Context; +import androidx.leanback.widget.picker.PinPicker; +import android.util.AttributeSet; +import android.view.accessibility.AccessibilityManager; + +/** 4 digit picker */ +public final class TvPinPicker extends PinPicker { + + private boolean mSkipPerformClick = true; + private boolean mIsAccessibilityEnabled = false; + + public TvPinPicker(Context context, AttributeSet attributeSet) { + this(context, attributeSet, 0); + } + + public TvPinPicker(Context context, AttributeSet attributeSet, int defStyleAttr) { + super(context, attributeSet, defStyleAttr); + setActivated(true); + AccessibilityManager am = + (AccessibilityManager) context.getSystemService(ACCESSIBILITY_SERVICE); + mIsAccessibilityEnabled = am.isEnabled(); + } + + @Override + public boolean performClick() { + // (b/120096347) Skip first click when talkback is enabled + if (mSkipPerformClick && mIsAccessibilityEnabled) { + mSkipPerformClick = false; + /* Force focus to next value */ + setColumnValue(getSelectedColumn(), 1, true); + return false; + } + return super.performClick(); + } +} diff --git a/src/com/android/tv/dvr/data/ScheduledRecording.java b/src/com/android/tv/dvr/data/ScheduledRecording.java index ba6d3cf9..7833f6f3 100644 --- a/src/com/android/tv/dvr/data/ScheduledRecording.java +++ b/src/com/android/tv/dvr/data/ScheduledRecording.java @@ -492,7 +492,7 @@ public final class ScheduledRecording implements Parcelable { } }; - /** The ID internal to Live TV */ + /** The ID internal to TV app */ private long mId; /** diff --git a/src/com/android/tv/dvr/provider/DvrContract.java b/src/com/android/tv/dvr/provider/DvrContract.java index a5f2e2cd..8539ae36 100644 --- a/src/com/android/tv/dvr/provider/DvrContract.java +++ b/src/com/android/tv/dvr/provider/DvrContract.java @@ -20,7 +20,7 @@ import android.provider.BaseColumns; /** * The contract between the DVR provider and applications. Contains definitions for the supported - * columns. It's for the internal use in Live TV. + * columns. It's for the internal use in TV app. */ public final class DvrContract { /** Column definition for Schedules table. */ @@ -69,8 +69,8 @@ public final class DvrContract { public static final String FAILED_REASON_INVALID_CHANNEL = "FAILED_REASON_INVALID_CHANNEL"; /** The recording failed because the scheduler was stopped */ - public static final String FAILED_REASON_SCHEDULER_STOPPED - = "FAILED_REASON_SCHEDULER_STOPPED"; + public static final String FAILED_REASON_SCHEDULER_STOPPED = + "FAILED_REASON_SCHEDULER_STOPPED"; /** The recording failed because some messages were not sent to the message queue */ public static final String FAILED_REASON_MESSAGE_NOT_SENT = @@ -84,8 +84,7 @@ public final class DvrContract { "FAILED_REASON_CONNECTION_FAILED"; /** - * The recording failed because a required recording resource was not able to be - * allocated. + * The recording failed because a required recording resource was not able to be allocated. */ public static final String FAILED_REASON_RESOURCE_BUSY = "FAILED_REASON_RESOURCE_BUSY"; diff --git a/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java b/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java index 696038cf..e8f077ca 100644 --- a/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java +++ b/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java @@ -43,6 +43,7 @@ import com.android.tv.dvr.data.SeasonEpisodeNumber; import com.android.tv.dvr.data.SeriesInfo; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.provider.EpisodicProgramLoadTask; +import dagger.Lazy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -54,7 +55,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import javax.inject.Provider; /** * Creates the {@link com.android.tv.dvr.data.ScheduledRecording}s for the {@link @@ -529,10 +529,9 @@ public class SeriesRecordingScheduler { private class FetchSeriesInfoTask extends AsyncTask<Void, Void, SeriesInfo> { private final SeriesRecording mSeriesRecording; - private final Provider<EpgReader> mEpgReaderProvider; + private final Lazy<EpgReader> mEpgReaderProvider; - FetchSeriesInfoTask( - SeriesRecording seriesRecording, Provider<EpgReader> epgReaderProvider) { + FetchSeriesInfoTask(SeriesRecording seriesRecording, Lazy<EpgReader> epgReaderProvider) { mSeriesRecording = seriesRecording; mEpgReaderProvider = epgReaderProvider; } diff --git a/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java b/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java index 5e3caa9c..a0daf5e7 100644 --- a/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java +++ b/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java @@ -22,8 +22,8 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.v17.leanback.widget.GuidanceStylist.Guidance; -import android.support.v17.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidanceStylist.Guidance; +import androidx.leanback.widget.GuidedAction; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.data.Program; diff --git a/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java b/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java index a6bbe137..bde896a8 100644 --- a/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java +++ b/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java @@ -22,8 +22,8 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.v17.leanback.widget.GuidanceStylist.Guidance; -import android.support.v17.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidanceStylist.Guidance; +import androidx.leanback.widget.GuidedAction; import android.text.format.DateUtils; import com.android.tv.R; import com.android.tv.TvSingletons; diff --git a/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java b/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java index 6be35cb2..b24281ad 100644 --- a/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java +++ b/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java @@ -18,9 +18,9 @@ package com.android.tv.dvr.ui; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.support.v17.leanback.app.GuidedStepFragment; -import android.support.v17.leanback.widget.GuidanceStylist.Guidance; -import android.support.v17.leanback.widget.GuidedAction; +import androidx.leanback.app.GuidedStepFragment; +import androidx.leanback.widget.GuidanceStylist.Guidance; +import androidx.leanback.widget.GuidedAction; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; diff --git a/src/com/android/tv/dvr/ui/DvrConflictFragment.java b/src/com/android/tv/dvr/ui/DvrConflictFragment.java index 649cc89a..31ef7339 100644 --- a/src/com/android/tv/dvr/ui/DvrConflictFragment.java +++ b/src/com/android/tv/dvr/ui/DvrConflictFragment.java @@ -21,8 +21,8 @@ import android.media.tv.TvInputInfo; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v17.leanback.widget.GuidanceStylist.Guidance; -import android.support.v17.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidanceStylist.Guidance; +import androidx.leanback.widget.GuidedAction; import android.util.Log; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java b/src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java index 611962d0..81fc3ed5 100644 --- a/src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java +++ b/src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java @@ -17,8 +17,8 @@ package com.android.tv.dvr.ui; import android.content.Context; -import android.support.v17.leanback.app.GuidedStepFragment; -import android.support.v17.leanback.widget.GuidedActionsStylist; +import androidx.leanback.app.GuidedStepFragment; +import androidx.leanback.widget.GuidedActionsStylist; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java b/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java index a900cc70..fda4cdee 100644 --- a/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java +++ b/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java @@ -20,9 +20,9 @@ import android.app.Activity; import android.app.DialogFragment; import android.content.Context; import android.os.Bundle; -import android.support.v17.leanback.widget.GuidanceStylist; -import android.support.v17.leanback.widget.GuidedAction; -import android.support.v17.leanback.widget.VerticalGridView; +import androidx.leanback.widget.GuidanceStylist; +import androidx.leanback.widget.GuidedAction; +import androidx.leanback.widget.VerticalGridView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java b/src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java index e6b54f67..608a5f8e 100644 --- a/src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java +++ b/src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java @@ -20,7 +20,7 @@ import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; -import android.support.v17.leanback.app.GuidedStepFragment; +import androidx.leanback.app.GuidedStepFragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java b/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java index 6fba4d98..01631b99 100644 --- a/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java +++ b/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java @@ -20,8 +20,8 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.v17.leanback.widget.GuidanceStylist.Guidance; -import android.support.v17.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidanceStylist.Guidance; +import androidx.leanback.widget.GuidedAction; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; diff --git a/src/com/android/tv/dvr/ui/DvrMissingStorageErrorFragment.java b/src/com/android/tv/dvr/ui/DvrMissingStorageErrorFragment.java index 02b2da1d..3237acd7 100644 --- a/src/com/android/tv/dvr/ui/DvrMissingStorageErrorFragment.java +++ b/src/com/android/tv/dvr/ui/DvrMissingStorageErrorFragment.java @@ -21,8 +21,8 @@ import android.content.ActivityNotFoundException; import android.content.Intent; import android.os.Bundle; import android.provider.Settings; -import android.support.v17.leanback.widget.GuidanceStylist.Guidance; -import android.support.v17.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidanceStylist.Guidance; +import androidx.leanback.widget.GuidedAction; import android.util.Log; import com.android.tv.R; import com.android.tv.ui.DetailsActivity; diff --git a/src/com/android/tv/dvr/ui/DvrPrioritySettingsFragment.java b/src/com/android/tv/dvr/ui/DvrPrioritySettingsFragment.java index 5bb97e90..ae41f501 100644 --- a/src/com/android/tv/dvr/ui/DvrPrioritySettingsFragment.java +++ b/src/com/android/tv/dvr/ui/DvrPrioritySettingsFragment.java @@ -22,9 +22,9 @@ import android.content.Context; import android.graphics.Typeface; import android.os.Build; import android.os.Bundle; -import android.support.v17.leanback.widget.GuidanceStylist.Guidance; -import android.support.v17.leanback.widget.GuidedAction; -import android.support.v17.leanback.widget.GuidedActionsStylist; +import androidx.leanback.widget.GuidanceStylist.Guidance; +import androidx.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidedActionsStylist; import android.view.View; import android.widget.ImageView; import android.widget.TextView; diff --git a/src/com/android/tv/dvr/ui/DvrScheduleFragment.java b/src/com/android/tv/dvr/ui/DvrScheduleFragment.java index 72603d03..613484d5 100644 --- a/src/com/android/tv/dvr/ui/DvrScheduleFragment.java +++ b/src/com/android/tv/dvr/ui/DvrScheduleFragment.java @@ -22,9 +22,9 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.v17.leanback.app.GuidedStepFragment; -import android.support.v17.leanback.widget.GuidanceStylist.Guidance; -import android.support.v17.leanback.widget.GuidedAction; +import androidx.leanback.app.GuidedStepFragment; +import androidx.leanback.widget.GuidanceStylist.Guidance; +import androidx.leanback.widget.GuidedAction; import android.text.format.DateUtils; import com.android.tv.R; import com.android.tv.TvSingletons; diff --git a/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java b/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java index a237f1d2..730237c4 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java @@ -20,15 +20,13 @@ import android.app.Activity; import android.content.pm.PackageManager; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.v17.leanback.app.GuidedStepFragment; +import androidx.leanback.app.GuidedStepFragment; import android.util.Log; import android.widget.Toast; - import com.android.tv.R; import com.android.tv.Starter; import com.android.tv.TvSingletons; import com.android.tv.dvr.DvrManager; - import java.util.ArrayList; import java.util.List; @@ -70,7 +68,7 @@ public class DvrSeriesDeletionActivity extends Activity { && grantResults[0] == PackageManager.PERMISSION_GRANTED) { deleteSelectedIds(true); } else { - // NOTE: If Live TV ever supports both embedded and separate DVR inputs + // NOTE: If TV app ever supports both embedded and separate DVR inputs // then we should try to do the delete regardless. Log.i( TAG, @@ -93,14 +91,14 @@ public class DvrSeriesDeletionActivity extends Activity { dvrManager.removeRecordedPrograms(mIdsToDelete, deleteFiles); } Toast.makeText( - this, - getResources() - .getQuantityString( - R.plurals.dvr_msg_episodes_deleted, - mIdsToDelete.size(), - mIdsToDelete.size(), - recordingSize), - Toast.LENGTH_LONG) + this, + getResources() + .getQuantityString( + R.plurals.dvr_msg_episodes_deleted, + mIdsToDelete.size(), + mIdsToDelete.size(), + recordingSize), + Toast.LENGTH_LONG) .show(); finish(); } diff --git a/src/com/android/tv/dvr/ui/DvrSeriesDeletionFragment.java b/src/com/android/tv/dvr/ui/DvrSeriesDeletionFragment.java index ff213231..10ef226b 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesDeletionFragment.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesDeletionFragment.java @@ -19,10 +19,10 @@ package com.android.tv.dvr.ui; import android.content.Context; import android.media.tv.TvInputManager; import android.os.Bundle; -import android.support.v17.leanback.app.GuidedStepFragment; -import android.support.v17.leanback.widget.GuidanceStylist.Guidance; -import android.support.v17.leanback.widget.GuidedAction; -import android.support.v17.leanback.widget.GuidedActionsStylist; +import androidx.leanback.app.GuidedStepFragment; +import androidx.leanback.widget.GuidanceStylist.Guidance; +import androidx.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidedActionsStylist; import android.text.TextUtils; import android.view.ViewGroup.LayoutParams; import android.widget.Toast; diff --git a/src/com/android/tv/dvr/ui/DvrSeriesScheduledDialogActivity.java b/src/com/android/tv/dvr/ui/DvrSeriesScheduledDialogActivity.java index 9acb5b5e..d72099ba 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesScheduledDialogActivity.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesScheduledDialogActivity.java @@ -18,7 +18,7 @@ package com.android.tv.dvr.ui; import android.app.Activity; import android.os.Bundle; -import android.support.v17.leanback.app.GuidedStepFragment; +import androidx.leanback.app.GuidedStepFragment; import com.android.tv.R; public class DvrSeriesScheduledDialogActivity extends Activity { diff --git a/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java b/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java index c6e26850..6cb8c1ad 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java @@ -20,8 +20,8 @@ import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.support.v17.leanback.widget.GuidanceStylist; -import android.support.v17.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidanceStylist; +import androidx.leanback.widget.GuidedAction; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.data.Program; diff --git a/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java b/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java index 1a51cf46..48bacf35 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java @@ -19,7 +19,7 @@ package com.android.tv.dvr.ui; import android.app.Activity; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; -import android.support.v17.leanback.app.GuidedStepFragment; +import androidx.leanback.app.GuidedStepFragment; import com.android.tv.R; import com.android.tv.Starter; import com.android.tv.common.SoftPreconditions; diff --git a/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java b/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java index eadb3b9e..f191582e 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java @@ -21,10 +21,10 @@ import android.app.FragmentManager; import android.content.Context; import android.os.Build; import android.os.Bundle; -import android.support.v17.leanback.app.GuidedStepFragment; -import android.support.v17.leanback.widget.GuidanceStylist.Guidance; -import android.support.v17.leanback.widget.GuidedAction; -import android.support.v17.leanback.widget.GuidedActionsStylist; +import androidx.leanback.app.GuidedStepFragment; +import androidx.leanback.widget.GuidanceStylist.Guidance; +import androidx.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidedActionsStylist; import android.util.LongSparseArray; import com.android.tv.R; import com.android.tv.TvSingletons; diff --git a/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java b/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java index 1ab4c500..ca2d8f89 100644 --- a/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java +++ b/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java @@ -23,8 +23,8 @@ import android.os.Build; import android.os.Bundle; import android.support.annotation.IntDef; import android.support.annotation.NonNull; -import android.support.v17.leanback.widget.GuidanceStylist.Guidance; -import android.support.v17.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidanceStylist.Guidance; +import androidx.leanback.widget.GuidedAction; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.dvr.DvrDataManager; diff --git a/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java index 15abf902..4a8ce04e 100644 --- a/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java +++ b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java @@ -18,7 +18,7 @@ package com.android.tv.dvr.ui; import android.app.DialogFragment; import android.os.Bundle; -import android.support.v17.leanback.app.GuidedStepFragment; +import androidx.leanback.app.GuidedStepFragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java index 99211fdb..0b8f5df0 100644 --- a/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java +++ b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java @@ -20,8 +20,8 @@ import android.app.Activity; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.v17.leanback.widget.GuidanceStylist; -import android.support.v17.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidanceStylist; +import androidx.leanback.widget.GuidedAction; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/src/com/android/tv/dvr/ui/DvrWriteStoragePermissionRationaleFragment.java b/src/com/android/tv/dvr/ui/DvrWriteStoragePermissionRationaleFragment.java index c93f5831..25f7f38b 100644 --- a/src/com/android/tv/dvr/ui/DvrWriteStoragePermissionRationaleFragment.java +++ b/src/com/android/tv/dvr/ui/DvrWriteStoragePermissionRationaleFragment.java @@ -19,8 +19,8 @@ package com.android.tv.dvr.ui; import android.app.Activity; import android.content.res.Resources; import android.os.Bundle; -import android.support.v17.leanback.widget.GuidanceStylist; -import android.support.v17.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidanceStylist; +import androidx.leanback.widget.GuidedAction; import com.android.tv.R; diff --git a/src/com/android/tv/dvr/ui/SortedArrayAdapter.java b/src/com/android/tv/dvr/ui/SortedArrayAdapter.java index 1eb8080a..7a26d5ed 100644 --- a/src/com/android/tv/dvr/ui/SortedArrayAdapter.java +++ b/src/com/android/tv/dvr/ui/SortedArrayAdapter.java @@ -17,8 +17,8 @@ package com.android.tv.dvr.ui; import android.support.annotation.VisibleForTesting; -import android.support.v17.leanback.widget.ArrayObjectAdapter; -import android.support.v17.leanback.widget.PresenterSelector; +import androidx.leanback.widget.ArrayObjectAdapter; +import androidx.leanback.widget.PresenterSelector; import com.android.tv.common.SoftPreconditions; import java.util.ArrayList; import java.util.Collection; diff --git a/src/com/android/tv/dvr/ui/TrackedGuidedStepFragment.java b/src/com/android/tv/dvr/ui/TrackedGuidedStepFragment.java index 0172f76f..c0a57c0f 100644 --- a/src/com/android/tv/dvr/ui/TrackedGuidedStepFragment.java +++ b/src/com/android/tv/dvr/ui/TrackedGuidedStepFragment.java @@ -17,8 +17,8 @@ package com.android.tv.dvr.ui; import android.content.Context; -import android.support.v17.leanback.app.GuidedStepFragment; -import android.support.v17.leanback.widget.GuidedAction; +import androidx.leanback.app.GuidedStepFragment; +import androidx.leanback.widget.GuidedAction; import com.android.tv.TvSingletons; import com.android.tv.analytics.Tracker; diff --git a/src/com/android/tv/dvr/ui/browse/ActionPresenterSelector.java b/src/com/android/tv/dvr/ui/browse/ActionPresenterSelector.java index 41ace9a4..a06705c6 100644 --- a/src/com/android/tv/dvr/ui/browse/ActionPresenterSelector.java +++ b/src/com/android/tv/dvr/ui/browse/ActionPresenterSelector.java @@ -17,10 +17,10 @@ package com.android.tv.dvr.ui.browse; import android.graphics.drawable.Drawable; -import android.support.v17.leanback.R; -import android.support.v17.leanback.widget.Action; -import android.support.v17.leanback.widget.Presenter; -import android.support.v17.leanback.widget.PresenterSelector; +import androidx.leanback.R; +import androidx.leanback.widget.Action; +import androidx.leanback.widget.Presenter; +import androidx.leanback.widget.PresenterSelector; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java index 8c311d68..ed548728 100644 --- a/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java @@ -19,12 +19,11 @@ package com.android.tv.dvr.ui.browse; import android.content.Context; import android.content.res.Resources; import android.media.tv.TvInputManager; -import android.support.v17.leanback.widget.Action; -import android.support.v17.leanback.widget.OnActionClickedListener; -import android.support.v17.leanback.widget.SparseArrayObjectAdapter; +import androidx.leanback.widget.Action; +import androidx.leanback.widget.OnActionClickedListener; +import androidx.leanback.widget.SparseArrayObjectAdapter; import com.android.tv.R; import com.android.tv.TvSingletons; -import com.android.tv.common.flags.has.HasConcurrentDvrPlaybackFlags; import com.android.tv.dialog.HalfSizedDialogFragment; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrManager; @@ -33,7 +32,9 @@ import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.ui.DvrStopRecordingFragment; import com.android.tv.dvr.ui.DvrUiHelper; +import dagger.android.AndroidInjection; import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; +import javax.inject.Inject; /** {@link RecordingDetailsFragment} for current recording in DVR. */ public class CurrentRecordingDetailsFragment extends RecordingDetailsFragment { @@ -43,8 +44,8 @@ public class CurrentRecordingDetailsFragment extends RecordingDetailsFragment { private DvrDataManager mDvrDataManger; private RecordedProgram mRecordedProgram; - private DvrWatchedPositionManager mDvrWatchedPositionManager; - private ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; + @Inject DvrWatchedPositionManager mDvrWatchedPositionManager; + @Inject ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; private boolean mPaused; private final DvrDataManager.ScheduledRecordingListener mScheduledRecordingListener = new DvrDataManager.ScheduledRecordingListener() { @@ -76,12 +77,10 @@ public class CurrentRecordingDetailsFragment extends RecordingDetailsFragment { @Override public void onAttach(Context context) { + AndroidInjection.inject(this); super.onAttach(context); mDvrDataManger = TvSingletons.getSingletons(context).getDvrDataManager(); mDvrDataManger.addScheduledRecordingListener(mScheduledRecordingListener); - mDvrWatchedPositionManager = - TvSingletons.getSingletons(getActivity()).getDvrWatchedPositionManager(); - mConcurrentDvrPlaybackFlags = HasConcurrentDvrPlaybackFlags.fromContext(context); } @Override diff --git a/src/com/android/tv/dvr/ui/browse/DetailsContentPresenter.java b/src/com/android/tv/dvr/ui/browse/DetailsContentPresenter.java index 6b5fd1fd..fafc70cf 100644 --- a/src/com/android/tv/dvr/ui/browse/DetailsContentPresenter.java +++ b/src/com/android/tv/dvr/ui/browse/DetailsContentPresenter.java @@ -24,7 +24,7 @@ import android.app.Activity; import android.content.Context; import android.graphics.Paint; import android.graphics.Paint.FontMetricsInt; -import android.support.v17.leanback.widget.Presenter; +import androidx.leanback.widget.Presenter; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; @@ -40,10 +40,10 @@ import com.android.tv.util.Utils; /** * An {@link Presenter} for rendering a detailed description of an DVR item. Typically this * Presenter will be used in a {@link - * android.support.v17.leanback.widget.DetailsOverviewRowPresenter}. Most codes of this class is - * originated from {@link android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter}. + * androidx.leanback.widget.DetailsOverviewRowPresenter}. Most codes of this class is + * originated from {@link androidx.leanback.widget.AbstractDetailsDescriptionPresenter}. * The latter class are re-used to provide a customized version of {@link - * android.support.v17.leanback.widget.DetailsOverviewRow}. + * androidx.leanback.widget.DetailsOverviewRow}. */ public class DetailsContentPresenter extends Presenter { /** The ViewHolder for the {@link DetailsContentPresenter}. */ diff --git a/src/com/android/tv/dvr/ui/browse/DetailsViewBackgroundHelper.java b/src/com/android/tv/dvr/ui/browse/DetailsViewBackgroundHelper.java index 4e41daee..8a4c7854 100644 --- a/src/com/android/tv/dvr/ui/browse/DetailsViewBackgroundHelper.java +++ b/src/com/android/tv/dvr/ui/browse/DetailsViewBackgroundHelper.java @@ -21,7 +21,7 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Handler; -import android.support.v17.leanback.app.BackgroundManager; +import androidx.leanback.app.BackgroundManager; /** The Background Helper. */ public class DetailsViewBackgroundHelper { diff --git a/src/com/android/tv/dvr/ui/browse/DvrBrowseActivity.java b/src/com/android/tv/dvr/ui/browse/DvrBrowseActivity.java index 5743ea5c..7262b4a0 100644 --- a/src/com/android/tv/dvr/ui/browse/DvrBrowseActivity.java +++ b/src/com/android/tv/dvr/ui/browse/DvrBrowseActivity.java @@ -22,13 +22,13 @@ import android.media.tv.TvInputManager; import android.os.Bundle; import com.android.tv.R; import com.android.tv.Starter; -import com.android.tv.perf.PerformanceMonitorManagerFactory; +import com.android.tv.perf.StartupMeasureFactory; /** {@link android.app.Activity} for DVR UI. */ public class DvrBrowseActivity extends Activity { { - PerformanceMonitorManagerFactory.create().getStartupMeasure().onActivityInit(); + StartupMeasureFactory.create().onActivityInit(); } private DvrBrowseFragment mFragment; diff --git a/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java b/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java index 3251200f..276bc114 100644 --- a/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java +++ b/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java @@ -21,14 +21,14 @@ import android.content.Context; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.support.v17.leanback.app.BrowseFragment; -import android.support.v17.leanback.widget.ArrayObjectAdapter; -import android.support.v17.leanback.widget.ClassPresenterSelector; -import android.support.v17.leanback.widget.HeaderItem; -import android.support.v17.leanback.widget.ListRow; -import android.support.v17.leanback.widget.Presenter; -import android.support.v17.leanback.widget.TitleViewAdapter; import android.text.TextUtils; +import androidx.leanback.app.BrowseFragment; +import androidx.leanback.widget.ArrayObjectAdapter; +import androidx.leanback.widget.ClassPresenterSelector; +import androidx.leanback.widget.HeaderItem; +import androidx.leanback.widget.ListRow; +import androidx.leanback.widget.Presenter; +import androidx.leanback.widget.TitleViewAdapter; import android.util.Log; import android.view.View; import android.view.ViewTreeObserver.OnGlobalFocusChangeListener; diff --git a/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java index f90981f0..a38180a5 100644 --- a/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java @@ -25,15 +25,15 @@ import android.media.tv.TvContentRating; import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.v17.leanback.app.DetailsFragment; -import android.support.v17.leanback.widget.ArrayObjectAdapter; -import android.support.v17.leanback.widget.ClassPresenterSelector; -import android.support.v17.leanback.widget.DetailsOverviewRow; -import android.support.v17.leanback.widget.DetailsOverviewRowPresenter; -import android.support.v17.leanback.widget.OnActionClickedListener; -import android.support.v17.leanback.widget.PresenterSelector; -import android.support.v17.leanback.widget.SparseArrayObjectAdapter; -import android.support.v17.leanback.widget.VerticalGridView; +import androidx.leanback.app.DetailsFragment; +import androidx.leanback.widget.ArrayObjectAdapter; +import androidx.leanback.widget.ClassPresenterSelector; +import androidx.leanback.widget.DetailsOverviewRow; +import androidx.leanback.widget.DetailsOverviewRowPresenter; +import androidx.leanback.widget.OnActionClickedListener; +import androidx.leanback.widget.PresenterSelector; +import androidx.leanback.widget.SparseArrayObjectAdapter; +import androidx.leanback.widget.VerticalGridView; import android.text.TextUtils; import android.widget.Toast; import com.android.tv.R; diff --git a/src/com/android/tv/dvr/ui/browse/DvrItemPresenter.java b/src/com/android/tv/dvr/ui/browse/DvrItemPresenter.java index 4298d86a..ebdee32f 100644 --- a/src/com/android/tv/dvr/ui/browse/DvrItemPresenter.java +++ b/src/com/android/tv/dvr/ui/browse/DvrItemPresenter.java @@ -19,7 +19,7 @@ package com.android.tv.dvr.ui.browse; import android.app.Activity; import android.content.Context; import android.support.annotation.CallSuper; -import android.support.v17.leanback.widget.Presenter; +import androidx.leanback.widget.Presenter; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; diff --git a/src/com/android/tv/dvr/ui/browse/DvrListRowPresenter.java b/src/com/android/tv/dvr/ui/browse/DvrListRowPresenter.java index a2d1cb28..625f8f76 100644 --- a/src/com/android/tv/dvr/ui/browse/DvrListRowPresenter.java +++ b/src/com/android/tv/dvr/ui/browse/DvrListRowPresenter.java @@ -17,7 +17,7 @@ package com.android.tv.dvr.ui.browse; import android.content.Context; -import android.support.v17.leanback.widget.ListRowPresenter; +import androidx.leanback.widget.ListRowPresenter; import android.view.ViewGroup; import com.android.tv.R; diff --git a/src/com/android/tv/dvr/ui/browse/RecordedProgramDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/RecordedProgramDetailsFragment.java index bf963547..5f58af8e 100644 --- a/src/com/android/tv/dvr/ui/browse/RecordedProgramDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/RecordedProgramDetailsFragment.java @@ -19,9 +19,9 @@ package com.android.tv.dvr.ui.browse; import android.content.res.Resources; import android.media.tv.TvInputManager; import android.os.Bundle; -import android.support.v17.leanback.widget.Action; -import android.support.v17.leanback.widget.OnActionClickedListener; -import android.support.v17.leanback.widget.SparseArrayObjectAdapter; +import androidx.leanback.widget.Action; +import androidx.leanback.widget.OnActionClickedListener; +import androidx.leanback.widget.SparseArrayObjectAdapter; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.util.PermissionUtils; @@ -32,7 +32,7 @@ import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.dvr.ui.DvrUiHelper; import com.android.tv.ui.DetailsActivity; -/** {@link android.support.v17.leanback.app.DetailsFragment} for recorded program in DVR. */ +/** {@link androidx.leanback.app.DetailsFragment} for recorded program in DVR. */ public class RecordedProgramDetailsFragment extends DvrDetailsFragment implements DvrDataManager.RecordedProgramListener { private static final int ACTION_RESUME_PLAYING = 1; diff --git a/src/com/android/tv/dvr/ui/browse/RecordingCardView.java b/src/com/android/tv/dvr/ui/browse/RecordingCardView.java index 2ffad327..ac7c5745 100644 --- a/src/com/android/tv/dvr/ui/browse/RecordingCardView.java +++ b/src/com/android/tv/dvr/ui/browse/RecordingCardView.java @@ -23,7 +23,6 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.support.annotation.Nullable; -import android.support.v17.leanback.widget.BaseCardView; import android.text.Layout; import android.text.TextUtils; import android.view.LayoutInflater; @@ -33,6 +32,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +import androidx.leanback.widget.BaseCardView; import com.android.tv.R; import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.ui.ViewUtils; @@ -44,7 +44,7 @@ import com.android.tv.util.images.ImageLoader; */ public class RecordingCardView extends BaseCardView { // This value should be the same with - // android.support.v17.leanback.widget.FocusHighlightHelper.BrowseItemFocusHighlight.DURATION_MS + // androidx.leanback.widget.FocusHighlightHelper.BrowseItemFocusHighlight.DURATION_MS private static final int ANIMATION_DURATION = 150; private final ImageView mImageView; private final int mImageWidth; diff --git a/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java index 243681c6..e85f983f 100644 --- a/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java @@ -17,7 +17,7 @@ package com.android.tv.dvr.ui.browse; import android.os.Bundle; -import android.support.v17.leanback.app.DetailsFragment; +import androidx.leanback.app.DetailsFragment; import com.android.tv.TvSingletons; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.ui.DetailsActivity; diff --git a/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java index f08bb12b..7ef8e59f 100644 --- a/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java @@ -18,9 +18,9 @@ package com.android.tv.dvr.ui.browse; import android.content.res.Resources; import android.os.Bundle; -import android.support.v17.leanback.widget.Action; -import android.support.v17.leanback.widget.OnActionClickedListener; -import android.support.v17.leanback.widget.SparseArrayObjectAdapter; +import androidx.leanback.widget.Action; +import androidx.leanback.widget.OnActionClickedListener; +import androidx.leanback.widget.SparseArrayObjectAdapter; import com.android.tv.R; import com.android.tv.TvSingletons; diff --git a/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java index 9104ef10..7c1e1164 100644 --- a/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java @@ -21,17 +21,17 @@ import android.graphics.drawable.Drawable; import android.media.tv.TvInputManager; import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.v17.leanback.app.DetailsFragment; -import android.support.v17.leanback.widget.Action; -import android.support.v17.leanback.widget.ArrayObjectAdapter; -import android.support.v17.leanback.widget.ClassPresenterSelector; -import android.support.v17.leanback.widget.DetailsOverviewRow; -import android.support.v17.leanback.widget.DetailsOverviewRowPresenter; -import android.support.v17.leanback.widget.HeaderItem; -import android.support.v17.leanback.widget.ListRow; -import android.support.v17.leanback.widget.OnActionClickedListener; -import android.support.v17.leanback.widget.PresenterSelector; -import android.support.v17.leanback.widget.SparseArrayObjectAdapter; +import androidx.leanback.app.DetailsFragment; +import androidx.leanback.widget.Action; +import androidx.leanback.widget.ArrayObjectAdapter; +import androidx.leanback.widget.ClassPresenterSelector; +import androidx.leanback.widget.DetailsOverviewRow; +import androidx.leanback.widget.DetailsOverviewRowPresenter; +import androidx.leanback.widget.HeaderItem; +import androidx.leanback.widget.ListRow; +import androidx.leanback.widget.OnActionClickedListener; +import androidx.leanback.widget.PresenterSelector; +import androidx.leanback.widget.SparseArrayObjectAdapter; import android.text.TextUtils; import com.android.tv.R; import com.android.tv.TvSingletons; diff --git a/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java index 77a63508..293e1d94 100644 --- a/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java +++ b/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java @@ -17,8 +17,8 @@ package com.android.tv.dvr.ui.list; import android.os.Bundle; -import android.support.v17.leanback.app.DetailsFragment; -import android.support.v17.leanback.widget.ClassPresenterSelector; +import androidx.leanback.app.DetailsFragment; +import androidx.leanback.widget.ClassPresenterSelector; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java b/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java index 0ca05fac..1d93c8cb 100644 --- a/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java +++ b/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java @@ -17,23 +17,24 @@ package com.android.tv.dvr.ui.list; import android.os.Bundle; -import android.support.v17.leanback.app.DetailsFragment; -import android.support.v17.leanback.widget.ClassPresenterSelector; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import androidx.leanback.app.DetailsFragment; +import androidx.leanback.widget.ClassPresenterSelector; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.ui.list.SchedulesHeaderRowPresenter.DateHeaderRowPresenter; +import com.android.tv.common.flags.UiFlags; /** A fragment to show the DVR history. */ public class DvrHistoryFragment extends DetailsFragment implements DvrDataManager.ScheduledRecordingListener, - DvrDataManager.RecordedProgramListener { + DvrDataManager.RecordedProgramListener { private DvrHistoryRowAdapter mRowsAdapter; private TextView mEmptyInfoScreenView; @@ -48,11 +49,17 @@ public class DvrHistoryFragment extends DetailsFragment presenterSelector.addClassPresenter( ScheduleRow.class, new ScheduleRowPresenter(getContext())); TvSingletons singletons = TvSingletons.getSingletons(getContext()); - mRowsAdapter = new DvrHistoryRowAdapter( - getContext(), presenterSelector, singletons.getClock()); + UiFlags uiFlags = singletons.getUiFlags(); + mDvrDataManager = singletons.getDvrDataManager(); + mRowsAdapter = + new DvrHistoryRowAdapter( + getContext(), + presenterSelector, + singletons.getClock(), + mDvrDataManager, + uiFlags); setAdapter(mRowsAdapter); mRowsAdapter.start(); - mDvrDataManager = singletons.getDvrDataManager(); mDvrDataManager.addScheduledRecordingListener(this); mDvrDataManager.addRecordedProgramListener(this); mEmptyInfoScreenView = (TextView) getActivity().findViewById(R.id.empty_info_screen); @@ -135,7 +142,6 @@ public class DvrHistoryFragment extends DetailsFragment hideEmptyMessage(); } } - } @Override diff --git a/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java b/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java index 156d1a7e..a10367fb 100644 --- a/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java +++ b/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java @@ -20,20 +20,19 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build.VERSION_CODES; import android.support.annotation.Nullable; -import android.support.v17.leanback.widget.ArrayObjectAdapter; -import android.support.v17.leanback.widget.ClassPresenterSelector; import android.text.format.DateUtils; import android.util.Log; +import androidx.leanback.widget.ArrayObjectAdapter; +import androidx.leanback.widget.ClassPresenterSelector; import com.android.tv.R; -import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.util.Clock; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.dvr.data.ScheduledRecording; -import com.android.tv.dvr.recorder.ScheduledProgramReaper; import com.android.tv.dvr.ui.list.SchedulesHeaderRow.DateHeaderRow; import com.android.tv.util.Utils; +import com.android.tv.common.flags.UiFlags; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -48,8 +47,8 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { private static final boolean DEBUG = false; private static final long ONE_DAY_MS = TimeUnit.DAYS.toMillis(1); - private static final int MAX_HISTORY_DAYS = ScheduledProgramReaper.DAYS; + private final long mMaxHistoryDays; private final Context mContext; private final Clock mClock; private final DvrDataManager mDvrDataManager; @@ -57,11 +56,16 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { private final Map<Long, ScheduledRecording> mRecordedProgramScheduleMap = new HashMap<>(); public DvrHistoryRowAdapter( - Context context, ClassPresenterSelector classPresenterSelector, Clock clock) { + Context context, + ClassPresenterSelector classPresenterSelector, + Clock clock, + DvrDataManager dvrDataManager, + UiFlags uiFlags) { super(classPresenterSelector); mContext = context; mClock = clock; - mDvrDataManager = TvSingletons.getSingletons(mContext).getDvrDataManager(); + mDvrDataManager = dvrDataManager; + mMaxHistoryDays = uiFlags.maxHistoryDays(); mTitles.add(mContext.getString(R.string.dvr_date_today)); mTitles.add(mContext.getString(R.string.dvr_date_yesterday)); } @@ -78,9 +82,9 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { List<RecordedProgram> recordedProgramList = mDvrDataManager.getRecordedPrograms(); recordingList.addAll( - recordedProgramsToScheduledRecordings(recordedProgramList, MAX_HISTORY_DAYS)); - recordingList - .sort(ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR.reversed()); + recordedProgramsToScheduledRecordings(recordedProgramList, mMaxHistoryDays)); + recordingList.sort( + ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR.reversed()); long deadLine = Utils.getFirstMillisecondOfDay(mClock.currentTimeMillis()); for (int i = 0; i < recordingList.size(); ) { ArrayList<ScheduledRecording> section = new ArrayList<>(); @@ -128,7 +132,7 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { } private List<ScheduledRecording> recordedProgramsToScheduledRecordings( - List<RecordedProgram> programs, int maxDays) { + List<RecordedProgram> programs, long maxDays) { List<ScheduledRecording> result = new ArrayList<>(); for (RecordedProgram recordedProgram : programs) { ScheduledRecording scheduledRecording = @@ -142,12 +146,12 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { @Nullable private ScheduledRecording recordedProgramsToScheduledRecordings( - RecordedProgram program, int maxDays) { + RecordedProgram program, long maxDays) { long firstMillisecondToday = Utils.getFirstMillisecondOfDay(mClock.currentTimeMillis()); - if (maxDays - < Utils.computeDateDifference( - program.getStartTimeUtcMillis(), - firstMillisecondToday)) { + if (maxDays != 0 + && maxDays + < Utils.computeDateDifference( + program.getStartTimeUtcMillis(), firstMillisecondToday)) { return null; } ScheduledRecording scheduledRecording = ScheduledRecording.builder(program).build(); @@ -175,7 +179,7 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { return; } ScheduledRecording schedule = - recordedProgramsToScheduledRecordings(program, MAX_HISTORY_DAYS); + recordedProgramsToScheduledRecordings(program, mMaxHistoryDays); if (schedule == null) { return; } @@ -248,8 +252,10 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { for (; index < size(); index++) { if (get(index) instanceof ScheduleRow) { ScheduleRow scheduleRow = (ScheduleRow) get(index); - if (ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR.reversed() - .compare(scheduleRow.getSchedule(), recording) > 0) { + if (ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR + .reversed() + .compare(scheduleRow.getSchedule(), recording) + > 0) { break; } pre = index; diff --git a/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java index d97b61f4..43a3579a 100644 --- a/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java +++ b/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java @@ -17,7 +17,7 @@ package com.android.tv.dvr.ui.list; import android.os.Bundle; -import android.support.v17.leanback.widget.ClassPresenterSelector; +import androidx.leanback.widget.ClassPresenterSelector; import com.android.tv.R; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.ui.list.SchedulesHeaderRowPresenter.DateHeaderRowPresenter; diff --git a/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java index d376e358..319b583b 100644 --- a/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java +++ b/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java @@ -25,7 +25,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.support.v17.leanback.widget.ClassPresenterSelector; +import androidx.leanback.widget.ClassPresenterSelector; import android.transition.Fade; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java index ef4a4337..de259f5a 100644 --- a/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java +++ b/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java @@ -22,8 +22,8 @@ import android.os.Build.VERSION_CODES; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.support.v17.leanback.widget.ArrayObjectAdapter; -import android.support.v17.leanback.widget.ClassPresenterSelector; +import androidx.leanback.widget.ArrayObjectAdapter; +import androidx.leanback.widget.ClassPresenterSelector; import android.text.format.DateUtils; import android.util.ArraySet; import android.util.Log; diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java index 11680a0d..ff296f49 100644 --- a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java +++ b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java @@ -24,7 +24,7 @@ import android.content.Context; import android.content.res.Resources; import android.os.Build; import android.support.annotation.IntDef; -import android.support.v17.leanback.widget.RowPresenter; +import androidx.leanback.widget.RowPresenter; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java index 28a44bf3..2550eebc 100644 --- a/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java +++ b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java @@ -19,7 +19,7 @@ package com.android.tv.dvr.ui.list; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.drawable.Drawable; -import android.support.v17.leanback.widget.RowPresenter; +import androidx.leanback.widget.RowPresenter; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; diff --git a/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java b/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java index 9a9c94ea..9158423c 100644 --- a/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java +++ b/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java @@ -20,7 +20,7 @@ import android.annotation.TargetApi; import android.content.Context; import android.media.tv.TvInputInfo; import android.os.Build; -import android.support.v17.leanback.widget.ClassPresenterSelector; +import androidx.leanback.widget.ClassPresenterSelector; import android.util.ArrayMap; import android.util.Log; import com.android.tv.R; diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java b/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java index f24ad2c0..4aa1200e 100644 --- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java +++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java @@ -16,7 +16,6 @@ package com.android.tv.dvr.ui.playback; -import android.app.Activity; import android.content.ContentUris; import android.content.Intent; import android.content.res.Configuration; @@ -28,9 +27,12 @@ import com.android.tv.Starter; import com.android.tv.dialog.PinDialogFragment.OnPinCheckedListener; import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.util.Utils; +import dagger.android.AndroidInjection; +import dagger.android.ContributesAndroidInjector; +import dagger.android.DaggerActivity; /** Activity to play a {@link RecordedProgram}. */ -public class DvrPlaybackActivity extends Activity implements OnPinCheckedListener { +public class DvrPlaybackActivity extends DaggerActivity implements OnPinCheckedListener { private static final String TAG = "DvrPlaybackActivity"; private static final boolean DEBUG = false; @@ -39,6 +41,7 @@ public class DvrPlaybackActivity extends Activity implements OnPinCheckedListene @Override public void onCreate(Bundle savedInstanceState) { + AndroidInjection.inject(this); Starter.start(this); if (DEBUG) Log.d(TAG, "onCreate"); super.onCreate(savedInstanceState); @@ -92,4 +95,16 @@ public class DvrPlaybackActivity extends Activity implements OnPinCheckedListene void setOnPinCheckListener(OnPinCheckedListener listener) { mOnPinCheckedListener = listener; } + + /** + * Exports {@link DvrPlaybackActivity} for Dagger codegen to create the appropriate injector. + */ + @dagger.Module + public abstract static class Module { + @ContributesAndroidInjector + abstract DvrPlaybackActivity contributesDvrPlaybackActivity(); + + @ContributesAndroidInjector + abstract DvrPlaybackOverlayFragment contributesDvrPlaybackOverlayFragment(); + } } diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlaybackControlHelper.java b/src/com/android/tv/dvr/ui/playback/DvrPlaybackControlHelper.java index 791d26bb..35c5d4e4 100644 --- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackControlHelper.java +++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackControlHelper.java @@ -26,15 +26,15 @@ import android.media.session.PlaybackState; import android.media.tv.TvTrackInfo; import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.v17.leanback.media.PlaybackControlGlue; -import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter; -import android.support.v17.leanback.widget.Action; -import android.support.v17.leanback.widget.ArrayObjectAdapter; -import android.support.v17.leanback.widget.PlaybackControlsRow; -import android.support.v17.leanback.widget.PlaybackControlsRow.ClosedCaptioningAction; -import android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction; -import android.support.v17.leanback.widget.PlaybackControlsRowPresenter; -import android.support.v17.leanback.widget.RowPresenter; +import androidx.leanback.media.PlaybackControlGlue; +import androidx.leanback.widget.AbstractDetailsDescriptionPresenter; +import androidx.leanback.widget.Action; +import androidx.leanback.widget.ArrayObjectAdapter; +import androidx.leanback.widget.PlaybackControlsRow; +import androidx.leanback.widget.PlaybackControlsRow.ClosedCaptioningAction; +import androidx.leanback.widget.PlaybackControlsRow.MultiAction; +import androidx.leanback.widget.PlaybackControlsRowPresenter; +import androidx.leanback.widget.RowPresenter; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java b/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java index 1059e852..a111738e 100644 --- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java +++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java @@ -26,23 +26,24 @@ import android.media.tv.TvContentRating; import android.media.tv.TvInputManager; import android.media.tv.TvTrackInfo; import android.os.Bundle; -import android.support.v17.leanback.app.PlaybackFragment; -import android.support.v17.leanback.app.PlaybackFragmentGlueHost; -import android.support.v17.leanback.widget.ArrayObjectAdapter; -import android.support.v17.leanback.widget.BaseOnItemViewClickedListener; -import android.support.v17.leanback.widget.ClassPresenterSelector; -import android.support.v17.leanback.widget.HeaderItem; -import android.support.v17.leanback.widget.ListRow; -import android.support.v17.leanback.widget.Presenter; -import android.support.v17.leanback.widget.RowPresenter; -import android.support.v17.leanback.widget.SinglePresenterSelector; import android.util.Log; import android.view.Display; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; +import androidx.leanback.app.PlaybackFragment; +import androidx.leanback.app.PlaybackFragmentGlueHost; +import androidx.leanback.widget.ArrayObjectAdapter; +import androidx.leanback.widget.BaseOnItemViewClickedListener; +import androidx.leanback.widget.ClassPresenterSelector; +import androidx.leanback.widget.HeaderItem; +import androidx.leanback.widget.ListRow; +import androidx.leanback.widget.Presenter; +import androidx.leanback.widget.RowPresenter; +import androidx.leanback.widget.SinglePresenterSelector; import com.android.tv.R; -import com.android.tv.TvSingletons; +import com.android.tv.audio.AudioManagerHelper; +import com.android.tv.common.buildtype.HasBuildType.BuildType; import com.android.tv.data.BaseProgram; import com.android.tv.dialog.PinDialogFragment; import com.android.tv.dvr.DvrDataManager; @@ -55,8 +56,11 @@ import com.android.tv.ui.AppLayerTvView; import com.android.tv.util.TvSettings; import com.android.tv.util.TvTrackInfoUtils; import com.android.tv.util.Utils; +import dagger.android.AndroidInjection; +import com.android.tv.common.flags.LegacyFlags; import java.util.ArrayList; import java.util.List; +import javax.inject.Inject; public class DvrPlaybackOverlayFragment extends PlaybackFragment { // TODO: Handles audio focus. Deals with block and ratings. @@ -75,7 +79,7 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { private ArrayObjectAdapter mRowsAdapter; private SortedArrayAdapter<BaseProgram> mRelatedRecordingsRowAdapter; private DvrPlaybackCardPresenter mRelatedRecordingCardPresenter; - private DvrDataManager mDvrDataManager; + private AudioManagerHelper mAudioManagerHelper; private AppLayerTvView mTvView; private View mBlockScreenView; private ListRow mRelatedRecordingsRow; @@ -97,9 +101,24 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { } }; + @Inject DvrDataManager mDvrDataManager; + @Inject LegacyFlags mLegacyFlags; + @Inject BuildType buildType; + + @Override + public void onAttach(Context context) { + if (DEBUG) { + Log.d(TAG, "onAttach"); + } + AndroidInjection.inject(this); + super.onAttach(context); + } + @Override public void onCreate(Bundle savedInstanceState) { - if (DEBUG) Log.d(TAG, "onCreate"); + if (DEBUG) { + Log.d(TAG, "onCreate"); + } super.onCreate(savedInstanceState); mVerticalPaddingBase = getActivity() @@ -115,7 +134,6 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { .getResources() .getDimensionPixelOffset( R.dimen.dvr_playback_overlay_padding_top_no_secondary_row); - mDvrDataManager = TvSingletons.getSingletons(getActivity()).getDvrDataManager(); if (!mDvrDataManager.isRecordedProgramLoadFinished()) { mDvrDataManager.addRecordedProgramLoadFinishedListener( new DvrDataManager.OnRecordedProgramLoadFinishedListener() { @@ -153,6 +171,8 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mTvView = getActivity().findViewById(R.id.dvr_tv_view); + mTvView.setUseSecureSurface( + buildType != BuildType.ENG && !mLegacyFlags.enableDeveloperFeatures()); mBlockScreenView = getActivity().findViewById(R.id.block_screen); mDvrPlayer = new DvrPlayer(mTvView, getActivity()); mMediaSessionHelper = @@ -240,13 +260,16 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { setFadingEnabled(false); long programId = ((RecordedProgram) itemViewHolder.view.getTag()).getId(); - if (DEBUG) Log.d(TAG, "Play Related Recording:" + programId); + if (DEBUG) { + Log.d(TAG, "Play Related Recording:" + programId); + } Intent intent = new Intent(getContext(), DvrPlaybackActivity.class); intent.putExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_ID, programId); getContext().startActivity(intent); } } }); + mAudioManagerHelper = new AudioManagerHelper(getActivity(), mDvrPlayer.getView()); if (mProgram != null) { setUpRows(); preparePlayback(getActivity().getIntent()); @@ -255,7 +278,9 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { @Override public void onPause() { - if (DEBUG) Log.d(TAG, "onPause"); + if (DEBUG) { + Log.d(TAG, "onPause"); + } super.onPause(); if (mMediaSessionHelper.getPlaybackState() == PlaybackState.STATE_FAST_FORWARDING || mMediaSessionHelper.getPlaybackState() == PlaybackState.STATE_REWINDING) { @@ -270,9 +295,12 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { @Override public void onDestroy() { - if (DEBUG) Log.d(TAG, "onDestroy"); + if (DEBUG) { + Log.d(TAG, "onDestroy"); + } mPlaybackControlHelper.unregisterCallback(); mMediaSessionHelper.release(); + mAudioManagerHelper.abandonAudioFocus(); mRelatedRecordingCardPresenter.unbindAllViewHolders(); mDvrPlayer.release(); super.onDestroy(); @@ -416,6 +444,7 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { private void preparePlayback(Intent intent) { mMediaSessionHelper.setupPlayback(mProgram, getSeekTimeFromIntent(intent)); mPlaybackControlHelper.updateSecondaryRow(false, false); + mAudioManagerHelper.requestAudioFocus(); getActivity().getMediaController().getTransportControls().prepare(); updateRelatedRecordingsRow(); } diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlaybackSideFragment.java b/src/com/android/tv/dvr/ui/playback/DvrPlaybackSideFragment.java index b4481df8..95858e3c 100644 --- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackSideFragment.java +++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackSideFragment.java @@ -19,8 +19,8 @@ package com.android.tv.dvr.ui.playback; import android.media.tv.TvTrackInfo; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.v17.leanback.app.GuidedStepFragment; -import android.support.v17.leanback.widget.GuidedAction; +import androidx.leanback.app.GuidedStepFragment; +import androidx.leanback.widget.GuidedAction; import android.text.TextUtils; import android.transition.Transition; import android.view.LayoutInflater; diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlayer.java b/src/com/android/tv/dvr/ui/playback/DvrPlayer.java index d14646b8..e8325e1f 100644 --- a/src/com/android/tv/dvr/ui/playback/DvrPlayer.java +++ b/src/com/android/tv/dvr/ui/playback/DvrPlayer.java @@ -326,6 +326,11 @@ public class DvrPlayer { return mProgram; } + /** Returns the DVR tv view. */ + public DvrTvView getView() { + return mTvView; + } + /** Returns the currrent playback posistion in msecs. */ public long getPlaybackPosition() { return mTimeShiftCurrentPositionMs; diff --git a/src/com/android/tv/features/TvFeatures.java b/src/com/android/tv/features/TvFeatures.java index 208d53f6..68988bb3 100644 --- a/src/com/android/tv/features/TvFeatures.java +++ b/src/com/android/tv/features/TvFeatures.java @@ -28,9 +28,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; import android.support.annotation.VisibleForTesting; -import com.android.tv.common.experiments.Experiments; import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.common.feature.ExperimentFeature; import com.android.tv.common.feature.Feature; import com.android.tv.common.feature.FeatureUtils; import com.android.tv.common.feature.FlagFeature; @@ -42,7 +40,7 @@ import com.android.tv.common.singletons.HasSingletons; import com.android.tv.common.util.PermissionUtils; /** - * List of {@link Feature} for the Live TV App. + * List of {@link Feature} for the TV app. * * <p>Remove the {@code Feature} once it is launched. */ @@ -51,16 +49,6 @@ public final class TvFeatures extends CommonFeatures { /** When enabled store network affiliation information to TV provider */ public static final Feature STORE_NETWORK_AFFILIATION = ENG_ONLY_FEATURE; - /** When enabled use system setting for turning on analytics. */ - public static final Feature ANALYTICS_OPT_IN = - ExperimentFeature.from(Experiments.ENABLE_ANALYTICS_VIA_CHECKBOX); - /** - * Analytics that include sensitive information such as channel or program identifiers. - * - * <p>See <a href="http://b/22062676">b/22062676</a> - */ - public static final Feature ANALYTICS_V2 = and(ON, ANALYTICS_OPT_IN); - private static final Feature TV_PROVIDER_ALLOWS_INSERT_TO_PROGRAM_TABLE = or(Sdk.AT_LEAST_O, PartnerFeatures.TVPROVIDER_ALLOWS_SYSTEM_INSERTS_TO_PROGRAM_TABLE); diff --git a/src/com/android/tv/guide/GenreListAdapter.java b/src/com/android/tv/guide/GenreListAdapter.java index b4baf421..995b053c 100644 --- a/src/com/android/tv/guide/GenreListAdapter.java +++ b/src/com/android/tv/guide/GenreListAdapter.java @@ -18,7 +18,7 @@ package com.android.tv.guide; import android.content.Context; import android.support.annotation.MainThread; -import android.support.v7.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/guide/ProgramGrid.java b/src/com/android/tv/guide/ProgramGrid.java index caafb045..d0e050b2 100644 --- a/src/com/android/tv/guide/ProgramGrid.java +++ b/src/com/android/tv/guide/ProgramGrid.java @@ -19,7 +19,7 @@ package com.android.tv.guide; import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; -import android.support.v17.leanback.widget.VerticalGridView; +import androidx.leanback.widget.VerticalGridView; import android.util.AttributeSet; import android.util.Log; import android.util.Range; diff --git a/src/com/android/tv/guide/ProgramGuide.java b/src/com/android/tv/guide/ProgramGuide.java index bc1b11b6..bddcc8bb 100644 --- a/src/com/android/tv/guide/ProgramGuide.java +++ b/src/com/android/tv/guide/ProgramGuide.java @@ -32,10 +32,7 @@ import android.os.SystemClock; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v17.leanback.widget.OnChildSelectedListener; -import android.support.v17.leanback.widget.SearchOrbView; -import android.support.v17.leanback.widget.VerticalGridView; -import android.support.v7.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView; import android.util.Log; import android.view.View; import android.view.View.MeasureSpec; @@ -44,6 +41,9 @@ import android.view.ViewGroup.LayoutParams; import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; +import androidx.leanback.widget.OnChildSelectedListener; +import androidx.leanback.widget.SearchOrbView; +import androidx.leanback.widget.VerticalGridView; import com.android.tv.ChannelTuner; import com.android.tv.MainActivity; import com.android.tv.R; @@ -66,6 +66,7 @@ import com.android.tv.ui.hideable.AutoHideScheduler; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; import com.android.tv.common.flags.BackendKnobsFlags; +import com.android.tv.common.flags.UiFlags; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; @@ -112,6 +113,7 @@ public class ProgramGuide private final int mAnimationDuration; private final int mDetailPadding; private final SearchOrbView mSearchOrb; + private final UiFlags mUiFlags; private int mCurrentTimeIndicatorWidth; private final View mContainer; @@ -186,6 +188,7 @@ public class ProgramGuide TvSingletons singletons = TvSingletons.getSingletons(mActivity); mPerformanceMonitor = singletons.getPerformanceMonitor(); BackendKnobsFlags backendKnobsFlags = singletons.getBackendKnobs(); + mUiFlags = singletons.getUiFlags(); mProgramManager = new ProgramManager( tvInputManagerHelper, @@ -193,7 +196,8 @@ public class ProgramGuide programDataManager, dvrDataManager, dvrScheduleManager, - backendKnobsFlags); + backendKnobsFlags, + mUiFlags); mChannelTuner = channelTuner; mTracker = tracker; mPreShowRunnable = preShowRunnable; @@ -261,7 +265,7 @@ public class ProgramGuide } }); mSidePanelGridView.setOnChildSelectedListener( - new android.support.v17.leanback.widget.OnChildSelectedListener() { + new androidx.leanback.widget.OnChildSelectedListener() { @Override public void onChildSelected(ViewGroup viewGroup, View view, int i, long l) { mSearchOrb.animate().alpha(i == 0 ? 1.0f : 0.0f); @@ -282,7 +286,8 @@ public class ProgramGuide res.getInteger(R.integer.max_recycled_view_pool_epg_header_row_item)); mTimelineRow.setAdapter(mTimeListAdapter); - ProgramTableAdapter programTableAdapter = new ProgramTableAdapter(mActivity, this); + ProgramTableAdapter programTableAdapter = + new ProgramTableAdapter(mActivity, this, mUiFlags); programTableAdapter.registerAdapterDataObserver( new RecyclerView.AdapterDataObserver() { @Override diff --git a/src/com/android/tv/guide/ProgramItemView.java b/src/com/android/tv/guide/ProgramItemView.java index a46beab7..a7a545e6 100644 --- a/src/com/android/tv/guide/ProgramItemView.java +++ b/src/com/android/tv/guide/ProgramItemView.java @@ -24,6 +24,7 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.StateListDrawable; import android.os.Handler; +import android.support.v4.os.BuildCompat; // AOSP_Before_Q_Comment_Out import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; @@ -530,6 +531,11 @@ public class ProgramItemView extends TextView { } private static int getStateCount(StateListDrawable stateListDrawable) { + /* Begin_AOSP_Before_Q_Comment_Out */ + if (BuildCompat.isAtLeastQ()) { + return stateListDrawable.getStateCount(); + } + /* End_AOSP_Before_Q_Comment_Out */ try { Object stateCount = StateListDrawable.class @@ -546,6 +552,11 @@ public class ProgramItemView extends TextView { } private static Drawable getStateDrawable(StateListDrawable stateListDrawable, int index) { + /* Begin_AOSP_Before_Q_Comment_Out */ + if (BuildCompat.isAtLeastQ()) { + return stateListDrawable.getStateDrawable(index); + } + /* End_AOSP_Before_Q_Comment_Out */ try { Object drawable = StateListDrawable.class diff --git a/src/com/android/tv/guide/ProgramListAdapter.java b/src/com/android/tv/guide/ProgramListAdapter.java index 397bacfb..68ae43ee 100644 --- a/src/com/android/tv/guide/ProgramListAdapter.java +++ b/src/com/android/tv/guide/ProgramListAdapter.java @@ -17,7 +17,7 @@ package com.android.tv.guide; import android.content.res.Resources; -import android.support.v7.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/guide/ProgramManager.java b/src/com/android/tv/guide/ProgramManager.java index 3a5a4a02..e059b259 100644 --- a/src/com/android/tv/guide/ProgramManager.java +++ b/src/com/android/tv/guide/ProgramManager.java @@ -33,6 +33,7 @@ import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; import com.android.tv.common.flags.BackendKnobsFlags; +import com.android.tv.common.flags.UiFlags; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -124,6 +125,12 @@ public class ProgramManager { } @Override + public void onChannelUpdated() { + updateTableEntriesWithoutNotification(false); + notifyTableEntriesUpdated(); + } + + @Override public void onSingleChannelUpdated(long channelId) { boolean parentalControlsEnabled = mTvInputManagerHelper @@ -216,7 +223,8 @@ public class ProgramManager { ProgramDataManager programDataManager, @Nullable DvrDataManager dvrDataManager, @Nullable DvrScheduleManager dvrScheduleManager, - BackendKnobsFlags backendKnobsFlags) { + BackendKnobsFlags backendKnobsFlags, + UiFlags uiFlags) { mTvInputManagerHelper = tvInputManagerHelper; mChannelDataManager = channelDataManager; mProgramDataManager = programDataManager; @@ -431,8 +439,9 @@ public class ProgramManager { * (e.g., whose channelId is INVALID_ID), when it corresponds to a gap between programs. */ TableEntry getTableEntry(long channelId, int index) { - if (mBackendKnobsFlags.enablePartialProgramFetch()) { - mProgramDataManager.prefetchChannel(channelId); + if (mBackendKnobsFlags.enablePartialProgramFetch() + || mBackendKnobsFlags.fetchProgramsAsNeeded()) { + mProgramDataManager.prefetchChannel(channelId, index); } return mChannelIdEntriesMap.get(channelId).get(index); } @@ -707,7 +716,7 @@ public class ProgramManager { /** * Entry for program guide table. An "entry" can be either an actual program or a gap between * programs. This is needed for {@link ProgramListAdapter} because {@link - * android.support.v17.leanback.widget.HorizontalGridView} ignores margins between items. + * androidx.leanback.widget.HorizontalGridView} ignores margins between items. */ static class TableEntry { /** Channel ID which this entry is included. */ @@ -759,7 +768,7 @@ public class ProgramManager { mIsBlocked = isBlocked; } - /** A stable id useful for {@link android.support.v7.widget.RecyclerView.Adapter}. */ + /** A stable id useful for {@link androidx.recyclerview.widget.RecyclerView.Adapter}. */ long getId() { // using a negative entryEndUtcMillis keeps it from conflicting with program Id return program != null ? program.getId() : -entryEndUtcMillis; diff --git a/src/com/android/tv/guide/ProgramRow.java b/src/com/android/tv/guide/ProgramRow.java index 3317c15f..6f8f31c1 100644 --- a/src/com/android/tv/guide/ProgramRow.java +++ b/src/com/android/tv/guide/ProgramRow.java @@ -18,7 +18,7 @@ package com.android.tv.guide; import android.content.Context; import android.graphics.Rect; -import android.support.v7.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; import android.util.AttributeSet; import android.util.Log; import android.util.Range; diff --git a/src/com/android/tv/guide/ProgramRowAccessibilityDelegate.java b/src/com/android/tv/guide/ProgramRowAccessibilityDelegate.java index 5e498be4..a6a4624b 100644 --- a/src/com/android/tv/guide/ProgramRowAccessibilityDelegate.java +++ b/src/com/android/tv/guide/ProgramRowAccessibilityDelegate.java @@ -17,8 +17,8 @@ package com.android.tv.guide; import android.os.Bundle; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.RecyclerViewAccessibilityDelegate; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; diff --git a/src/com/android/tv/guide/ProgramTableAdapter.java b/src/com/android/tv/guide/ProgramTableAdapter.java index 7576bf50..2028c649 100644 --- a/src/com/android/tv/guide/ProgramTableAdapter.java +++ b/src/com/android/tv/guide/ProgramTableAdapter.java @@ -28,8 +28,8 @@ import android.media.tv.TvInputInfo; import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.RecyclerView.RecycledViewPool; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView.RecycledViewPool; import android.text.Html; import android.text.Spannable; import android.text.SpannableString; @@ -66,7 +66,7 @@ import com.android.tv.util.images.ImageCache; import com.android.tv.util.images.ImageLoader; import com.android.tv.util.images.ImageLoader.ImageLoaderCallback; import com.android.tv.util.images.ImageLoader.LoadTvInputLogoTask; - +import com.android.tv.common.flags.UiFlags; import java.util.ArrayList; import java.util.List; @@ -109,10 +109,11 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr private final String mRecordingInProgressText; private final int mDvrPaddingStartWithTrack; private final int mDvrPaddingStartWithOutTrack; + private final UiFlags mUiFlags; private RecyclerView mRecyclerView; - ProgramTableAdapter(Context context, ProgramGuide programGuide) { + ProgramTableAdapter(Context context, ProgramGuide programGuide, UiFlags uiFlags) { mContext = context; mAccessibilityManager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); @@ -126,6 +127,7 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr } mProgramGuide = programGuide; mProgramManager = programGuide.getProgramManager(); + mUiFlags = uiFlags; Resources res = context.getResources(); mChannelLogoWidth = @@ -656,6 +658,35 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr mDvrIndicator.setVisibility(View.GONE); } + if (mUiFlags.enableCriticRatings()) { + // display critic scores if any exist + List<CriticScore> criticScores = program.getCriticScores(); + if (criticScores != null) { + // inflate more critic score views if required + if (criticScores.size() > mCriticScoreViews.size()) { + LayoutInflater inflater = LayoutInflater.from(mContext); + LinearLayout layout = + (LinearLayout) + inflater.inflate( + R.layout.program_guide_critic_score_layout, + null); + mCriticScoreViews.add(layout); + } + // fill critic score views and add to layout + for (int i = 0; i < criticScores.size(); i++) { + View criticScoreView = mCriticScoreViews.get(i); + ViewParent previousParentView = criticScoreView.getParent(); + if (previousParentView != null + && previousParentView instanceof ViewGroup) { + ((ViewGroup) previousParentView).removeView(criticScoreView); + } + updateCriticScoreView( + this, program.getId(), criticScores.get(i), criticScoreView); + mCriticScoresLayout.addView(mCriticScoreViews.get(i)); + } + } + } + if (blockedRating == null) { mBlockView.setVisibility(View.GONE); updateTextView(mDescriptionView, program.getDescription()); diff --git a/src/com/android/tv/guide/TimeListAdapter.java b/src/com/android/tv/guide/TimeListAdapter.java index 9c10c952..62fec69a 100644 --- a/src/com/android/tv/guide/TimeListAdapter.java +++ b/src/com/android/tv/guide/TimeListAdapter.java @@ -17,7 +17,7 @@ package com.android.tv.guide; import android.content.res.Resources; -import android.support.v7.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView; import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/guide/TimelineGridView.java b/src/com/android/tv/guide/TimelineGridView.java index c4922b75..2d257878 100644 --- a/src/com/android/tv/guide/TimelineGridView.java +++ b/src/com/android/tv/guide/TimelineGridView.java @@ -17,8 +17,8 @@ package com.android.tv.guide; import android.content.Context; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import android.util.AttributeSet; import android.view.View; diff --git a/src/com/android/tv/menu/AppLinkCardView.java b/src/com/android/tv/menu/AppLinkCardView.java index fd93c314..49d32fed 100644 --- a/src/com/android/tv/menu/AppLinkCardView.java +++ b/src/com/android/tv/menu/AppLinkCardView.java @@ -26,13 +26,13 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.support.annotation.Nullable; -import android.support.v7.graphics.Palette; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import androidx.palette.graphics.Palette; import com.android.tv.MainActivity; import com.android.tv.R; import com.android.tv.data.api.Channel; diff --git a/src/com/android/tv/menu/ChannelsRow.java b/src/com/android/tv/menu/ChannelsRow.java index 7d03bf2b..dbfc7820 100644 --- a/src/com/android/tv/menu/ChannelsRow.java +++ b/src/com/android/tv/menu/ChannelsRow.java @@ -73,6 +73,7 @@ public class ChannelsRow extends ItemListRow { mTvRecommendation = null; } mChannelsPosterPrefetcher.cancel(); + mChannelsAdapter.release(); } /** Handle the update event of the recent channel. */ diff --git a/src/com/android/tv/menu/ChannelsRowAdapter.java b/src/com/android/tv/menu/ChannelsRowAdapter.java index 4a9e4765..e6b61037 100644 --- a/src/com/android/tv/menu/ChannelsRowAdapter.java +++ b/src/com/android/tv/menu/ChannelsRowAdapter.java @@ -47,6 +47,7 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channels private final int mMaxCount; private final int mMinCount; private final ChannelChanger mChannelChanger; + private final AccessibilityManager mAccessibilityManager; private boolean mShowChannelUpDown; @@ -66,10 +67,9 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channels mMaxCount = maxCount; setHasStableIds(true); mChannelChanger = (ChannelChanger) (context); - AccessibilityManager accessibilityManager = - context.getSystemService(AccessibilityManager.class); - mShowChannelUpDown = accessibilityManager.isEnabled(); - accessibilityManager.addAccessibilityStateChangeListener(this); + mAccessibilityManager = context.getSystemService(AccessibilityManager.class); + mShowChannelUpDown = mAccessibilityManager.isEnabled(); + mAccessibilityManager.addAccessibilityStateChangeListener(this); } @Override @@ -316,4 +316,10 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channels mShowChannelUpDown = enabled; update(); } + + @Override + public void release() { + mAccessibilityManager.removeAccessibilityStateChangeListener(this); + super.release(); + } } diff --git a/src/com/android/tv/menu/ItemListRowView.java b/src/com/android/tv/menu/ItemListRowView.java index 7042324d..16d5c3eb 100644 --- a/src/com/android/tv/menu/ItemListRowView.java +++ b/src/com/android/tv/menu/ItemListRowView.java @@ -17,9 +17,9 @@ package com.android.tv.menu; import android.content.Context; -import android.support.v17.leanback.widget.HorizontalGridView; -import android.support.v17.leanback.widget.OnChildSelectedListener; -import android.support.v7.widget.RecyclerView; +import androidx.leanback.widget.HorizontalGridView; +import androidx.leanback.widget.OnChildSelectedListener; +import androidx.recyclerview.widget.RecyclerView; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; diff --git a/src/com/android/tv/menu/Menu.java b/src/com/android/tv/menu/Menu.java index 6bdbf87b..0687441e 100644 --- a/src/com/android/tv/menu/Menu.java +++ b/src/com/android/tv/menu/Menu.java @@ -23,7 +23,7 @@ import android.content.Context; import android.content.res.Resources; import android.support.annotation.IntDef; import android.support.annotation.VisibleForTesting; -import android.support.v17.leanback.widget.HorizontalGridView; +import androidx.leanback.widget.HorizontalGridView; import android.util.Log; import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; import com.android.tv.ChannelTuner; diff --git a/src/com/android/tv/menu/MenuLayoutManager.java b/src/com/android/tv/menu/MenuLayoutManager.java index a600f704..8f95db77 100644 --- a/src/com/android/tv/menu/MenuLayoutManager.java +++ b/src/com/android/tv/menu/MenuLayoutManager.java @@ -25,15 +25,15 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; import android.support.annotation.UiThread; -import android.support.v4.view.animation.FastOutLinearInInterpolator; -import android.support.v4.view.animation.FastOutSlowInInterpolator; -import android.support.v4.view.animation.LinearOutSlowInInterpolator; -import android.support.v7.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView; import android.util.Log; import android.util.Property; import android.view.View; import android.view.ViewGroup.MarginLayoutParams; import android.widget.TextView; +import androidx.interpolator.view.animation.FastOutLinearInInterpolator; +import androidx.interpolator.view.animation.FastOutSlowInInterpolator; +import androidx.interpolator.view.animation.LinearOutSlowInInterpolator; import com.android.tv.R; import com.android.tv.common.SoftPreconditions; import com.android.tv.util.Utils; diff --git a/src/com/android/tv/menu/MenuRowFactory.java b/src/com/android/tv/menu/MenuRowFactory.java index 048d725d..a3837a10 100644 --- a/src/com/android/tv/menu/MenuRowFactory.java +++ b/src/com/android/tv/menu/MenuRowFactory.java @@ -24,6 +24,7 @@ import com.android.tv.R; import com.android.tv.common.customization.CustomAction; import com.android.tv.common.customization.CustomizationManager; import com.android.tv.ui.TunableTvView; +import com.android.tv.common.flags.LegacyFlags; import java.util.List; /** A factory class to create menu rows. */ @@ -31,12 +32,15 @@ public class MenuRowFactory { private final MainActivity mMainActivity; private final TunableTvView mTvView; private final CustomizationManager mCustomizationManager; + private final LegacyFlags mLegacyFlags; /** A constructor. */ - public MenuRowFactory(MainActivity mainActivity, TunableTvView tvView) { + public MenuRowFactory( + MainActivity mainActivity, TunableTvView tvView, LegacyFlags mLegacyFlags) { mMainActivity = mainActivity; mTvView = tvView; mCustomizationManager = new CustomizationManager(mainActivity); + this.mLegacyFlags = mLegacyFlags; mCustomizationManager.initialize(); } @@ -60,7 +64,8 @@ public class MenuRowFactory { return new TvOptionsRow( mMainActivity, menu, - mCustomizationManager.getCustomActions(CustomizationManager.ID_OPTIONS_ROW)); + mCustomizationManager.getCustomActions(CustomizationManager.ID_OPTIONS_ROW), + mLegacyFlags); } return null; } @@ -70,13 +75,17 @@ public class MenuRowFactory { /** The ID of the row. */ public static final String ID = TvOptionsRow.class.getName(); - private TvOptionsRow(Context context, Menu menu, List<CustomAction> customActions) { + private TvOptionsRow( + Context context, + Menu menu, + List<CustomAction> customActions, + LegacyFlags legacyFlags) { super( context, menu, R.string.menu_title_options, R.dimen.action_card_height, - new TvOptionsRowAdapter(context, customActions)); + new TvOptionsRowAdapter(context, customActions, legacyFlags)); } } diff --git a/src/com/android/tv/menu/TvOptionsRowAdapter.java b/src/com/android/tv/menu/TvOptionsRowAdapter.java index fe52b25e..418560a8 100644 --- a/src/com/android/tv/menu/TvOptionsRowAdapter.java +++ b/src/com/android/tv/menu/TvOptionsRowAdapter.java @@ -19,8 +19,8 @@ package com.android.tv.menu; import android.content.Context; import android.media.tv.TvTrackInfo; import com.android.tv.TvOptionsManager; +import com.android.tv.common.BuildConfig; import com.android.tv.common.customization.CustomAction; -import com.android.tv.common.util.CommonUtils; import com.android.tv.data.DisplayMode; import com.android.tv.features.TvFeatures; import com.android.tv.ui.TvViewUiManager; @@ -28,6 +28,7 @@ import com.android.tv.ui.sidepanel.ClosedCaptionFragment; import com.android.tv.ui.sidepanel.DeveloperOptionFragment; import com.android.tv.ui.sidepanel.DisplayModeFragment; import com.android.tv.ui.sidepanel.MultiAudioFragment; +import com.android.tv.common.flags.LegacyFlags; import java.util.ArrayList; import java.util.List; @@ -35,8 +36,12 @@ import java.util.List; * An adapter of options. */ public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter { - public TvOptionsRowAdapter(Context context, List<CustomAction> customActions) { + private final LegacyFlags mLegacyFlags; + + public TvOptionsRowAdapter( + Context context, List<CustomAction> customActions, LegacyFlags mLegacyFlags) { super(context, customActions); + this.mLegacyFlags = mLegacyFlags; } @Override @@ -49,7 +54,7 @@ public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter { } actionList.add(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION); actionList.add(MenuAction.MORE_CHANNELS_ACTION); - if (CommonUtils.isDeveloper()) { + if (BuildConfig.ENG || mLegacyFlags.enableDeveloperFeatures()) { actionList.add(MenuAction.DEV_ACTION); } actionList.add(MenuAction.SETTINGS_ACTION); diff --git a/src/com/android/tv/modules/TvApplicationModule.java b/src/com/android/tv/modules/TvApplicationModule.java index 45383ae1..26c2be23 100644 --- a/src/com/android/tv/modules/TvApplicationModule.java +++ b/src/com/android/tv/modules/TvApplicationModule.java @@ -17,15 +17,24 @@ package com.android.tv.modules; import android.content.Context; import com.android.tv.MainActivity; +import com.android.tv.SetupPassthroughActivity; import com.android.tv.TvApplication; +import com.android.tv.common.buildtype.BuildTypeModule; import com.android.tv.common.concurrent.NamedThreadFactory; import com.android.tv.common.dagger.ApplicationModule; import com.android.tv.common.dagger.annotations.ApplicationContext; +import com.android.tv.data.ChannelDataManager; +import com.android.tv.data.ChannelDataManagerFactory; +import com.android.tv.dialog.PinDialogFragment; +import com.android.tv.dvr.ui.playback.DvrPlaybackActivity; import com.android.tv.onboarding.OnboardingActivity; +import com.android.tv.ui.DetailsActivity; import com.android.tv.util.AsyncDbTask; import com.android.tv.util.TvInputManagerHelper; import dagger.Module; import dagger.Provides; +import dagger.android.ContributesAndroidInjector; +import com.android.tv.common.flags.LegacyFlags; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import javax.inject.Singleton; @@ -34,25 +43,43 @@ import javax.inject.Singleton; @Module( includes = { ApplicationModule.class, - TvSingletonsModule.class, + BuildTypeModule.class, + DetailsActivity.Module.class, + DvrPlaybackActivity.Module.class, MainActivity.Module.class, - OnboardingActivity.Module.class + OnboardingActivity.Module.class, + SetupPassthroughActivity.Module.class, + TvSingletonsModule.class, }) -public class TvApplicationModule { +public abstract class TvApplicationModule { private static final NamedThreadFactory THREAD_FACTORY = new NamedThreadFactory("tv-app-db"); @Provides @AsyncDbTask.DbExecutor @Singleton - Executor providesDbExecutor() { + static Executor providesDbExecutor() { return Executors.newSingleThreadExecutor(THREAD_FACTORY); } @Provides @Singleton - TvInputManagerHelper providesTvInputManagerHelper(@ApplicationContext Context context) { - TvInputManagerHelper tvInputManagerHelper = new TvInputManagerHelper(context); + static TvInputManagerHelper providesTvInputManagerHelper( + @ApplicationContext Context context, LegacyFlags legacyFlags) { + TvInputManagerHelper tvInputManagerHelper = new TvInputManagerHelper(context, legacyFlags); tvInputManagerHelper.start(); + // Since this is injected as a Lazy in the application start is delayed. return tvInputManagerHelper; } + + @Provides + @Singleton + static ChannelDataManager providesChannelDataManager(ChannelDataManagerFactory factory) { + ChannelDataManager channelDataManager = factory.create(); + channelDataManager.start(); + // Since this is injected as a Lazy in the application start is delayed. + return channelDataManager; + } + + @ContributesAndroidInjector + abstract PinDialogFragment contributesPinDialogFragment(); } diff --git a/src/com/android/tv/modules/TvSingletonsModule.java b/src/com/android/tv/modules/TvSingletonsModule.java index f998c08b..41206c9b 100644 --- a/src/com/android/tv/modules/TvSingletonsModule.java +++ b/src/com/android/tv/modules/TvSingletonsModule.java @@ -16,8 +16,9 @@ package com.android.tv.modules; import com.android.tv.TvSingletons; -import com.android.tv.data.ChannelDataManager; import com.android.tv.data.ProgramDataManager; +import com.android.tv.dvr.DvrDataManager; +import com.android.tv.dvr.DvrWatchedPositionManager; import dagger.Module; import dagger.Provides; @@ -36,8 +37,13 @@ public class TvSingletonsModule { } @Provides - ChannelDataManager providesChannelDataManager() { - return mTvSingletons.getChannelDataManager(); + DvrDataManager providesDvrDataManager() { + return mTvSingletons.getDvrDataManager(); + } + + @Provides + DvrWatchedPositionManager providesDvrWatchedPositionManager() { + return mTvSingletons.getDvrWatchedPositionManager(); } @Provides diff --git a/src/com/android/tv/onboarding/OnboardingActivity.java b/src/com/android/tv/onboarding/OnboardingActivity.java index 776ae664..1739e5a0 100644 --- a/src/com/android/tv/onboarding/OnboardingActivity.java +++ b/src/com/android/tv/onboarding/OnboardingActivity.java @@ -88,7 +88,7 @@ public class OnboardingActivity extends SetupActivity { TvSingletons singletons = TvSingletons.getSingletons(this); mInputManager = singletons.getTvInputManagerHelper(); if (PermissionUtils.hasAccessAllEpg(this) || PermissionUtils.hasReadTvListings(this)) { - // Make the channels of the new inputs which have been setup outside Live TV + // Make the channels of the new inputs which have been setup outside TV app // browsable. if (mChannelDataManager.isDbLoadFinished()) { mSetupUtils.markNewChannelsBrowsable(); @@ -187,7 +187,7 @@ public class OnboardingActivity extends SetupActivity { } // Even though other app can handle the intent, the setup launched by // Live - // channels should go through Live channels SetupPassthroughActivity. + // channels should go through TV app SetupPassthroughActivity. intent.setComponent( new ComponentName(this, SetupPassthroughActivity.class)); try { diff --git a/src/com/android/tv/onboarding/SetupSourcesFragment.java b/src/com/android/tv/onboarding/SetupSourcesFragment.java index 3566c9c3..bf842dd8 100644 --- a/src/com/android/tv/onboarding/SetupSourcesFragment.java +++ b/src/com/android/tv/onboarding/SetupSourcesFragment.java @@ -22,10 +22,10 @@ import android.media.tv.TvInputInfo; import android.media.tv.TvInputManager.TvInputCallback; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.v17.leanback.widget.GuidanceStylist.Guidance; -import android.support.v17.leanback.widget.GuidedAction; -import android.support.v17.leanback.widget.GuidedActionsStylist; -import android.support.v17.leanback.widget.VerticalGridView; +import androidx.leanback.widget.GuidanceStylist.Guidance; +import androidx.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidedActionsStylist; +import androidx.leanback.widget.VerticalGridView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/src/com/android/tv/onboarding/WelcomeFragment.java b/src/com/android/tv/onboarding/WelcomeFragment.java index 8c119a8a..667da058 100644 --- a/src/com/android/tv/onboarding/WelcomeFragment.java +++ b/src/com/android/tv/onboarding/WelcomeFragment.java @@ -25,7 +25,7 @@ import android.animation.AnimatorSet; import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.v17.leanback.app.OnboardingFragment; +import androidx.leanback.app.OnboardingFragment; import android.text.Editable; import android.text.TextWatcher; import android.view.Gravity; @@ -621,9 +621,9 @@ public class WelcomeFragment extends OnboardingFragment { LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = super.onCreateView(inflater, container, savedInstanceState); setLogoResourceId(R.drawable.splash_logo); - mTitleView = view.findViewById(android.support.v17.leanback.R.id.title); - mPagingIndicator = view.findViewById(android.support.v17.leanback.R.id.page_indicator); - mStartButton = view.findViewById(android.support.v17.leanback.R.id.button_start); + mTitleView = view.findViewById(androidx.leanback.R.id.title); + mPagingIndicator = view.findViewById(androidx.leanback.R.id.page_indicator); + mStartButton = view.findViewById(androidx.leanback.R.id.button_start); mStartButton.setAccessibilityDelegate( new AccessibilityDelegate() { diff --git a/src/com/android/tv/parental/ContentRatingsManager.java b/src/com/android/tv/parental/ContentRatingsManager.java index 32a1325b..174039ba 100644 --- a/src/com/android/tv/parental/ContentRatingsManager.java +++ b/src/com/android/tv/parental/ContentRatingsManager.java @@ -22,6 +22,7 @@ import android.media.tv.TvContentRatingSystemInfo; import android.support.annotation.Nullable; import android.text.TextUtils; import com.android.tv.R; +import com.android.tv.common.util.PermissionUtils; import com.android.tv.parental.ContentRatingSystem.Rating; import com.android.tv.parental.ContentRatingSystem.SubRating; import com.android.tv.util.TvInputManagerHelper; @@ -42,13 +43,14 @@ public class ContentRatingsManager { public void update() { mContentRatingSystems.clear(); - ContentRatingsParser parser = new ContentRatingsParser(mContext); - - List<TvContentRatingSystemInfo> infos = mTvInputManager.getTvContentRatingSystemList(); - for (TvContentRatingSystemInfo info : infos) { - List<ContentRatingSystem> list = parser.parse(info); - if (list != null) { - mContentRatingSystems.addAll(list); + if (PermissionUtils.hasReadContetnRatingSystem(mContext)) { + ContentRatingsParser parser = new ContentRatingsParser(mContext); + List<TvContentRatingSystemInfo> infos = mTvInputManager.getTvContentRatingSystemList(); + for (TvContentRatingSystemInfo info : infos) { + List<ContentRatingSystem> list = parser.parse(info); + if (list != null) { + mContentRatingSystems.addAll(list); + } } } } diff --git a/src/com/android/tv/parental/ParentalControlSettings.java b/src/com/android/tv/parental/ParentalControlSettings.java index b41b160e..9990ae35 100644 --- a/src/com/android/tv/parental/ParentalControlSettings.java +++ b/src/com/android/tv/parental/ParentalControlSettings.java @@ -19,12 +19,12 @@ package com.android.tv.parental; import android.content.Context; import android.media.tv.TvContentRating; import android.media.tv.TvInputManager; -import com.android.tv.common.experiments.Experiments; import com.android.tv.parental.ContentRatingSystem.Rating; import com.android.tv.parental.ContentRatingSystem.SubRating; import com.android.tv.util.TvSettings; import com.android.tv.util.TvSettings.ContentRatingLevel; import com.google.common.collect.ImmutableList; +import com.android.tv.common.flags.LegacyFlags; import java.util.HashSet; import java.util.Set; @@ -40,14 +40,16 @@ public class ParentalControlSettings { private final Context mContext; private final TvInputManager mTvInputManager; + private final LegacyFlags mLegacyFlags; // mRatings is expected to be synchronized with mTvInputManager.getBlockedRatings(). private Set<TvContentRating> mRatings; private Set<TvContentRating> mCustomRatings; - public ParentalControlSettings(Context context) { + public ParentalControlSettings(Context context, LegacyFlags legacyFlags) { mContext = context; mTvInputManager = (TvInputManager) mContext.getSystemService(Context.TV_INPUT_SERVICE); + mLegacyFlags = legacyFlags; } public boolean isParentalControlsEnabled() { @@ -130,7 +132,7 @@ public class ParentalControlSettings { } else { mRatings = ContentRatingLevelPolicy.getRatingsForLevel(this, manager, level); if (level != TvSettings.CONTENT_RATING_LEVEL_NONE - && Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { + && mLegacyFlags.enableUnratedContentSettings()) { // UNRATED contents should be blocked unless the rating level is none or custom mRatings.add(TvContentRating.UNRATED); } diff --git a/src/com/android/tv/perf/PerformanceMonitor.java b/src/com/android/tv/perf/PerformanceMonitor.java index b1ae759d..30197c74 100644 --- a/src/com/android/tv/perf/PerformanceMonitor.java +++ b/src/com/android/tv/perf/PerformanceMonitor.java @@ -96,4 +96,14 @@ public interface PerformanceMonitor { * @return true if the activity is available to start */ boolean startPerformanceMonitorEventDebugActivity(Context context); + + /** + * Initialize crash monitoring for an app by wrapping the default {@link + * Thread.UncaughtExceptionHandler} with a handler that can report crashes to the performance + * montitor and then delegate the handling of the UncaughtException to the original default + * {@link Thread.UncaughtExceptionHandler}. + * + * <p>Note: This will override the current {@link Thread.UncaughtExceptionHandler}. + */ + void startCrashMonitor(); } diff --git a/src/com/android/tv/perf/PerformanceMonitorManager.java b/src/com/android/tv/perf/PerformanceMonitorManager.java deleted file mode 100644 index db6667d1..00000000 --- a/src/com/android/tv/perf/PerformanceMonitorManager.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.tv.perf; - -import android.app.Application; - -/** Manages the initialization of Performance Monitoring. */ -public interface PerformanceMonitorManager { - - /** - * Initializes the {@link com.android.tv.perf.PerformanceMonitor}. - * - * <p>This should only be called once. - */ - PerformanceMonitor initialize(Application app); - - /** - * Returns a lightweight object to help measure both cold and warm startup latency. - * - * <p>This method is idempotent and lightweight. It can be called multiple times and does not - * need to be cached. - */ - StartupMeasure getStartupMeasure(); -} diff --git a/src/com/android/tv/perf/StartupMeasure.java b/src/com/android/tv/perf/StartupMeasure.java index 5cf183ca..c7fa50fe 100644 --- a/src/com/android/tv/perf/StartupMeasure.java +++ b/src/com/android/tv/perf/StartupMeasure.java @@ -19,8 +19,16 @@ import android.app.Activity; import android.app.Application; /** - * Measures App startup. This interface is lightweight to help measure both cold and warm startup - * latency. Implementations must not throw any Exception. + * Measures App startup. + * + * <p>This interface is lightweight to help measure both cold and warm startup latency. + * Implementations must not throw any Exception. + * + * <p>Because this class needs to be used in static initialization blocks, it can not be injected + * via dagger. + * + * <p>Creating implementations of this interface must be idempotent and lightweight. It does not + * need to be cached. */ public interface StartupMeasure { diff --git a/src/com/android/tv/perf/stub/StubPerformanceMonitor.java b/src/com/android/tv/perf/stub/StubPerformanceMonitor.java index 80c2f6c5..ac3dc250 100644 --- a/src/com/android/tv/perf/stub/StubPerformanceMonitor.java +++ b/src/com/android/tv/perf/stub/StubPerformanceMonitor.java @@ -56,7 +56,6 @@ public final class StubPerformanceMonitor implements PerformanceMonitor { return false; } - public static TimerEvent startBootstrapTimer() { - return new TimerEvent() {}; - } + @Override + public void startCrashMonitor() {} } diff --git a/src/com/android/tv/perf/stub/StubPerformanceMonitorManager.java b/src/com/android/tv/perf/stub/StubPerformanceMonitorManager.java deleted file mode 100644 index 0c268155..00000000 --- a/src/com/android/tv/perf/stub/StubPerformanceMonitorManager.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.tv.perf.stub; - -import android.app.Application; -import com.android.tv.perf.PerformanceMonitor; -import com.android.tv.perf.PerformanceMonitorManager; -import com.android.tv.perf.StartupMeasure; - -/** Manages a stub implementation of Performance Monitoring. */ -public class StubPerformanceMonitorManager implements PerformanceMonitorManager { - - @Override - public PerformanceMonitor initialize(Application app) { - return new StubPerformanceMonitor(); - } - - @Override - public StartupMeasure getStartupMeasure() { - return new StubStartupMeasure(); - } -} diff --git a/src/com/android/tv/receiver/PackageIntentsReceiver.java b/src/com/android/tv/receiver/PackageIntentsReceiver.java index 5bc6d724..7ff67b50 100644 --- a/src/com/android/tv/receiver/PackageIntentsReceiver.java +++ b/src/com/android/tv/receiver/PackageIntentsReceiver.java @@ -23,9 +23,7 @@ import android.net.Uri; import android.util.Log; import com.android.tv.Starter; import com.android.tv.TvSingletons; -import com.android.tv.features.TvFeatures; import com.android.tv.util.Partner; -import com.google.android.tv.partner.support.EpgContract; /** A class for handling the broadcast intents from PackageManager. */ public class PackageIntentsReceiver extends BroadcastReceiver { diff --git a/src/com/android/tv/recommendation/RecommendationDataManager.java b/src/com/android/tv/recommendation/RecommendationDataManager.java index fc20031c..83f11bd4 100644 --- a/src/com/android/tv/recommendation/RecommendationDataManager.java +++ b/src/com/android/tv/recommendation/RecommendationDataManager.java @@ -232,6 +232,9 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener @MainThread private void stop() { + if (mWatchedHistoryManager != null) { + mWatchedHistoryManager.setListener(null); + } for (int what = MSG_FIRST; what <= MSG_LAST; ++what) { mHandler.removeMessages(what); } diff --git a/src/com/android/tv/search/ProgramGuideSearchFragment.java b/src/com/android/tv/search/ProgramGuideSearchFragment.java index 6c94bd33..fa2e4516 100644 --- a/src/com/android/tv/search/ProgramGuideSearchFragment.java +++ b/src/com/android/tv/search/ProgramGuideSearchFragment.java @@ -21,18 +21,18 @@ import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.os.AsyncTask; import android.os.Bundle; -import android.support.v17.leanback.app.SearchFragment; -import android.support.v17.leanback.widget.ArrayObjectAdapter; -import android.support.v17.leanback.widget.HeaderItem; -import android.support.v17.leanback.widget.ImageCardView; -import android.support.v17.leanback.widget.ListRow; -import android.support.v17.leanback.widget.ListRowPresenter; -import android.support.v17.leanback.widget.ObjectAdapter; -import android.support.v17.leanback.widget.OnItemViewClickedListener; -import android.support.v17.leanback.widget.Presenter; -import android.support.v17.leanback.widget.Row; -import android.support.v17.leanback.widget.RowPresenter; -import android.support.v17.leanback.widget.SearchBar; +import androidx.leanback.app.SearchFragment; +import androidx.leanback.widget.ArrayObjectAdapter; +import androidx.leanback.widget.HeaderItem; +import androidx.leanback.widget.ImageCardView; +import androidx.leanback.widget.ListRow; +import androidx.leanback.widget.ListRowPresenter; +import androidx.leanback.widget.ObjectAdapter; +import androidx.leanback.widget.OnItemViewClickedListener; +import androidx.leanback.widget.Presenter; +import androidx.leanback.widget.Row; +import androidx.leanback.widget.RowPresenter; +import androidx.leanback.widget.SearchBar; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; diff --git a/src/com/android/tv/setup/SystemSetupActivity.java b/src/com/android/tv/setup/SystemSetupActivity.java index b2160b3a..a392fdbe 100644 --- a/src/com/android/tv/setup/SystemSetupActivity.java +++ b/src/com/android/tv/setup/SystemSetupActivity.java @@ -92,7 +92,7 @@ public class SystemSetupActivity extends SetupActivity { } // Even though other app can handle the intent, the setup launched by // Live - // channels should go through Live channels SetupPassthroughActivity. + // channels should go through TV app SetupPassthroughActivity. intent.setComponent( new ComponentName(this, SetupPassthroughActivity.class)); try { diff --git a/src/com/android/tv/ui/AppLayerTvView.java b/src/com/android/tv/ui/AppLayerTvView.java index e2b64a1e..4c54fb3c 100644 --- a/src/com/android/tv/ui/AppLayerTvView.java +++ b/src/com/android/tv/ui/AppLayerTvView.java @@ -21,7 +21,6 @@ import android.util.AttributeSet; import android.view.SurfaceView; import android.view.View; import com.android.tv.common.compat.TvViewCompat; -import com.android.tv.common.util.CommonUtils; import com.android.tv.common.util.Debug; /** @@ -29,9 +28,14 @@ import com.android.tv.common.util.Debug; * * <p>Once an app starts using additional window like SubPanel and it gets window focus, the {@link * android.media.tv.TvView#setMain()} does not work because its implementation assumes that the app - * uses only application layer. TODO: remove this class once the TvView.setMain() is revisited. + * uses only application layer. + * + * <p>TODO: remove this class once the TvView.setMain() is revisited. */ public class AppLayerTvView extends TvViewCompat { + + boolean mUseSecureSurface = true; + public AppLayerTvView(Context context) { super(context); } @@ -44,6 +48,11 @@ public class AppLayerTvView extends TvViewCompat { super(context, attrs, defStyleAttr); } + /** Set the security of children {@link SurfaceView}s to {@code secure} */ + public void setUseSecureSurface(boolean secure) { + mUseSecureSurface = secure; + } + @Override public boolean hasWindowFocus() { return true; @@ -53,7 +62,7 @@ public class AppLayerTvView extends TvViewCompat { public void onViewAdded(View child) { if (child instanceof SurfaceView) { // Note: See b/29118070 for detail. - ((SurfaceView) child).setSecure(!CommonUtils.isDeveloper()); + ((SurfaceView) child).setSecure(mUseSecureSurface); } super.onViewAdded(child); } diff --git a/src/com/android/tv/ui/ChannelBannerView.java b/src/com/android/tv/ui/ChannelBannerView.java index 00ac7e32..bce4d6b5 100644 --- a/src/com/android/tv/ui/ChannelBannerView.java +++ b/src/com/android/tv/ui/ChannelBannerView.java @@ -118,6 +118,7 @@ public class ChannelBannerView extends FrameLayout private final TvInputManagerHelper mTvInputManagerHelper; // TvOverlayManager is always created after ChannelBannerView private final Provider<TvOverlayManager> mTvOverlayManager; + private final AccessibilityManager mAccessibilityManager; private View mChannelView; @@ -278,8 +279,7 @@ public class ChannelBannerView extends FrameLayout sClosedCaptionMark = context.getString(R.string.closed_caption); } mAutoHideScheduler = new AutoHideScheduler(context, this::hide); - context.getSystemService(AccessibilityManager.class) - .addAccessibilityStateChangeListener(mAutoHideScheduler); + mAccessibilityManager = context.getSystemService(AccessibilityManager.class); } @Override @@ -319,6 +319,20 @@ public class ChannelBannerView extends FrameLayout } @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mAccessibilityManager + .addAccessibilityStateChangeListener(mAutoHideScheduler); + } + + @Override + protected void onDetachedFromWindow() { + mAccessibilityManager + .removeAccessibilityStateChangeListener(mAutoHideScheduler); + super.onDetachedFromWindow(); + } + + @Override public void onEnterAction(boolean fromEmptyScene) { resetAnimationEffects(); if (fromEmptyScene) { diff --git a/src/com/android/tv/ui/DetailsActivity.java b/src/com/android/tv/ui/DetailsActivity.java index 80c0f64b..92c13f57 100644 --- a/src/com/android/tv/ui/DetailsActivity.java +++ b/src/com/android/tv/ui/DetailsActivity.java @@ -16,12 +16,11 @@ package com.android.tv.ui; -import android.app.Activity; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.NonNull; -import android.support.v17.leanback.app.DetailsFragment; +import androidx.leanback.app.DetailsFragment; import android.transition.Transition; import android.transition.Transition.TransitionListener; import android.util.Log; @@ -35,9 +34,12 @@ import com.android.tv.dvr.ui.browse.CurrentRecordingDetailsFragment; import com.android.tv.dvr.ui.browse.RecordedProgramDetailsFragment; import com.android.tv.dvr.ui.browse.ScheduledRecordingDetailsFragment; import com.android.tv.dvr.ui.browse.SeriesRecordingDetailsFragment; +import dagger.android.ContributesAndroidInjector; +import dagger.android.DaggerActivity; /** Activity to show details view. */ -public class DetailsActivity extends Activity implements PinDialogFragment.OnPinCheckedListener { +public class DetailsActivity extends DaggerActivity + implements PinDialogFragment.OnPinCheckedListener { private static final String TAG = "DetailsActivity"; private static final long INVALID_RECORD_ID = -1; @@ -206,4 +208,15 @@ public class DetailsActivity extends Activity implements PinDialogFragment.OnPin } finish(); } + + /** Exports {@link DaggerActivity} for Dagger codegen to create the appropriate injector. */ + @dagger.Module + public abstract static class Module { + @ContributesAndroidInjector + abstract DetailsActivity contributesDetailsActivityInjector(); + + @ContributesAndroidInjector + abstract CurrentRecordingDetailsFragment + contributesCurrentRecordingDetailsFragmentInjector(); + } } diff --git a/src/com/android/tv/ui/GuidedActionsStylistWithDivider.java b/src/com/android/tv/ui/GuidedActionsStylistWithDivider.java index 9685b04b..3aba5d1d 100644 --- a/src/com/android/tv/ui/GuidedActionsStylistWithDivider.java +++ b/src/com/android/tv/ui/GuidedActionsStylistWithDivider.java @@ -17,9 +17,9 @@ package com.android.tv.ui; import android.content.Context; -import android.support.v17.leanback.app.GuidedStepFragment; -import android.support.v17.leanback.widget.GuidedAction; -import android.support.v17.leanback.widget.GuidedActionsStylist; +import androidx.leanback.app.GuidedStepFragment; +import androidx.leanback.widget.GuidedAction; +import androidx.leanback.widget.GuidedActionsStylist; import com.android.tv.R; /** Extended stylist class used for {@link GuidedStepFragment} with divider support. */ diff --git a/src/com/android/tv/ui/OnRepeatedKeyInterceptListener.java b/src/com/android/tv/ui/OnRepeatedKeyInterceptListener.java index 9b916afe..703dc242 100644 --- a/src/com/android/tv/ui/OnRepeatedKeyInterceptListener.java +++ b/src/com/android/tv/ui/OnRepeatedKeyInterceptListener.java @@ -17,7 +17,7 @@ package com.android.tv.ui; import android.os.Message; import android.support.annotation.NonNull; -import android.support.v17.leanback.widget.VerticalGridView; +import androidx.leanback.widget.VerticalGridView; import android.util.Log; import android.view.KeyEvent; import android.view.View; diff --git a/src/com/android/tv/ui/ProgramDetailsFragment.java b/src/com/android/tv/ui/ProgramDetailsFragment.java index 88a7b2ca..3d62e494 100644 --- a/src/com/android/tv/ui/ProgramDetailsFragment.java +++ b/src/com/android/tv/ui/ProgramDetailsFragment.java @@ -23,16 +23,16 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.v17.leanback.app.DetailsFragment; -import android.support.v17.leanback.widget.Action; -import android.support.v17.leanback.widget.ArrayObjectAdapter; -import android.support.v17.leanback.widget.ClassPresenterSelector; -import android.support.v17.leanback.widget.DetailsOverviewRow; -import android.support.v17.leanback.widget.DetailsOverviewRowPresenter; -import android.support.v17.leanback.widget.OnActionClickedListener; -import android.support.v17.leanback.widget.PresenterSelector; -import android.support.v17.leanback.widget.SparseArrayObjectAdapter; -import android.support.v17.leanback.widget.VerticalGridView; +import androidx.leanback.app.DetailsFragment; +import androidx.leanback.widget.Action; +import androidx.leanback.widget.ArrayObjectAdapter; +import androidx.leanback.widget.ClassPresenterSelector; +import androidx.leanback.widget.DetailsOverviewRow; +import androidx.leanback.widget.DetailsOverviewRowPresenter; +import androidx.leanback.widget.OnActionClickedListener; +import androidx.leanback.widget.PresenterSelector; +import androidx.leanback.widget.SparseArrayObjectAdapter; +import androidx.leanback.widget.VerticalGridView; import android.text.TextUtils; import com.android.tv.R; import com.android.tv.TvSingletons; diff --git a/src/com/android/tv/ui/SelectInputView.java b/src/com/android/tv/ui/SelectInputView.java index f4949f08..a0cfad32 100644 --- a/src/com/android/tv/ui/SelectInputView.java +++ b/src/com/android/tv/ui/SelectInputView.java @@ -22,8 +22,8 @@ import android.media.tv.TvInputInfo; import android.media.tv.TvInputManager; import android.media.tv.TvInputManager.TvInputCallback; import android.support.annotation.NonNull; -import android.support.v17.leanback.widget.VerticalGridView; -import android.support.v7.widget.RecyclerView; +import androidx.leanback.widget.VerticalGridView; +import androidx.recyclerview.widget.RecyclerView; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; diff --git a/src/com/android/tv/ui/TunableTvView.java b/src/com/android/tv/ui/TunableTvView.java index 5ac6bd83..5a99b8be 100644 --- a/src/com/android/tv/ui/TunableTvView.java +++ b/src/com/android/tv/ui/TunableTvView.java @@ -59,6 +59,7 @@ import com.android.tv.InputSessionManager.TvViewSession; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.analytics.Tracker; +import com.android.tv.common.BuildConfig; import com.android.tv.common.CommonConstants; import com.android.tv.common.compat.TvInputConstantCompat; import com.android.tv.common.compat.TvViewCompat.TvInputCallbackCompat; @@ -81,6 +82,7 @@ import com.android.tv.util.NetworkUtils; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; import com.android.tv.util.images.ImageLoader; +import com.android.tv.common.flags.LegacyFlags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; @@ -317,7 +319,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo, TunableTvV if (DEBUG) Log.d(TAG, "onVideoAvailable: {inputId=" + inputId + "}"); Debug.getTimer(Debug.TAG_START_UP_TIMER) .log( - "Start up of Live TV ends," + "Start up of TV app ends," + " TunableTvView.onVideoAvailable resets timer"); Debug.getTimer(Debug.TAG_START_UP_TIMER).reset(); Debug.removeTimer(Debug.TAG_START_UP_TIMER); @@ -473,8 +475,12 @@ public class TunableTvView extends FrameLayout implements StreamInfo, TunableTvV } public void initialize( - ProgramDataManager programDataManager, TvInputManagerHelper tvInputManagerHelper) { + ProgramDataManager programDataManager, + TvInputManagerHelper tvInputManagerHelper, + LegacyFlags mLegacyFlags) { mTvView = findViewById(R.id.tv_view); + mTvView.setUseSecureSurface(!BuildConfig.ENG && !mLegacyFlags.enableDeveloperFeatures()); + mProgramDataManager = programDataManager; mInputManagerHelper = tvInputManagerHelper; mContentRatingsManager = tvInputManagerHelper.getContentRatingsManager(); @@ -553,7 +559,9 @@ public class TunableTvView extends FrameLayout implements StreamInfo, TunableTvV } public void setMain() { - mTvView.setMain(); + if (PermissionUtils.hasChangeHdmiCecActiveSource(getContext())) { + mTvView.setMain(); + } } public void setWatchedHistoryManager(WatchedHistoryManager watchedHistoryManager) { diff --git a/src/com/android/tv/ui/TvOverlayManager.java b/src/com/android/tv/ui/TvOverlayManager.java index b2854a1f..9b04d74e 100644 --- a/src/com/android/tv/ui/TvOverlayManager.java +++ b/src/com/android/tv/ui/TvOverlayManager.java @@ -68,6 +68,7 @@ import com.android.tv.ui.TvTransitionManager.SceneType; import com.android.tv.ui.sidepanel.SideFragmentManager; import com.android.tv.ui.sidepanel.parentalcontrols.RatingsFragment; import com.android.tv.util.TvInputManagerHelper; +import com.android.tv.common.flags.LegacyFlags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -216,6 +217,7 @@ public class TvOverlayManager implements AccessibilityStateChangeListener { private final List<Runnable> mPendingActions = new ArrayList<>(); private final Queue<PendingDialogAction> mPendingDialogActionQueue = new LinkedList<>(); + private final LegacyFlags mLegacyFlags; private OnBackStackChangedListener mOnBackStackChangedListener; @@ -229,9 +231,11 @@ public class TvOverlayManager implements AccessibilityStateChangeListener { InputBannerView inputBannerView, SelectInputView selectInputView, ViewGroup sceneContainer, - ProgramGuideSearchFragment searchFragment) { + ProgramGuideSearchFragment searchFragment, + LegacyFlags mLegacyFlags) { mMainActivity = mainActivity; mChannelTuner = channelTuner; + this.mLegacyFlags = mLegacyFlags; TvSingletons singletons = TvSingletons.getSingletons(mainActivity); mChannelDataManager = singletons.getChannelDataManager(); mInputManager = singletons.getTvInputManagerHelper(); @@ -271,7 +275,7 @@ public class TvOverlayManager implements AccessibilityStateChangeListener { tvView, optionsManager, menuView, - new MenuRowFactory(mainActivity, tvView), + new MenuRowFactory(mainActivity, tvView, this.mLegacyFlags), new Menu.OnMenuVisibilityChangeListener() { @Override public void onMenuVisibilityChange(boolean visible) { diff --git a/src/com/android/tv/ui/ViewUtils.java b/src/com/android/tv/ui/ViewUtils.java index f64a70b2..faef2f50 100644 --- a/src/com/android/tv/ui/ViewUtils.java +++ b/src/com/android/tv/ui/ViewUtils.java @@ -18,6 +18,7 @@ package com.android.tv.ui; import android.animation.Animator; import android.animation.ValueAnimator; +import android.support.v4.os.BuildCompat; // AOSP_Before_Q_Comment_Out import android.util.Log; import android.view.View; import android.view.ViewGroup.LayoutParams; @@ -33,6 +34,11 @@ public class ViewUtils { } public static void setTransitionAlpha(View v, float alpha) { + // Begin_AOSP_Before_Q_Comment_Out + if (BuildCompat.isAtLeastQ()) { + v.setTransitionAlpha(alpha); + } + // End_AOSP_Before_Q_Comment_Out Method method; try { method = View.class.getDeclaredMethod("setTransitionAlpha", Float.TYPE); diff --git a/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java b/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java index 62130b64..b62a57ee 100644 --- a/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java +++ b/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java @@ -20,7 +20,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.media.tv.TvContract.Channels; import android.os.Bundle; -import android.support.v17.leanback.widget.VerticalGridView; +import androidx.leanback.widget.VerticalGridView; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java b/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java index 36ee5a2d..81ff1fc5 100644 --- a/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java +++ b/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java @@ -16,29 +16,33 @@ package com.android.tv.ui.sidepanel; -import android.accounts.Account; -import android.app.Activity; -import android.support.annotation.NonNull; -import android.util.Log; -import android.widget.Toast; +import android.content.Context; +import com.android.tv.MainActivity; import com.android.tv.R; -import com.android.tv.TvSingletons; +import com.android.tv.common.BuildConfig; import com.android.tv.common.CommonPreferences; import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.common.util.CommonUtils; - - - - - -import java.util.ArrayList; -import java.util.List; +import com.android.tv.perf.PerformanceMonitor; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; +import dagger.android.AndroidInjection; +import com.android.tv.common.flags.LegacyFlags; +import javax.inject.Inject; /** Options for developers only */ public class DeveloperOptionFragment extends SideFragment { - private static final String TAG = "DeveloperOptionFragment"; private static final String TRACKER_LABEL = "debug options"; + @Inject Optional<AdditionalDeveloperItemsFactory> mAdditionalDeveloperItemsFactory; + @Inject PerformanceMonitor mPerformanceMonitor; + @Inject LegacyFlags mLegacyFlags; + + @Override + public void onAttach(Context context) { + AndroidInjection.inject(this); + super.onAttach(context); + } + @Override protected String getTitle() { return getString(R.string.menu_developer_options); @@ -50,8 +54,15 @@ public class DeveloperOptionFragment extends SideFragment { } @Override - protected List<Item> getItemList() { - List<Item> items = new ArrayList<>(); + protected ImmutableList<Item> getItemList() { + ImmutableList.Builder<Item> items = ImmutableList.builder(); + if (mAdditionalDeveloperItemsFactory.isPresent()) { + items.addAll( + mAdditionalDeveloperItemsFactory + .get() + .getAdditionalDevItems(getMainActivity())); + items.add(new DividerItem()); + } if (CommonFeatures.DVR.isEnabled(getContext())) { items.add( new ActionItem(getString(R.string.dev_item_dvr_history)) { @@ -61,7 +72,7 @@ public class DeveloperOptionFragment extends SideFragment { } }); } - if (CommonUtils.isDeveloper()) { + if (BuildConfig.ENG || mLegacyFlags.enableDeveloperFeatures()) { items.add( new ActionItem(getString(R.string.dev_item_watch_history)) { @Override @@ -87,17 +98,21 @@ public class DeveloperOptionFragment extends SideFragment { CommonPreferences.setStoreTsStream(getContext(), isChecked()); } }); - if (CommonUtils.isDeveloper()) { + if (BuildConfig.ENG || mLegacyFlags.enableDeveloperFeatures()) { items.add( new ActionItem(getString(R.string.dev_item_show_performance_monitor_log)) { @Override protected void onSelected() { - TvSingletons.getSingletons(getContext()) - .getPerformanceMonitor() - .startPerformanceMonitorEventDebugActivity(getContext()); + mPerformanceMonitor.startPerformanceMonitorEventDebugActivity( + getContext()); } }); } - return items; + return items.build(); + } + + /** Factory to create additional items. */ + public interface AdditionalDeveloperItemsFactory { + ImmutableList<Item> getAdditionalDevItems(MainActivity mainActivity); } } diff --git a/src/com/android/tv/ui/sidepanel/SettingsFragment.java b/src/com/android/tv/ui/sidepanel/SettingsFragment.java index aa71fb75..1c03b6a9 100644 --- a/src/com/android/tv/ui/sidepanel/SettingsFragment.java +++ b/src/com/android/tv/ui/sidepanel/SettingsFragment.java @@ -35,7 +35,7 @@ import com.android.tv.util.Utils; import java.util.ArrayList; import java.util.List; -/** Shows Live TV settings. */ +/** Shows TV app settings. */ public class SettingsFragment extends SideFragment { private static final String TRACKER_LABEL = "settings"; diff --git a/src/com/android/tv/ui/sidepanel/SideFragment.java b/src/com/android/tv/ui/sidepanel/SideFragment.java index 590f1300..1cbeeab5 100644 --- a/src/com/android/tv/ui/sidepanel/SideFragment.java +++ b/src/com/android/tv/ui/sidepanel/SideFragment.java @@ -20,8 +20,8 @@ import android.app.Fragment; import android.content.Context; import android.graphics.drawable.RippleDrawable; import android.os.Bundle; -import android.support.v17.leanback.widget.VerticalGridView; -import android.support.v7.widget.RecyclerView; +import androidx.leanback.widget.VerticalGridView; +import androidx.recyclerview.widget.RecyclerView; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java b/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java index b14bf78d..620b7017 100644 --- a/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java +++ b/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java @@ -23,7 +23,7 @@ import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.Handler; -import android.support.v17.leanback.widget.VerticalGridView; +import androidx.leanback.widget.VerticalGridView; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java b/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java index d1ae4423..064f86f1 100644 --- a/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java +++ b/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java @@ -16,6 +16,7 @@ package com.android.tv.ui.sidepanel.parentalcontrols; +import android.content.Context; import android.graphics.drawable.Drawable; import android.media.tv.TvContentRating; import android.os.Bundle; @@ -26,7 +27,6 @@ import android.widget.CompoundButton; import android.widget.ImageView; import com.android.tv.MainActivity; import com.android.tv.R; -import com.android.tv.common.experiments.Experiments; import com.android.tv.dialog.WebDialogFragment; import com.android.tv.license.LicenseUtils; import com.android.tv.parental.ContentRatingSystem; @@ -40,10 +40,13 @@ import com.android.tv.ui.sidepanel.SideFragment; import com.android.tv.util.TvSettings; import com.android.tv.util.TvSettings.ContentRatingLevel; import com.google.common.collect.ImmutableList; +import dagger.android.AndroidInjection; +import com.android.tv.common.flags.LegacyFlags; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import javax.inject.Inject; public class RatingsFragment extends SideFragment { private static final SparseIntArray sLevelResourceIdMap; @@ -51,6 +54,8 @@ public class RatingsFragment extends SideFragment { private static final String TRACKER_LABEL = "Ratings"; private int mItemsSize; + @Inject LegacyFlags mLegacyFlags; + static { sLevelResourceIdMap = new SparseIntArray(5); sLevelResourceIdMap.put(TvSettings.CONTENT_RATING_LEVEL_NONE, R.string.option_rating_none); @@ -101,8 +106,7 @@ public class RatingsFragment extends SideFragment { protected List<Item> getItemList() { List<Item> items = new ArrayList<>(); - if (mBlockUnratedItem != null - && Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { + if (mBlockUnratedItem != null && mLegacyFlags.enableUnratedContentSettings()) { items.add(mBlockUnratedItem); items.add(new DividerItem()); } @@ -158,7 +162,13 @@ public class RatingsFragment extends SideFragment { super.onCreate(savedInstanceState); mParentalControlSettings = getMainActivity().getParentalControlSettings(); mParentalControlSettings.loadRatings(); - if (Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { + } + + @Override + public void onAttach(Context context) { + AndroidInjection.inject(this); + super.onAttach(context); + if (mLegacyFlags.enableUnratedContentSettings()) { mBlockUnratedItem = new CheckBoxItem( getResources().getString(R.string.option_block_unrated_programs)) { @@ -179,6 +189,8 @@ public class RatingsFragment extends SideFragment { } } }; + } else { + mBlockUnratedItem = null; } } @@ -235,8 +247,7 @@ public class RatingsFragment extends SideFragment { super.onSelected(); mParentalControlSettings.setContentRatingLevel( getMainActivity().getContentRatingsManager(), mRatingLevel); - if (mBlockUnratedItem != null - && Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { + if (mBlockUnratedItem != null && mLegacyFlags.enableUnratedContentSettings()) { // set checked if UNRATED is blocked, and set unchecked otherwise. mBlockUnratedItem.setChecked( mParentalControlSettings.isRatingBlocked( diff --git a/src/com/android/tv/util/OnboardingUtils.java b/src/com/android/tv/util/OnboardingUtils.java index 3b72e091..4fae2f00 100644 --- a/src/com/android/tv/util/OnboardingUtils.java +++ b/src/com/android/tv/util/OnboardingUtils.java @@ -27,7 +27,9 @@ public final class OnboardingUtils { private static final String PREF_KEY_ONBOARDING_VERSION_CODE = "pref_onbaording_versionCode"; private static final int ONBOARDING_VERSION = 1; - private static final String MERCHANT_COLLECTION_URL_STRING = getMerchantCollectionUrl(); + // Replace as needed + private static final String MERCHANT_COLLECTION_URL_STRING = + "https://play.google.com/store/apps/collection/promotion_3001bf9_ATV_livechannels"; /** Intent to show merchant collection in online store. */ public static final Intent ONLINE_STORE_INTENT = @@ -69,10 +71,5 @@ public final class OnboardingUtils { .apply(); } - /** Returns merchant collection URL. */ - private static String getMerchantCollectionUrl() { - return "TODO: add a merchant collection url"; - } - private OnboardingUtils() {} } diff --git a/src/com/android/tv/util/SetupUtils.java b/src/com/android/tv/util/SetupUtils.java index a9b67fa8..52b3e3e8 100644 --- a/src/com/android/tv/util/SetupUtils.java +++ b/src/com/android/tv/util/SetupUtils.java @@ -307,8 +307,7 @@ public class SetupUtils { } /** - * Called when Live channels app is launched. Once it is called, {@link #isFirstTune} will - * return false. + * Called when TV app is launched. Once it is called, {@link #isFirstTune} will return false. */ public void onTuned() { if (!mIsFirstTune) { diff --git a/src/com/android/tv/util/TvInputManagerHelper.java b/src/com/android/tv/util/TvInputManagerHelper.java index a3064953..9945fbda 100644 --- a/src/com/android/tv/util/TvInputManagerHelper.java +++ b/src/com/android/tv/util/TvInputManagerHelper.java @@ -46,6 +46,7 @@ import com.android.tv.parental.ContentRatingsManager; import com.android.tv.parental.ParentalControlSettings; import com.android.tv.util.images.ImageCache; import com.android.tv.util.images.ImageLoader; +import com.android.tv.common.flags.LegacyFlags; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -127,6 +128,7 @@ public class TvInputManagerHelper { private static final String PERMISSION_ACCESS_ALL_EPG_DATA = "com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA"; private static final String[] mPhysicalTunerBlackList = { + "com.google.android.videos", // Play Movies }; private static final String META_LABEL_SORT_KEY = "input_sort_key"; @@ -158,6 +160,10 @@ public class TvInputManagerHelper { } private static final String[] PARTNER_TUNER_INPUT_PREFIX_BLACKLIST = { + /* Begin_AOSP_Comment_Out + // Disabled partner's tuner input prefix list. + "com.mediatek.tvinput/.dtv" + End_AOSP_Comment_Out */ }; private static final String[] TESTABLE_INPUTS = { @@ -292,8 +298,8 @@ public class TvInputManagerHelper { private boolean mAllow3rdPartyInputs; @Inject - public TvInputManagerHelper(@ApplicationContext Context context) { - this(context, createTvInputManagerWrapper(context)); + public TvInputManagerHelper(@ApplicationContext Context context, LegacyFlags legacyFlags) { + this(context, createTvInputManagerWrapper(context), legacyFlags); } @Nullable @@ -305,12 +311,14 @@ public class TvInputManagerHelper { @VisibleForTesting protected TvInputManagerHelper( - Context context, @Nullable TvInputManagerInterface tvInputManager) { + Context context, + @Nullable TvInputManagerInterface tvInputManager, + LegacyFlags legacyFlags) { mContext = context.getApplicationContext(); mPackageManager = context.getPackageManager(); mTvInputManager = tvInputManager; mContentRatingsManager = new ContentRatingsManager(context, tvInputManager); - mParentalControlSettings = new ParentalControlSettings(context); + mParentalControlSettings = new ParentalControlSettings(context, legacyFlags); mTvInputInfoComparator = new InputComparatorInternal(this); mContentObserver = new ContentObserver(mHandler) { diff --git a/src/com/android/tv/util/TvProviderUtils.java b/src/com/android/tv/util/TvProviderUtils.java index 6b5aaecc..8cdf1c71 100644 --- a/src/com/android/tv/util/TvProviderUtils.java +++ b/src/com/android/tv/util/TvProviderUtils.java @@ -67,6 +67,9 @@ public final class TvProviderUtils { @WorkerThread public static synchronized boolean checkSeriesIdColumn(Context context, Uri uri) { boolean canCreateColumn = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O); + canCreateColumn = + (canCreateColumn + || PartnerFeatures.TVPROVIDER_ALLOWS_COLUMN_CREATION.isEnabled(context)); if (!canCreateColumn) { return false; } @@ -112,6 +115,9 @@ public final class TvProviderUtils { @WorkerThread public static synchronized boolean checkStateColumn(Context context, Uri uri) { boolean canCreateColumn = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O); + canCreateColumn = + (canCreateColumn + || PartnerFeatures.TVPROVIDER_ALLOWS_COLUMN_CREATION.isEnabled(context)); if (!canCreateColumn) { return false; } diff --git a/src/com/android/tv/util/account/AccountHelper.java b/src/com/android/tv/util/account/AccountHelper.java index e98b42ec..d54c2f56 100644 --- a/src/com/android/tv/util/account/AccountHelper.java +++ b/src/com/android/tv/util/account/AccountHelper.java @@ -35,4 +35,11 @@ public interface AccountHelper { /** Returns all eligible accounts . */ @Nullable Account getFirstEligibleAccount(); + + /** + * Initialize the account helper. + * + * <p>This method is a no op if called more than once. + */ + void init(); } diff --git a/src/com/android/tv/util/account/AccountHelperImpl.java b/src/com/android/tv/util/account/AccountHelperImpl.java index 58fbd27e..e97cc3f2 100644 --- a/src/com/android/tv/util/account/AccountHelperImpl.java +++ b/src/com/android/tv/util/account/AccountHelperImpl.java @@ -21,8 +21,12 @@ import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.support.annotation.Nullable; +import com.android.tv.common.dagger.annotations.ApplicationContext; +import javax.inject.Inject; +import javax.inject.Singleton; /** Helper methods for getting and selecting a user account. */ +@Singleton public class AccountHelperImpl implements com.android.tv.util.account.AccountHelper { private static final String SELECTED_ACCOUNT = "android.tv.livechannels.selected_account"; @@ -31,7 +35,8 @@ public class AccountHelperImpl implements com.android.tv.util.account.AccountHel @Nullable private Account mSelectedAccount; - public AccountHelperImpl(Context context) { + @Inject + public AccountHelperImpl(@ApplicationContext Context context) { mContext = context.getApplicationContext(); mDefaultPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); } @@ -98,4 +103,9 @@ public class AccountHelperImpl implements com.android.tv.util.account.AccountHel PreferenceManager.getDefaultSharedPreferences(mContext); defaultPreferences.edit().putString(SELECTED_ACCOUNT, account.name).commit(); } + + @Override + public void init() { + // do nothing. + } } diff --git a/src/com/android/tv/util/images/ImageLoader.java b/src/com/android/tv/util/images/ImageLoader.java index d2ad0eb1..cbd386ad 100644 --- a/src/com/android/tv/util/images/ImageLoader.java +++ b/src/com/android/tv/util/images/ImageLoader.java @@ -29,6 +29,7 @@ import android.support.annotation.UiThread; import android.support.annotation.WorkerThread; import android.util.ArraySet; import android.util.Log; +import androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms; import com.android.tv.R; import com.android.tv.common.concurrent.NamedThreadFactory; import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo; @@ -428,6 +429,47 @@ public final class ImageLoader { } } + /** + * Calculates Aspect Ratio of Poster Art from Uri. + * + * <p><b>Note</b> the function will check the cache before loading the bitmap + * + * @return the Aspect Ratio of the Poster Art. + */ + public static int getAspectRatioFromPosterArtUri( + Context context, + String uriString) { + // Check the cache before loading the bitmap. + ImageCache imageCache = ImageCache.getInstance(); + ScaledBitmapInfo bitmapInfo = imageCache.get(uriString); + int bitmapWidth; + int bitmapHeight; + float bitmapAspectRatio; + int aspectRatio; + if (bitmapInfo == null) { + bitmapInfo = BitmapUtils.decodeSampledBitmapFromUriString( + context, uriString, Integer.MAX_VALUE, Integer.MAX_VALUE); + } + bitmapWidth = bitmapInfo.bitmap.getWidth(); + bitmapHeight = bitmapInfo.bitmap.getHeight(); + bitmapAspectRatio = (float) bitmapWidth / bitmapHeight; + /* Assign nearest aspect ratio from the defined values in Preview Programs */ + if (bitmapAspectRatio > 0 && bitmapAspectRatio <= 0.6803) { + aspectRatio = PreviewPrograms.ASPECT_RATIO_2_3; + } else if (bitmapAspectRatio > 0.6803 && bitmapAspectRatio <= 0.8469) { + aspectRatio = PreviewPrograms.ASPECT_RATIO_MOVIE_POSTER; + } else if (bitmapAspectRatio > 0.8469 && bitmapAspectRatio <= 1.1667) { + aspectRatio = PreviewPrograms.ASPECT_RATIO_1_1; + } else if (bitmapAspectRatio > 1.1667 && bitmapAspectRatio <= 1.4167) { + aspectRatio = PreviewPrograms.ASPECT_RATIO_4_3; + } else if (bitmapAspectRatio > 1.4167 && bitmapAspectRatio <= 1.6389) { + aspectRatio = PreviewPrograms.ASPECT_RATIO_3_2; + } else { + aspectRatio = PreviewPrograms.ASPECT_RATIO_16_9; + } + return aspectRatio; + } + private static synchronized Handler getMainHandler() { if (sMainHandler == null) { sMainHandler = new Handler(Looper.getMainLooper()); |