diff options
Diffstat (limited to 'src/com')
184 files changed, 1795 insertions, 2558 deletions
diff --git a/src/com/android/tv/LauncherActivity.java b/src/com/android/tv/LauncherActivity.java index ccc5600a..679d612d 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}, 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}, 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. */ 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 7a591500..b4cf71db 100644 --- a/src/com/android/tv/MainActivity.java +++ b/src/com/android/tv/MainActivity.java @@ -16,8 +16,6 @@ package com.android.tv; -import static com.android.tv.common.feature.SystemAppFeature.SYSTEM_APP_FEATURE; - import android.app.Activity; import android.app.PendingIntent; import android.app.SearchManager; @@ -46,7 +44,6 @@ 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; @@ -68,7 +65,6 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.widget.FrameLayout; import android.widget.Toast; - import com.android.tv.MainActivity.MySingletons; import com.android.tv.analytics.SendChannelStatusRunnable; import com.android.tv.analytics.SendConfigInfoRunnable; @@ -82,7 +78,6 @@ import com.android.tv.common.SoftPreconditions; import com.android.tv.common.TvContentRatingCache; import com.android.tv.common.WeakHandler; import com.android.tv.common.compat.TvInputInfoCompat; -import com.android.tv.common.dev.DeveloperPreferences; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.memory.MemoryManageable; import com.android.tv.common.singletons.HasSingletons; @@ -96,13 +91,11 @@ import com.android.tv.common.util.SystemProperties; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.ChannelImpl; import com.android.tv.data.OnCurrentProgramUpdatedListener; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; -import com.android.tv.data.ProgramImpl; import com.android.tv.data.StreamInfo; import com.android.tv.data.WatchedHistoryManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; -import com.android.tv.data.epg.EpgFetcher; import com.android.tv.dialog.HalfSizedDialogFragment; import com.android.tv.dialog.PinDialogFragment; import com.android.tv.dialog.PinDialogFragment.OnPinCheckedListener; @@ -113,12 +106,11 @@ import com.android.tv.dvr.recorder.ConflictChecker; import com.android.tv.dvr.ui.DvrStopRecordingFragment; import com.android.tv.dvr.ui.DvrUiHelper; import com.android.tv.features.TvFeatures; -import com.android.tv.guide.ProgramItemView; 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.StartupMeasureFactory; +import com.android.tv.perf.PerformanceMonitorManagerFactory; import com.android.tv.receiver.AudioCapabilitiesReceiver; import com.android.tv.recommendation.ChannelPreviewUpdater; import com.android.tv.recommendation.NotificationService; @@ -134,7 +126,6 @@ import com.android.tv.ui.TunableTvView; import com.android.tv.ui.TunableTvView.BlockScreenType; import com.android.tv.ui.TunableTvView.OnTuneListener; import com.android.tv.ui.TvOverlayManager; -import com.android.tv.ui.TvOverlayManagerFactory; import com.android.tv.ui.TvViewUiManager; import com.android.tv.ui.sidepanel.ClosedCaptionFragment; import com.android.tv.ui.sidepanel.CustomizeChannelListFragment; @@ -144,7 +135,6 @@ 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; @@ -160,17 +150,9 @@ 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.AndroidInjector; import dagger.android.ContributesAndroidInjector; -import dagger.android.DispatchingAndroidInjector; -import dagger.android.HasAndroidInjector; - 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; @@ -181,17 +163,15 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; - import javax.inject.Inject; import javax.inject.Provider; -/** The main activity for the TV app. */ +/** The main activity for the Live TV app. */ public class MainActivity extends Activity implements OnActionClickListener, OnPinCheckedListener, ChannelChanger, - HasSingletons<MySingletons>, - HasAndroidInjector { + HasSingletons<MySingletons> { private static final String TAG = "MainActivity"; private static final boolean DEBUG = false; private AudioCapabilitiesReceiver mAudioCapabilitiesReceiver; @@ -278,11 +258,10 @@ public class MainActivity extends Activity private static final long START_UP_TIMER_RESET_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(3); { - StartupMeasureFactory.create().onActivityInit(); + PerformanceMonitorManagerFactory.create().getStartupMeasure().onActivityInit(); } private final MySingletonsImpl mMySingletons = new MySingletonsImpl(); - @Inject DispatchingAndroidInjector<Object> mAndroidInjector; @Inject @DbExecutor Executor mDbExecutor; private AccessibilityManager mAccessibilityManager; @@ -299,12 +278,8 @@ 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; - @Inject EpgFetcher mEpgFetcher; @VisibleForTesting protected TunableTvView mTvView; private View mContentView; @@ -339,7 +314,6 @@ public class MainActivity extends Activity private boolean mIsFilmModeSet; private float mDefaultRefreshRate; - @Inject TvOverlayManagerFactory mOverlayFactory; private TvOverlayManager mOverlayManager; // mIsCurrentChannelUnblockedByUser and mWasChannelUnblockedBeforeShrunkenByUser are used for @@ -503,6 +477,7 @@ 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) { @@ -521,7 +496,6 @@ public class MainActivity extends Activity finishAndRemoveTask(); return; } - mAccountHelper.init(); TvSingletons tvApplication = (TvSingletons) getApplication(); // In API 23, TvContract.isChannelUriForPassthroughInput is hidden. @@ -540,8 +514,8 @@ public class MainActivity extends Activity return; } setContentView(R.layout.activity_tv); - mTvView = findViewById(R.id.main_tunable_tv_view); - mTvView.initialize(mProgramDataManager, mTvInputManagerHelper, mLegacyFlags); + mTvView = (TunableTvView) findViewById(R.id.main_tunable_tv_view); + mTvView.initialize(mProgramDataManager, mTvInputManagerHelper); mTvView.setOnUnhandledInputEventListener( new OnUnhandledInputEventListener() { @Override @@ -571,13 +545,12 @@ 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)); } tvApplication.getMainActivityWrapper().onMainActivityCreated(this); - if (BuildConfig.ENG && DeveloperPreferences.ALLOW_STRICT_MODE.get(this)) { + if (BuildConfig.ENG && SystemProperties.ALLOW_STRICT_MODE.getValue()) { Toast.makeText(this, "Using Strict Mode for eng builds", Toast.LENGTH_SHORT).show(); } mTracker = tvApplication.getTracker(); @@ -639,10 +612,13 @@ public class MainActivity extends Activity } mTvViewUiManager = new TvViewUiManager( - this, mTvView, findViewById(android.R.id.content), mTvOptionsManager); + this, + mTvView, + (FrameLayout) findViewById(android.R.id.content), + mTvOptionsManager); mContentView = findViewById(android.R.id.content); - ViewGroup sceneContainer = findViewById(R.id.scene_container); + ViewGroup sceneContainer = (ViewGroup) findViewById(R.id.scene_container); ChannelBannerView channelBannerView = (ChannelBannerView) getLayoutInflater().inflate(R.layout.channel_banner, sceneContainer, false); @@ -695,7 +671,7 @@ public class MainActivity extends Activity }); mSearchFragment = new ProgramGuideSearchFragment(); mOverlayManager = - mOverlayFactory.create( + new TvOverlayManager( this, mChannelTuner, mTvView, @@ -733,6 +709,8 @@ public class MainActivity extends Activity SendChannelStatusRunnable.startChannelStatusRecurringRunner( this, mTracker, mChannelDataManager); + // To avoid not updating Rating systems when changing language. + mTvInputManagerHelper.getContentRatingsManager().update(); if (CommonFeatures.DVR.isEnabled(this) && TvFeatures.SHOW_UPCOMING_CONFLICT_DIALOG.isEnabled(this)) { mDvrConflictChecker = new ConflictChecker(this); @@ -764,7 +742,7 @@ public class MainActivity extends Activity mChannelDataManager.reload(); mProgramDataManager.reload(); - // Restart TV app. + // Restart live channels. Intent intent = getIntent(); finish(); startActivity(intent); @@ -852,7 +830,7 @@ public class MainActivity extends Activity .getTunerInputController() .executeNetworkTunerDiscoveryAsyncTask(this); } - mEpgFetcher.fetchImmediatelyIfNeeded(); + TvSingletons.getSingletons(this).getEpgFetcher().fetchImmediatelyIfNeeded(); } @Override @@ -1149,8 +1127,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 TV app - // should go through TV app SetupPassthroughActivity. + // Even though other app can handle the intent, the setup launched by Live channels + // should go through Live channels 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 @@ -1420,9 +1398,7 @@ public class MainActivity extends Activity @Override public boolean dispatchKeyEvent(KeyEvent event) { - if (DeveloperPreferences.LOG_KEYEVENT.get(this)) { - Log.d(TAG, "dispatchKeyEvent(" + event + ")"); - } + if (SystemProperties.LOG_KEYEVENT.getValue()) Log.d(TAG, "dispatchKeyEvent(" + event + ")"); // If an activity is closed on a back key down event, back key down events with none zero // repeat count or a back key up event can be happened without the first back key down // event which should be ignored in this activity. @@ -1527,7 +1503,7 @@ public class MainActivity extends Activity new AsyncQueryProgramTask( mDbExecutor, programUriFromIntent, - ProgramImpl.PROJECTION, + Program.PROJECTION, null, null, null, @@ -1558,7 +1534,7 @@ public class MainActivity extends Activity String inputId = mInitChannelUri.getQueryParameter("input"); long channelId = Utils.getLastWatchedChannelIdForInput(this, inputId); if (channelId == Channel.INVALID_ID) { - String[] projection = {BaseColumns._ID}; + String[] projection = {Channels._ID}; long time = System.currentTimeMillis(); try (Cursor cursor = getContentResolver().query(uri, projection, null, null, null)) { @@ -1606,7 +1582,7 @@ public class MainActivity extends Activity protected Program onQuery(Cursor c) { Program program = null; if (c != null && c.moveToNext()) { - program = ProgramImpl.fromCursor(c); + program = Program.fromCursor(c); } return program; } @@ -1622,7 +1598,7 @@ public class MainActivity extends Activity Intent intent = new Intent(MainActivity.this, DetailsActivity.class); intent.putExtra(DetailsActivity.CHANNEL_ID, mChannelIdFromIntent); intent.putExtra(DetailsActivity.DETAILS_VIEW_TYPE, DetailsActivity.PROGRAM_VIEW); - intent.putExtra(DetailsActivity.PROGRAM, program.toParcelable()); + intent.putExtra(DetailsActivity.PROGRAM, program); intent.putExtra(DetailsActivity.INPUT_ID, channel.getInputId()); startActivity(intent); } @@ -2101,7 +2077,7 @@ public class MainActivity extends Activity @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (DeveloperPreferences.LOG_KEYEVENT.get(this)) { + if (SystemProperties.LOG_KEYEVENT.getValue()) { Log.d(TAG, "onKeyDown(" + keyCode + ", " + event + ")"); } switch (mOverlayManager.onKeyDown(keyCode, event)) { @@ -2191,7 +2167,7 @@ public class MainActivity extends Activity * W debug: toggle screen size * V KEYCODE_MEDIA_RECORD debug: record the current channel for 30 sec */ - if (DeveloperPreferences.LOG_KEYEVENT.get(this)) { + if (SystemProperties.LOG_KEYEVENT.getValue()) { Log.d(TAG, "onKeyUp(" + keyCode + ", " + event + ")"); } // If we are in the middle of channel change, finish it before showing overlays. @@ -2289,7 +2265,7 @@ public class MainActivity extends Activity // Channel change is already done in the head of this method. return true; case KeyEvent.KEYCODE_S: - if (!DeveloperPreferences.USE_DEBUG_KEYS.get(this)) { + if (!SystemProperties.USE_DEBUG_KEYS.getValue()) { break; } // fall through. @@ -2297,7 +2273,7 @@ public class MainActivity extends Activity mOverlayManager.getSideFragmentManager().show(new ClosedCaptionFragment()); return true; case KeyEvent.KEYCODE_A: - if (!DeveloperPreferences.USE_DEBUG_KEYS.get(this)) { + if (!SystemProperties.USE_DEBUG_KEYS.getValue()) { break; } // fall through. @@ -2363,7 +2339,7 @@ public class MainActivity extends Activity // in case that TV isn't showing properly (e.g. no browsable channel) return true; } - if (DeveloperPreferences.USE_DEBUG_KEYS.get(this) || BuildConfig.ENG) { + if (SystemProperties.USE_DEBUG_KEYS.getValue() || BuildConfig.ENG) { switch (keyCode) { case KeyEvent.KEYCODE_W: mDebugNonFullSizeScreen = !mDebugNonFullSizeScreen; @@ -2419,7 +2395,7 @@ public class MainActivity extends Activity @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { - if (DeveloperPreferences.LOG_KEYEVENT.get(this)) Log.d(TAG, "onKeyLongPress(" + event); + if (SystemProperties.LOG_KEYEVENT.getValue()) Log.d(TAG, "onKeyLongPress(" + event); if (USE_BACK_KEY_LONG_PRESS) { // Treat the BACK key long press as the normal press since we changed the behavior in // onBackPressed(). @@ -2489,7 +2465,7 @@ public class MainActivity extends Activity } private boolean dispatchKeyEventToSession(final KeyEvent event) { - if (DeveloperPreferences.LOG_KEYEVENT.get(this)) { + if (SystemProperties.LOG_KEYEVENT.getValue()) { Log.d(TAG, "dispatchKeyEventToSession(" + event + ")"); } boolean handled = false; @@ -2742,10 +2718,7 @@ public class MainActivity extends Activity return; } - // Only try to set the channels browseable if we are a system app. - if (SYSTEM_APP_FEATURE.isEnabled(getApplicationContext())) { - Utils.enableAllChannels(this); - } + Utils.enableAllChannels(this); } // Lazy initialization @@ -2805,11 +2778,6 @@ public class MainActivity extends Activity } } - @Override - public AndroidInjector<Object> androidInjector() { - return mAndroidInjector; - } - private static class MainActivityHandler extends WeakHandler<MainActivity> { MainActivityHandler(MainActivity mainActivity) { super(mainActivity); @@ -2855,8 +2823,11 @@ public class MainActivity extends Activity Debug.getTimer(Debug.TAG_START_UP_TIMER).log("MainActivity.MyOnTuneListener.onTune"); mChannel = channel; mWasUnderShrunkenTvView = wasUnderShrunkenTvView; - // Fetch complete projection of tuned channel. - mProgramDataManager.onChannelTuned(channel.getId()); + + if (mBackendKnobs.enablePartialProgramFetch()) { + // Fetch complete projection of tuned channel. + mProgramDataManager.prefetchChannel(channel.getId()); + } } @Override @@ -3011,14 +2982,5 @@ public class MainActivity extends Activity public abstract static class Module { @ContributesAndroidInjector abstract MainActivity contributesMainActivityActivityInjector(); - - @ContributesAndroidInjector - abstract DeveloperOptionFragment contributesDeveloperOptionFragment(); - - @ContributesAndroidInjector - abstract RatingsFragment contributesRatingsFragment(); - - @ContributesAndroidInjector - abstract ProgramItemView contributesProgramItemView(); } } diff --git a/src/com/android/tv/MediaSessionWrapper.java b/src/com/android/tv/MediaSessionWrapper.java index df886391..a647a06f 100644 --- a/src/com/android/tv/MediaSessionWrapper.java +++ b/src/com/android/tv/MediaSessionWrapper.java @@ -34,9 +34,8 @@ import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; - +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.util.Utils; import com.android.tv.util.images.ImageLoader; diff --git a/src/com/android/tv/SetupPassthroughActivity.java b/src/com/android/tv/SetupPassthroughActivity.java index 25049f1d..5185b122 100644 --- a/src/com/android/tv/SetupPassthroughActivity.java +++ b/src/com/android/tv/SetupPassthroughActivity.java @@ -18,7 +18,7 @@ package com.android.tv; import android.app.Activity; import android.content.ActivityNotFoundException; -import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.media.tv.TvInputInfo; import android.os.Bundle; @@ -26,8 +26,6 @@ import android.os.Handler; import android.os.Looper; import android.support.annotation.MainThread; import android.util.Log; - -import com.android.tv.common.CommonConstants; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.actions.InputSetupActionUtils; import com.android.tv.data.ChannelDataManager; @@ -38,16 +36,9 @@ import com.android.tv.features.TvFeatures; 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. * @@ -64,20 +55,18 @@ public class SetupPassthroughActivity extends Activity { private TvInputInfo mTvInputInfo; private Intent mActivityAfterCompletion; private boolean mEpgFetcherDuringScan; - @Inject EpgInputWhiteList mEpgInputWhiteList; - @Inject TvInputManagerHelper mInputManager; - @Inject SetupUtils mSetupUtils; - @Inject ChannelDataManager mChannelDataManager; - @Inject EpgFetcher mEpgFetcher; + private EpgInputWhiteList mEpgInputWhiteList; @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 = mInputManager.getTvInputInfo(inputId); + mTvInputInfo = inputManager.getTvInputInfo(inputId); + mEpgInputWhiteList = new EpgInputWhiteList(tvSingletons.getCloudEpgFlags()); mActivityAfterCompletion = InputSetupActionUtils.getExtraActivityAfter(intent); boolean needToFetchEpg = mTvInputInfo != null && Utils.isInternalTvInput(this, mTvInputInfo.getId()); @@ -117,17 +106,6 @@ public class SetupPassthroughActivity extends Activity { InputSetupActionUtils.removeSetupIntent(extras); setupIntent.putExtras(extras); try { - ComponentName callingActivity = getCallingActivity(); - if (callingActivity != null - && !callingActivity.getPackageName().equals(CommonConstants.BASE_PACKAGE)) { - Log.w( - TAG, - "Calling activity " - + callingActivity.getPackageName() - + " is not trusted. Not forwarding intent."); - finish(); - return; - } startActivityForResult(setupIntent, REQUEST_START_SETUP_ACTIVITY); } catch (ActivityNotFoundException e) { Log.e(TAG, "Can't find activity: " + setupIntent.getComponent()); @@ -136,10 +114,10 @@ public class SetupPassthroughActivity extends Activity { } if (needToFetchEpg) { if (sScanTimeoutMonitor == null) { - sScanTimeoutMonitor = new ScanTimeoutMonitor(mEpgFetcher, mChannelDataManager); + sScanTimeoutMonitor = new ScanTimeoutMonitor(this); } sScanTimeoutMonitor.startMonitoring(); - mEpgFetcher.onChannelScanStarted(); + TvSingletons.getSingletons(this).getEpgFetcher().onChannelScanStarted(); } } } @@ -155,25 +133,15 @@ public class SetupPassthroughActivity extends Activity { boolean setupComplete = requestCode == REQUEST_START_SETUP_ACTIVITY && resultCode == Activity.RESULT_OK; // Tells EpgFetcher that channel source setup is finished. - + EpgFetcher epgFetcher = TvSingletons.getSingletons(this).getEpgFetcher(); if (mEpgFetcherDuringScan) { - mEpgFetcher.onChannelScanFinished(); + epgFetcher.onChannelScanFinished(); } if (!setupComplete) { setResult(resultCode, data); 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)) { - mEpgFetcher.fetchImmediately(); - } - } - if (mTvInputInfo == null) { Log.w( TAG, @@ -184,19 +152,21 @@ public class SetupPassthroughActivity extends Activity { finish(); return; } - mSetupUtils.onTvInputSetupFinished( - mTvInputInfo.getId(), - () -> { - if (mActivityAfterCompletion != null) { - try { - startActivity(mActivityAfterCompletion); - } catch (ActivityNotFoundException e) { - Log.w(TAG, "Activity launch failed", e); - } - } - setResult(resultCode, data); - finish(); - }); + 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(); + }); } /** @@ -209,7 +179,7 @@ public class SetupPassthroughActivity extends Activity { // Set timeout long enough. The message in Sony TV says the scanning takes about 30 minutes. private static final long SCAN_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(30); - private final EpgFetcher mEpgFetcher; + private final Context mContext; private final ChannelDataManager mChannelDataManager; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Runnable mScanTimeoutRunnable = @@ -237,9 +207,9 @@ public class SetupPassthroughActivity extends Activity { }; private boolean mStarted; - private ScanTimeoutMonitor(EpgFetcher epgFetcher, ChannelDataManager mChannelDataManager) { - mEpgFetcher = epgFetcher; - this.mChannelDataManager = mChannelDataManager; + private ScanTimeoutMonitor(Context context) { + mContext = context.getApplicationContext(); + mChannelDataManager = TvSingletons.getSingletons(context).getChannelDataManager(); } private void startMonitoring() { @@ -267,14 +237,7 @@ public class SetupPassthroughActivity extends Activity { private void onScanTimedOut() { stopMonitoring(); - mEpgFetcher.onChannelScanFinished(); + 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 f08b5e85..779e8df6 100644 --- a/src/com/android/tv/TimeShiftManager.java +++ b/src/com/android/tv/TimeShiftManager.java @@ -26,21 +26,18 @@ import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.util.Log; import android.util.Range; - import com.android.tv.analytics.Tracker; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.WeakHandler; import com.android.tv.data.OnCurrentProgramUpdatedListener; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; -import com.android.tv.data.ProgramImpl; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.ui.TunableTvView; import com.android.tv.ui.api.TunableTvViewPlayingApi.TimeShiftListener; import com.android.tv.util.AsyncDbTask; import com.android.tv.util.TimeShiftUtils; import com.android.tv.util.Utils; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -53,7 +50,7 @@ import java.util.Queue; import java.util.concurrent.TimeUnit; /** - * A class which manages the time shift feature in TV app. It consists of two parts. {@link + * A class which manages the time shift feature in Live TV. 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 @@ -147,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 TV app. 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 Live TV. 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; @@ -622,8 +619,8 @@ public class TimeShiftManager { < mAvailablityChangedTimeMs - ALLOWED_START_TIME_OFFSET) { Log.e( TAG, - "The start time is too earlier than the time of" - + " availability: {startTime: " + "The start time is too earlier than the time of availability: {" + + "startTime: " + recordStartTimeMs + ", availability: " + mAvailablityChangedTimeMs); @@ -635,9 +632,9 @@ public class TimeShiftManager { // clock,, use system's current time instead. Log.e( TAG, - "The start time should not be earlier than the current" - + " time, reset the start time to the system's current" - + " time: {startTime: " + "The start time should not be earlier than the current time, " + + "reset the start time to the system's current time: {" + + "startTime: " + recordStartTimeMs + ", current time: " + System.currentTimeMillis()); @@ -1106,7 +1103,7 @@ public class TimeShiftManager { long end = Utils.ceilTime(startTimeMs, MAX_DUMMY_PROGRAM_DURATION); while (end < endTimeMs) { programs.add( - new ProgramImpl.Builder() + new Program.Builder() .setStartTimeUtcMillis(start) .setEndTimeUtcMillis(end) .build()); @@ -1114,7 +1111,7 @@ public class TimeShiftManager { end += MAX_DUMMY_PROGRAM_DURATION; } programs.add( - new ProgramImpl.Builder() + new Program.Builder() .setStartTimeUtcMillis(start) .setEndTimeUtcMillis(endTimeMs) .build()); diff --git a/src/com/android/tv/TvApplication.java b/src/com/android/tv/TvApplication.java index bc8226cf..5f25a24b 100644 --- a/src/com/android/tv/TvApplication.java +++ b/src/com/android/tv/TvApplication.java @@ -35,19 +35,20 @@ import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.widget.Toast; - import com.android.tv.common.BaseApplication; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.recording.RecordingStorageStatusManager; import com.android.tv.common.ui.setup.animation.SetupAnimationHelper; +import com.android.tv.common.util.Clock; import com.android.tv.common.util.Debug; import com.android.tv.common.util.SharedPreferencesUtils; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.PreviewDataManager; import com.android.tv.data.ProgramDataManager; import com.android.tv.data.epg.EpgFetcher; -import com.android.tv.data.epg.EpgReader; +import com.android.tv.data.epg.EpgFetcherImpl; import com.android.tv.dvr.DvrDataManager; +import com.android.tv.dvr.DvrDataManagerImpl; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.DvrScheduleManager; import com.android.tv.dvr.DvrStorageStatusManager; @@ -55,9 +56,8 @@ 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.PerformanceMonitor; -import com.android.tv.perf.StartupMeasure; -import com.android.tv.perf.StartupMeasureFactory; +import com.android.tv.perf.PerformanceMonitorManager; +import com.android.tv.perf.PerformanceMonitorManagerFactory; import com.android.tv.recommendation.ChannelPreviewUpdater; import com.android.tv.recommendation.RecordedProgramPreviewUpdater; import com.android.tv.tunerinputcontroller.BuiltInTunerManager; @@ -66,30 +66,27 @@ import com.android.tv.util.AsyncDbTask.DbExecutor; import com.android.tv.util.SetupUtils; 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; /** - * TV application. + * Live TV application. * * <p>This includes all the Google specific hooks. */ public abstract class TvApplication extends BaseApplication implements TvSingletons, Starter { - protected static final StartupMeasure STARTUP_MEASURE = StartupMeasureFactory.create(); + protected static final PerformanceMonitorManager PERFORMANCE_MONITOR_MANAGER = + PerformanceMonitorManagerFactory.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 @@ -105,12 +102,12 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet private final MainActivityWrapper mMainActivityWrapper = new MainActivityWrapper(); private SelectInputActivity mSelectInputActivity; - @Inject Lazy<ChannelDataManager> mChannelDataManager; + private ChannelDataManager mChannelDataManager; private volatile ProgramDataManager mProgramDataManager; private PreviewDataManager mPreviewDataManager; private DvrManager mDvrManager; private DvrScheduleManager mDvrScheduleManager; - @Inject Lazy<DvrDataManager> mDvrDataManager; + private DvrDataManager mDvrDataManager; private DvrWatchedPositionManager mDvrWatchedPositionManager; private RecordingScheduler mRecordingScheduler; private RecordingStorageStatusManager mDvrStorageStatusManager; @@ -120,16 +117,11 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet private Boolean mRunningInMainProcess; @Inject Lazy<TvInputManagerHelper> mLazyTvInputManagerHelper; private boolean mStarted; - @Inject EpgFetcher mEpgFetcher; + private EpgFetcher mEpgFetcher; @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() { @@ -140,8 +132,6 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet throw new IllegalStateException(msg); } super.onCreate(); - mPerformanceMonitor.startMemoryMonitor(); - mPerformanceMonitor.startCrashMonitor(); SharedPreferencesUtils.initialize( this, () -> { @@ -156,15 +146,16 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet Log.w(TAG, "Unable to find package '" + getPackageName() + "'.", e); mVersionName = ""; } - Log.i(TAG, "Starting TV app " + getVersionName()); + Log.i(TAG, "Starting Live TV " + 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); SetupAnimationHelper.initialize(this); getTvInputManagerHelper(); - Log.i(TAG, "Started TV app " + mVersionName); + Log.i(TAG, "Started Live TV " + mVersionName); Debug.getTimer(Debug.TAG_START_UP_TIMER).log("finish TvApplication.onCreate"); } @@ -219,10 +210,8 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet mEpgFetcher.startRoutineService(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ChannelPreviewUpdater.getInstance(this).startRoutineService(); - if (CommonFeatures.DVR.isEnabled(this)) { - RecordedProgramPreviewUpdater.getInstance(this) - .updatePreviewDataForRecordedPrograms(); - } + RecordedProgramPreviewUpdater.getInstance(this) + .updatePreviewDataForRecordedPrograms(); } } Debug.getTimer(Debug.TAG_START_UP_TIMER).log("finish TvApplication.start"); @@ -248,6 +237,11 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet } @Override + public EpgFetcher getEpgFetcher() { + return mEpgFetcher; + } + + @Override public synchronized SetupUtils getSetupUtils() { return mSetupUtils; } @@ -292,7 +286,16 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet /** Returns {@link ChannelDataManager}. */ @Override public ChannelDataManager getChannelDataManager() { - return mChannelDataManager.get(); + if (mChannelDataManager == null) { + mChannelDataManager = new ChannelDataManager(this, getTvInputManagerHelper()); + mChannelDataManager.start(); + } + return mChannelDataManager; + } + + @Override + public boolean isChannelDataManagerLoadFinished() { + return mChannelDataManager != null && mChannelDataManager.isDbLoadFinished(); } /** Returns {@link ProgramDataManager}. */ @@ -311,6 +314,11 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet return mProgramDataManager; } + @Override + public boolean isProgramDataManagerCurrentProgramsLoadFinished() { + return mProgramDataManager != null && mProgramDataManager.isCurrentProgramsLoadFinished(); + } + /** Returns {@link PreviewDataManager}. */ @TargetApi(Build.VERSION_CODES.O) @Override @@ -326,7 +334,12 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet @TargetApi(Build.VERSION_CODES.N) @Override public DvrDataManager getDvrDataManager() { - return mDvrDataManager.get(); + if (mDvrDataManager == null) { + DvrDataManagerImpl dvrDataManager = new DvrDataManagerImpl(this, Clock.SYSTEM); + mDvrDataManager = dvrDataManager; + dvrDataManager.start(); + } + return mDvrDataManager; } @Override @@ -338,11 +351,6 @@ 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() { @@ -442,7 +450,7 @@ public abstract class TvApplication extends BaseApplication implements TvSinglet } /** - * Returns the version name of the TV app. + * Returns the version name of the live channels. * * @see PackageInfo#versionName */ @@ -481,37 +489,6 @@ 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) { @@ -538,24 +515,13 @@ 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") + " TV app."); + Log.i(TAG, (enable ? "Un-hide" : "Hide") + " Live TV."); } 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 9e4f4620..20edf3d4 100644 --- a/src/com/android/tv/TvSingletons.java +++ b/src/com/android/tv/TvSingletons.java @@ -17,15 +17,16 @@ package com.android.tv; import android.content.Context; - 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; import com.android.tv.data.ProgramDataManager; +import com.android.tv.data.epg.EpgFetcher; import com.android.tv.data.epg.EpgReader; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrManager; @@ -36,27 +37,14 @@ import com.android.tv.perf.PerformanceMonitor; import com.android.tv.tunerinputcontroller.HasBuiltInTunerManager; import com.android.tv.util.SetupUtils; import com.android.tv.util.TvInputManagerHelper; - -import dagger.Lazy; - +import com.android.tv.util.account.AccountHelper; 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 { - /* - * Do not add any new methods here. - * - * To move a getter to Injection. - * 1. Make a type injectable @Singleton. - * 2. Mark the getter here as deprecated. - * 3. Lazily inject the object in TvApplication. - * 4. Move easy usages of getters to injection instead. - * 5. Delete the method when all usages are migrated. - */ - /** * Returns the @{@link TvSingletons} using the application context. * @@ -74,14 +62,24 @@ public interface TvSingletons extends BaseSingletons, HasBuiltInTunerManager, Ha @Deprecated ChannelDataManager getChannelDataManager(); + /** + * Checks if the {@link ChannelDataManager} instance has been created and all the channels has + * been loaded. + */ + boolean isChannelDataManagerLoadFinished(); + /** @deprecated use injection instead. */ @Deprecated ProgramDataManager getProgramDataManager(); + /** + * Checks if the {@link ProgramDataManager} instance has been created and the current programs + * for all the channels has been loaded. + */ + boolean isProgramDataManagerCurrentProgramsLoadFinished(); + PreviewDataManager getPreviewDataManager(); - /** @deprecated use injection instead. */ - @Deprecated DvrDataManager getDvrDataManager(); DvrScheduleManager getDvrScheduleManager(); @@ -90,8 +88,6 @@ public interface TvSingletons extends BaseSingletons, HasBuiltInTunerManager, Ha RecordingScheduler getRecordingScheduler(); - /** @deprecated use injection instead. */ - @Deprecated DvrWatchedPositionManager getDvrWatchedPositionManager(); InputSessionManager getInputSessionManager(); @@ -100,22 +96,26 @@ public interface TvSingletons extends BaseSingletons, HasBuiltInTunerManager, Ha MainActivityWrapper getMainActivityWrapper(); + AccountHelper getAccountHelper(); + boolean isRunningInMainProcess(); - /** @deprecated use injection instead. */ - @Deprecated PerformanceMonitor getPerformanceMonitor(); /** @deprecated use injection instead. */ @Deprecated TvInputManagerHelper getTvInputManagerHelper(); - Lazy<EpgReader> providesEpgReader(); + Provider<EpgReader> providesEpgReader(); + + EpgFetcher getEpgFetcher(); /** @deprecated use injection instead. */ @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 80906537..38e85e48 100644 --- a/src/com/android/tv/app/LiveTvApplication.java +++ b/src/com/android/tv/app/LiveTvApplication.java @@ -22,34 +22,50 @@ 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.Inject; +import javax.inject.Provider; /** The top level application for Live TV. */ public class LiveTvApplication extends TvApplication implements HasSingletons<TvSingletons> { static { - STARTUP_MEASURE.onAppClassLoaded(); + PERFORMANCE_MONITOR_MANAGER.getStartupMeasure().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; private Analytics mAnalytics; private Tracker mTracker; - @Inject PerformanceMonitor mPerformanceMonitor; + private ExperimentLoader mExperimentLoader; + private PerformanceMonitor mPerformanceMonitor; @Override protected AndroidInjector<LiveTvApplication> applicationInjector() { @@ -62,15 +78,38 @@ public class LiveTvApplication extends TvApplication implements HasSingletons<Tv @Override public void onCreate() { super.onCreate(); - STARTUP_MEASURE.onAppCreate(this); + PERFORMANCE_MONITOR_MANAGER.getStartupMeasure().onAppCreate(this); } + /** Returns the {@link AccountHelperImpl}. */ @Override - public PerformanceMonitor getPerformanceMonitor() { + 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); + } return mPerformanceMonitor; } @Override + public Provider<EpgReader> providesEpgReader() { + return mEpgReaderProvider; + } + + @Override + public ExperimentLoader getExperimentLoader() { + mExperimentLoader = new ExperimentLoader(); + return mExperimentLoader; + } + + @Override public DefaultBackendKnobsFlags getBackendKnobs() { return mBackendKnobsFlags; } @@ -109,6 +148,16 @@ public class LiveTvApplication extends TvApplication implements HasSingletons<Tv } @Override + public BuildType getBuildType() { + return BuildType.AOSP; + } + + @Override + public DefaultConcurrentDvrPlaybackFlags getConcurrentDvrPlaybackFlags() { + return mConcurrentDvrPlaybackFlags; + } + + @Override public TvSingletons singletons() { return this; } diff --git a/src/com/android/tv/app/LiveTvApplicationComponent.java b/src/com/android/tv/app/LiveTvApplicationComponent.java index 71ce1a8a..3d3f0492 100644 --- a/src/com/android/tv/app/LiveTvApplicationComponent.java +++ b/src/com/android/tv/app/LiveTvApplicationComponent.java @@ -15,7 +15,6 @@ */ package com.android.tv.app; -import com.android.tv.search.LocalSearchProvider; import dagger.Component; import dagger.android.AndroidInjectionModule; import dagger.android.AndroidInjector; @@ -23,10 +22,5 @@ import javax.inject.Singleton; /** Dagger component for {@link LiveTvApplication}. */ @Singleton -@Component( - modules = { - AndroidInjectionModule.class, - LiveTvModule.class, - LocalSearchProvider.Module.class - }) +@Component(modules = {AndroidInjectionModule.class, LiveTvModule.class}) public interface LiveTvApplicationComponent extends AndroidInjector<LiveTvApplication> {} diff --git a/src/com/android/tv/app/LiveTvModule.java b/src/com/android/tv/app/LiveTvModule.java index db631bc0..a28749bd 100644 --- a/src/com/android/tv/app/LiveTvModule.java +++ b/src/com/android/tv/app/LiveTvModule.java @@ -16,49 +16,18 @@ 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/BaseProgram.java b/src/com/android/tv/data/BaseProgram.java new file mode 100644 index 00000000..9650fd18 --- /dev/null +++ b/src/com/android/tv/data/BaseProgram.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2016 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.data; + +import android.content.Context; +import android.media.tv.TvContentRating; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import com.android.tv.R; +import com.google.common.collect.ImmutableList; +import java.util.Comparator; +import java.util.Objects; + +/** + * Base class for {@link com.android.tv.data.Program} and {@link + * com.android.tv.dvr.data.RecordedProgram}. + */ +public abstract class BaseProgram { + /** + * Comparator used to compare {@link BaseProgram} according to its season and episodes number. + * If a program's season or episode number is null, it will be consider "smaller" than programs + * with season or episode numbers. + */ + public static final Comparator<BaseProgram> EPISODE_COMPARATOR = new EpisodeComparator(false); + + /** + * Comparator used to compare {@link BaseProgram} according to its season and episodes number + * with season numbers in a reversed order. If a program's season or episode number is null, it + * will be consider "smaller" than programs with season or episode numbers. + */ + public static final Comparator<BaseProgram> SEASON_REVERSED_EPISODE_COMPARATOR = + new EpisodeComparator(true); + + public static final String COLUMN_SERIES_ID = "series_id"; + + public static final String COLUMN_STATE = "state"; + + private static class EpisodeComparator implements Comparator<BaseProgram> { + private final boolean mReversedSeason; + + EpisodeComparator(boolean reversedSeason) { + mReversedSeason = reversedSeason; + } + + @Override + public int compare(BaseProgram lhs, BaseProgram rhs) { + if (lhs == rhs) { + return 0; + } + int seasonNumberCompare = numberCompare(lhs.getSeasonNumber(), rhs.getSeasonNumber()); + if (seasonNumberCompare != 0) { + return mReversedSeason ? -seasonNumberCompare : seasonNumberCompare; + } else { + return numberCompare(lhs.getEpisodeNumber(), rhs.getEpisodeNumber()); + } + } + } + + /** Compares two strings represent season numbers or episode numbers of programs. */ + public static int numberCompare(String s1, String s2) { + if (Objects.equals(s1, s2)) { + return 0; + } else if (s1 == null) { + return -1; + } else if (s2 == null) { + return 1; + } else if (s1.equals(s2)) { + return 0; + } + try { + return Integer.compare(Integer.parseInt(s1), Integer.parseInt(s2)); + } catch (NumberFormatException e) { + return s1.compareTo(s2); + } + } + + /** Returns ID of the program. */ + public abstract long getId(); + + /** Returns the title of the program. */ + public abstract String getTitle(); + + /** Returns the episode title. */ + public abstract String getEpisodeTitle(); + + /** Returns the displayed title of the program episode. */ + @Nullable + public String getEpisodeDisplayTitle(Context context) { + String episodeNumber = getEpisodeNumber(); + String episodeTitle = getEpisodeTitle(); + if (!TextUtils.isEmpty(episodeNumber)) { + episodeTitle = episodeTitle == null ? "" : episodeTitle; + String seasonNumber = getSeasonNumber(); + if (TextUtils.isEmpty(seasonNumber) || TextUtils.equals(seasonNumber, "0")) { + // Do not show "S0: ". + return context.getResources() + .getString( + R.string.display_episode_title_format_no_season_number, + episodeNumber, + episodeTitle); + } else { + return context.getResources() + .getString( + R.string.display_episode_title_format, + seasonNumber, + episodeNumber, + episodeTitle); + } + } + return episodeTitle; + } + + /** + * Returns the content description of the program episode, suitable for being spoken by an + * accessibility service. + */ + public String getEpisodeContentDescription(Context context) { + String episodeNumber = getEpisodeNumber(); + String episodeTitle = getEpisodeTitle(); + if (!TextUtils.isEmpty(episodeNumber)) { + episodeTitle = episodeTitle == null ? "" : episodeTitle; + String seasonNumber = getSeasonNumber(); + if (TextUtils.isEmpty(seasonNumber) || TextUtils.equals(seasonNumber, "0")) { + // Do not list season if it is empty or 0 + return context.getResources() + .getString( + R.string.content_description_episode_format_no_season_number, + episodeNumber, + episodeTitle); + } else { + return context.getResources() + .getString( + R.string.content_description_episode_format, + seasonNumber, + episodeNumber, + episodeTitle); + } + } + return episodeTitle; + } + + /** Returns the description of the program. */ + public abstract String getDescription(); + + /** Returns the long description of the program. */ + public abstract String getLongDescription(); + + /** Returns the start time of the program in Milliseconds. */ + public abstract long getStartTimeUtcMillis(); + + /** Returns the end time of the program in Milliseconds. */ + public abstract long getEndTimeUtcMillis(); + + /** Returns the duration of the program in Milliseconds. */ + public abstract long getDurationMillis(); + + /** Returns the series ID. */ + @Nullable + public abstract String getSeriesId(); + + /** Returns the season number. */ + public abstract String getSeasonNumber(); + + /** Returns the episode number. */ + public abstract String getEpisodeNumber(); + + /** Returns URI of the program's poster. */ + public abstract String getPosterArtUri(); + + /** Returns URI of the program's thumbnail. */ + public abstract String getThumbnailUri(); + + /** Returns the array of the ID's of the canonical genres. */ + public abstract int[] getCanonicalGenreIds(); + + /** Returns the array of content ratings. */ + public abstract ImmutableList<TvContentRating> getContentRatings(); + + /** Returns channel's ID of the program. */ + public abstract long getChannelId(); + + /** Returns if the program is valid. */ + public abstract boolean isValid(); + + /** Checks whether the program is episodic or not. */ + public boolean isEpisodic() { + return getSeriesId() != null; + } + + /** Generates the series ID for the other inputs than the tuner TV input. */ + public static String generateSeriesId(String packageName, String title) { + return packageName + "/" + title; + } +} diff --git a/src/com/android/tv/data/BaseProgramImpl.java b/src/com/android/tv/data/BaseProgramImpl.java deleted file mode 100644 index 9c8d0256..00000000 --- a/src/com/android/tv/data/BaseProgramImpl.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2016 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.data; - -import android.content.Context; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.android.tv.R; -import com.android.tv.data.api.BaseProgram; - -/** Base class for {@link ProgramImpl} and {@link com.android.tv.dvr.data.RecordedProgram}. */ -public abstract class BaseProgramImpl implements BaseProgram { - - @Override - @Nullable - public String getEpisodeDisplayTitle(Context context) { - String episodeNumber = getEpisodeNumber(); - String episodeTitle = getEpisodeTitle(); - if (!TextUtils.isEmpty(episodeNumber)) { - episodeTitle = episodeTitle == null ? "" : episodeTitle; - String seasonNumber = getSeasonNumber(); - if (TextUtils.isEmpty(seasonNumber) || TextUtils.equals(seasonNumber, "0")) { - // Do not show "S0: ". - return context.getResources() - .getString( - R.string.display_episode_title_format_no_season_number, - episodeNumber, - episodeTitle); - } else { - return context.getResources() - .getString( - R.string.display_episode_title_format, - seasonNumber, - episodeNumber, - episodeTitle); - } - } - return episodeTitle; - } - - @Override - public String getEpisodeContentDescription(Context context) { - String episodeNumber = getEpisodeNumber(); - String episodeTitle = getEpisodeTitle(); - if (!TextUtils.isEmpty(episodeNumber)) { - episodeTitle = episodeTitle == null ? "" : episodeTitle; - String seasonNumber = getSeasonNumber(); - if (TextUtils.isEmpty(seasonNumber) || TextUtils.equals(seasonNumber, "0")) { - // Do not list season if it is empty or 0 - return context.getResources() - .getString( - R.string.content_description_episode_format_no_season_number, - episodeNumber, - episodeTitle); - } else { - return context.getResources() - .getString( - R.string.content_description_episode_format, - seasonNumber, - episodeNumber, - episodeTitle); - } - } - return episodeTitle; - } - - @Override - public boolean isEpisodic() { - return !TextUtils.isEmpty(getSeriesId()); - } -} diff --git a/src/com/android/tv/data/ChannelDataManager.java b/src/com/android/tv/data/ChannelDataManager.java index 67c32309..a5c786cf 100644 --- a/src/com/android/tv/data/ChannelDataManager.java +++ b/src/com/android/tv/data/ChannelDataManager.java @@ -37,18 +37,15 @@ 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; @@ -59,7 +56,6 @@ 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 @@ -68,8 +64,6 @@ import javax.inject.Singleton; * 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; @@ -149,11 +143,21 @@ public class ChannelDataManager { }; @MainThread - public ChannelDataManager( - @Provided @ApplicationContext Context context, - @Provided TvInputManagerHelper inputManager, - @Provided @DbExecutor Executor executor, - @Provided ContentResolver contentResolver) { + 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) { mContext = context; mInputManager = inputManager; mDbExecutor = executor; @@ -725,7 +729,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 DbExecutor}. + * operations will run on {@link TvSingletons#getDbExecutor()}. */ private void updateOneColumnValue( final String columnName, final int columnValue, final List<Long> ids) { diff --git a/src/com/android/tv/data/InternalDataUtils.java b/src/com/android/tv/data/InternalDataUtils.java index b17ed092..4c30d395 100644 --- a/src/com/android/tv/data/InternalDataUtils.java +++ b/src/com/android/tv/data/InternalDataUtils.java @@ -19,11 +19,8 @@ package com.android.tv.data; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; - -import com.android.tv.data.api.Program; -import com.android.tv.data.api.Program.CriticScore; +import com.android.tv.data.Program.CriticScore; import com.android.tv.dvr.data.RecordedProgram; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -52,7 +49,7 @@ public final class InternalDataUtils { * @param bytes the bytes to be deserialized * @param builder the builder for the Program class */ - public static void deserializeInternalProviderData(byte[] bytes, ProgramImpl.Builder builder) { + public static void deserializeInternalProviderData(byte[] bytes, Program.Builder builder) { if (bytes == null || bytes.length == 0) { return; } diff --git a/src/com/android/tv/data/OnCurrentProgramUpdatedListener.java b/src/com/android/tv/data/OnCurrentProgramUpdatedListener.java index 2332cda4..edb33556 100644 --- a/src/com/android/tv/data/OnCurrentProgramUpdatedListener.java +++ b/src/com/android/tv/data/OnCurrentProgramUpdatedListener.java @@ -16,8 +16,6 @@ package com.android.tv.data; -import com.android.tv.data.api.Program; - public interface OnCurrentProgramUpdatedListener { /** Called when the current program is updated. */ void onCurrentProgramUpdated(long channelId, Program program); diff --git a/src/com/android/tv/data/PreviewDataManager.java b/src/com/android/tv/data/PreviewDataManager.java index dbe6028c..8616aeec 100644 --- a/src/com/android/tv/data/PreviewDataManager.java +++ b/src/com/android/tv/data/PreviewDataManager.java @@ -32,14 +32,10 @@ import android.support.annotation.IntDef; import android.support.annotation.MainThread; import android.util.Log; import android.util.Pair; - 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; @@ -222,7 +218,7 @@ public class PreviewDataManager { Uri previewChannelsUri = PreviewDataUtils.addQueryParamToUri( TvContract.Channels.CONTENT_URI, - Pair.create(PARAM_PREVIEW, String.valueOf(true))); + new Pair<>(PARAM_PREVIEW, String.valueOf(true))); String packageName = mContext.getPackageName(); if (PermissionUtils.hasAccessAllEpg(mContext)) { try (Cursor cursor = @@ -432,14 +428,10 @@ public class PreviewDataManager { continue; } try { - int aspectRatio = - ImageLoader.getAspectRatioFromPosterArtUri( - mContext, program.getPosterArtUri().toString()); Uri programUri = mContentResolver.insert( TvContract.PreviewPrograms.CONTENT_URI, - PreviewDataUtils.createPreviewProgramFromContent( - program, aspectRatio) + PreviewDataUtils.createPreviewProgramFromContent(program) .toContentValues()); if (programUri != null) { long previewProgramId = ContentUris.parseId(programUri); @@ -600,14 +592,13 @@ public class PreviewDataManager { /** Creates a preview program. */ public static PreviewProgram createPreviewProgramFromContent( - PreviewProgramContent program, int aspectRatio) { + PreviewProgramContent program) { 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/PreviewProgramContent.java b/src/com/android/tv/data/PreviewProgramContent.java index 4ee57104..8d4b88cf 100644 --- a/src/com/android/tv/data/PreviewProgramContent.java +++ b/src/com/android/tv/data/PreviewProgramContent.java @@ -21,14 +21,10 @@ import android.net.Uri; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Pair; - import androidx.tvprovider.media.tv.TvContractCompat; - import com.android.tv.TvSingletons; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.data.RecordedProgram; - import java.util.Objects; /** A class to store the content of preview programs. */ @@ -45,7 +41,7 @@ public class PreviewProgramContent { private Uri mIntentUri; private Uri mPreviewVideoUri; - /** Create preview program content from {@link ProgramImpl} */ + /** Create preview program content from {@link Program} */ public static PreviewProgramContent createFromProgram( Context context, long previewChannelId, Program program) { Channel channel = @@ -83,7 +79,7 @@ public class PreviewProgramContent { .setIntentUri(channel.getUri()) .setPreviewVideoUri( PreviewDataManager.PreviewDataUtils.addQueryParamToUri( - channel.getUri(), Pair.create(PARAM_INPUT, channel.getInputId()))) + channel.getUri(), new Pair<>(PARAM_INPUT, channel.getInputId()))) .build(); } @@ -103,7 +99,7 @@ public class PreviewProgramContent { .setPreviewVideoUri( PreviewDataManager.PreviewDataUtils.addQueryParamToUri( recordedProgramUri, - Pair.create(PARAM_INPUT, recordedProgram.getInputId()))) + new Pair<>(PARAM_INPUT, recordedProgram.getInputId()))) .build(); } diff --git a/src/com/android/tv/data/ProgramImpl.java b/src/com/android/tv/data/Program.java index 5097e2d4..b688927a 100644 --- a/src/com/android/tv/data/ProgramImpl.java +++ b/src/com/android/tv/data/Program.java @@ -32,26 +32,24 @@ import android.support.annotation.UiThread; import android.support.annotation.VisibleForTesting; import android.support.annotation.WorkerThread; import android.text.TextUtils; - +import android.util.Log; +import com.android.tv.common.BuildConfig; import com.android.tv.common.TvContentRatingCache; import com.android.tv.common.util.CollectionUtils; import com.android.tv.common.util.CommonUtils; -import com.android.tv.data.api.BaseProgram; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.util.TvProviderUtils; import com.android.tv.util.Utils; import com.android.tv.util.images.ImageLoader; - import com.google.common.collect.ImmutableList; - +import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** A convenience class to create and insert program information entries into the database. */ -public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Program { +public final class Program extends BaseProgram implements Comparable<Program>, Parcelable { private static final boolean DEBUG = false; private static final boolean DEBUG_DUMP_DESCRIPTION = false; private static final String TAG = "Program"; @@ -181,8 +179,8 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return builder.build(); } - public static ProgramImpl fromParcel(Parcel in) { - ProgramImpl program = new ProgramImpl(); + public static Program fromParcel(Parcel in) { + Program program = new Program(); program.mId = in.readLong(); program.mPackageName = in.readString(); program.mChannelId = in.readLong(); @@ -221,7 +219,7 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr new Parcelable.Creator<Program>() { @Override public Program createFromParcel(Parcel in) { - return ProgramImpl.fromParcel(in); + return Program.fromParcel(in); } @Override @@ -253,21 +251,19 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr private ImmutableList<TvContentRating> mContentRatings; private boolean mRecordingProhibited; - private ProgramImpl() { + private Program() { // Do nothing. } - @Override public long getId() { return mId; } - @Override + /** Returns the package name of this program. */ public String getPackageName() { return mPackageName; } - @Override public long getChannelId() { return mChannelId; } @@ -278,6 +274,11 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return mChannelId >= 0; } + /** Returns {@code true} if the program is valid and {@code false} otherwise. */ + public static boolean isProgramValid(Program program) { + return program != null && program.isValid(); + } + @Override public String getTitle() { return mTitle; @@ -301,11 +302,6 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr } @Override - public String getSeasonTitle() { - return mSeasonTitle; - } - - @Override public String getEpisodeNumber() { return mEpisodeNumber; } @@ -320,7 +316,6 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return mEndTimeUtcMillis; } - @Override public String getDurationString(Context context) { // TODO(b/71717446): expire the calculated string if (mDurationString == null) { @@ -346,17 +341,15 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return mLongDescription; } - @Override public int getVideoWidth() { return mVideoWidth; } - @Override public int getVideoHeight() { return mVideoHeight; } - @Override + /** Returns the list of Critic Scores for this program */ @Nullable public List<CriticScore> getCriticScores() { return mCriticScores; @@ -378,12 +371,12 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return mThumbnailUri; } - @Override + /** Returns {@code true} if the recording of this program is prohibited. */ public boolean isRecordingProhibited() { return mRecordingProhibited; } - @Override + /** Returns array of canonical genres for this program. This is expected to be called rarely. */ @Nullable public String[] getCanonicalGenres() { if (mCanonicalGenreIds == null) { @@ -402,7 +395,7 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return mCanonicalGenreIds; } - @Override + /** Returns if this program has the genre. */ public boolean hasGenre(int genreId) { if (genreId == GenreItems.ID_ALL_CHANNELS) { return true; @@ -443,11 +436,11 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr @Override public boolean equals(Object other) { - if (!(other instanceof ProgramImpl)) { + if (!(other instanceof Program)) { return false; } // Compare all the properties because program ID can be invalid for the dummy programs. - ProgramImpl program = (ProgramImpl) other; + Program program = (Program) other; return Objects.equals(mPackageName, program.mPackageName) && mChannelId == program.mChannelId && mStartTimeUtcMillis == program.mStartTimeUtcMillis @@ -471,7 +464,7 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr @Override public int compareTo(@NonNull Program other) { - return Long.compare(mStartTimeUtcMillis, other.getStartTimeUtcMillis()); + return Long.compare(mStartTimeUtcMillis, other.mStartTimeUtcMillis); } @Override @@ -523,7 +516,7 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr } /** - * Translates a {@link ProgramImpl} to {@link ContentValues} that are ready to be written into + * Translates a {@link Program} to {@link ContentValues} that are ready to be written into * Database. */ @SuppressLint("InlinedApi") @@ -602,37 +595,37 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr return; } - mId = other.getId(); - mPackageName = other.getPackageName(); - mChannelId = other.getChannelId(); - mTitle = other.getTitle(); - mSeriesId = other.getSeriesId(); - mEpisodeTitle = other.getEpisodeTitle(); - mSeasonNumber = other.getSeasonNumber(); - mSeasonTitle = other.getSeasonTitle(); - mEpisodeNumber = other.getEpisodeNumber(); - mStartTimeUtcMillis = other.getStartTimeUtcMillis(); - mEndTimeUtcMillis = other.getEndTimeUtcMillis(); + mId = other.mId; + mPackageName = other.mPackageName; + mChannelId = other.mChannelId; + mTitle = other.mTitle; + mSeriesId = other.mSeriesId; + mEpisodeTitle = other.mEpisodeTitle; + mSeasonNumber = other.mSeasonNumber; + mSeasonTitle = other.mSeasonTitle; + mEpisodeNumber = other.mEpisodeNumber; + mStartTimeUtcMillis = other.mStartTimeUtcMillis; + mEndTimeUtcMillis = other.mEndTimeUtcMillis; mDurationString = null; // Recreate Duration when needed. - mDescription = other.getDescription(); - mLongDescription = other.getLongDescription(); - mVideoWidth = other.getVideoWidth(); - mVideoHeight = other.getVideoHeight(); - mCriticScores = other.getCriticScores(); - mPosterArtUri = other.getPosterArtUri(); - mThumbnailUri = other.getThumbnailUri(); - mCanonicalGenreIds = other.getCanonicalGenreIds(); - mContentRatings = other.getContentRatings(); - mRecordingProhibited = other.isRecordingProhibited(); + mDescription = other.mDescription; + mLongDescription = other.mLongDescription; + mVideoWidth = other.mVideoWidth; + mVideoHeight = other.mVideoHeight; + mCriticScores = other.mCriticScores; + mPosterArtUri = other.mPosterArtUri; + mThumbnailUri = other.mThumbnailUri; + mCanonicalGenreIds = other.mCanonicalGenreIds; + mContentRatings = other.mContentRatings; + mRecordingProhibited = other.mRecordingProhibited; } /** A Builder for the Program class */ public static final class Builder { - private final ProgramImpl mProgram; + private final Program mProgram; /** Creates a Builder for this Program class */ public Builder() { - mProgram = new ProgramImpl(); + mProgram = new Program(); // Fill initial data. mProgram.mPackageName = null; mProgram.mChannelId = Channel.INVALID_ID; @@ -657,7 +650,7 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr */ @VisibleForTesting public Builder(Program other) { - mProgram = new ProgramImpl(); + mProgram = new Program(); mProgram.copyFrom(other); } @@ -913,7 +906,7 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr * * @return the Program object constructed */ - public ProgramImpl build() { + public Program build() { // Generate the series ID for the episodic program of other TV input. if (TextUtils.isEmpty(mProgram.mTitle)) { // If title is null, series cannot be generated for this program. @@ -923,13 +916,17 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr // If series ID is not set, generate it for the episodic program of other TV input. setSeriesId(BaseProgram.generateSeriesId(mProgram.mPackageName, mProgram.mTitle)); } - ProgramImpl program = new ProgramImpl(); + Program program = new Program(); program.copyFrom(mProgram); return program; } } - @Override + /** + * Prefetches the program poster art. + * + * <p> + */ public void prefetchPosterArt(Context context, int posterArtWidth, int posterArtHeight) { if (mPosterArtUri == null) { return; @@ -937,13 +934,20 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr ImageLoader.prefetchBitmap(context, mPosterArtUri, posterArtWidth, posterArtHeight); } - @Override + /** + * Loads the program poster art and returns it via {@code callback}. + * + * <p>Note that it may directly call {@code callback} if the program poster art already is + * loaded. + * + * @return {@code true} if the load is complete and the callback is executed. + */ @UiThread public boolean loadPosterArt( Context context, int posterArtWidth, int posterArtHeight, - ImageLoader.ImageLoaderCallback<?> callback) { + ImageLoader.ImageLoaderCallback callback) { if (mPosterArtUri == null) { return false; } @@ -951,9 +955,24 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr context, mPosterArtUri, posterArtWidth, posterArtHeight, callback); } - @Override - public Parcelable toParcelable() { - return this; + public static boolean isDuplicate(Program p1, Program p2) { + if (p1 == null || p2 == null) { + return false; + } + boolean isDuplicate = + p1.getChannelId() == p2.getChannelId() + && p1.getStartTimeUtcMillis() == p2.getStartTimeUtcMillis() + && p1.getEndTimeUtcMillis() == p2.getEndTimeUtcMillis(); + if (DEBUG && BuildConfig.ENG && isDuplicate) { + Log.w( + TAG, + "Duplicate programs detected! - \"" + + p1.getTitle() + + "\" and \"" + + p2.getTitle() + + "\""); + } + return isDuplicate; } @Override @@ -990,4 +1009,54 @@ public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Pr } out.writeByte((byte) (mRecordingProhibited ? 1 : 0)); } + + /** Holds one type of critic score and its source. */ + public static final class CriticScore implements Serializable, Parcelable { + /** The source of the rating. */ + public final String source; + /** The score. */ + public final String score; + /** The url of the logo image */ + public final String logoUrl; + + public static final Parcelable.Creator<CriticScore> CREATOR = + new Parcelable.Creator<CriticScore>() { + @Override + public CriticScore createFromParcel(Parcel in) { + String source = in.readString(); + String score = in.readString(); + String logoUri = in.readString(); + return new CriticScore(source, score, logoUri); + } + + @Override + public CriticScore[] newArray(int size) { + return new CriticScore[size]; + } + }; + + /** + * Constructor for this class. + * + * @param source the source of the rating + * @param score the score + */ + public CriticScore(String source, String score, String logoUrl) { + this.source = source; + this.score = score; + this.logoUrl = logoUrl; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int i) { + out.writeString(source); + out.writeString(score); + out.writeString(logoUrl); + } + } } diff --git a/src/com/android/tv/data/ProgramDataManager.java b/src/com/android/tv/data/ProgramDataManager.java index a866c78e..2f20c89a 100644 --- a/src/com/android/tv/data/ProgramDataManager.java +++ b/src/com/android/tv/data/ProgramDataManager.java @@ -33,24 +33,19 @@ import android.util.ArraySet; import android.util.Log; import android.util.LongSparseArray; import android.util.LruCache; - import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.memory.MemoryManageable; import com.android.tv.common.util.Clock; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.perf.EventNames; import com.android.tv.perf.PerformanceMonitor; import com.android.tv.perf.TimerEvent; import com.android.tv.util.AsyncDbTask; import com.android.tv.util.MultiLongSparseArray; -import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.TvProviderUtils; import com.android.tv.util.Utils; - import com.android.tv.common.flags.BackendKnobsFlags; - import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -80,11 +75,6 @@ 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"; @@ -96,20 +86,10 @@ public class ProgramDataManager implements MemoryManageable { + Programs.COLUMN_CHANNEL_ID + ", " + Programs.COLUMN_END_TIME_UTC_MILLIS; - private static final String SORT_BY_CHANNEL_ID = - Programs.COLUMN_CHANNEL_ID - + ", " - + Programs.COLUMN_START_TIME_UTC_MILLIS - + " DESC, " - + Programs.COLUMN_END_TIME_UTC_MILLIS - + " ASC, " - + Programs._ID - + " DESC"; private static final int MSG_UPDATE_CURRENT_PROGRAMS = 1000; private static final int MSG_UPDATE_ONE_CURRENT_PROGRAM = 1001; private static final int MSG_UPDATE_PREFETCH_PROGRAM = 1002; - private static final int MSG_UPDATE_CONTENT_RATINGS = 1003; private final Context mContext; private final Clock mClock; @@ -118,7 +98,6 @@ public class ProgramDataManager implements MemoryManageable { private final BackendKnobsFlags mBackendKnobsFlags; private final PerformanceMonitor mPerformanceMonitor; private final ChannelDataManager mChannelDataManager; - private final TvInputManagerHelper mTvInputManagerHelper; private boolean mStarted; // Updated only on the main thread. private volatile boolean mCurrentProgramsLoadFinished; @@ -146,11 +125,6 @@ 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) { @@ -162,8 +136,7 @@ public class ProgramDataManager implements MemoryManageable { Looper.myLooper(), TvSingletons.getSingletons(context).getBackendKnobs(), TvSingletons.getSingletons(context).getPerformanceMonitor(), - TvSingletons.getSingletons(context).getChannelDataManager(), - TvSingletons.getSingletons(context).getTvInputManagerHelper()); + TvSingletons.getSingletons(context).getChannelDataManager()); } @VisibleForTesting @@ -175,8 +148,7 @@ public class ProgramDataManager implements MemoryManageable { Looper looper, BackendKnobsFlags backendKnobsFlags, PerformanceMonitor performanceMonitor, - ChannelDataManager channelDataManager, - TvInputManagerHelper tvInputManagerHelper) { + ChannelDataManager channelDataManager) { mContext = context; mDbExecutor = executor; mClock = time; @@ -185,7 +157,6 @@ public class ProgramDataManager implements MemoryManageable { mBackendKnobsFlags = backendKnobsFlags; mPerformanceMonitor = performanceMonitor; mChannelDataManager = channelDataManager; - mTvInputManagerHelper = tvInputManagerHelper; mProgramObserver = new ContentObserver(mHandler) { @Override @@ -234,7 +205,6 @@ public class ProgramDataManager implements MemoryManageable { // Should be called directly instead of posting MSG_UPDATE_CURRENT_PROGRAMS message // to the handler. If not, another DB task can be executed before loading current programs. handleUpdateCurrentPrograms(); - mHandler.sendEmptyMessage(MSG_UPDATE_CONTENT_RATINGS); if (mPrefetchEnabled) { mHandler.sendEmptyMessage(MSG_UPDATE_PREFETCH_PROGRAM); } @@ -289,67 +259,15 @@ public class ProgramDataManager implements MemoryManageable { } } - /** - * 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); - 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(); - } - } - public void prefetchChannel(long channelId) { - prefetchChannel(channelId, 0); - } - - /** - * 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) { - if (mChannelIdProgramCache.containsKey(channelId)) { - ArrayList<Program> programs = mChannelIdProgramCache.get(channelId); - long marginEndTime = startTimeMs + mMaxFetchHoursMs - BUFFER_HOURS_MS; - return programs.size() > selectedProgramIndex && - programs.get(selectedProgramIndex).getEndTimeUtcMillis() > marginEndTime; + 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(); } - return false; - } - - public void onChannelTuned(long channelId) { - mTunedChannelId = channelId; - prefetchChannel(channelId); } /** A Callback interface to receive notification on program data retrieval from DB. */ @@ -362,10 +280,12 @@ public class ProgramDataManager implements MemoryManageable { void onProgramUpdated(); /** - * 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. + * Called when we update complete program data of specific channel during scrolling. Data is + * loaded from DB on request basis. + * + * @param channelId */ - void onChannelUpdated(); + void onSingleChannelUpdated(long channelId); } /** Adds the {@link Callback}. */ @@ -392,7 +312,7 @@ public class ProgramDataManager implements MemoryManageable { } else { mPrefetchEnabled = false; cancelPrefetchTask(); - clearChannelInfoMap(); + mChannelIdProgramCache.clear(); mHandler.removeMessages(MSG_UPDATE_PREFETCH_PROGRAM); } } @@ -619,7 +539,10 @@ public class ProgramDataManager implements MemoryManageable { } programMap.clear(); - String[] projection = ProgramImpl.PARTIAL_PROJECTION; + String[] projection = + mBackendKnobsFlags.enablePartialProgramFetch() + ? Program.PARTIAL_PROJECTION + : Program.PROJECTION; if (TvProviderUtils.checkSeriesIdColumn(mContext, Programs.CONTENT_URI)) { if (Utils.isProgramsUri(uri)) { projection = @@ -639,7 +562,10 @@ public class ProgramDataManager implements MemoryManageable { } return null; } - Program program = ProgramImpl.fromCursorPartialProjection(c); + Program program = + mBackendKnobsFlags.enablePartialProgramFetch() + ? Program.fromCursorPartialProjection(c) + : Program.fromCursor(c); if (Program.isDuplicate(program, lastReadProgram)) { duplicateCount++; continue; @@ -649,14 +575,15 @@ public class ProgramDataManager implements MemoryManageable { ArrayList<Program> programs = programMap.get(program.getChannelId()); if (programs == null) { programs = new ArrayList<>(); - // To skip already loaded complete data. - Program currentProgramInfo = - mChannelIdCurrentProgramMap.get(program.getChannelId()); - if (currentProgramInfo != null - && Program.isDuplicate(program, currentProgramInfo)) { - program = currentProgramInfo; + if (mBackendKnobsFlags.enablePartialProgramFetch()) { + // To skip already loaded complete data. + Program currentProgramInfo = + mChannelIdCurrentProgramMap.get(program.getChannelId()); + if (currentProgramInfo != null + && Program.isDuplicate(program, currentProgramInfo)) { + program = currentProgramInfo; + } } - programMap.put(program.getChannelId(), programs); } programs.add(program); @@ -701,12 +628,15 @@ public class ProgramDataManager implements MemoryManageable { mLastPrefetchTaskRunMs + PROGRAM_GUIDE_SNAP_TIME_MS, PROGRAM_GUIDE_SNAP_TIME_MS) - currentTime; + // Issue second pre-fetch immediately after the first partial update + if (mChannelIdProgramCache.isEmpty()) { + nextMessageDelayedTime = 0; + } mChannelIdProgramCache = programs; - // Since cache has partial data we need to reset the map of complete data. - clearChannelInfoMap(); - // Get complete projection of tuned channel. - prefetchChannel(mTunedChannelId); - + if (mBackendKnobsFlags.enablePartialProgramFetch()) { + // Since cache has partial data we need to reset the map of complete data. + mCompleteInfoChannelIds.clear(); + } notifyProgramUpdated(); if (mFromEmptyCacheTimeEvent != null) { mPerformanceMonitor.stopTimer( @@ -724,11 +654,6 @@ 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()); @@ -760,7 +685,7 @@ public class ProgramDataManager implements MemoryManageable { mDbExecutor, mContext, TvContract.buildProgramsUriForChannel(channelId, startTimeMs, endTimeMs), - ProgramImpl.PROJECTION, + Program.PROJECTION, null, null, SORT_BY_TIME); @@ -771,7 +696,7 @@ public class ProgramDataManager implements MemoryManageable { protected ArrayList<Program> onQuery(Cursor c) { ArrayList<Program> programMap = new ArrayList<>(); while (c.moveToNext()) { - Program program = ProgramImpl.fromCursor(c); + Program program = Program.fromCursor(c); programMap.add(program); } return programMap; @@ -780,7 +705,7 @@ public class ProgramDataManager implements MemoryManageable { @Override protected void onPostExecute(ArrayList<Program> programs) { mChannelIdProgramCache.put(mChannelId, programs); - notifyChannelUpdated(); + notifySingleChannelUpdated(mChannelId); } } @@ -790,9 +715,9 @@ public class ProgramDataManager implements MemoryManageable { } } - private void notifyChannelUpdated() { + private void notifySingleChannelUpdated(long channelId) { for (Callback callback : mCallbacks) { - callback.onChannelUpdated(); + callback.onSingleChannelUpdated(channelId); } } @@ -806,10 +731,10 @@ public class ProgramDataManager implements MemoryManageable { .appendQueryParameter(PARAM_START_TIME, String.valueOf(time)) .appendQueryParameter(PARAM_END_TIME, String.valueOf(time)) .build(), - ProgramImpl.PROJECTION, + Program.PROJECTION, null, null, - SORT_BY_CHANNEL_ID); + SORT_BY_TIME); } @Override @@ -822,21 +747,17 @@ public class ProgramDataManager implements MemoryManageable { if (isCancelled()) { return programs; } - Program program = ProgramImpl.fromCursor(c); - // Only one program is expected per channel for this query - // However, skip overlapping programs from same channel - if (Program.sameChannel(program, lastReadProgram) - && Program.isOverlapping(program, lastReadProgram)) { + Program program = Program.fromCursor(c); + if (Program.isDuplicate(program, lastReadProgram)) { duplicateCount++; continue; } else { lastReadProgram = program; } - programs.add(program); } if (duplicateCount > 0) { - Log.w(TAG, "Found " + duplicateCount + " overlapping programs"); + Log.w(TAG, "Found " + duplicateCount + " duplicate programs"); } } return programs; @@ -856,7 +777,9 @@ public class ProgramDataManager implements MemoryManageable { for (Long channelId : removedChannelIds) { if (mPrefetchEnabled) { mChannelIdProgramCache.remove(channelId); - mCompleteInfoChannelIds.remove(channelId); + if (mBackendKnobsFlags.enablePartialProgramFetch()) { + mCompleteInfoChannelIds.remove(channelId); + } } mChannelIdCurrentProgramMap.remove(channelId); notifyCurrentProgramUpdate(channelId, null); @@ -874,7 +797,7 @@ public class ProgramDataManager implements MemoryManageable { mDbExecutor, mContext, TvContract.buildProgramsUriForChannel(channelId, time, time), - ProgramImpl.PROJECTION, + Program.PROJECTION, null, null, SORT_BY_TIME); @@ -885,7 +808,7 @@ public class ProgramDataManager implements MemoryManageable { public Program onQuery(Cursor c) { Program program = null; if (c != null && c.moveToNext()) { - program = ProgramImpl.fromCursor(c); + program = Program.fromCursor(c); } return program; } @@ -946,9 +869,6 @@ public class ProgramDataManager implements MemoryManageable { } break; } - case MSG_UPDATE_CONTENT_RATINGS: - mTvInputManagerHelper.getContentRatingsManager().update(); - break; default: // Do nothing } @@ -1012,7 +932,7 @@ public class ProgramDataManager implements MemoryManageable { // Create dummy program which indicates data isn't loaded yet so DB query is required. private Program createDummyProgram(long startTimeMs, long endTimeMs) { - return new ProgramImpl.Builder() + return new Program.Builder() .setChannelId(Channel.INVALID_ID) .setStartTimeUtcMillis(startTimeMs) .setEndTimeUtcMillis(endTimeMs) diff --git a/src/com/android/tv/data/api/BaseProgram.java b/src/com/android/tv/data/api/BaseProgram.java deleted file mode 100644 index 8acaf79e..00000000 --- a/src/com/android/tv/data/api/BaseProgram.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.android.tv.data.api; - -import android.content.Context; -import android.media.tv.TvContentRating; -import android.support.annotation.Nullable; -import com.google.common.collect.ImmutableList; -import java.util.Comparator; -import java.util.Objects; - -/** - * Base class for {@link com.android.tv.data.Program} and {@link - * com.android.tv.dvr.data.RecordedProgram}. - */ -public interface BaseProgram { - - /** - * Comparator used to compare {@link BaseProgram} according to its season and episodes number. - * If a program's season or episode number is null, it will be consider "smaller" than programs - * with season or episode numbers. - */ - Comparator<BaseProgram> EPISODE_COMPARATOR = new EpisodeComparator(false); - /** - * Comparator used to compare {@link BaseProgram} according to its season and episodes number - * with season numbers in a reversed order. If a program's season or episode number is null, it - * will be consider "smaller" than programs with season or episode numbers. - */ - Comparator<BaseProgram> SEASON_REVERSED_EPISODE_COMPARATOR = new EpisodeComparator(true); - - String COLUMN_SERIES_ID = "series_id"; - String COLUMN_STATE = "state"; - - /** Compares two strings represent season numbers or episode numbers of programs. */ - static int numberCompare(String s1, String s2) { - if (Objects.equals(s1, s2)) { - return 0; - } else if (s1 == null) { - return -1; - } else if (s2 == null) { - return 1; - } else if (s1.equals(s2)) { - return 0; - } - try { - return Integer.compare(Integer.parseInt(s1), Integer.parseInt(s2)); - } catch (NumberFormatException e) { - return s1.compareTo(s2); - } - } - - /** Generates the series ID for the other inputs than the tuner TV input. */ - static String generateSeriesId(String packageName, String title) { - return packageName + "/" + title; - } - - /** Returns ID of the program. */ - long getId(); - - /** Returns the title of the program. */ - String getTitle(); - - /** Returns the episode title. */ - String getEpisodeTitle(); - - /** Returns the displayed title of the program episode. */ - @Nullable - String getEpisodeDisplayTitle(Context context); - - /** - * Returns the content description of the program episode, suitable for being spoken by an - * accessibility service. - */ - String getEpisodeContentDescription(Context context); - - /** Returns the description of the program. */ - String getDescription(); - - /** Returns the long description of the program. */ - String getLongDescription(); - - /** Returns the start time of the program in Milliseconds. */ - long getStartTimeUtcMillis(); - - /** Returns the end time of the program in Milliseconds. */ - long getEndTimeUtcMillis(); - - /** Returns the duration of the program in Milliseconds. */ - long getDurationMillis(); - - /** Returns the series ID. */ - @Nullable - String getSeriesId(); - - /** Returns the season number. */ - String getSeasonNumber(); - - /** Returns the episode number. */ - String getEpisodeNumber(); - - /** Returns URI of the program's poster. */ - String getPosterArtUri(); - - /** Returns URI of the program's thumbnail. */ - String getThumbnailUri(); - - /** Returns the array of the ID's of the canonical genres. */ - int[] getCanonicalGenreIds(); - - /** Returns the array of content ratings. */ - ImmutableList<TvContentRating> getContentRatings(); - - /** Returns channel's ID of the program. */ - long getChannelId(); - - /** Returns if the program is valid. */ - boolean isValid(); - - /** Checks whether the program is episodic or not. */ - boolean isEpisodic(); - - /** Generates the series ID for the other inputs than the tuner TV input. */ - class EpisodeComparator implements Comparator<BaseProgram> { - private final boolean mReversedSeason; - - EpisodeComparator(boolean reversedSeason) { - mReversedSeason = reversedSeason; - } - - @Override - public int compare(BaseProgram lhs, BaseProgram rhs) { - if (lhs == rhs) { - return 0; - } - int seasonNumberCompare = numberCompare(lhs.getSeasonNumber(), rhs.getSeasonNumber()); - if (seasonNumberCompare != 0) { - return mReversedSeason ? -seasonNumberCompare : seasonNumberCompare; - } else { - return numberCompare(lhs.getEpisodeNumber(), rhs.getEpisodeNumber()); - } - } - } -} diff --git a/src/com/android/tv/data/api/Program.java b/src/com/android/tv/data/api/Program.java deleted file mode 100644 index f2221f6e..00000000 --- a/src/com/android/tv/data/api/Program.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.android.tv.data.api; - -import android.content.Context; -import android.os.Parcel; -import android.os.Parcelable; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; - -import com.android.tv.util.images.ImageLoader; - -import java.io.Serializable; -import java.util.List; - -/** A convenience interface to create and insert program information entries into the database. */ -public interface Program extends BaseProgram, Comparable<Program> { - - /** Returns {@code true} if the program is valid and {@code false} otherwise. */ - static boolean isProgramValid(Program program) { - return program != null && program.isValid(); - } - - static boolean isDuplicate(Program p1, Program p2) { - if (p1 == null || p2 == null) { - return false; - } - return p1.getChannelId() == p2.getChannelId() - && p1.getStartTimeUtcMillis() == p2.getStartTimeUtcMillis() - && p1.getEndTimeUtcMillis() == p2.getEndTimeUtcMillis(); - } - - /** True if the start or end times overlap. */ - static boolean isOverlapping(@Nullable Program p1, @Nullable Program p2) { - return p1 != null - && p2 != null - && p1.getStartTimeUtcMillis() < p2.getEndTimeUtcMillis() - && p1.getEndTimeUtcMillis() > p2.getStartTimeUtcMillis(); - } - - /** True if the channels IDs are the same. */ - static boolean sameChannel(@Nullable Program p1, @Nullable Program p2) { - return p1 != null && p2 != null && p1.getChannelId() == p2.getChannelId(); - } - - /** Returns the package name of this program. */ - String getPackageName(); - - /** Returns the season title */ - String getSeasonTitle(); - - /** Gets the localized duration of the program */ - String getDurationString(Context context); - - int getVideoWidth(); - - int getVideoHeight(); - - /** Returns the list of Critic Scores for this program */ - @Nullable - List<CriticScore> getCriticScores(); - - /** Returns {@code true} if the recording of this program is prohibited. */ - boolean isRecordingProhibited(); - - /** Returns array of canonical genres for this program. This is expected to be called rarely. */ - @Nullable - String[] getCanonicalGenres(); - - /** Returns if this program has the genre. */ - boolean hasGenre(int genreId); - - /** Prefetch the program poster art. */ - void prefetchPosterArt(Context context, int posterArtWidth, int posterArtHeight); - - /** - * Loads the program poster art and returns it via {@code callback}. - * - * <p>Note that it may directly call {@code callback} if the program poster art already is - * loaded. - * - * @return {@code true} if the load is complete and the callback is executed. - */ - @UiThread - boolean loadPosterArt( - Context context, - int posterArtWidth, - int posterArtHeight, - ImageLoader.ImageLoaderCallback<?> callback); - - /** Returns a {@link Parcelable} representation of this instance. */ - Parcelable toParcelable(); - - /** Holds one type of critic score and its source. */ - final class CriticScore implements Serializable, Parcelable { - /** The source of the rating. */ - public final String source; - /** The score. */ - public final String score; - /** The url of the logo image */ - public final String logoUrl; - - public static final Creator<CriticScore> CREATOR = - new Creator<CriticScore>() { - @Override - public CriticScore createFromParcel(Parcel in) { - String source = in.readString(); - String score = in.readString(); - String logoUri = in.readString(); - return new CriticScore(source, score, logoUri); - } - - @Override - public CriticScore[] newArray(int size) { - return new CriticScore[size]; - } - }; - - /** - * Constructor for this class. - * - * @param source the source of the rating - * @param score the score - */ - public CriticScore(String source, String score, String logoUrl) { - this.source = source; - this.score = score; - this.logoUrl = logoUrl; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int i) { - out.writeString(source); - out.writeString(score); - out.writeString(logoUrl); - } - } -} diff --git a/src/com/android/tv/data/epg/EpgFetchHelper.java b/src/com/android/tv/data/epg/EpgFetchHelper.java index 4e889115..3843ca99 100644 --- a/src/com/android/tv/data/epg/EpgFetchHelper.java +++ b/src/com/android/tv/data/epg/EpgFetchHelper.java @@ -28,15 +28,12 @@ import android.preference.PreferenceManager; import android.support.annotation.WorkerThread; import android.text.TextUtils; import android.util.Log; - import com.android.tv.common.CommonConstants; import com.android.tv.common.util.Clock; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.features.TvFeatures; import com.android.tv.util.TvProviderUtils; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -109,7 +106,7 @@ class EpgFetchHelper { ops.add( ContentProviderOperation.newUpdate( TvContract.buildProgramUri(oldProgram.getId())) - .withValues(ProgramImpl.toContentValues(newProgram, context)) + .withValues(Program.toContentValues(newProgram, context)) .build()); oldProgramsIndex++; newProgramsIndex++; @@ -135,7 +132,7 @@ class EpgFetchHelper { if (addNewProgram) { ops.add( ContentProviderOperation.newInsert(Programs.CONTENT_URI) - .withValues(ProgramImpl.toContentValues(newProgram, context)) + .withValues(Program.toContentValues(newProgram, context)) .build()); } // Throttle the batch operation not to cause TransactionTooLargeException. @@ -202,7 +199,7 @@ class EpgFetchHelper { @WorkerThread private static List<Program> queryPrograms( Context context, long channelId, long startTimeMs, long endTimeMs) { - String[] projection = ProgramImpl.PROJECTION; + String[] projection = Program.PROJECTION; if (TvProviderUtils.checkSeriesIdColumn(context, Programs.CONTENT_URI)) { projection = TvProviderUtils.addExtraColumnsToProjection( @@ -222,7 +219,7 @@ class EpgFetchHelper { } ArrayList<Program> programs = new ArrayList<>(); while (c.moveToNext()) { - programs.add(ProgramImpl.fromCursor(c)); + programs.add(Program.fromCursor(c)); } return programs; } diff --git a/src/com/android/tv/data/epg/EpgFetchService.java b/src/com/android/tv/data/epg/EpgFetchService.java index cfa79cb0..aa4f3588 100644 --- a/src/com/android/tv/data/epg/EpgFetchService.java +++ b/src/com/android/tv/data/epg/EpgFetchService.java @@ -18,24 +18,22 @@ package com.android.tv.data.epg; import android.app.job.JobParameters; import android.app.job.JobService; - import com.android.tv.Starter; +import com.android.tv.TvSingletons; import com.android.tv.data.ChannelDataManager; -import dagger.android.AndroidInjection; - -import javax.inject.Inject; - /** JobService to Fetch EPG data. */ public class EpgFetchService extends JobService { - @Inject EpgFetcher mEpgFetcher; - @Inject ChannelDataManager mChannelDataManager; + private EpgFetcher mEpgFetcher; + private ChannelDataManager mChannelDataManager; @Override public void onCreate() { - AndroidInjection.inject(this); super.onCreate(); Starter.start(this); + TvSingletons tvSingletons = TvSingletons.getSingletons(getApplicationContext()); + mEpgFetcher = tvSingletons.getEpgFetcher(); + mChannelDataManager = tvSingletons.getChannelDataManager(); } @Override diff --git a/src/com/android/tv/data/epg/EpgFetcherImpl.java b/src/com/android/tv/data/epg/EpgFetcherImpl.java index 27d7f8d5..b191421f 100644 --- a/src/com/android/tv/data/epg/EpgFetcherImpl.java +++ b/src/com/android/tv/data/epg/EpgFetcherImpl.java @@ -38,12 +38,10 @@ import android.support.annotation.VisibleForTesting; import android.support.annotation.WorkerThread; import android.text.TextUtils; import android.util.Log; - import com.android.tv.TvSingletons; import com.android.tv.common.BuildConfig; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.buildtype.HasBuildType; -import com.android.tv.common.dagger.annotations.ApplicationContext; import com.android.tv.common.util.Clock; import com.android.tv.common.util.CommonUtils; import com.android.tv.common.util.LocationUtils; @@ -54,22 +52,17 @@ import com.android.tv.data.ChannelDataManager; import com.android.tv.data.ChannelImpl; import com.android.tv.data.ChannelLogoFetcher; import com.android.tv.data.Lineup; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; -import com.android.tv.data.epg.EpgReader.EpgChannel; import com.android.tv.features.TvFeatures; import com.android.tv.perf.EventNames; import com.android.tv.perf.PerformanceMonitor; import com.android.tv.perf.TimerEvent; import com.android.tv.util.Utils; - import com.google.android.tv.partner.support.EpgInput; import com.google.android.tv.partner.support.EpgInputs; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; - import com.android.tv.common.flags.BackendKnobsFlags; - import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -80,8 +73,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; -import javax.inject.Inject; - /** * The service class to fetch EPG routinely or on-demand during channel scanning * @@ -118,6 +109,7 @@ public class EpgFetcherImpl implements EpgFetcher { private static final int MSG_FINISH_FETCH_DURING_SCAN = 3; private static final int MSG_RETRY_PREPARE_FETCH_DURING_SCAN = 4; + private static final int QUERY_CHANNEL_COUNT = 50; private static final int MINIMUM_CHANNELS_TO_DECIDE_LINEUP = 3; private final Context mContext; @@ -138,9 +130,31 @@ public class EpgFetcherImpl implements EpgFetcher { private Clock mClock; - @Inject - public EpgFetcherImpl( - @ApplicationContext Context context, + public static EpgFetcher create(Context context) { + 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()); + BackendKnobsFlags backendKnobsFlags = tvSingletons.getBackendKnobs(); + HasBuildType.BuildType buildType = tvSingletons.getBuildType(); + return new EpgFetcherImpl( + context, + epgInputWhiteList, + channelDataManager, + epgReader, + performanceMonitor, + clock, + backendKnobsFlags, + buildType); + } + + @VisibleForTesting + EpgFetcherImpl( + Context context, EpgInputWhiteList epgInputWhiteList, ChannelDataManager channelDataManager, EpgReader epgReader, @@ -455,16 +469,23 @@ public class EpgFetcherImpl implements EpgFetcher { if (epgChannels.size() == 0) { return; } - int batchSize = (int) Math.max(1, mBackendKnobsFlags.epgFetcherChannelsPerProgramFetch()); - for (Iterable<EpgChannel> batch : Iterables.partition(epgChannels, batchSize)) { - batchUpdateEpg(mEpgReader.getPrograms(ImmutableSet.copyOf(batch), durationSec)); + Set<EpgReader.EpgChannel> batch = new HashSet<>(QUERY_CHANNEL_COUNT); + for (EpgReader.EpgChannel epgChannel : epgChannels) { + batch.add(epgChannel); + if (batch.size() >= QUERY_CHANNEL_COUNT) { + batchUpdateEpg(mEpgReader.getPrograms(batch, durationSec)); + batch.clear(); + } + } + if (!batch.isEmpty()) { + batchUpdateEpg(mEpgReader.getPrograms(batch, durationSec)); } } @WorkerThread private void batchUpdateEpg(Map<EpgReader.EpgChannel, Collection<Program>> allPrograms) { for (Map.Entry<EpgReader.EpgChannel, Collection<Program>> entry : allPrograms.entrySet()) { - List<Program> programs = new ArrayList<>(entry.getValue()); + List<Program> programs = new ArrayList(entry.getValue()); if (programs == null) { continue; } @@ -583,7 +604,6 @@ 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 4a5f98bb..24b4fe3d 100644 --- a/src/com/android/tv/data/epg/EpgInputWhiteList.java +++ b/src/com/android/tv/data/epg/EpgInputWhiteList.java @@ -21,14 +21,13 @@ 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 { @@ -37,7 +36,6 @@ 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 @@ -45,12 +43,10 @@ public final class EpgInputWhiteList { return inputId == null ? null : inputId.substring(0, inputId.indexOf("/")); } - private final CloudEpgFlags mCloudEpgFlags; + private final CloudEpgFlags cloudEpgFlags; - @Inject - public EpgInputWhiteList(CloudEpgFlags cloudEpgFlags, LegacyFlags legacyFlags) { - mCloudEpgFlags = cloudEpgFlags; - mLegacyFlags = legacyFlags; + public EpgInputWhiteList(CloudEpgFlags cloudEpgFlags) { + this.cloudEpgFlags = cloudEpgFlags; } public boolean isInputWhiteListed(String inputId) { @@ -75,8 +71,8 @@ public final class EpgInputWhiteList { } private Set<String> getWhiteListedInputs() { - Set<String> result = toInputSet(mCloudEpgFlags.thirdPartyEpgInputsCsv()); - if (BuildConfig.ENG || mLegacyFlags.enableQaFeatures()) { + Set<String> result = toInputSet(cloudEpgFlags.thirdPartyEpgInputsCsv()); + if (BuildConfig.ENG || Experiments.ENABLE_QA_FEATURES.get()) { HashSet<String> moreInputs = new HashSet<>(toInputSet(QA_DEV_INPUTS)); if (result.isEmpty()) { result = moreInputs; diff --git a/src/com/android/tv/data/epg/EpgReader.java b/src/com/android/tv/data/epg/EpgReader.java index 8c0e3f09..c9fcd979 100644 --- a/src/com/android/tv/data/epg/EpgReader.java +++ b/src/com/android/tv/data/epg/EpgReader.java @@ -19,14 +19,11 @@ package com.android.tv.data.epg; import android.support.annotation.AnyThread; import android.support.annotation.NonNull; import android.support.annotation.WorkerThread; - import com.android.tv.data.Lineup; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.data.SeriesInfo; - import com.google.auto.value.AutoValue; - import java.util.Collection; import java.util.List; import java.util.Map; @@ -39,8 +36,8 @@ public interface EpgReader { /** Value class that holds a EpgChannelId and its corresponding {@link Channel} */ @AutoValue abstract class EpgChannel { - public static EpgChannel createEpgChannel( - Channel channel, String epgChannelId, boolean dbUpdateNeeded) { + public static EpgChannel createEpgChannel(Channel channel, String epgChannelId, + boolean dbUpdateNeeded) { return new AutoValue_EpgReader_EpgChannel(channel, epgChannelId, dbUpdateNeeded); } diff --git a/src/com/android/tv/data/epg/StubEpgReader.java b/src/com/android/tv/data/epg/StubEpgReader.java index 19bf786e..3b001481 100644 --- a/src/com/android/tv/data/epg/StubEpgReader.java +++ b/src/com/android/tv/data/epg/StubEpgReader.java @@ -16,25 +16,21 @@ 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; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.data.SeriesInfo; - import java.util.Collection; 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 { - @Inject - public StubEpgReader() {} + public StubEpgReader(@SuppressWarnings("unused") Context context) {} @Override public boolean isAvailable() { diff --git a/src/com/android/tv/dialog/PinDialogFragment.java b/src/com/android/tv/dialog/PinDialogFragment.java index c7145583..87308093 100644 --- a/src/com/android/tv/dialog/PinDialogFragment.java +++ b/src/com/android/tv/dialog/PinDialogFragment.java @@ -18,7 +18,6 @@ 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; @@ -34,13 +33,10 @@ 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.TvPinPicker; -import com.android.tv.util.TvInputManagerHelper; +import com.android.tv.dialog.picker.PinPicker; 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"; @@ -84,8 +80,7 @@ public class PinDialogFragment extends SafeDismissDialogFragment { private TextView mWrongPinView; private View mEnterPinView; private TextView mTitleView; - - private TvPinPicker mTvPinPicker; + private PinPicker mPicker; private SharedPreferences mSharedPreferences; private String mPrevPin; private String mPin; @@ -93,8 +88,6 @@ 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); @@ -110,12 +103,6 @@ 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); @@ -167,8 +154,8 @@ public class PinDialogFragment extends SafeDismissDialogFragment { mWrongPinView = (TextView) v.findViewById(R.id.wrong_pin); mEnterPinView = v.findViewById(R.id.enter_pin); mTitleView = (TextView) mEnterPinView.findViewById(R.id.title); - mTvPinPicker = v.findViewById(R.id.tv_pin_picker); - mTvPinPicker.setOnClickListener( + mPicker = v.findViewById(R.id.pin_picker); + mPicker.setOnClickListener( view -> { String pin = getPinInput(); if (!TextUtils.isEmpty(pin)) { @@ -196,7 +183,8 @@ public class PinDialogFragment extends SafeDismissDialogFragment { mTitleView.setText( getString( R.string.pin_enter_unlock_dvr, - mTvInputManagerHelper + TvSingletons.getSingletons(getContext()) + .getTvInputManagerHelper() .getContentRatingsManager() .getDisplayNameForRating(tvContentRating))); } @@ -216,8 +204,7 @@ public class PinDialogFragment extends SafeDismissDialogFragment { if (mType != PIN_DIALOG_TYPE_NEW_PIN) { updateWrongPin(); } - - mTvPinPicker.requestFocus(); + mPicker.requestFocus(); return v; } @@ -351,11 +338,11 @@ public class PinDialogFragment extends SafeDismissDialogFragment { } private String getPinInput() { - return mTvPinPicker.getPin(); + return mPicker.getPinInput(); } private void resetPinInput() { - mTvPinPicker.resetPin(); + mPicker.resetPinInput(); } /** diff --git a/src/com/android/tv/dialog/picker/PinPicker.java b/src/com/android/tv/dialog/picker/PinPicker.java new file mode 100644 index 00000000..f501dfd1 --- /dev/null +++ b/src/com/android/tv/dialog/picker/PinPicker.java @@ -0,0 +1,131 @@ +/* + * 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.dialog.picker; + +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 android.util.AttributeSet; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; +import java.util.ArrayList; +import java.util.List; + +/** 4 digit picker */ +public final class PinPicker extends Picker { + // TODO(b/116144491): use leanback pin picker. + + private final List<PickerColumn> mPickers = new ArrayList<>(); + private OnClickListener mOnClickListener; + + // the version of picker I link to does not have this constructor + public PinPicker(Context context, AttributeSet attributeSet) { + this(context, attributeSet, 0); + } + + public PinPicker(Context context, AttributeSet attributeSet, int defStyleAttr) { + super(context, attributeSet, defStyleAttr); + + for (int i = 0; i < 4; i++) { + PickerColumn pickerColumn = new PickerColumn(); + pickerColumn.setMinValue(0); + pickerColumn.setMaxValue(9); + pickerColumn.setLabelFormat("%d"); + mPickers.add(pickerColumn); + } + setSeparator(" "); + setColumns(mPickers); + setActivated(true); + setFocusable(true); + super.setOnClickListener(this::onClick); + } + + public String getPinInput() { + String result = ""; + try { + for (PickerColumn column : mPickers) { + + result += column.getCurrentValue(); + } + } catch (IllegalStateException e) { + result = ""; + } + return result; + } + + @Override + public void setOnClickListener(@Nullable OnClickListener l) { + mOnClickListener = l; + } + + private void onClick(View v) { + int selectedColumn = getSelectedColumn(); + int nextColumn = selectedColumn + 1; + // Only call the click listener if we are on the last column + // Otherwise move to the next column + if (nextColumn == getColumnsCount()) { + if (mOnClickListener != null) { + mOnClickListener.onClick(v); + } + } else { + setSelectedColumn(nextColumn); + onRequestFocusInDescendants(ViewGroup.FOCUS_FORWARD, null); + } + } + + public void resetPinInput() { + setActivated(false); + for (int i = 0; i < 4; i++) { + setColumnValue(i, 0, true); + } + setSelectedColumn(0); + setActivated(true); // This resets the focus + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_UP) { + int keyCode = event.getKeyCode(); + int digit = digitFromKeyCode(keyCode); + if (digit != -1) { + int selectedColumn = getSelectedColumn(); + setColumnValue(selectedColumn, digit, false); + int nextColumn = selectedColumn + 1; + if (nextColumn < getColumnsCount()) { + setSelectedColumn(nextColumn); + onRequestFocusInDescendants(ViewGroup.FOCUS_FORWARD, null); + } else { + callOnClick(); + } + return true; + } + } + return super.dispatchKeyEvent(event); + } + + @VisibleForTesting + static int digitFromKeyCode(int keyCode) { + if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) { + return keyCode - KeyEvent.KEYCODE_0; + } else if (keyCode >= KeyEvent.KEYCODE_NUMPAD_0 && keyCode <= KeyEvent.KEYCODE_NUMPAD_9) { + return keyCode - KeyEvent.KEYCODE_NUMPAD_0; + } + return -1; + } +} diff --git a/src/com/android/tv/dialog/picker/TvPinPicker.java b/src/com/android/tv/dialog/picker/TvPinPicker.java deleted file mode 100644 index 064b7f02..00000000 --- a/src/com/android/tv/dialog/picker/TvPinPicker.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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/DvrDataManagerImpl.java b/src/com/android/tv/dvr/DvrDataManagerImpl.java index 3e26a231..0053650b 100644 --- a/src/com/android/tv/dvr/DvrDataManagerImpl.java +++ b/src/com/android/tv/dvr/DvrDataManagerImpl.java @@ -37,10 +37,8 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.Range; - import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; -import com.android.tv.common.dagger.annotations.ApplicationContext; import com.android.tv.common.recording.RecordingStorageStatusManager; import com.android.tv.common.recording.RecordingStorageStatusManager.OnStorageMountChangedListener; import com.android.tv.common.util.Clock; @@ -50,7 +48,6 @@ import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.ScheduledRecording.RecordingState; import com.android.tv.dvr.data.SeriesRecording; -import com.android.tv.dvr.provider.DvrDatabaseHelper; import com.android.tv.dvr.provider.DvrDbFuture.AddScheduleFuture; import com.android.tv.dvr.provider.DvrDbFuture.AddSeriesRecordingFuture; import com.android.tv.dvr.provider.DvrDbFuture.DeleteScheduleFuture; @@ -63,14 +60,11 @@ import com.android.tv.dvr.provider.DvrDbSync; import com.android.tv.dvr.recorder.SeriesRecordingScheduler; import com.android.tv.util.AsyncDbTask; import com.android.tv.util.AsyncDbTask.AsyncRecordedProgramQueryTask; -import com.android.tv.util.AsyncDbTask.DbExecutor; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.TvUriMatcher; - import com.google.common.base.Predicate; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.ListenableFuture; - import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -82,13 +76,9 @@ import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.Future; -import javax.inject.Inject; -import javax.inject.Singleton; - /** DVR Data manager to handle recordings and schedules. */ @MainThread @TargetApi(Build.VERSION_CODES.N) -@Singleton public class DvrDataManagerImpl extends BaseDvrDataManager { private static final String TAG = "DvrDataManagerImpl"; private static final boolean DEBUG = false; @@ -108,7 +98,6 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { private final HashMap<Long, SeriesRecording> mSeriesRecordingsForRemovedInput = new HashMap<>(); private final Context mContext; - private final DvrDatabaseHelper mDbHelper; private Executor mDbExecutor; private final ContentObserver mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { @@ -198,28 +187,20 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { return moved; } - @Inject - public DvrDataManagerImpl( - @ApplicationContext Context context, - Clock clock, - TvInputManagerHelper tvInputManagerHelper, - @DbExecutor Executor dbExecutor, - DvrDatabaseHelper dbHelper) { + public DvrDataManagerImpl(Context context, Clock clock) { super(context, clock); mContext = context; TvSingletons tvSingletons = TvSingletons.getSingletons(context); - mInputManager = tvInputManagerHelper; + mInputManager = tvSingletons.getTvInputManagerHelper(); mStorageStatusManager = tvSingletons.getRecordingStorageStatusManager(); - mDbExecutor = dbExecutor; - mDbHelper = dbHelper; - start(); + mDbExecutor = tvSingletons.getDbExecutor(); } - private void start() { + public void start() { mInputManager.addCallback(mInputCallback); mStorageStatusManager.addListener(mStorageMountChangedListener); DvrQuerySeriesRecordingFuture dvrQuerySeriesRecordingTask = - new DvrQuerySeriesRecordingFuture(mDbHelper); + new DvrQuerySeriesRecordingFuture(mContext); ListenableFuture<List<SeriesRecording>> dvrQuerySeriesRecordingFuture = dvrQuerySeriesRecordingTask.executeOnDbThread( new FutureCallback<List<SeriesRecording>>() { @@ -232,8 +213,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { if (SoftPreconditions.checkState( !seriesIds.contains(r.getSeriesId()), TAG, - "Skip loading series recording with duplicate series" - + " ID: " + "Skip loading series recording with duplicate series ID: " + r)) { seriesIds.add(r.getSeriesId()); if (isInputAvailable(r.getInputId())) { @@ -257,7 +237,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } }); mPendingDvrFuture.add(dvrQuerySeriesRecordingFuture); - DvrQueryScheduleFuture dvrQueryScheduleTask = new DvrQueryScheduleFuture(mDbHelper); + DvrQueryScheduleFuture dvrQueryScheduleTask = new DvrQueryScheduleFuture(mContext); ListenableFuture<List<ScheduledRecording>> dvrQueryScheduleFuture = dvrQueryScheduleTask.executeOnDbThread( new FutureCallback<List<ScheduledRecording>>() { @@ -661,7 +641,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { notifyScheduledRecordingAdded(schedules); } ListenableFuture addScheduleFuture = - new AddScheduleFuture(mDbHelper) + new AddScheduleFuture(mContext) .executeOnDbThread(removeFromSetOnCompletion, schedules); mNoStopFuture.add(addScheduleFuture); removeDeletedSchedules(schedules); @@ -683,7 +663,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { notifySeriesRecordingAdded(seriesRecordings); } ListenableFuture addSeriesRecordingFuture = - new AddSeriesRecordingFuture(mDbHelper) + new AddSeriesRecordingFuture(mContext) .executeOnDbThread(removeFromSetOnCompletion, seriesRecordings); mNoStopFuture.add(addSeriesRecordingFuture); } @@ -743,7 +723,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } if (!schedulesToDelete.isEmpty()) { ListenableFuture deleteScheduleFuture = - new DeleteScheduleFuture(mDbHelper) + new DeleteScheduleFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, ScheduledRecording.toArray(schedulesToDelete)); @@ -751,7 +731,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } if (!schedulesNotToDelete.isEmpty()) { ListenableFuture updateScheduleFuture = - new UpdateScheduleFuture(mDbHelper) + new UpdateScheduleFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, ScheduledRecording.toArray(schedulesNotToDelete)); @@ -794,7 +774,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { notifySeriesRecordingRemoved(seriesRecordings); } ListenableFuture deleteSeriesRecordingFuture = - new DeleteSeriesRecordingFuture(mDbHelper) + new DeleteSeriesRecordingFuture(mContext) .executeOnDbThread(removeFromSetOnCompletion, seriesRecordings); mNoStopFuture.add(deleteSeriesRecordingFuture); removeDeletedSchedules(seriesRecordings); @@ -849,7 +829,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } if (updateDb) { ListenableFuture updateScheduleFuture = - new UpdateScheduleFuture(mDbHelper) + new UpdateScheduleFuture(mContext) .executeOnDbThread(removeFromSetOnCompletion, scheduleArray); mNoStopFuture.add(updateScheduleFuture); } @@ -876,7 +856,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { notifySeriesRecordingChanged(seriesRecordings); } ListenableFuture updateSeriesRecordingFuture = - new UpdateSeriesRecordingFuture(mDbHelper) + new UpdateSeriesRecordingFuture(mContext) .executeOnDbThread(removeFromSetOnCompletion, seriesRecordings); mNoStopFuture.add(updateSeriesRecordingFuture); } @@ -897,7 +877,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } if (!schedulesToDelete.isEmpty()) { ListenableFuture deleteScheduleFuture = - new DeleteScheduleFuture(mDbHelper) + new DeleteScheduleFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, ScheduledRecording.toArray(schedulesToDelete)); @@ -922,7 +902,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } if (!schedulesToDelete.isEmpty()) { ListenableFuture deleteScheduleFuture = - new DeleteScheduleFuture(mDbHelper) + new DeleteScheduleFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, ScheduledRecording.toArray(schedulesToDelete)); @@ -970,7 +950,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { mSeriesRecordingsForRemovedInput.remove(r.getId()); } ListenableFuture deleteSeriesRecordingFuture = - new DeleteSeriesRecordingFuture(mDbHelper) + new DeleteSeriesRecordingFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, SeriesRecording.toArray(removedSeriesRecordings)); @@ -1063,13 +1043,13 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } } ListenableFuture deleteScheduleFuture = - new DeleteScheduleFuture(mDbHelper) + new DeleteScheduleFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, ScheduledRecording.toArray(schedulesToDelete)); mNoStopFuture.add(deleteScheduleFuture); ListenableFuture deleteSeriesRecordingFuture = - new DeleteSeriesRecordingFuture(mDbHelper) + new DeleteSeriesRecordingFuture(mContext) .executeOnDbThread( removeFromSetOnCompletion, SeriesRecording.toArray(seriesRecordingsToDelete)); @@ -1105,7 +1085,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { if (!removedSeriesRecordings.isEmpty()) { SeriesRecording[] removed = SeriesRecording.toArray(removedSeriesRecordings); ListenableFuture deleteSeriesRecordingFuture = - new DeleteSeriesRecordingFuture(mDbHelper) + new DeleteSeriesRecordingFuture(mContext) .executeOnDbThread(removeFromSetOnCompletion, removed); mNoStopFuture.add(deleteSeriesRecordingFuture); if (mDvrLoadFinished) { diff --git a/src/com/android/tv/dvr/DvrManager.java b/src/com/android/tv/dvr/DvrManager.java index 12982c6c..cc9ad37a 100644 --- a/src/com/android/tv/dvr/DvrManager.java +++ b/src/com/android/tv/dvr/DvrManager.java @@ -37,13 +37,12 @@ import android.support.annotation.VisibleForTesting; import android.support.annotation.WorkerThread; import android.util.Log; import android.util.Range; - import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.util.CommonUtils; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrDataManager.OnRecordedProgramLoadFinishedListener; import com.android.tv.dvr.DvrDataManager.RecordedProgramListener; import com.android.tv.dvr.DvrScheduleManager.OnInitializeListener; @@ -52,7 +51,6 @@ import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.util.AsyncDbTask; import com.android.tv.util.Utils; - import java.io.File; import java.util.ArrayList; import java.util.Arrays; @@ -189,7 +187,7 @@ public class DvrManager { ? mScheduleManager.suggestNewPriority() : mScheduleManager.suggestHighestPriority( seriesRecording.getInputId(), - Range.create( + new Range( program.getStartTimeUtcMillis(), program.getEndTimeUtcMillis()), seriesRecording.getPriority())); diff --git a/src/com/android/tv/dvr/DvrScheduleManager.java b/src/com/android/tv/dvr/DvrScheduleManager.java index 3afcc422..7202dce0 100644 --- a/src/com/android/tv/dvr/DvrScheduleManager.java +++ b/src/com/android/tv/dvr/DvrScheduleManager.java @@ -25,12 +25,11 @@ import android.support.annotation.NonNull; import android.support.annotation.VisibleForTesting; import android.util.ArraySet; import android.util.Range; - import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.data.ChannelDataManager; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrDataManager.OnDvrScheduleLoadFinishedListener; import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener; import com.android.tv.dvr.data.ScheduledRecording; @@ -38,7 +37,6 @@ import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.recorder.InputTaskScheduler; import com.android.tv.util.CompositeComparator; import com.android.tv.util.Utils; - import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -78,7 +76,7 @@ public class DvrScheduleManager { ScheduledRecording.ID_COMPARATOR); private final Context mContext; - private final DvrDataManager mDataManager; + private final DvrDataManagerImpl mDataManager; private final ChannelDataManager mChannelDataManager; private final Map<String, List<ScheduledRecording>> mInputScheduleMap = new HashMap<>(); @@ -97,7 +95,7 @@ public class DvrScheduleManager { public DvrScheduleManager(Context context) { mContext = context; TvSingletons tvSingletons = TvSingletons.getSingletons(context); - mDataManager = tvSingletons.getDvrDataManager(); + mDataManager = (DvrDataManagerImpl) tvSingletons.getDvrDataManager(); mChannelDataManager = tvSingletons.getChannelDataManager(); if (mDataManager.isDvrScheduleLoadFinished() && mChannelDataManager.isDbLoadFinished()) { buildData(); diff --git a/src/com/android/tv/dvr/DvrStorageStatusManager.java b/src/com/android/tv/dvr/DvrStorageStatusManager.java index a0ae8939..dc347a9e 100644 --- a/src/com/android/tv/dvr/DvrStorageStatusManager.java +++ b/src/com/android/tv/dvr/DvrStorageStatusManager.java @@ -114,7 +114,7 @@ public class DvrStorageStatusManager extends RecordingStorageStatusManager { return; } for (TvInputInfo info : tvInputInfoList) { - if (CommonUtils.isBundledInput(info.getId()) && dvrManager != null) { + if (CommonUtils.isBundledInput(info.getId())) { dvrManager.forgetStorage(info.getId()); } } diff --git a/src/com/android/tv/dvr/DvrWatchedPositionManager.java b/src/com/android/tv/dvr/DvrWatchedPositionManager.java index b4fea7f3..8616962f 100644 --- a/src/com/android/tv/dvr/DvrWatchedPositionManager.java +++ b/src/com/android/tv/dvr/DvrWatchedPositionManager.java @@ -20,10 +20,8 @@ import android.content.Context; import android.content.SharedPreferences; import android.media.tv.TvInputManager; import android.support.annotation.IntDef; - import com.android.tv.common.util.SharedPreferencesUtils; import com.android.tv.dvr.data.RecordedProgram; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -38,7 +36,7 @@ import java.util.concurrent.CopyOnWriteArraySet; */ public class DvrWatchedPositionManager { private SharedPreferences mWatchedPositions; - private final Map<Long, Set<WatchedPositionChangedListener>> mListeners = new HashMap<>(); + private final Map<Long, Set> mListeners = new HashMap<>(); /** * The minimum percentage of recorded program being watched that will be considered as being diff --git a/src/com/android/tv/dvr/data/RecordedProgram.java b/src/com/android/tv/dvr/data/RecordedProgram.java index 61430551..899e65ac 100644 --- a/src/com/android/tv/dvr/data/RecordedProgram.java +++ b/src/com/android/tv/dvr/data/RecordedProgram.java @@ -36,10 +36,9 @@ import com.android.tv.common.TvContentRatingCache; import com.android.tv.common.data.RecordedProgramState; import com.android.tv.common.util.CommonUtils; import com.android.tv.common.util.StringUtils; -import com.android.tv.data.BaseProgramImpl; +import com.android.tv.data.BaseProgram; import com.android.tv.data.GenreItems; import com.android.tv.data.InternalDataUtils; -import com.android.tv.data.api.BaseProgram; import com.android.tv.util.TvProviderUtils; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; @@ -50,7 +49,7 @@ import java.util.concurrent.TimeUnit; /** Immutable instance of {@link android.media.tv.TvContract.RecordedPrograms}. */ @TargetApi(Build.VERSION_CODES.N) @AutoValue -public abstract class RecordedProgram extends BaseProgramImpl { +public abstract class RecordedProgram extends BaseProgram { public static final int ID_NOT_SET = -1; private static final String TAG = "RecordedProgram"; diff --git a/src/com/android/tv/dvr/data/ScheduledRecording.java b/src/com/android/tv/dvr/data/ScheduledRecording.java index 1237fb3e..ba6d3cf9 100644 --- a/src/com/android/tv/dvr/data/ScheduledRecording.java +++ b/src/com/android/tv/dvr/data/ScheduledRecording.java @@ -27,17 +27,15 @@ import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Range; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.util.CommonUtils; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrScheduleManager; import com.android.tv.dvr.provider.DvrContract.Schedules; import com.android.tv.util.CompositeComparator; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collection; @@ -494,7 +492,7 @@ public final class ScheduledRecording implements Parcelable { } }; - /** The ID internal to TV app */ + /** The ID internal to Live TV */ private long mId; /** diff --git a/src/com/android/tv/dvr/data/SeriesRecording.java b/src/com/android/tv/dvr/data/SeriesRecording.java index cd7d9662..6cb0e836 100644 --- a/src/com/android/tv/dvr/data/SeriesRecording.java +++ b/src/com/android/tv/dvr/data/SeriesRecording.java @@ -22,14 +22,11 @@ import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.IntDef; import android.text.TextUtils; - -import com.android.tv.data.BaseProgramImpl; -import com.android.tv.data.api.BaseProgram; -import com.android.tv.data.api.Program; +import com.android.tv.data.BaseProgram; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrScheduleManager; import com.android.tv.dvr.provider.DvrContract.SeriesRecordings; import com.android.tv.util.Utils; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; @@ -88,8 +85,7 @@ public class SeriesRecording implements Parcelable { (SeriesRecording lhs, SeriesRecording rhs) -> Long.compare(lhs.mId, rhs.mId); /** - * Creates a new Builder with the values set from the series information of {@link - * BaseProgramImpl}. + * Creates a new Builder with the values set from the series information of {@link BaseProgram}. */ public static Builder builder(String inputId, BaseProgram p) { return new Builder() diff --git a/src/com/android/tv/dvr/provider/DvrContract.java b/src/com/android/tv/dvr/provider/DvrContract.java index 8539ae36..a5f2e2cd 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 TV app. + * columns. It's for the internal use in Live TV. */ 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,7 +84,8 @@ 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/provider/DvrDatabaseHelper.java b/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java index 1dcda8e0..ebf133db 100644 --- a/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java +++ b/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java @@ -26,18 +26,12 @@ import android.database.sqlite.SQLiteStatement; import android.provider.BaseColumns; import android.text.TextUtils; import android.util.Log; - -import com.android.tv.common.dagger.annotations.ApplicationContext; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.provider.DvrContract.Schedules; import com.android.tv.dvr.provider.DvrContract.SeriesRecordings; -import javax.inject.Inject; -import javax.inject.Singleton; - /** A data class for one recorded contents. */ -@Singleton public class DvrDatabaseHelper extends SQLiteOpenHelper { private static final String TAG = "DvrDatabaseHelper"; private static final boolean DEBUG = false; @@ -244,9 +238,8 @@ public class DvrDatabaseHelper extends SQLiteOpenHelper { return "DELETE FROM " + tableName + " WHERE " + BaseColumns._ID + "=?"; } - @Inject - public DvrDatabaseHelper(@ApplicationContext Context context) { - super(context, DB_NAME, null, DATABASE_VERSION); + public DvrDatabaseHelper(Context context) { + super(context.getApplicationContext(), DB_NAME, null, DATABASE_VERSION); } @Override @@ -273,12 +266,8 @@ public class DvrDatabaseHelper extends SQLiteOpenHelper { return; } if (oldVersion < 18) { - db.execSQL( - "ALTER TABLE " - + Schedules.TABLE_NAME - + " ADD COLUMN " - + Schedules.COLUMN_FAILED_REASON - + " TEXT DEFAULT null;"); + db.execSQL("ALTER TABLE " + Schedules.TABLE_NAME + " ADD COLUMN " + + Schedules.COLUMN_FAILED_REASON + " TEXT DEFAULT null;"); } } diff --git a/src/com/android/tv/dvr/provider/DvrDbFuture.java b/src/com/android/tv/dvr/provider/DvrDbFuture.java index cbc2c07d..ae8c480b 100644 --- a/src/com/android/tv/dvr/provider/DvrDbFuture.java +++ b/src/com/android/tv/dvr/provider/DvrDbFuture.java @@ -16,23 +16,21 @@ package com.android.tv.dvr.provider; +import android.content.Context; import android.database.Cursor; import android.support.annotation.Nullable; import android.util.Log; - import com.android.tv.common.concurrent.NamedThreadFactory; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.provider.DvrContract.Schedules; import com.android.tv.dvr.provider.DvrContract.SeriesRecordings; import com.android.tv.util.MainThreadExecutor; - import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; - import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; @@ -40,24 +38,29 @@ import java.util.concurrent.Executors; /** {@link DvrDbFuture} that defaults to executing on its own single threaded Executor Service. */ public abstract class DvrDbFuture<ParamsT, ResultT> { private static final NamedThreadFactory THREAD_FACTORY = - new NamedThreadFactory(DvrDbFuture.class.getSimpleName()); + new NamedThreadFactory(DvrDbFuture.class.getSimpleName()); private static final ListeningExecutorService DB_EXECUTOR = - MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(THREAD_FACTORY)); + MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(THREAD_FACTORY)); - final DvrDatabaseHelper mDbHelper; + private static DvrDatabaseHelper sDbHelper; private ListenableFuture<ResultT> mFuture; - private DvrDbFuture(DvrDatabaseHelper mDbHelper) { - this.mDbHelper = mDbHelper; + final Context mContext; + + private DvrDbFuture(Context context) { + mContext = context; } - /** Execute the task on the {@link #DB_EXECUTOR} thread and return Future */ + /** Execute the task on the {@link #DB_EXECUTOR} thread and return Future*/ @SafeVarargs public final ListenableFuture<ResultT> executeOnDbThread( - FutureCallback<ResultT> callback, ParamsT... params) { - mFuture = DB_EXECUTOR.submit(() -> dbHelperInBackground(params)); - Futures.addCallback(mFuture, callback, MainThreadExecutor.getInstance()); - return mFuture; + FutureCallback<ResultT> callback, ParamsT... params) { + if (sDbHelper == null) { + sDbHelper = new DvrDatabaseHelper(mContext.getApplicationContext()); + } + mFuture = DB_EXECUTOR.submit(() -> dbHelperInBackground(params)); + Futures.addCallback(mFuture, callback, MainThreadExecutor.getInstance()); + return mFuture; } /** Executes in the background after initializing DbHelper} */ @@ -69,48 +72,52 @@ public abstract class DvrDbFuture<ParamsT, ResultT> { } /** Inserts schedules. */ - public static class AddScheduleFuture extends DvrDbFuture<ScheduledRecording, Void> { - public AddScheduleFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class AddScheduleFuture + extends DvrDbFuture<ScheduledRecording, Void> { + public AddScheduleFuture(Context context) { + super(context); } @Override protected final Void dbHelperInBackground(ScheduledRecording... params) { - mDbHelper.insertSchedules(params); + sDbHelper.insertSchedules(params); return null; } } /** Update schedules. */ - public static class UpdateScheduleFuture extends DvrDbFuture<ScheduledRecording, Void> { - public UpdateScheduleFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class UpdateScheduleFuture + extends DvrDbFuture<ScheduledRecording, Void> { + public UpdateScheduleFuture(Context context) { + super(context); } @Override protected final Void dbHelperInBackground(ScheduledRecording... params) { - mDbHelper.updateSchedules(params); + sDbHelper.updateSchedules(params); return null; } } /** Delete schedules. */ - public static class DeleteScheduleFuture extends DvrDbFuture<ScheduledRecording, Void> { - public DeleteScheduleFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class DeleteScheduleFuture + extends DvrDbFuture<ScheduledRecording, Void> { + public DeleteScheduleFuture(Context context) { + super(context); } @Override protected final Void dbHelperInBackground(ScheduledRecording... params) { - mDbHelper.deleteSchedules(params); + sDbHelper.deleteSchedules(params); return null; } } /** Returns all {@link ScheduledRecording}s. */ - public static class DvrQueryScheduleFuture extends DvrDbFuture<Void, List<ScheduledRecording>> { - public DvrQueryScheduleFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class DvrQueryScheduleFuture + extends DvrDbFuture<Void, List<ScheduledRecording>> { + public DvrQueryScheduleFuture(Context context) { + super(context); } @Override @@ -120,7 +127,7 @@ public abstract class DvrDbFuture<ParamsT, ResultT> { return null; } List<ScheduledRecording> scheduledRecordings = new ArrayList<>(); - try (Cursor c = mDbHelper.query(Schedules.TABLE_NAME, ScheduledRecording.PROJECTION)) { + try (Cursor c = sDbHelper.query(Schedules.TABLE_NAME, ScheduledRecording.PROJECTION)) { while (c.moveToNext() && !isCancelled()) { scheduledRecordings.add(ScheduledRecording.fromCursor(c)); } @@ -130,40 +137,43 @@ public abstract class DvrDbFuture<ParamsT, ResultT> { } /** Inserts series recordings. */ - public static class AddSeriesRecordingFuture extends DvrDbFuture<SeriesRecording, Void> { - public AddSeriesRecordingFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class AddSeriesRecordingFuture + extends DvrDbFuture<SeriesRecording, Void> { + public AddSeriesRecordingFuture(Context context) { + super(context); } @Override protected final Void dbHelperInBackground(SeriesRecording... params) { - mDbHelper.insertSeriesRecordings(params); + sDbHelper.insertSeriesRecordings(params); return null; } } /** Update series recordings. */ - public static class UpdateSeriesRecordingFuture extends DvrDbFuture<SeriesRecording, Void> { - public UpdateSeriesRecordingFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class UpdateSeriesRecordingFuture + extends DvrDbFuture<SeriesRecording, Void> { + public UpdateSeriesRecordingFuture(Context context) { + super(context); } @Override protected final Void dbHelperInBackground(SeriesRecording... params) { - mDbHelper.updateSeriesRecordings(params); + sDbHelper.updateSeriesRecordings(params); return null; } } /** Delete series recordings. */ - public static class DeleteSeriesRecordingFuture extends DvrDbFuture<SeriesRecording, Void> { - public DeleteSeriesRecordingFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public static class DeleteSeriesRecordingFuture + extends DvrDbFuture<SeriesRecording, Void> { + public DeleteSeriesRecordingFuture(Context context) { + super(context); } @Override protected final Void dbHelperInBackground(SeriesRecording... params) { - mDbHelper.deleteSeriesRecordings(params); + sDbHelper.deleteSeriesRecordings(params); return null; } } @@ -173,8 +183,8 @@ public abstract class DvrDbFuture<ParamsT, ResultT> { extends DvrDbFuture<Void, List<SeriesRecording>> { private static final String TAG = "DvrQuerySeriesRecording"; - public DvrQuerySeriesRecordingFuture(DvrDatabaseHelper dbHelper) { - super(dbHelper); + public DvrQuerySeriesRecordingFuture(Context context) { + super(context); } @Override @@ -185,7 +195,7 @@ public abstract class DvrDbFuture<ParamsT, ResultT> { } List<SeriesRecording> scheduledRecordings = new ArrayList<>(); try (Cursor c = - mDbHelper.query(SeriesRecordings.TABLE_NAME, SeriesRecording.PROJECTION)) { + sDbHelper.query(SeriesRecordings.TABLE_NAME, SeriesRecording.PROJECTION)) { while (c.moveToNext() && !isCancelled()) { scheduledRecordings.add(SeriesRecording.fromCursor(c)); } diff --git a/src/com/android/tv/dvr/provider/DvrDbSync.java b/src/com/android/tv/dvr/provider/DvrDbSync.java index c2eae771..7658ca45 100644 --- a/src/com/android/tv/dvr/provider/DvrDbSync.java +++ b/src/com/android/tv/dvr/provider/DvrDbSync.java @@ -29,19 +29,17 @@ import android.os.Looper; import android.support.annotation.MainThread; import android.support.annotation.VisibleForTesting; import android.util.Log; - import com.android.tv.TvSingletons; import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener; +import com.android.tv.dvr.DvrDataManagerImpl; import com.android.tv.dvr.DvrManager; -import com.android.tv.dvr.WritableDvrDataManager; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.recorder.SeriesRecordingScheduler; import com.android.tv.util.AsyncDbTask.AsyncQueryProgramTask; import com.android.tv.util.TvUriMatcher; - import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -51,7 +49,6 @@ import java.util.Objects; import java.util.Queue; import java.util.Set; import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; /** * A class to synchronizes DVR DB with TvProvider. @@ -68,11 +65,9 @@ public class DvrDbSync { private static final String TAG = "DvrDbSync"; private static final boolean DEBUG = false; - private static final long RECORD_MARGIN_MS = TimeUnit.SECONDS.toMillis(10); - private final Context mContext; private final DvrManager mDvrManager; - private final WritableDvrDataManager mDataManager; + private final DvrDataManagerImpl mDataManager; private final ChannelDataManager mChannelDataManager; private final Executor mDbExecutor; private final Queue<Long> mProgramIdQueue = new LinkedList<>(); @@ -143,7 +138,7 @@ public class DvrDbSync { } }; - public DvrDbSync(Context context, WritableDvrDataManager dataManager) { + public DvrDbSync(Context context, DvrDataManagerImpl dataManager) { this( context, dataManager, @@ -156,7 +151,7 @@ public class DvrDbSync { @VisibleForTesting DvrDbSync( Context context, - WritableDvrDataManager dataManager, + DvrDataManagerImpl dataManager, ChannelDataManager channelDataManager, DvrManager dvrManager, SeriesRecordingScheduler seriesRecordingScheduler, @@ -330,15 +325,10 @@ public class DvrDbSync { // Old program belongs to a series but the new one doesn't. seriesRecordingsToUpdate.add(seriesRecordingForOldSchedule); } - // Change start time only when the recording is not started yet and if it is not - // within marginal time of current time. Marginal check is needed to prevent the - // update of start time if recording is just triggered or about to get triggered. - boolean marginalToCurrentTime = RECORD_MARGIN_MS > - Math.abs(System.currentTimeMillis() - schedule.getStartTimeMs()); + // Change start time only when the recording is not started yet. boolean needToChangeStartTime = schedule.getState() != ScheduledRecording.STATE_RECORDING_IN_PROGRESS - && program.getStartTimeUtcMillis() != schedule.getStartTimeMs() - && !marginalToCurrentTime; + && program.getStartTimeUtcMillis() != schedule.getStartTimeMs(); if (needToChangeStartTime) { builder.setStartTimeMs(program.getStartTimeUtcMillis()); needUpdate = true; diff --git a/src/com/android/tv/dvr/provider/EpisodicProgramLoadTask.java b/src/com/android/tv/dvr/provider/EpisodicProgramLoadTask.java index a66e5b02..02e197f1 100644 --- a/src/com/android/tv/dvr/provider/EpisodicProgramLoadTask.java +++ b/src/com/android/tv/dvr/provider/EpisodicProgramLoadTask.java @@ -25,19 +25,16 @@ import android.net.Uri; import android.os.Build; import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; - import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.util.PermissionUtils; -import com.android.tv.data.ProgramImpl; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeasonEpisodeNumber; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.util.AsyncDbTask.AsyncProgramQueryTask; import com.android.tv.util.AsyncDbTask.CursorFilter; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -50,11 +47,11 @@ import java.util.Set; public abstract class EpisodicProgramLoadTask { private static final String TAG = "EpisodicProgramLoadTask"; - private static final int PROGRAM_ID_INDEX = ProgramImpl.getColumnIndex(Programs._ID); + private static final int PROGRAM_ID_INDEX = Program.getColumnIndex(Programs._ID); private static final int START_TIME_INDEX = - ProgramImpl.getColumnIndex(Programs.COLUMN_START_TIME_UTC_MILLIS); + Program.getColumnIndex(Programs.COLUMN_START_TIME_UTC_MILLIS); private static final int RECORDING_PROHIBITED_INDEX = - ProgramImpl.getColumnIndex(Programs.COLUMN_RECORDING_PROHIBITED); + Program.getColumnIndex(Programs.COLUMN_RECORDING_PROHIBITED); private static final String PARAM_START_TIME = "start_time"; private static final String PARAM_END_TIME = "end_time"; @@ -292,7 +289,7 @@ public abstract class EpisodicProgramLoadTask { && mDisallowedProgramIds.contains(c.getLong(PROGRAM_ID_INDEX))) { return false; } - Program program = ProgramImpl.fromCursor(c); + Program program = Program.fromCursor(c); for (SeriesRecording seriesRecording : mSeriesRecordings) { boolean programMatches; if (mIgnoreChannelOption) { diff --git a/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java b/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java index 92b4e06a..696038cf 100644 --- a/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java +++ b/src/com/android/tv/dvr/recorder/SeriesRecordingScheduler.java @@ -27,12 +27,11 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.LongSparseArray; - import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.util.CollectionUtils; import com.android.tv.common.util.SharedPreferencesUtils; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.data.epg.EpgReader; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener; @@ -44,9 +43,6 @@ 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; @@ -58,6 +54,7 @@ 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 @@ -532,9 +529,10 @@ public class SeriesRecordingScheduler { private class FetchSeriesInfoTask extends AsyncTask<Void, Void, SeriesInfo> { private final SeriesRecording mSeriesRecording; - private final Lazy<EpgReader> mEpgReaderProvider; + private final Provider<EpgReader> mEpgReaderProvider; - FetchSeriesInfoTask(SeriesRecording seriesRecording, Lazy<EpgReader> epgReaderProvider) { + FetchSeriesInfoTask( + SeriesRecording seriesRecording, Provider<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 1f4faf31..5e3caa9c 100644 --- a/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java +++ b/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java @@ -22,16 +22,13 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; - -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; - +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import com.android.tv.R; import com.android.tv.TvSingletons; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.RecordedProgram; - import java.util.List; /** diff --git a/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java b/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java index 56ffc884..a6bbe137 100644 --- a/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java +++ b/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java @@ -22,17 +22,14 @@ 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 android.text.format.DateUtils; - -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.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.ScheduledRecording; - import java.util.List; /** diff --git a/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java b/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java index b24281ad..6be35cb2 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 androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.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 5e0a96bb..649cc89a 100644 --- a/src/com/android/tv/dvr/ui/DvrConflictFragment.java +++ b/src/com/android/tv/dvr/ui/DvrConflictFragment.java @@ -21,25 +21,22 @@ 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 android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; - -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; - import com.android.tv.MainActivity; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.recorder.ConflictChecker; import com.android.tv.dvr.recorder.ConflictChecker.OnUpcomingConflictChangeListener; import com.android.tv.util.Utils; - import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; diff --git a/src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java b/src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java index 81fc3ed5..611962d0 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 androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidedActionsStylist; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.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 fda4cdee..a900cc70 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 androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.VerticalGridView; +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidedAction; +import android.support.v17.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 e8f501e9..e6b54f67 100644 --- a/src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java +++ b/src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java @@ -20,15 +20,13 @@ import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; +import android.support.v17.leanback.app.GuidedStepFragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import androidx.leanback.app.GuidedStepFragment; - import com.android.tv.MainActivity; import com.android.tv.R; -import com.android.tv.data.ProgramImpl; import com.android.tv.dialog.HalfSizedDialogFragment; import com.android.tv.dvr.ui.DvrConflictFragment.DvrChannelWatchConflictFragment; import com.android.tv.dvr.ui.DvrConflictFragment.DvrProgramConflictFragment; @@ -38,7 +36,7 @@ import com.android.tv.ui.DetailsActivity; public class DvrHalfSizedDialogFragment extends HalfSizedDialogFragment { /** Key for input ID. Type: String. */ public static final String KEY_INPUT_ID = "DvrHalfSizedDialogFragment.input_id"; - /** Key for the program. Type: {@link ProgramImpl}. */ + /** Key for the program. Type: {@link com.android.tv.data.Program}. */ public static final String KEY_PROGRAM = "DvrHalfSizedDialogFragment.program"; /** Key for the channel ID. Type: long. */ public static final String KEY_CHANNEL_ID = "DvrHalfSizedDialogFragment.channel_id"; diff --git a/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java b/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java index 01631b99..6fba4d98 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 androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.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 3237acd7..02b2da1d 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 androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.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 ae41f501..5bb97e90 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 androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.GuidedActionsStylist; +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; +import android.support.v17.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 7131f626..72603d03 100644 --- a/src/com/android/tv/dvr/ui/DvrScheduleFragment.java +++ b/src/com/android/tv/dvr/ui/DvrScheduleFragment.java @@ -22,21 +22,18 @@ 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 android.text.format.DateUtils; - -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; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.ui.DvrConflictFragment.DvrProgramConflictFragment; - import java.util.Collections; import java.util.List; @@ -55,7 +52,7 @@ public class DvrScheduleFragment extends DvrGuidedStepFragment { private static final int ACTION_RECORD_EPISODE = 1; private static final int ACTION_RECORD_SERIES = 2; - private ProgramImpl mProgram; + private Program mProgram; private boolean mAddCurrentProgramToSeries; @Override diff --git a/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java b/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java index 730237c4..a237f1d2 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java @@ -20,13 +20,15 @@ import android.app.Activity; import android.content.pm.PackageManager; import android.os.Bundle; import android.support.annotation.NonNull; -import androidx.leanback.app.GuidedStepFragment; +import android.support.v17.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; @@ -68,7 +70,7 @@ public class DvrSeriesDeletionActivity extends Activity { && grantResults[0] == PackageManager.PERMISSION_GRANTED) { deleteSelectedIds(true); } else { - // NOTE: If TV app ever supports both embedded and separate DVR inputs + // NOTE: If Live TV ever supports both embedded and separate DVR inputs // then we should try to do the delete regardless. Log.i( TAG, @@ -91,14 +93,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 10ef226b..ff213231 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 androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.GuidedActionsStylist; +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 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 d72099ba..9acb5b5e 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 androidx.leanback.app.GuidedStepFragment; +import android.support.v17.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 7d369904..c6e26850 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java @@ -20,26 +20,22 @@ import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Bundle; - -import androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidedAction; - +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidedAction; import com.android.tv.R; import com.android.tv.TvSingletons; -import com.android.tv.data.ProgramImpl; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrScheduleManager; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.ui.list.DvrSchedulesActivity; import com.android.tv.dvr.ui.list.DvrSeriesSchedulesFragment; - import java.util.List; public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { /** * The key for program list which will be passed to {@link DvrSeriesSchedulesFragment}. Type: - * List<{@link ProgramImpl}> + * List<{@link Program}> */ public static final String SERIES_SCHEDULED_KEY_PROGRAMS = "series_scheduled_key_programs"; @@ -50,7 +46,6 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { private SeriesRecording mSeriesRecording; private boolean mShowViewScheduleOption; private List<Program> mPrograms; - private String mSeriesRecordingTitle; private int mSchedulesAddedCount = 0; private boolean mHasConflict = false; @@ -80,7 +75,6 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { getActivity().finish(); return; } - mSeriesRecordingTitle = mSeriesRecording.getTitle(); mPrograms = (List<Program>) BigArguments.getArgument(SERIES_SCHEDULED_KEY_PROGRAMS); BigArguments.reset(); mSchedulesAddedCount = @@ -168,7 +162,7 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { R.plurals.dvr_series_scheduled_no_conflict, mSchedulesAddedCount, mSchedulesAddedCount, - mSeriesRecordingTitle); + mSeriesRecording.getTitle()); } else { // mInThisSeriesConflictCount equals 0 and mOutThisSeriesConflictCount equals 0 means // mHasConflict is false. So we don't need to check that case. @@ -178,7 +172,7 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { R.plurals.dvr_series_scheduled_this_and_other_series_conflict, mSchedulesAddedCount, mSchedulesAddedCount, - mSeriesRecordingTitle, + mSeriesRecording.getTitle(), mInThisSeriesConflictCount + mOutThisSeriesConflictCount); } else if (mInThisSeriesConflictCount != 0) { return getResources() @@ -186,7 +180,7 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { R.plurals.dvr_series_recording_scheduled_only_this_series_conflict, mSchedulesAddedCount, mSchedulesAddedCount, - mSeriesRecordingTitle, + mSeriesRecording.getTitle(), mInThisSeriesConflictCount); } else { if (mOutThisSeriesConflictCount == 1) { @@ -195,14 +189,14 @@ public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment { R.plurals.dvr_series_scheduled_only_other_series_one_conflict, mSchedulesAddedCount, mSchedulesAddedCount, - mSeriesRecordingTitle); + mSeriesRecording.getTitle()); } else { return getResources() .getQuantityString( R.plurals.dvr_series_scheduled_only_other_series_many_conflicts, mSchedulesAddedCount, mSchedulesAddedCount, - mSeriesRecordingTitle, + mSeriesRecording.getTitle(), mOutThisSeriesConflictCount); } } diff --git a/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java b/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java index eb3ca283..1a51cf46 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java @@ -19,13 +19,10 @@ package com.android.tv.dvr.ui; import android.app.Activity; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; - -import androidx.leanback.app.GuidedStepFragment; - +import android.support.v17.leanback.app.GuidedStepFragment; import com.android.tv.R; import com.android.tv.Starter; import com.android.tv.common.SoftPreconditions; -import com.android.tv.data.ProgramImpl; /** Activity to show details view in DVR. */ public class DvrSeriesSettingsActivity extends Activity { @@ -43,7 +40,7 @@ public class DvrSeriesSettingsActivity extends Activity { public static final String IS_WINDOW_TRANSLUCENT = "windows_translucent"; /** * Name of the program list. The list contains the programs which belong to the series. Type: - * List<{@link ProgramImpl}> + * List<{@link com.android.tv.data.Program}> */ public static final String PROGRAM_LIST = "program_list"; diff --git a/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java b/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java index 7fc201c5..eadb3b9e 100644 --- a/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java +++ b/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java @@ -21,19 +21,17 @@ 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 android.util.LongSparseArray; - -import androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.GuidedActionsStylist; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.ChannelImpl; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.ScheduledRecording; @@ -41,7 +39,6 @@ import com.android.tv.dvr.data.SeasonEpisodeNumber; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.data.SeriesRecording.ChannelOption; import com.android.tv.dvr.recorder.SeriesRecordingScheduler; - import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -72,7 +69,6 @@ public class DvrSeriesSettingsFragment extends GuidedStepFragment private Program mCurrentProgram; private String mFragmentTitle; - private String mSeriesRecordingTitle; private String mProrityActionTitle; private String mProrityActionHighestText; private String mProrityActionLowestText; @@ -96,7 +92,6 @@ public class DvrSeriesSettingsFragment extends GuidedStepFragment getActivity().finish(); return; } - mSeriesRecordingTitle = mSeriesRecording.getTitle(); mShowViewScheduleOptionInDialog = getArguments() .getBoolean(DvrSeriesSettingsActivity.SHOW_VIEW_SCHEDULE_OPTION_IN_DIALOG); @@ -166,8 +161,9 @@ public class DvrSeriesSettingsFragment extends GuidedStepFragment @Override public Guidance onCreateGuidance(Bundle savedInstanceState) { + String breadcrumb = mSeriesRecording.getTitle(); String title = mFragmentTitle; - return new Guidance(title, null, mSeriesRecordingTitle, null); + return new Guidance(title, null, breadcrumb, null); } @Override diff --git a/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java b/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java index 1475a8c3..1ab4c500 100644 --- a/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java +++ b/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java @@ -23,17 +23,13 @@ import android.os.Build; import android.os.Bundle; import android.support.annotation.IntDef; import android.support.annotation.NonNull; - -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; - +import android.support.v17.leanback.widget.GuidanceStylist.Guidance; +import android.support.v17.leanback.widget.GuidedAction; import com.android.tv.R; import com.android.tv.TvSingletons; -import com.android.tv.data.ProgramImpl; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener; import com.android.tv.dvr.data.ScheduledRecording; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; @@ -48,7 +44,7 @@ import java.util.List; public class DvrStopRecordingFragment extends DvrGuidedStepFragment { /** The action ID for the stop action. */ public static final int ACTION_STOP = 1; - /** Key for the program. Type: {@link ProgramImpl}. */ + /** Key for the program. Type: {@link com.android.tv.data.Program}. */ public static final String KEY_REASON = "DvrStopRecordingFragment.type"; @Retention(RetentionPolicy.SOURCE) diff --git a/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java index 4a8ce04e..15abf902 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 androidx.leanback.app.GuidedStepFragment; +import android.support.v17.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 0b8f5df0..99211fdb 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 androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidedAction; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/src/com/android/tv/dvr/ui/DvrUiHelper.java b/src/com/android/tv/dvr/ui/DvrUiHelper.java index 657abfa2..a121cf99 100644 --- a/src/com/android/tv/dvr/ui/DvrUiHelper.java +++ b/src/com/android/tv/dvr/ui/DvrUiHelper.java @@ -33,7 +33,6 @@ import android.text.Html; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; -import android.text.Spanned; import android.text.TextUtils; import android.text.style.TextAppearanceSpan; import android.widget.ImageView; @@ -45,9 +44,9 @@ import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.recording.RecordingStorageStatusManager; import com.android.tv.common.util.CommonUtils; -import com.android.tv.data.api.BaseProgram; +import com.android.tv.data.BaseProgram; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dialog.HalfSizedDialogFragment; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.RecordedProgram; @@ -76,7 +75,6 @@ import com.android.tv.ui.DetailsActivity; import com.android.tv.util.ToastUtils; import com.android.tv.util.Utils; -import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -124,7 +122,7 @@ public class DvrUiHelper { return; } Bundle args = new Bundle(); - args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program.toParcelable()); + args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program); args.putBoolean( DvrScheduleFragment.KEY_ADD_CURRENT_PROGRAM_TO_SERIES, addCurrentProgramToSeries); showDialogFragment(activity, new DvrScheduleDialogFragment(), args, true, true); @@ -146,7 +144,7 @@ public class DvrUiHelper { return; } Bundle args = new Bundle(); - args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program.toParcelable()); + args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program); showDialogFragment(activity, new DvrProgramConflictDialogFragment(), args, false, true); } @@ -229,7 +227,7 @@ public class DvrUiHelper { return; } Bundle args = new Bundle(); - args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program.toParcelable()); + args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program); showDialogFragment(activity, new DvrAlreadyScheduledDialogFragment(), args, false, true); } @@ -239,18 +237,14 @@ public class DvrUiHelper { return; } Bundle args = new Bundle(); - args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program.toParcelable()); + args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program); showDialogFragment(activity, new DvrAlreadyRecordedDialogFragment(), args, false, true); } /** Shows program information dialog. */ public static void showWriteStoragePermissionRationaleDialog(Activity activity) { - showDialogFragment( - activity, - new DvrWriteStoragePermissionRationaleDialogFragment(), - new Bundle(), - false, - false); + showDialogFragment(activity, new DvrWriteStoragePermissionRationaleDialogFragment(), + new Bundle(), false, false); } /** @@ -465,7 +459,7 @@ public class DvrUiHelper { boolean removeEmptySeriesSchedule, boolean isWindowTranslucent, boolean showViewScheduleOptionInDialog, - @Nullable Program currentProgram) { + Program currentProgram) { SeriesRecording series = TvSingletons.getSingletons(context) .getDvrDataManager() @@ -487,15 +481,13 @@ public class DvrUiHelper { new EpisodicProgramLoadTask(context, series) { @Override protected void onPostExecute(List<Program> loadedPrograms) { - if (sProgressDialog != null) { - sProgressDialog.dismiss(); - sProgressDialog = null; - } + sProgressDialog.dismiss(); + sProgressDialog = null; startSeriesSettingsActivityInternal( context, seriesRecordingId, loadedPrograms == null - ? ImmutableList.of() + ? Collections.EMPTY_LIST : loadedPrograms, removeEmptySeriesSchedule, isWindowTranslucent, @@ -532,7 +524,7 @@ public class DvrUiHelper { boolean removeEmptySeriesSchedule, boolean isWindowTranslucent, boolean showViewScheduleOptionInDialog, - @Nullable Program currentProgram) { + Program currentProgram) { SoftPreconditions.checkState( programs != null, TAG, "Start series settings activity but programs is null"); Intent intent = new Intent(context, DvrSeriesSettingsActivity.class); @@ -545,9 +537,7 @@ public class DvrUiHelper { intent.putExtra( DvrSeriesSettingsActivity.SHOW_VIEW_SCHEDULE_OPTION_IN_DIALOG, showViewScheduleOptionInDialog); - if (currentProgram != null) { - intent.putExtra(DvrSeriesSettingsActivity.CURRENT_PROGRAM, currentProgram.toParcelable()); - } + intent.putExtra(DvrSeriesSettingsActivity.CURRENT_PROGRAM, currentProgram); context.startActivity(intent); } @@ -692,18 +682,16 @@ public class DvrUiHelper { } SpannableStringBuilder builder; if (TextUtils.isEmpty(seasonNumber) || seasonNumber.equals("0")) { - Spanned temp = + builder = TextUtils.isEmpty(episodeNumber) - ? SpannableStringBuilder.valueOf(title) - : Html.fromHtml( - context.getString( - R.string.program_title_with_episode_number_no_season, - title, - episodeNumber)); - builder = SpannableStringBuilder.valueOf(temp); + ? new SpannableStringBuilder(title) + : new SpannableStringBuilder(Html.fromHtml(context.getString( + R.string.program_title_with_episode_number_no_season, + title, + episodeNumber))); } else { builder = - SpannableStringBuilder.valueOf( + new SpannableStringBuilder( Html.fromHtml( context.getString( R.string.program_title_with_episode_number, diff --git a/src/com/android/tv/dvr/ui/DvrWriteStoragePermissionRationaleFragment.java b/src/com/android/tv/dvr/ui/DvrWriteStoragePermissionRationaleFragment.java index 25f7f38b..c93f5831 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 androidx.leanback.widget.GuidanceStylist; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.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 7a26d5ed..1eb8080a 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 androidx.leanback.widget.ArrayObjectAdapter; -import androidx.leanback.widget.PresenterSelector; +import android.support.v17.leanback.widget.ArrayObjectAdapter; +import android.support.v17.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 c0a57c0f..0172f76f 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 androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.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 a06705c6..41ace9a4 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 androidx.leanback.R; -import androidx.leanback.widget.Action; -import androidx.leanback.widget.Presenter; -import androidx.leanback.widget.PresenterSelector; +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 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 88ef112f..8c311d68 100644 --- a/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/CurrentRecordingDetailsFragment.java @@ -19,13 +19,12 @@ package com.android.tv.dvr.ui.browse; import android.content.Context; import android.content.res.Resources; import android.media.tv.TvInputManager; - -import androidx.leanback.widget.Action; -import androidx.leanback.widget.OnActionClickedListener; -import androidx.leanback.widget.SparseArrayObjectAdapter; - +import android.support.v17.leanback.widget.Action; +import android.support.v17.leanback.widget.OnActionClickedListener; +import android.support.v17.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; @@ -34,10 +33,7 @@ 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 javax.inject.Inject; +import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags; /** {@link RecordingDetailsFragment} for current recording in DVR. */ public class CurrentRecordingDetailsFragment extends RecordingDetailsFragment { @@ -47,7 +43,8 @@ public class CurrentRecordingDetailsFragment extends RecordingDetailsFragment { private DvrDataManager mDvrDataManger; private RecordedProgram mRecordedProgram; - @Inject DvrWatchedPositionManager mDvrWatchedPositionManager; + private DvrWatchedPositionManager mDvrWatchedPositionManager; + private ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags; private boolean mPaused; private final DvrDataManager.ScheduledRecordingListener mScheduledRecordingListener = new DvrDataManager.ScheduledRecordingListener() { @@ -79,10 +76,12 @@ 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 @@ -116,7 +115,9 @@ public class CurrentRecordingDetailsFragment extends RecordingDetailsFragment { res.getString(R.string.dvr_detail_stop_recording), null, res.getDrawable(R.drawable.lb_ic_stop))); - if (mRecordedProgram != null && mRecordedProgram.isPartial()) { + if (mConcurrentDvrPlaybackFlags.enabled() + && mRecordedProgram != null + && mRecordedProgram.isPartial()) { if (mDvrWatchedPositionManager.getWatchedStatus(mRecordedProgram) == DvrWatchedPositionManager.DVR_WATCHED_STATUS_WATCHING) { adapter.set( diff --git a/src/com/android/tv/dvr/ui/browse/DetailsContent.java b/src/com/android/tv/dvr/ui/browse/DetailsContent.java index b5e05264..e179743c 100644 --- a/src/com/android/tv/dvr/ui/browse/DetailsContent.java +++ b/src/com/android/tv/dvr/ui/browse/DetailsContent.java @@ -20,11 +20,10 @@ import android.content.Context; import android.media.tv.TvContract; import android.support.annotation.Nullable; import android.text.TextUtils; - import com.android.tv.R; import com.android.tv.TvSingletons; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; @@ -127,10 +126,9 @@ public class DetailsContent { } private static String getErrorMessage(Context context, ScheduledRecording recording) { - int reason = - recording.getFailedReason() == null - ? ScheduledRecording.FAILED_REASON_OTHER - : recording.getFailedReason(); + int reason = recording.getFailedReason() == null + ? ScheduledRecording.FAILED_REASON_OTHER + : recording.getFailedReason(); switch (reason) { case ScheduledRecording.FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED: return context.getString(R.string.dvr_recording_failed_not_started); @@ -138,7 +136,8 @@ public class DetailsContent { return context.getString(R.string.dvr_recording_failed_resource_busy); case ScheduledRecording.FAILED_REASON_INPUT_UNAVAILABLE: return context.getString( - R.string.dvr_recording_failed_input_unavailable, recording.getInputId()); + R.string.dvr_recording_failed_input_unavailable, + recording.getInputId()); case ScheduledRecording.FAILED_REASON_INPUT_DVR_UNSUPPORTED: return context.getString(R.string.dvr_recording_failed_input_dvr_unsupported); case ScheduledRecording.FAILED_REASON_INSUFFICIENT_SPACE: diff --git a/src/com/android/tv/dvr/ui/browse/DetailsContentPresenter.java b/src/com/android/tv/dvr/ui/browse/DetailsContentPresenter.java index fafc70cf..6b5fd1fd 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 androidx.leanback.widget.Presenter; +import android.support.v17.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 - * androidx.leanback.widget.DetailsOverviewRowPresenter}. Most codes of this class is - * originated from {@link androidx.leanback.widget.AbstractDetailsDescriptionPresenter}. + * android.support.v17.leanback.widget.DetailsOverviewRowPresenter}. Most codes of this class is + * originated from {@link android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter}. * The latter class are re-used to provide a customized version of {@link - * androidx.leanback.widget.DetailsOverviewRow}. + * android.support.v17.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 8a4c7854..4e41daee 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 androidx.leanback.app.BackgroundManager; +import android.support.v17.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 7262b4a0..5743ea5c 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.StartupMeasureFactory; +import com.android.tv.perf.PerformanceMonitorManagerFactory; /** {@link android.app.Activity} for DVR UI. */ public class DvrBrowseActivity extends Activity { { - StartupMeasureFactory.create().onActivityInit(); + PerformanceMonitorManagerFactory.create().getStartupMeasure().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 786942e0..17ba1939 100644 --- a/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java +++ b/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java @@ -21,14 +21,13 @@ import android.content.Context; import android.os.Build; import android.os.Bundle; import android.os.Handler; -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.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.util.Log; import android.view.View; import android.view.ViewTreeObserver.OnGlobalFocusChangeListener; @@ -476,7 +475,7 @@ public class DvrBrowseFragment extends BrowseFragment mRecentAdapter.add(recordedProgram); String seriesId = recordedProgram.getSeriesId(); SeriesRecording seriesRecording = null; - if (!TextUtils.isEmpty(seriesId)) { + if (seriesId != null) { seriesRecording = mDvrDataManager.getSeriesRecording(seriesId); RecordedProgram latestProgram = mSeriesId2LatestProgram.get(seriesId); if (latestProgram == null @@ -500,7 +499,7 @@ public class DvrBrowseFragment extends BrowseFragment private void handleRecordedProgramRemoved(RecordedProgram recordedProgram) { mRecentAdapter.remove(recordedProgram); String seriesId = recordedProgram.getSeriesId(); - if (!TextUtils.isEmpty(seriesId)) { + if (seriesId != null) { SeriesRecording seriesRecording = mDvrDataManager.getSeriesRecording(seriesId); RecordedProgram latestProgram = mSeriesId2LatestProgram.get(recordedProgram.getSeriesId()); @@ -521,7 +520,7 @@ public class DvrBrowseFragment extends BrowseFragment mRecentAdapter.change(recordedProgram); String seriesId = recordedProgram.getSeriesId(); SeriesRecording seriesRecording = null; - if (!TextUtils.isEmpty(seriesId)) { + if (seriesId != null) { seriesRecording = mDvrDataManager.getSeriesRecording(seriesId); RecordedProgram latestProgram = mSeriesId2LatestProgram.get(seriesId); if (latestProgram == null @@ -664,7 +663,7 @@ public class DvrBrowseFragment extends BrowseFragment } } if (getSelectedPosition() >= mRowsAdapter.size()) { - setSelectedPosition(mRowsAdapter.size() - 1); + setSelectedPosition(mRecentAdapter.size() - 1); } } diff --git a/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java index a38180a5..f90981f0 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 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.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 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 ebdee32f..4298d86a 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 androidx.leanback.widget.Presenter; +import android.support.v17.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 625f8f76..a2d1cb28 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 androidx.leanback.widget.ListRowPresenter; +import android.support.v17.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 5f58af8e..bf963547 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 androidx.leanback.widget.Action; -import androidx.leanback.widget.OnActionClickedListener; -import androidx.leanback.widget.SparseArrayObjectAdapter; +import android.support.v17.leanback.widget.Action; +import android.support.v17.leanback.widget.OnActionClickedListener; +import android.support.v17.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 androidx.leanback.app.DetailsFragment} for recorded program in DVR. */ +/** {@link android.support.v17.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 ac7c5745..c83ceaf0 100644 --- a/src/com/android/tv/dvr/ui/browse/RecordingCardView.java +++ b/src/com/android/tv/dvr/ui/browse/RecordingCardView.java @@ -23,16 +23,14 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.support.annotation.Nullable; -import android.text.Layout; +import android.support.v17.leanback.widget.BaseCardView; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewTreeObserver; 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 +42,7 @@ import com.android.tv.util.images.ImageLoader; */ public class RecordingCardView extends BaseCardView { // This value should be the same with - // androidx.leanback.widget.FocusHighlightHelper.BrowseItemFocusHighlight.DURATION_MS + // android.support.v17.leanback.widget.FocusHighlightHelper.BrowseItemFocusHighlight.DURATION_MS private static final int ANIMATION_DURATION = 150; private final ImageView mImageView; private final int mImageWidth; @@ -64,7 +62,6 @@ public class RecordingCardView extends BaseCardView { private final boolean mExpandTitleWhenFocused; private boolean mExpanded; private String mDetailBackgroundImageUri; - private Layout mTitleViewLayout; public RecordingCardView(Context context) { this(context, false); @@ -123,14 +120,6 @@ public class RecordingCardView extends BaseCardView { * value)); } }); - getViewTreeObserver().addOnGlobalLayoutListener( - new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - getViewTreeObserver().removeOnGlobalLayoutListener(this); - mTitleViewLayout = mFoldedTitleView.getLayout(); - } - }); mExpandTitleWhenFocused = expandTitleWhenFocused; } @@ -165,8 +154,7 @@ public class RecordingCardView extends BaseCardView { * @param withAnimation {@code true} to expand/fold with animation. */ public void expandTitle(boolean expand, boolean withAnimation) { - if (expand != mExpanded && mTitleViewLayout != null - && mTitleViewLayout.getEllipsisCount(0) > 0) { + if (expand != mExpanded && mFoldedTitleView.getLayout().getEllipsisCount(0) > 0) { if (withAnimation) { if (expand) { mExpandTitleAnimator.start(); diff --git a/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java index e85f983f..243681c6 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 androidx.leanback.app.DetailsFragment; +import android.support.v17.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 7ef8e59f..f08bb12b 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 androidx.leanback.widget.Action; -import androidx.leanback.widget.OnActionClickedListener; -import androidx.leanback.widget.SparseArrayObjectAdapter; +import android.support.v17.leanback.widget.Action; +import android.support.v17.leanback.widget.OnActionClickedListener; +import android.support.v17.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 1c020091..9104ef10 100644 --- a/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/SeriesRecordingDetailsFragment.java @@ -21,21 +21,21 @@ 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 android.text.TextUtils; -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 com.android.tv.R; import com.android.tv.TvSingletons; -import com.android.tv.data.api.BaseProgram; +import com.android.tv.data.BaseProgram; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrWatchedPositionManager; import com.android.tv.dvr.data.RecordedProgram; diff --git a/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java index 293e1d94..77a63508 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 androidx.leanback.app.DetailsFragment; -import androidx.leanback.widget.ClassPresenterSelector; +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; diff --git a/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java b/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java index 1d93c8cb..0ca05fac 100644 --- a/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java +++ b/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java @@ -17,24 +17,23 @@ 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; @@ -49,17 +48,11 @@ public class DvrHistoryFragment extends DetailsFragment presenterSelector.addClassPresenter( ScheduleRow.class, new ScheduleRowPresenter(getContext())); TvSingletons singletons = TvSingletons.getSingletons(getContext()); - UiFlags uiFlags = singletons.getUiFlags(); - mDvrDataManager = singletons.getDvrDataManager(); - mRowsAdapter = - new DvrHistoryRowAdapter( - getContext(), - presenterSelector, - singletons.getClock(), - mDvrDataManager, - uiFlags); + mRowsAdapter = new DvrHistoryRowAdapter( + getContext(), presenterSelector, singletons.getClock()); setAdapter(mRowsAdapter); mRowsAdapter.start(); + mDvrDataManager = singletons.getDvrDataManager(); mDvrDataManager.addScheduledRecordingListener(this); mDvrDataManager.addRecordedProgramListener(this); mEmptyInfoScreenView = (TextView) getActivity().findViewById(R.id.empty_info_screen); @@ -142,6 +135,7 @@ 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 a10367fb..156d1a7e 100644 --- a/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java +++ b/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java @@ -20,19 +20,20 @@ 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; @@ -47,8 +48,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; @@ -56,16 +57,11 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { private final Map<Long, ScheduledRecording> mRecordedProgramScheduleMap = new HashMap<>(); public DvrHistoryRowAdapter( - Context context, - ClassPresenterSelector classPresenterSelector, - Clock clock, - DvrDataManager dvrDataManager, - UiFlags uiFlags) { + Context context, ClassPresenterSelector classPresenterSelector, Clock clock) { super(classPresenterSelector); mContext = context; mClock = clock; - mDvrDataManager = dvrDataManager; - mMaxHistoryDays = uiFlags.maxHistoryDays(); + mDvrDataManager = TvSingletons.getSingletons(mContext).getDvrDataManager(); mTitles.add(mContext.getString(R.string.dvr_date_today)); mTitles.add(mContext.getString(R.string.dvr_date_yesterday)); } @@ -82,9 +78,9 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { List<RecordedProgram> recordedProgramList = mDvrDataManager.getRecordedPrograms(); recordingList.addAll( - recordedProgramsToScheduledRecordings(recordedProgramList, mMaxHistoryDays)); - recordingList.sort( - ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR.reversed()); + recordedProgramsToScheduledRecordings(recordedProgramList, MAX_HISTORY_DAYS)); + 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<>(); @@ -132,7 +128,7 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { } private List<ScheduledRecording> recordedProgramsToScheduledRecordings( - List<RecordedProgram> programs, long maxDays) { + List<RecordedProgram> programs, int maxDays) { List<ScheduledRecording> result = new ArrayList<>(); for (RecordedProgram recordedProgram : programs) { ScheduledRecording scheduledRecording = @@ -146,12 +142,12 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { @Nullable private ScheduledRecording recordedProgramsToScheduledRecordings( - RecordedProgram program, long maxDays) { + RecordedProgram program, int maxDays) { long firstMillisecondToday = Utils.getFirstMillisecondOfDay(mClock.currentTimeMillis()); - if (maxDays != 0 - && maxDays - < Utils.computeDateDifference( - program.getStartTimeUtcMillis(), firstMillisecondToday)) { + if (maxDays + < Utils.computeDateDifference( + program.getStartTimeUtcMillis(), + firstMillisecondToday)) { return null; } ScheduledRecording scheduledRecording = ScheduledRecording.builder(program).build(); @@ -179,7 +175,7 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter { return; } ScheduledRecording schedule = - recordedProgramsToScheduledRecordings(program, mMaxHistoryDays); + recordedProgramsToScheduledRecordings(program, MAX_HISTORY_DAYS); if (schedule == null) { return; } @@ -252,10 +248,8 @@ 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/DvrSchedulesActivity.java b/src/com/android/tv/dvr/ui/list/DvrSchedulesActivity.java index d0884f99..82b85630 100644 --- a/src/com/android/tv/dvr/ui/list/DvrSchedulesActivity.java +++ b/src/com/android/tv/dvr/ui/list/DvrSchedulesActivity.java @@ -20,15 +20,13 @@ import android.app.Activity; import android.app.ProgressDialog; import android.os.Bundle; import android.support.annotation.IntDef; - import com.android.tv.R; import com.android.tv.Starter; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.provider.EpisodicProgramLoadTask; import com.android.tv.dvr.recorder.SeriesRecordingScheduler; import com.android.tv.dvr.ui.BigArguments; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collections; diff --git a/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java index 43a3579a..d97b61f4 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 androidx.leanback.widget.ClassPresenterSelector; +import android.support.v17.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 50bc04c7..d376e358 100644 --- a/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java +++ b/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java @@ -25,24 +25,20 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.support.v17.leanback.widget.ClassPresenterSelector; import android.transition.Fade; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; - -import androidx.leanback.widget.ClassPresenterSelector; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.ProgramImpl; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrDataManager.SeriesRecordingListener; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.provider.EpisodicProgramLoadTask; import com.android.tv.dvr.ui.BigArguments; - import java.util.Collections; import java.util.List; @@ -57,7 +53,7 @@ public class DvrSeriesSchedulesFragment extends BaseDvrSchedulesFragment { "series_schedules_key_series_recording"; /** * The key for programs which belong to the series recording whose scheduled recording list will - * be displayed. Type: List<{@link ProgramImpl}> + * be displayed. Type: List<{@link Program}> */ public static final String SERIES_SCHEDULES_KEY_SERIES_PROGRAMS = "series_schedules_key_series_programs"; diff --git a/src/com/android/tv/dvr/ui/list/EpisodicProgramRow.java b/src/com/android/tv/dvr/ui/list/EpisodicProgramRow.java index ccb497fb..d5808412 100644 --- a/src/com/android/tv/dvr/ui/list/EpisodicProgramRow.java +++ b/src/com/android/tv/dvr/ui/list/EpisodicProgramRow.java @@ -17,8 +17,7 @@ package com.android.tv.dvr.ui.list; import android.content.Context; - -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.ScheduledRecording.Builder; import com.android.tv.dvr.ui.DvrUiHelper; diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java index de259f5a..ef4a4337 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 androidx.leanback.widget.ArrayObjectAdapter; -import androidx.leanback.widget.ClassPresenterSelector; +import android.support.v17.leanback.widget.ArrayObjectAdapter; +import android.support.v17.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 ff296f49..11680a0d 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 androidx.leanback.widget.RowPresenter; +import android.support.v17.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/SchedulesHeaderRow.java b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRow.java index 5c687cde..bbddc07f 100644 --- a/src/com/android/tv/dvr/ui/list/SchedulesHeaderRow.java +++ b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRow.java @@ -16,9 +16,8 @@ package com.android.tv.dvr.ui.list; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.data.SeriesRecording; - import java.util.List; /** A base class for the rows for schedules' header. */ diff --git a/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java index 2550eebc..28a44bf3 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 androidx.leanback.widget.RowPresenter; +import android.support.v17.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 2c377549..9a9c94ea 100644 --- a/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java +++ b/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java @@ -20,22 +20,19 @@ 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 android.util.ArrayMap; import android.util.Log; - -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.data.api.Program; +import com.android.tv.data.Program; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.ui.list.SchedulesHeaderRow.SeriesRecordingHeaderRow; import com.android.tv.util.Utils; - import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java b/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java index 4aa1200e..f24ad2c0 100644 --- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java +++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackActivity.java @@ -16,6 +16,7 @@ package com.android.tv.dvr.ui.playback; +import android.app.Activity; import android.content.ContentUris; import android.content.Intent; import android.content.res.Configuration; @@ -27,12 +28,9 @@ 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 DaggerActivity implements OnPinCheckedListener { +public class DvrPlaybackActivity extends Activity implements OnPinCheckedListener { private static final String TAG = "DvrPlaybackActivity"; private static final boolean DEBUG = false; @@ -41,7 +39,6 @@ public class DvrPlaybackActivity extends DaggerActivity implements OnPinCheckedL @Override public void onCreate(Bundle savedInstanceState) { - AndroidInjection.inject(this); Starter.start(this); if (DEBUG) Log.d(TAG, "onCreate"); super.onCreate(savedInstanceState); @@ -95,16 +92,4 @@ public class DvrPlaybackActivity extends DaggerActivity implements OnPinCheckedL 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 35c5d4e4..791d26bb 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 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.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 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 0c96cac8..1059e852 100644 --- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java +++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackOverlayFragment.java @@ -26,25 +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.audio.AudioManagerHelper; -import com.android.tv.common.buildtype.HasBuildType.BuildType; -import com.android.tv.data.api.BaseProgram; +import com.android.tv.TvSingletons; +import com.android.tv.data.BaseProgram; import com.android.tv.dialog.PinDialogFragment; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.data.RecordedProgram; @@ -56,11 +55,8 @@ 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. @@ -79,7 +75,7 @@ public class DvrPlaybackOverlayFragment extends PlaybackFragment { private ArrayObjectAdapter mRowsAdapter; private SortedArrayAdapter<BaseProgram> mRelatedRecordingsRowAdapter; private DvrPlaybackCardPresenter mRelatedRecordingCardPresenter; - private AudioManagerHelper mAudioManagerHelper; + private DvrDataManager mDvrDataManager; private AppLayerTvView mTvView; private View mBlockScreenView; private ListRow mRelatedRecordingsRow; @@ -101,24 +97,9 @@ 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() @@ -134,6 +115,7 @@ 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() { @@ -171,8 +153,6 @@ 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 = @@ -260,16 +240,13 @@ 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()); @@ -278,9 +255,7 @@ 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) { @@ -295,12 +270,9 @@ 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(); @@ -444,7 +416,6 @@ 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 95858e3c..b4481df8 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 androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidedAction; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.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 6cfa2e20..d14646b8 100644 --- a/src/com/android/tv/dvr/ui/playback/DvrPlayer.java +++ b/src/com/android/tv/dvr/ui/playback/DvrPlayer.java @@ -326,11 +326,6 @@ 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; @@ -521,17 +516,13 @@ public class DvrPlayer { for (TvTrackInfo trackInfo : trackInfos) { if (trackInfo.getId().equals(trackId)) { float videoAspectRatio; - float videoPixelAspectRatio = - trackInfo.getVideoPixelAspectRatio(); int videoWidth = trackInfo.getVideoWidth(); int videoHeight = trackInfo.getVideoHeight(); if (videoWidth > 0 && videoHeight > 0) { videoAspectRatio = - (float) trackInfo.getVideoWidth() + trackInfo.getVideoPixelAspectRatio() + * trackInfo.getVideoWidth() / trackInfo.getVideoHeight(); - videoAspectRatio *= - videoPixelAspectRatio > 0 ? - videoPixelAspectRatio : 1; } else { // Aspect ratio is unknown. Pass the message to // listeners. diff --git a/src/com/android/tv/features/TvFeatures.java b/src/com/android/tv/features/TvFeatures.java index a18d9c89..208d53f6 100644 --- a/src/com/android/tv/features/TvFeatures.java +++ b/src/com/android/tv/features/TvFeatures.java @@ -27,11 +27,14 @@ import static com.android.tv.common.feature.FeatureUtils.or; 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; +import com.android.tv.common.feature.PropertyFeature; import com.android.tv.common.feature.Sdk; import com.android.tv.common.feature.TestableFeature; import com.android.tv.common.flags.has.HasUiFlags; @@ -39,7 +42,7 @@ import com.android.tv.common.singletons.HasSingletons; import com.android.tv.common.util.PermissionUtils; /** - * List of {@link Feature} for the TV app. + * List of {@link Feature} for the Live TV App. * * <p>Remove the {@code Feature} once it is launched. */ @@ -48,6 +51,16 @@ 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); @@ -74,7 +87,7 @@ public final class TvFeatures extends CommonFeatures { or( FlagFeature.from( context -> HasSingletons.get(HasUiFlags.class, context), - input -> input.getUiFlags().unhideLauncher()), + input -> input.getUiFlags().uhideLauncher()), // If LC app runs as non-system app, we unhide the app. not(PermissionUtils::hasAccessAllEpg)); @@ -101,5 +114,8 @@ public final class TvFeatures extends CommonFeatures { /** Use input blacklist to disable partner's tuner input. */ public static final Feature USE_PARTNER_INPUT_BLACKLIST = ON; + @VisibleForTesting + public static final Feature TEST_FEATURE = PropertyFeature.create("test_feature", false); + private TvFeatures() {} } diff --git a/src/com/android/tv/guide/GenreListAdapter.java b/src/com/android/tv/guide/GenreListAdapter.java index 995b053c..b4baf421 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 androidx.recyclerview.widget.RecyclerView; +import android.support.v7.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 96e161cd..caafb045 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 androidx.leanback.widget.VerticalGridView; +import android.support.v17.leanback.widget.VerticalGridView; import android.util.AttributeSet; import android.util.Log; import android.util.Range; @@ -256,19 +256,8 @@ public class ProgramGrid extends VerticalGridView { scrollToPosition(getAdapter().getItemCount() - 1); return null; } else if (getSelectedPosition() == getAdapter().getItemCount() - 1) { - int itemCount = getLayoutManager().getItemCount(); - int childCount = getChildCount(); - // b/129466363 For an item which overalps with previous layout GridLayoutManager - // will scroll to first child of current layout, instead of going to previous one. - // smoothscrollToPosition will invalidate all layouts and scroll to position 0. - // This condition checks for an item which overlaps with the first layout - if (itemCount > 2 * (childCount + 1) || itemCount <= childCount) { - scrollToPosition(0); - return null; - } else { - smoothScrollToPosition(0); - return getChildAt(0); - } + scrollToPosition(0); + return null; } return focused; } diff --git a/src/com/android/tv/guide/ProgramGuide.java b/src/com/android/tv/guide/ProgramGuide.java index 8ae61e8a..bc1b11b6 100644 --- a/src/com/android/tv/guide/ProgramGuide.java +++ b/src/com/android/tv/guide/ProgramGuide.java @@ -32,7 +32,10 @@ import android.os.SystemClock; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import androidx.recyclerview.widget.RecyclerView; +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 android.util.Log; import android.view.View; import android.view.View.MeasureSpec; @@ -41,11 +44,6 @@ 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; @@ -67,9 +65,7 @@ import com.android.tv.ui.ViewUtils; 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.UiFlags; - +import com.android.tv.common.flags.BackendKnobsFlags; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; @@ -116,7 +112,6 @@ 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; @@ -190,14 +185,15 @@ public class ProgramGuide mActivity = activity; TvSingletons singletons = TvSingletons.getSingletons(mActivity); mPerformanceMonitor = singletons.getPerformanceMonitor(); - mUiFlags = singletons.getUiFlags(); + BackendKnobsFlags backendKnobsFlags = singletons.getBackendKnobs(); mProgramManager = new ProgramManager( tvInputManagerHelper, channelDataManager, programDataManager, dvrDataManager, - dvrScheduleManager); + dvrScheduleManager, + backendKnobsFlags); mChannelTuner = channelTuner; mTracker = tracker; mPreShowRunnable = preShowRunnable; @@ -265,7 +261,7 @@ public class ProgramGuide } }); mSidePanelGridView.setOnChildSelectedListener( - new androidx.leanback.widget.OnChildSelectedListener() { + new android.support.v17.leanback.widget.OnChildSelectedListener() { @Override public void onChildSelected(ViewGroup viewGroup, View view, int i, long l) { mSearchOrb.animate().alpha(i == 0 ? 1.0f : 0.0f); @@ -286,8 +282,7 @@ public class ProgramGuide res.getInteger(R.integer.max_recycled_view_pool_epg_header_row_item)); mTimelineRow.setAdapter(mTimeListAdapter); - ProgramTableAdapter programTableAdapter = - new ProgramTableAdapter(mActivity, this, mUiFlags); + ProgramTableAdapter programTableAdapter = new ProgramTableAdapter(mActivity, this); 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 5ec293f7..a46beab7 100644 --- a/src/com/android/tv/guide/ProgramItemView.java +++ b/src/com/android/tv/guide/ProgramItemView.java @@ -23,7 +23,6 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.StateListDrawable; -import android.os.Build; import android.os.Handler; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -35,7 +34,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; - import com.android.tv.MainActivity; import com.android.tv.R; import com.android.tv.TvSingletons; @@ -43,22 +41,17 @@ import com.android.tv.analytics.Tracker; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.util.Clock; import com.android.tv.data.ChannelDataManager; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.ui.DvrUiHelper; import com.android.tv.guide.ProgramManager.TableEntry; import com.android.tv.util.ToastUtils; import com.android.tv.util.Utils; - -import dagger.android.HasAndroidInjector; - import java.lang.reflect.InvocationTargetException; import java.util.concurrent.TimeUnit; -import javax.inject.Inject; - public class ProgramItemView extends TextView { private static final String TAG = "ProgramItemView"; @@ -80,8 +73,8 @@ public class ProgramItemView extends TextView { private static TextAppearanceSpan sGrayedOutEpisodeTitleStyle; private final DvrManager mDvrManager; - @Inject Clock mClock; - @Inject ChannelDataManager mChannelDataManager; + private final Clock mClock; + private final ChannelDataManager mChannelDataManager; private ProgramGuide mProgramGuide; private TableEntry mTableEntry; private int mMaxWidthForRipple; @@ -209,11 +202,12 @@ public class ProgramItemView extends TextView { public ProgramItemView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - ((HasAndroidInjector) context).androidInjector().inject(this); setOnClickListener(ON_CLICKED); setOnFocusChangeListener(ON_FOCUS_CHANGED); TvSingletons singletons = TvSingletons.getSingletons(getContext()); mDvrManager = singletons.getDvrManager(); + mChannelDataManager = singletons.getChannelDataManager(); + mClock = singletons.getClock(); } private void initIfNeeded() { @@ -536,9 +530,6 @@ public class ProgramItemView extends TextView { } private static int getStateCount(StateListDrawable stateListDrawable) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - return stateListDrawable.getStateCount(); - } try { Object stateCount = StateListDrawable.class @@ -555,9 +546,6 @@ public class ProgramItemView extends TextView { } private static Drawable getStateDrawable(StateListDrawable stateListDrawable, int index) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - return stateListDrawable.getStateDrawable(index); - } try { Object drawable = StateListDrawable.class diff --git a/src/com/android/tv/guide/ProgramListAdapter.java b/src/com/android/tv/guide/ProgramListAdapter.java index 68ae43ee..397bacfb 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 androidx.recyclerview.widget.RecyclerView; +import android.support.v7.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 516a4d9c..3a5a4a02 100644 --- a/src/com/android/tv/guide/ProgramManager.java +++ b/src/com/android/tv/guide/ProgramManager.java @@ -21,20 +21,18 @@ import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.util.ArraySet; import android.util.Log; - import com.android.tv.data.ChannelDataManager; import com.android.tv.data.GenreItems; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; -import com.android.tv.data.ProgramImpl; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrScheduleManager; import com.android.tv.dvr.DvrScheduleManager.OnConflictStateChangeListener; 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 java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -62,6 +60,7 @@ public class ProgramManager { private final ProgramDataManager mProgramDataManager; private final DvrDataManager mDvrDataManager; // Only set if DVR is enabled private final DvrScheduleManager mDvrScheduleManager; + private final BackendKnobsFlags mBackendKnobsFlags; private long mStartUtcMillis; private long mEndUtcMillis; @@ -125,8 +124,16 @@ public class ProgramManager { } @Override - public void onChannelUpdated() { - updateTableEntriesWithoutNotification(false); + public void onSingleChannelUpdated(long channelId) { + boolean parentalControlsEnabled = + mTvInputManagerHelper + .getParentalControlSettings() + .isParentalControlsEnabled(); + // Inline the updating of the mChannelIdEntriesMap here so we can only call + // getParentalControlSettings once. + List<TableEntry> entries = + createProgramEntries(channelId, parentalControlsEnabled); + mChannelIdEntriesMap.put(channelId, entries); notifyTableEntriesUpdated(); } }; @@ -208,12 +215,14 @@ public class ProgramManager { ChannelDataManager channelDataManager, ProgramDataManager programDataManager, @Nullable DvrDataManager dvrDataManager, - @Nullable DvrScheduleManager dvrScheduleManager) { + @Nullable DvrScheduleManager dvrScheduleManager, + BackendKnobsFlags backendKnobsFlags) { mTvInputManagerHelper = tvInputManagerHelper; mChannelDataManager = channelDataManager; mProgramDataManager = programDataManager; mDvrDataManager = dvrDataManager; mDvrScheduleManager = dvrScheduleManager; + mBackendKnobsFlags = backendKnobsFlags; } void programGuideVisibilityChanged(boolean visible) { @@ -242,6 +251,7 @@ public class ProgramManager { mDvrScheduleManager.removeOnConflictStateChangeListener( mOnConflictStateChangeListener); } + mChannelIdEntriesMap.clear(); } } @@ -416,12 +426,14 @@ public class ProgramManager { } /** - * Returns an entry as {@link ProgramImpl} for a given {@code channelId} and {@code index} of - * entries within the currently managed time range. Returned {@link ProgramImpl} can be a dummy - * one (e.g., whose channelId is INVALID_ID), when it corresponds to a gap between programs. + * Returns an entry as {@link Program} for a given {@code channelId} and {@code index} of + * entries within the currently managed time range. Returned {@link Program} can be a dummy one + * (e.g., whose channelId is INVALID_ID), when it corresponds to a gap between programs. */ TableEntry getTableEntry(long channelId, int index) { - mProgramDataManager.prefetchChannel(channelId, index); + if (mBackendKnobsFlags.enablePartialProgramFetch()) { + mProgramDataManager.prefetchChannel(channelId); + } return mChannelIdEntriesMap.get(channelId).get(index); } @@ -695,7 +707,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 - * androidx.leanback.widget.HorizontalGridView} ignores margins between items. + * android.support.v17.leanback.widget.HorizontalGridView} ignores margins between items. */ static class TableEntry { /** Channel ID which this entry is included. */ @@ -725,7 +737,7 @@ public class ProgramManager { private TableEntry( long channelId, - ProgramImpl program, + Program program, long entryStartUtcMillis, long entryEndUtcMillis, boolean isBlocked) { @@ -747,7 +759,7 @@ public class ProgramManager { mIsBlocked = isBlocked; } - /** A stable id useful for {@link androidx.recyclerview.widget.RecyclerView.Adapter}. */ + /** A stable id useful for {@link android.support.v7.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 6f8f31c1..3317c15f 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 androidx.recyclerview.widget.LinearLayoutManager; +import android.support.v7.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 a6a4624b..5e498be4 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 androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate; +import android.support.v7.widget.RecyclerView; +import android.support.v7.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 aed8b900..7576bf50 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 androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.RecycledViewPool; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.RecycledViewPool; import android.text.Html; import android.text.Spannable; import android.text.SpannableString; @@ -47,14 +47,13 @@ import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeL import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.util.CommonUtils; +import com.android.tv.data.Program; +import com.android.tv.data.Program.CriticScore; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; -import com.android.tv.data.api.Program.CriticScore; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.ScheduledRecording; @@ -68,8 +67,6 @@ 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; @@ -112,11 +109,10 @@ 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, UiFlags uiFlags) { + ProgramTableAdapter(Context context, ProgramGuide programGuide) { mContext = context; mAccessibilityManager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); @@ -130,7 +126,6 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr } mProgramGuide = programGuide; mProgramManager = programGuide.getProgramManager(); - mUiFlags = uiFlags; Resources res = context.getResources(); mChannelLogoWidth = @@ -661,35 +656,6 @@ 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 62fec69a..9c10c952 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 androidx.recyclerview.widget.RecyclerView; +import android.support.v7.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 2d257878..c4922b75 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 androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.View; diff --git a/src/com/android/tv/menu/ActionCardView.java b/src/com/android/tv/menu/ActionCardView.java index 0e789c67..3ecd5f5c 100644 --- a/src/com/android/tv/menu/ActionCardView.java +++ b/src/com/android/tv/menu/ActionCardView.java @@ -19,7 +19,6 @@ package com.android.tv.menu; import android.content.Context; import android.util.AttributeSet; import android.util.Log; -import android.view.accessibility.AccessibilityNodeInfo; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; @@ -94,13 +93,6 @@ public class ActionCardView extends RelativeLayout implements ItemListRowView.Ca } } - /** Request focus and accessibility focus on card view. */ - @Override - public boolean requestFocusWithAccessibility() { - return requestFocus() && - performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); - } - @Override public void onRecycled() {} } diff --git a/src/com/android/tv/menu/AppLinkCardView.java b/src/com/android/tv/menu/AppLinkCardView.java index 49d32fed..fd93c314 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/BaseCardView.java b/src/com/android/tv/menu/BaseCardView.java index ed78cb73..3a94ebbf 100644 --- a/src/com/android/tv/menu/BaseCardView.java +++ b/src/com/android/tv/menu/BaseCardView.java @@ -27,7 +27,6 @@ import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewOutlineProvider; -import android.view.accessibility.AccessibilityNodeInfo; import android.widget.LinearLayout; import android.widget.TextView; import com.android.tv.R; @@ -136,13 +135,6 @@ public abstract class BaseCardView<T> extends LinearLayout implements ItemListRo } } - /** Request focus and accessibility focus on card view. */ - @Override - public boolean requestFocusWithAccessibility() { - return requestFocus() && - performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); - } - /** Sets text of this card view. */ public void setText(int resId) { if (mTextResId != resId) { diff --git a/src/com/android/tv/menu/ChannelCardView.java b/src/com/android/tv/menu/ChannelCardView.java index 7fe5e491..76056ee4 100644 --- a/src/com/android/tv/menu/ChannelCardView.java +++ b/src/com/android/tv/menu/ChannelCardView.java @@ -26,14 +26,12 @@ import android.view.View; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; - import com.android.tv.MainActivity; import com.android.tv.R; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.parental.ParentalControlSettings; import com.android.tv.util.images.ImageLoader; - import java.util.Objects; /** A view to render channel card. */ diff --git a/src/com/android/tv/menu/ChannelsPosterPrefetcher.java b/src/com/android/tv/menu/ChannelsPosterPrefetcher.java index 3a502304..9cecb9c0 100644 --- a/src/com/android/tv/menu/ChannelsPosterPrefetcher.java +++ b/src/com/android/tv/menu/ChannelsPosterPrefetcher.java @@ -23,15 +23,13 @@ import android.os.Message; import android.support.annotation.MainThread; import android.support.annotation.NonNull; import android.util.Log; - import com.android.tv.R; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.WeakHandler; import com.android.tv.data.ChannelImpl; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; - import java.util.List; /** A poster image prefetcher to show the program poster art in the Channels row faster. */ diff --git a/src/com/android/tv/menu/ChannelsRow.java b/src/com/android/tv/menu/ChannelsRow.java index dbfc7820..7d03bf2b 100644 --- a/src/com/android/tv/menu/ChannelsRow.java +++ b/src/com/android/tv/menu/ChannelsRow.java @@ -73,7 +73,6 @@ 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 e6b61037..4a9e4765 100644 --- a/src/com/android/tv/menu/ChannelsRowAdapter.java +++ b/src/com/android/tv/menu/ChannelsRowAdapter.java @@ -47,7 +47,6 @@ 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; @@ -67,9 +66,10 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channels mMaxCount = maxCount; setHasStableIds(true); mChannelChanger = (ChannelChanger) (context); - mAccessibilityManager = context.getSystemService(AccessibilityManager.class); - mShowChannelUpDown = mAccessibilityManager.isEnabled(); - mAccessibilityManager.addAccessibilityStateChangeListener(this); + AccessibilityManager accessibilityManager = + context.getSystemService(AccessibilityManager.class); + mShowChannelUpDown = accessibilityManager.isEnabled(); + accessibilityManager.addAccessibilityStateChangeListener(this); } @Override @@ -316,10 +316,4 @@ 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 cc6d23c3..7042324d 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 androidx.leanback.widget.HorizontalGridView; -import androidx.leanback.widget.OnChildSelectedListener; -import androidx.recyclerview.widget.RecyclerView; +import android.support.v17.leanback.widget.HorizontalGridView; +import android.support.v17.leanback.widget.OnChildSelectedListener; +import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; @@ -44,8 +44,6 @@ public class ItemListRowView extends MenuRowView implements OnChildSelectedListe void onSelected(); void onDeselected(); - - boolean requestFocusWithAccessibility(); } private HorizontalGridView mListView; @@ -116,13 +114,6 @@ public class ItemListRowView extends MenuRowView implements OnChildSelectedListe } } - @Override - protected void requestChildFocus() { - if (mSelectedCard != null) { - mSelectedCard.requestFocusWithAccessibility(); - } - } - public abstract static class ItemListAdapter<T> extends RecyclerView.Adapter<ItemListAdapter.MyViewHolder> { private final MainActivity mMainActivity; diff --git a/src/com/android/tv/menu/Menu.java b/src/com/android/tv/menu/Menu.java index 0687441e..6bdbf87b 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 androidx.leanback.widget.HorizontalGridView; +import android.support.v17.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 8f95db77..a600f704 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 androidx.recyclerview.widget.RecyclerView; +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 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/MenuRow.java b/src/com/android/tv/menu/MenuRow.java index 0945a0c5..8dc12bad 100644 --- a/src/com/android/tv/menu/MenuRow.java +++ b/src/com/android/tv/menu/MenuRow.java @@ -31,8 +31,6 @@ public abstract class MenuRow { private MenuRowView mMenuRowView; - private boolean mIsReselected = false; - // TODO: Check if the heightResId is really necessary. public MenuRow(Context context, Menu menu, int titleResId, int heightResId) { this(context, menu, context.getString(titleResId), heightResId); @@ -102,19 +100,4 @@ public abstract class MenuRow { public boolean hideTitleWhenSelected() { return false; } - - /** - * Sets if menu row is reselected. - * - * @param isReselected {@code true} if row is reselected; - * else {@code false}. - */ - public void setIsReselected(boolean isReselected) { - mIsReselected = isReselected; - } - - /** Returns true if row is reselected. */ - public boolean isReselected() { - return mIsReselected; - } } diff --git a/src/com/android/tv/menu/MenuRowFactory.java b/src/com/android/tv/menu/MenuRowFactory.java index a3837a10..048d725d 100644 --- a/src/com/android/tv/menu/MenuRowFactory.java +++ b/src/com/android/tv/menu/MenuRowFactory.java @@ -24,7 +24,6 @@ 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. */ @@ -32,15 +31,12 @@ 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, LegacyFlags mLegacyFlags) { + public MenuRowFactory(MainActivity mainActivity, TunableTvView tvView) { mMainActivity = mainActivity; mTvView = tvView; mCustomizationManager = new CustomizationManager(mainActivity); - this.mLegacyFlags = mLegacyFlags; mCustomizationManager.initialize(); } @@ -64,8 +60,7 @@ public class MenuRowFactory { return new TvOptionsRow( mMainActivity, menu, - mCustomizationManager.getCustomActions(CustomizationManager.ID_OPTIONS_ROW), - mLegacyFlags); + mCustomizationManager.getCustomActions(CustomizationManager.ID_OPTIONS_ROW)); } return null; } @@ -75,17 +70,13 @@ 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, - LegacyFlags legacyFlags) { + private TvOptionsRow(Context context, Menu menu, List<CustomAction> customActions) { super( context, menu, R.string.menu_title_options, R.dimen.action_card_height, - new TvOptionsRowAdapter(context, customActions, legacyFlags)); + new TvOptionsRowAdapter(context, customActions)); } } diff --git a/src/com/android/tv/menu/MenuRowView.java b/src/com/android/tv/menu/MenuRowView.java index e09a4ef0..a064f352 100644 --- a/src/com/android/tv/menu/MenuRowView.java +++ b/src/com/android/tv/menu/MenuRowView.java @@ -25,7 +25,6 @@ import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; -import android.view.accessibility.AccessibilityEvent; import android.widget.LinearLayout; import android.widget.TextView; import com.android.tv.R; @@ -90,18 +89,6 @@ public abstract class MenuRowView extends LinearLayout { float textSizeDeselected = res.getDimensionPixelSize(R.dimen.menu_row_title_text_size_deselected); mTitleViewScaleSelected = textSizeSelected / textSizeDeselected; - this.setAccessibilityDelegate( - new AccessibilityDelegate() { - @Override - public void sendAccessibilityEvent(View host, int eventType) { - super.sendAccessibilityEvent(host, eventType); - if (eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED && - !mRow.isReselected()) { - requestChildFocus(); - } - } - } - ); } @Override @@ -190,9 +177,6 @@ public abstract class MenuRowView extends LinearLayout { mLastFocusView = v; } - /** Subclasses should implement this to request focus on child. */ - protected abstract void requestChildFocus(); - /** * Called when the focus of a child view is changed. The inherited class should override this * method instead of calling {@link diff --git a/src/com/android/tv/menu/MenuView.java b/src/com/android/tv/menu/MenuView.java index add4a774..f5fec000 100644 --- a/src/com/android/tv/menu/MenuView.java +++ b/src/com/android/tv/menu/MenuView.java @@ -250,40 +250,39 @@ public class MenuView extends FrameLayout implements IMenuView { // The bounds of the views move and overlap with each other during the animation. In this // situation, the framework can't perform the correct focus navigation. So the menu view // should search by itself. - if (direction == View.FOCUS_UP || direction == View.FOCUS_DOWN) { - return getUpDownFocus(focused, direction); - } - return super.focusSearch(focused, direction); - } - - private View getUpDownFocus(View focused, int direction) { - View newView = super.focusSearch(focused, direction); - MenuRowView oldfocusedParent = getParentMenuRowView(focused); - MenuRowView newFocusedParent = getParentMenuRowView(newView); - int selectedPosition = mLayoutManager.getSelectedPosition(); - int start, delta; if (direction == View.FOCUS_UP) { - start = selectedPosition - 1; - delta = -1; - } else { - start = selectedPosition + 1; - delta = 1; - } - if (newFocusedParent != oldfocusedParent) { - // The focus leaves from the current menu row view. - int count = mMenuRowViews.size(); - int i = start; - while (i < count && i >= 0) { - MenuRowView view = mMenuRowViews.get(i); - if (view.getVisibility() == View.VISIBLE) { - mMenuRows.get(i).setIsReselected(false); - return view; + View newView = super.focusSearch(focused, direction); + MenuRowView oldfocusedParent = getParentMenuRowView(focused); + MenuRowView newFocusedParent = getParentMenuRowView(newView); + int selectedPosition = mLayoutManager.getSelectedPosition(); + if (newFocusedParent != oldfocusedParent) { + // The focus leaves from the current menu row view. + for (int i = selectedPosition - 1; i >= 0; --i) { + MenuRowView view = mMenuRowViews.get(i); + if (view.getVisibility() == View.VISIBLE) { + return view; + } + } + } + return newView; + } else if (direction == View.FOCUS_DOWN) { + View newView = super.focusSearch(focused, direction); + MenuRowView oldfocusedParent = getParentMenuRowView(focused); + MenuRowView newFocusedParent = getParentMenuRowView(newView); + int selectedPosition = mLayoutManager.getSelectedPosition(); + if (newFocusedParent != oldfocusedParent) { + // The focus leaves from the current menu row view. + int count = mMenuRowViews.size(); + for (int i = selectedPosition + 1; i < count; ++i) { + MenuRowView view = mMenuRowViews.get(i); + if (view.getVisibility() == View.VISIBLE) { + return view; + } } - i += delta; } + return newView; } - mMenuRows.get(selectedPosition).setIsReselected(true); - return newView; + return super.focusSearch(focused, direction); } private MenuRowView getParentMenuRowView(View view) { diff --git a/src/com/android/tv/menu/PlayControlsButton.java b/src/com/android/tv/menu/PlayControlsButton.java index 1b85d632..ac3292a3 100644 --- a/src/com/android/tv/menu/PlayControlsButton.java +++ b/src/com/android/tv/menu/PlayControlsButton.java @@ -22,7 +22,6 @@ import android.content.Context; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; -import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -147,11 +146,4 @@ public class PlayControlsButton extends FrameLayout { mIcon.setAlpha(enabled ? ALPHA_ENABLED : ALPHA_DISABLED); mLabel.setEnabled(enabled); } - - /** Request focus and accessibility focus to the button */ - public boolean requestFocusWithAccessibility() { - return mButton.requestFocus() && - mButton.performAccessibilityAction( - AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); - } } diff --git a/src/com/android/tv/menu/PlayControlsRowView.java b/src/com/android/tv/menu/PlayControlsRowView.java index 5dde3be0..0ce74ae1 100644 --- a/src/com/android/tv/menu/PlayControlsRowView.java +++ b/src/com/android/tv/menu/PlayControlsRowView.java @@ -24,7 +24,6 @@ import android.util.AttributeSet; import android.view.View; import android.widget.TextView; import android.widget.Toast; - import com.android.tv.MainActivity; import com.android.tv.R; import com.android.tv.TimeShiftManager; @@ -32,8 +31,8 @@ import com.android.tv.TimeShiftManager.TimeShiftActionId; import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.feature.CommonFeatures; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dialog.HalfSizedDialogFragment; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrDataManager.OnDvrScheduleLoadFinishedListener; @@ -488,11 +487,6 @@ public class PlayControlsRowView extends MenuRowView { } } - @Override - protected void requestChildFocus() { - mPlayPauseButton.requestFocusWithAccessibility(); - } - /** Updates the view contents. It is called from the PlayControlsRow. */ public void update() { updateAll(false); diff --git a/src/com/android/tv/menu/TvOptionsRowAdapter.java b/src/com/android/tv/menu/TvOptionsRowAdapter.java index 418560a8..fe52b25e 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,7 +28,6 @@ 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; @@ -36,12 +35,8 @@ import java.util.List; * An adapter of options. */ public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter { - private final LegacyFlags mLegacyFlags; - - public TvOptionsRowAdapter( - Context context, List<CustomAction> customActions, LegacyFlags mLegacyFlags) { + public TvOptionsRowAdapter(Context context, List<CustomAction> customActions) { super(context, customActions); - this.mLegacyFlags = mLegacyFlags; } @Override @@ -54,7 +49,7 @@ public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter { } actionList.add(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION); actionList.add(MenuAction.MORE_CHANNELS_ACTION); - if (BuildConfig.ENG || mLegacyFlags.enableDeveloperFeatures()) { + if (CommonUtils.isDeveloper()) { 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 99753d1e..45383ae1 100644 --- a/src/com/android/tv/modules/TvApplicationModule.java +++ b/src/com/android/tv/modules/TvApplicationModule.java @@ -16,101 +16,43 @@ 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.data.epg.EpgFetchService; -import com.android.tv.data.epg.EpgFetcher; -import com.android.tv.data.epg.EpgFetcherImpl; -import com.android.tv.dialog.PinDialogFragment; -import com.android.tv.dvr.DvrDataManager; -import com.android.tv.dvr.DvrDataManagerImpl; -import com.android.tv.dvr.WritableDvrDataManager; -import com.android.tv.dvr.ui.playback.DvrPlaybackActivity; import com.android.tv.onboarding.OnboardingActivity; -import com.android.tv.onboarding.SetupSourcesFragment; -import com.android.tv.setup.SystemSetupActivity; -import com.android.tv.ui.DetailsActivity; import com.android.tv.util.AsyncDbTask; import com.android.tv.util.TvInputManagerHelper; - -import dagger.Binds; 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; /** Dagger module for {@link TvApplication}. */ @Module( includes = { ApplicationModule.class, - BuildTypeModule.class, - DetailsActivity.Module.class, - DvrPlaybackActivity.Module.class, - MainActivity.Module.class, - OnboardingActivity.Module.class, - SetupPassthroughActivity.Module.class, - SetupSourcesFragment.ContentFragment.Module.class, - SystemSetupActivity.Module.class, TvSingletonsModule.class, + MainActivity.Module.class, + OnboardingActivity.Module.class }) -public abstract class TvApplicationModule { +public class TvApplicationModule { private static final NamedThreadFactory THREAD_FACTORY = new NamedThreadFactory("tv-app-db"); @Provides @AsyncDbTask.DbExecutor @Singleton - static Executor providesDbExecutor() { + Executor providesDbExecutor() { return Executors.newSingleThreadExecutor(THREAD_FACTORY); } @Provides @Singleton - static TvInputManagerHelper providesTvInputManagerHelper( - @ApplicationContext Context context, LegacyFlags legacyFlags) { - TvInputManagerHelper tvInputManagerHelper = new TvInputManagerHelper(context, legacyFlags); + TvInputManagerHelper providesTvInputManagerHelper(@ApplicationContext Context context) { + TvInputManagerHelper tvInputManagerHelper = new TvInputManagerHelper(context); 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; - } - - @Binds - @Singleton - abstract DvrDataManager providesDvrDataManager(DvrDataManagerImpl impl); - - @Binds - @Singleton - abstract WritableDvrDataManager providesWritableDvrDataManager(DvrDataManagerImpl impl); - - @Binds - @Singleton - abstract EpgFetcher epgFetcher(EpgFetcherImpl impl); - - @ContributesAndroidInjector - abstract PinDialogFragment contributesPinDialogFragment(); - - @ContributesAndroidInjector - abstract EpgFetchService contributesEpgFetchService(); } diff --git a/src/com/android/tv/modules/TvSingletonsModule.java b/src/com/android/tv/modules/TvSingletonsModule.java index f8d10fde..f998c08b 100644 --- a/src/com/android/tv/modules/TvSingletonsModule.java +++ b/src/com/android/tv/modules/TvSingletonsModule.java @@ -16,9 +16,8 @@ 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.DvrWatchedPositionManager; - import dagger.Module; import dagger.Provides; @@ -37,8 +36,8 @@ public class TvSingletonsModule { } @Provides - DvrWatchedPositionManager providesDvrWatchedPositionManager() { - return mTvSingletons.getDvrWatchedPositionManager(); + ChannelDataManager providesChannelDataManager() { + return mTvSingletons.getChannelDataManager(); } @Provides diff --git a/src/com/android/tv/onboarding/OnboardingActivity.java b/src/com/android/tv/onboarding/OnboardingActivity.java index 1739e5a0..776ae664 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 TV app + // Make the channels of the new inputs which have been setup outside Live TV // 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 TV app SetupPassthroughActivity. + // channels should go through Live channels 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 b54d1bc9..3566c9c3 100644 --- a/src/com/android/tv/onboarding/SetupSourcesFragment.java +++ b/src/com/android/tv/onboarding/SetupSourcesFragment.java @@ -16,44 +16,33 @@ package com.android.tv.onboarding; -import android.app.Activity; +import android.content.Context; import android.graphics.Typeface; 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 android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; - -import androidx.leanback.widget.GuidanceStylist.Guidance; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.GuidedActionsStylist; -import androidx.leanback.widget.VerticalGridView; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.ui.setup.SetupGuidedStepFragment; import com.android.tv.common.ui.setup.SetupMultiPaneFragment; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.TvInputNewComparator; -import com.android.tv.tunerinputcontroller.BuiltInTunerManager; import com.android.tv.ui.GuidedActionsStylistWithDivider; import com.android.tv.util.SetupUtils; import com.android.tv.util.TvInputManagerHelper; - -import com.google.common.base.Optional; - -import dagger.android.AndroidInjection; -import dagger.android.ContributesAndroidInjector; - import java.util.ArrayList; import java.util.Collections; import java.util.List; -import javax.inject.Inject; - /** A fragment for channel source info/setup. */ public class SetupSourcesFragment extends SetupMultiPaneFragment { /** The action category for the actions which is fired from this fragment. */ @@ -117,10 +106,9 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment { private static final int PENDING_ACTION_INPUT_CHANGED = 1; private static final int PENDING_ACTION_CHANNEL_CHANGED = 2; - @Inject TvInputManagerHelper mInputManager; - @Inject ChannelDataManager mChannelDataManager; - @Inject SetupUtils mSetupUtils; - @Inject Optional<BuiltInTunerManager> mBuiltInTunerManagerOptional; + private TvInputManagerHelper mInputManager; + private ChannelDataManager mChannelDataManager; + private SetupUtils mSetupUtils; private List<TvInputInfo> mInputs; private int mKnownInputStartIndex; private int mDoneInputStartIndex; @@ -199,38 +187,37 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment { @Override public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mParentFragment = (SetupSourcesFragment) getParentFragment(); - } - - @Override - public void onAttach(Activity activity) { - AndroidInjection.inject(this); - super.onAttach(activity); + Context context = getActivity(); + TvSingletons singletons = TvSingletons.getSingletons(context); + mInputManager = singletons.getTvInputManagerHelper(); + mChannelDataManager = singletons.getChannelDataManager(); + mSetupUtils = singletons.getSetupUtils(); buildInputs(); mInputManager.addCallback(mInputCallback); mChannelDataManager.addListener(mChannelDataManagerListener); + super.onCreate(savedInstanceState); mParentFragment = (SetupSourcesFragment) getParentFragment(); - if (mBuiltInTunerManagerOptional.isPresent()) { - mBuiltInTunerManagerOptional + if (singletons.getBuiltInTunerManager().isPresent()) { + singletons + .getBuiltInTunerManager() .get() .getTunerInputController() - .executeNetworkTunerDiscoveryAsyncTask(activity); + .executeNetworkTunerDiscoveryAsyncTask(getContext()); } } @Override - public void onDetach() { + public void onDestroy() { + super.onDestroy(); mChannelDataManager.removeListener(mChannelDataManagerListener); mInputManager.removeCallback(mInputCallback); - super.onDetach(); } @NonNull @Override public Guidance onCreateGuidance(Bundle savedInstanceState) { String title = getString(R.string.setup_sources_text); - String description = getString(R.string.setup_sources_description2); + String description = getString(R.string.setup_sources_description); return new Guidance(title, description, null, null); } @@ -417,13 +404,5 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment { setAccessibilityDelegate(vh, action); } } - /** - * Exports {@link ContentFragment} for Dagger codegen to create the appropriate injector. - */ - @dagger.Module - public abstract static class Module { - @ContributesAndroidInjector - abstract ContentFragment contributesContentFragment(); - } } } diff --git a/src/com/android/tv/onboarding/WelcomeFragment.java b/src/com/android/tv/onboarding/WelcomeFragment.java index 667da058..8c119a8a 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 androidx.leanback.app.OnboardingFragment; +import android.support.v17.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(androidx.leanback.R.id.title); - mPagingIndicator = view.findViewById(androidx.leanback.R.id.page_indicator); - mStartButton = view.findViewById(androidx.leanback.R.id.button_start); + 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); mStartButton.setAccessibilityDelegate( new AccessibilityDelegate() { diff --git a/src/com/android/tv/parental/ContentRatingsManager.java b/src/com/android/tv/parental/ContentRatingsManager.java index 174039ba..32a1325b 100644 --- a/src/com/android/tv/parental/ContentRatingsManager.java +++ b/src/com/android/tv/parental/ContentRatingsManager.java @@ -22,7 +22,6 @@ 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; @@ -43,14 +42,13 @@ public class ContentRatingsManager { public void update() { mContentRatingSystems.clear(); - 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); - } + 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 9990ae35..b41b160e 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,16 +40,14 @@ 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, LegacyFlags legacyFlags) { + public ParentalControlSettings(Context context) { mContext = context; mTvInputManager = (TvInputManager) mContext.getSystemService(Context.TV_INPUT_SERVICE); - mLegacyFlags = legacyFlags; } public boolean isParentalControlsEnabled() { @@ -132,7 +130,7 @@ public class ParentalControlSettings { } else { mRatings = ContentRatingLevelPolicy.getRatingsForLevel(this, manager, level); if (level != TvSettings.CONTENT_RATING_LEVEL_NONE - && mLegacyFlags.enableUnratedContentSettings()) { + && Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { // 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 30197c74..b1ae759d 100644 --- a/src/com/android/tv/perf/PerformanceMonitor.java +++ b/src/com/android/tv/perf/PerformanceMonitor.java @@ -96,14 +96,4 @@ 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 new file mode 100644 index 00000000..db6667d1 --- /dev/null +++ b/src/com/android/tv/perf/PerformanceMonitorManager.java @@ -0,0 +1,38 @@ +/* + * 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/StartupMeasureFactory.java b/src/com/android/tv/perf/PerformanceMonitorManagerFactory.java index a99c88af..fe3ea14b 100644 --- a/src/com/android/tv/perf/StartupMeasureFactory.java +++ b/src/com/android/tv/perf/PerformanceMonitorManagerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -11,33 +11,25 @@ * 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 + * limitations under the License. */ package com.android.tv.perf; - -import com.android.tv.perf.stub.StubStartupMeasure; - -import com.google.common.base.Supplier; -import java.lang.Override; +import com.android.tv.perf.stub.StubPerformanceMonitorManager; import javax.inject.Inject; -/** Factory for {@link StartupMeasure}. - * - * <p>Hardcoded to {@link StubStartupMeasure}. - */ -public final class StartupMeasureFactory implements Supplier<StartupMeasure> { - private static final StartupMeasureFactory INSTANCE = new StartupMeasureFactory(); +public final class PerformanceMonitorManagerFactory { + private static final PerformanceMonitorManagerFactory INSTANCE = + new PerformanceMonitorManagerFactory(); @Inject - public StartupMeasureFactory() {} + public PerformanceMonitorManagerFactory() {} - public static StartupMeasure create() { + public static PerformanceMonitorManager create() { return INSTANCE.get(); } - @Override - public StartupMeasure get() { - return new StubStartupMeasure(); + public PerformanceMonitorManager get() { + return new StubPerformanceMonitorManager(); } } diff --git a/src/com/android/tv/perf/StartupMeasure.java b/src/com/android/tv/perf/StartupMeasure.java index c7fa50fe..5cf183ca 100644 --- a/src/com/android/tv/perf/StartupMeasure.java +++ b/src/com/android/tv/perf/StartupMeasure.java @@ -19,16 +19,8 @@ import android.app.Activity; import android.app.Application; /** - * 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. + * Measures App startup. This interface is lightweight to help measure both cold and warm startup + * latency. Implementations must not throw any Exception. */ public interface StartupMeasure { diff --git a/src/com/android/tv/perf/stub/StubPerformanceMonitor.java b/src/com/android/tv/perf/stub/StubPerformanceMonitor.java index ac3dc250..80c2f6c5 100644 --- a/src/com/android/tv/perf/stub/StubPerformanceMonitor.java +++ b/src/com/android/tv/perf/stub/StubPerformanceMonitor.java @@ -56,6 +56,7 @@ public final class StubPerformanceMonitor implements PerformanceMonitor { return false; } - @Override - public void startCrashMonitor() {} + public static TimerEvent startBootstrapTimer() { + return new TimerEvent() {}; + } } diff --git a/src/com/android/tv/perf/stub/StubPerformanceMonitorManager.java b/src/com/android/tv/perf/stub/StubPerformanceMonitorManager.java new file mode 100644 index 00000000..0c268155 --- /dev/null +++ b/src/com/android/tv/perf/stub/StubPerformanceMonitorManager.java @@ -0,0 +1,36 @@ +/* + * 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/AudioCapabilitiesReceiver.java b/src/com/android/tv/receiver/AudioCapabilitiesReceiver.java index 5fa7606d..3fb66245 100644 --- a/src/com/android/tv/receiver/AudioCapabilitiesReceiver.java +++ b/src/com/android/tv/receiver/AudioCapabilitiesReceiver.java @@ -42,7 +42,7 @@ public final class AudioCapabilitiesReceiver { // AC3 capabilities stat is sent to Google Analytics just once in order to avoid // duplicated stat reports since it doesn't change over time in most cases. // Increase this revision when we should force the stat to be sent again. - // TODO: Consider using custom metrics. + // TODO: Consier using custom metrics. private static final int REPORT_REVISION = 1; private final Context mContext; diff --git a/src/com/android/tv/receiver/PackageIntentsReceiver.java b/src/com/android/tv/receiver/PackageIntentsReceiver.java index 7ff67b50..5bc6d724 100644 --- a/src/com/android/tv/receiver/PackageIntentsReceiver.java +++ b/src/com/android/tv/receiver/PackageIntentsReceiver.java @@ -23,7 +23,9 @@ 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/ChannelPreviewUpdater.java b/src/com/android/tv/recommendation/ChannelPreviewUpdater.java index 61ebb2d0..2590a337 100644 --- a/src/com/android/tv/recommendation/ChannelPreviewUpdater.java +++ b/src/com/android/tv/recommendation/ChannelPreviewUpdater.java @@ -27,18 +27,15 @@ import android.os.Build; import android.support.annotation.RequiresApi; import android.text.TextUtils; import android.util.Log; - import androidx.tvprovider.media.tv.TvContractCompat; - import com.android.tv.Starter; import com.android.tv.TvSingletons; import com.android.tv.data.PreviewDataManager; import com.android.tv.data.PreviewProgramContent; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.parental.ParentalControlSettings; import com.android.tv.util.Utils; - import java.util.ArrayList; import java.util.HashSet; import java.util.List; diff --git a/src/com/android/tv/recommendation/ChannelRecord.java b/src/com/android/tv/recommendation/ChannelRecord.java index f047aac6..c7a7cb37 100644 --- a/src/com/android/tv/recommendation/ChannelRecord.java +++ b/src/com/android/tv/recommendation/ChannelRecord.java @@ -19,12 +19,10 @@ package com.android.tv.recommendation; import android.content.Context; import android.support.annotation.GuardedBy; import android.support.annotation.VisibleForTesting; - import com.android.tv.TvSingletons; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; - import java.util.ArrayDeque; import java.util.Deque; diff --git a/src/com/android/tv/recommendation/NotificationService.java b/src/com/android/tv/recommendation/NotificationService.java index 1652bd77..f40a0862 100644 --- a/src/com/android/tv/recommendation/NotificationService.java +++ b/src/com/android/tv/recommendation/NotificationService.java @@ -40,21 +40,19 @@ import android.text.TextUtils; import android.util.Log; import android.util.SparseLongArray; import android.view.View; - import com.android.tv.MainActivityWrapper.OnCurrentChannelChangeListener; import com.android.tv.R; import com.android.tv.Starter; import com.android.tv.TvSingletons; import com.android.tv.common.CommonConstants; import com.android.tv.common.WeakHandler; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.util.TvInputManagerHelper; import com.android.tv.util.Utils; import com.android.tv.util.images.BitmapUtils; import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo; import com.android.tv.util.images.ImageLoader; - import java.util.ArrayList; import java.util.List; diff --git a/src/com/android/tv/recommendation/RecommendationDataManager.java b/src/com/android/tv/recommendation/RecommendationDataManager.java index e254ba58..fc20031c 100644 --- a/src/com/android/tv/recommendation/RecommendationDataManager.java +++ b/src/com/android/tv/recommendation/RecommendationDataManager.java @@ -34,17 +34,14 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; import android.util.Log; - import com.android.tv.TvSingletons; import com.android.tv.common.WeakHandler; import com.android.tv.common.util.PermissionUtils; import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.WatchedHistoryManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.util.TvUriMatcher; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -235,9 +232,6 @@ 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); } @@ -365,7 +359,7 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener WatchedHistoryManager.WatchedRecord watchedRecord) { long endTime = watchedRecord.watchedStartTime + watchedRecord.duration; Program program = - new ProgramImpl.Builder() + new Program.Builder() .setChannelId(watchedRecord.channelId) .setTitle("") .setStartTimeUtcMillis(watchedRecord.watchedStartTime) @@ -417,7 +411,7 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener } Program program = - new ProgramImpl.Builder() + new Program.Builder() .setChannelId(cursor.getLong(mIndexWatchChannelId)) .setTitle(cursor.getString(mIndexProgramTitle)) .setStartTimeUtcMillis(cursor.getLong(mIndexProgramStartTime)) diff --git a/src/com/android/tv/recommendation/Recommender.java b/src/com/android/tv/recommendation/Recommender.java index a8535a49..f350799f 100644 --- a/src/com/android/tv/recommendation/Recommender.java +++ b/src/com/android/tv/recommendation/Recommender.java @@ -20,9 +20,7 @@ import android.content.Context; import android.support.annotation.VisibleForTesting; import android.util.Log; import android.util.Pair; - import com.android.tv.data.api.Channel; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -129,7 +127,7 @@ public class Recommender implements RecommendationDataManager.Listener { } } if (!mIncludeRecommendedOnly || maxScore != Evaluator.NOT_RECOMMENDED) { - records.add(Pair.create(cr.getChannel(), maxScore)); + records.add(new Pair<>(cr.getChannel(), maxScore)); } } if (size > records.size()) { diff --git a/src/com/android/tv/recommendation/RoutineWatchEvaluator.java b/src/com/android/tv/recommendation/RoutineWatchEvaluator.java index b3952c01..9240682a 100644 --- a/src/com/android/tv/recommendation/RoutineWatchEvaluator.java +++ b/src/com/android/tv/recommendation/RoutineWatchEvaluator.java @@ -19,9 +19,7 @@ package com.android.tv.recommendation; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; - -import com.android.tv.data.api.Program; - +import com.android.tv.data.Program; import java.text.BreakIterator; import java.util.ArrayList; import java.util.Calendar; diff --git a/src/com/android/tv/recommendation/WatchedProgram.java b/src/com/android/tv/recommendation/WatchedProgram.java index 0da9c620..239de1f2 100644 --- a/src/com/android/tv/recommendation/WatchedProgram.java +++ b/src/com/android/tv/recommendation/WatchedProgram.java @@ -16,7 +16,7 @@ package com.android.tv.recommendation; -import com.android.tv.data.api.Program; +import com.android.tv.data.Program; public final class WatchedProgram { private final Program mProgram; diff --git a/src/com/android/tv/search/DataManagerSearch.java b/src/com/android/tv/search/DataManagerSearch.java index 1a0ada3a..a649c0ac 100644 --- a/src/com/android/tv/search/DataManagerSearch.java +++ b/src/com/android/tv/search/DataManagerSearch.java @@ -26,18 +26,15 @@ import android.os.SystemClock; import android.support.annotation.MainThread; import android.text.TextUtils; import android.util.Log; - import com.android.tv.TvSingletons; import com.android.tv.data.ChannelDataManager; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.search.LocalSearchProvider.SearchResult; import com.android.tv.util.MainThreadExecutor; import com.android.tv.util.Utils; - import com.google.common.collect.ImmutableList; - import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; diff --git a/src/com/android/tv/search/LocalSearchProvider.java b/src/com/android/tv/search/LocalSearchProvider.java index 86999560..5652c986 100644 --- a/src/com/android/tv/search/LocalSearchProvider.java +++ b/src/com/android/tv/search/LocalSearchProvider.java @@ -17,6 +17,7 @@ package com.android.tv.search; import android.app.SearchManager; +import android.content.ContentProvider; import android.content.ContentValues; import android.database.Cursor; import android.database.MatrixCursor; @@ -27,30 +28,21 @@ import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; - +import com.android.tv.TvSingletons; import com.android.tv.common.CommonConstants; import com.android.tv.common.SoftPreconditions; -import com.android.tv.common.dagger.init.SafePreDaggerInitializer; import com.android.tv.common.util.CommonUtils; import com.android.tv.common.util.PermissionUtils; import com.android.tv.perf.EventNames; import com.android.tv.perf.PerformanceMonitor; import com.android.tv.perf.TimerEvent; import com.android.tv.util.TvUriMatcher; - import com.google.auto.value.AutoValue; - -import dagger.android.ContributesAndroidInjector; -import dagger.android.DaggerContentProvider; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import javax.inject.Inject; - -/** Content provider for local search */ -public class LocalSearchProvider extends DaggerContentProvider { +public class LocalSearchProvider extends ContentProvider { private static final String TAG = "LocalSearchProvider"; private static final boolean DEBUG = false; @@ -87,18 +79,14 @@ public class LocalSearchProvider extends DaggerContentProvider { private static final String NO_LIVE_CONTENTS = "0"; private static final String LIVE_CONTENTS = "1"; - @Inject PerformanceMonitor mPerformanceMonitor; + private PerformanceMonitor mPerformanceMonitor; /** Used only for testing */ private SearchInterface mSearchInterface; @Override public boolean onCreate() { - SafePreDaggerInitializer.init(getContext()); - if (!super.onCreate()) { - Log.e(TAG, "LocalSearchProvider.onCreate() failed."); - return false; - } + mPerformanceMonitor = TvSingletons.getSingletons(getContext()).getPerformanceMonitor(); return true; } @@ -233,13 +221,6 @@ public class LocalSearchProvider extends DaggerContentProvider { throw new UnsupportedOperationException(); } - /** Module for {@link LocalSearchProvider} */ - @dagger.Module - public abstract static class Module { - @ContributesAndroidInjector - abstract LocalSearchProvider contributesLocalSearchProviderInjector(); - } - /** A placeholder to a search result. */ @AutoValue public abstract static class SearchResult { @@ -254,8 +235,6 @@ public class LocalSearchProvider extends DaggerContentProvider { .setProgressPercentage(0); } - public abstract Builder toBuilder(); - @AutoValue.Builder abstract static class Builder { abstract Builder setChannelId(long value); diff --git a/src/com/android/tv/search/ProgramGuideSearchFragment.java b/src/com/android/tv/search/ProgramGuideSearchFragment.java index fa2e4516..6c94bd33 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 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.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 android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; diff --git a/src/com/android/tv/search/TvProviderSearch.java b/src/com/android/tv/search/TvProviderSearch.java index c46938a9..8a1f51f9 100644 --- a/src/com/android/tv/search/TvProviderSearch.java +++ b/src/com/android/tv/search/TvProviderSearch.java @@ -308,7 +308,7 @@ public class TvProviderSearch implements SearchInterface { if (c != null && c.moveToNext() && !isRatingBlocked(c.getString(2))) { String channelName = result.getTitle(); String channelNumber = result.getChannelNumber(); - SearchResult.Builder builder = result.toBuilder(); + SearchResult.Builder builder = SearchResult.builder(); long startUtcMillis = c.getLong(5); long endUtcMillis = c.getLong(6); builder.setTitle(c.getString(0)); diff --git a/src/com/android/tv/setup/SystemSetupActivity.java b/src/com/android/tv/setup/SystemSetupActivity.java index 999b157a..b2160b3a 100644 --- a/src/com/android/tv/setup/SystemSetupActivity.java +++ b/src/com/android/tv/setup/SystemSetupActivity.java @@ -24,9 +24,9 @@ import android.content.Intent; import android.media.tv.TvInputInfo; import android.os.Bundle; import android.widget.Toast; - import com.android.tv.R; import com.android.tv.SetupPassthroughActivity; +import com.android.tv.TvSingletons; import com.android.tv.common.CommonConstants; import com.android.tv.common.ui.setup.SetupActivity; import com.android.tv.common.ui.setup.SetupMultiPaneFragment; @@ -36,11 +36,6 @@ import com.android.tv.util.OnboardingUtils; import com.android.tv.util.SetupUtils; import com.android.tv.util.TvInputManagerHelper; -import dagger.android.AndroidInjection; -import dagger.android.ContributesAndroidInjector; - -import javax.inject.Inject; - /** A activity to start input sources setup fragment for initial setup flow. */ public class SystemSetupActivity extends SetupActivity { private static final String SYSTEM_SETUP = @@ -48,17 +43,18 @@ public class SystemSetupActivity extends SetupActivity { private static final int SHOW_RIPPLE_DURATION_MS = 266; private static final int REQUEST_CODE_START_SETUP_ACTIVITY = 1; - @Inject TvInputManagerHelper mInputManager; + private TvInputManagerHelper mInputManager; @Override protected void onCreate(Bundle savedInstanceState) { - AndroidInjection.inject(this); super.onCreate(savedInstanceState); Intent intent = getIntent(); if (!SYSTEM_SETUP.equals(intent.getAction())) { finish(); return; } + TvSingletons singletons = TvSingletons.getSingletons(this); + mInputManager = singletons.getTvInputManagerHelper(); } @Override @@ -96,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 TV app SetupPassthroughActivity. + // channels should go through Live channels SetupPassthroughActivity. intent.setComponent( new ComponentName(this, SetupPassthroughActivity.class)); try { @@ -128,13 +124,4 @@ public class SystemSetupActivity extends SetupActivity { } return false; } - - /** - * Exports {@link SystemSetupActivity} for Dagger codegen to create the appropriate injector. - */ - @dagger.Module - public abstract static class Module { - @ContributesAndroidInjector - abstract SystemSetupActivity contributeSystemSetupActivity(); - } } diff --git a/src/com/android/tv/ui/AppLayerTvView.java b/src/com/android/tv/ui/AppLayerTvView.java index 4c54fb3c..e2b64a1e 100644 --- a/src/com/android/tv/ui/AppLayerTvView.java +++ b/src/com/android/tv/ui/AppLayerTvView.java @@ -21,6 +21,7 @@ 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; /** @@ -28,14 +29,9 @@ 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. - * - * <p>TODO: remove this class once the TvView.setMain() is revisited. + * uses only application layer. TODO: remove this class once the TvView.setMain() is revisited. */ public class AppLayerTvView extends TvViewCompat { - - boolean mUseSecureSurface = true; - public AppLayerTvView(Context context) { super(context); } @@ -48,11 +44,6 @@ 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; @@ -62,7 +53,7 @@ public class AppLayerTvView extends TvViewCompat { public void onViewAdded(View child) { if (child instanceof SurfaceView) { // Note: See b/29118070 for detail. - ((SurfaceView) child).setSecure(mUseSecureSurface); + ((SurfaceView) child).setSecure(!CommonUtils.isDeveloper()); } super.onViewAdded(child); } diff --git a/src/com/android/tv/ui/ChannelBannerView.java b/src/com/android/tv/ui/ChannelBannerView.java index f0781214..00ac7e32 100644 --- a/src/com/android/tv/ui/ChannelBannerView.java +++ b/src/com/android/tv/ui/ChannelBannerView.java @@ -46,15 +46,13 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; - import com.android.tv.R; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.singletons.HasSingletons; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.StreamInfo; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.parental.ContentRatingsManager; @@ -66,9 +64,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.google.common.collect.ImmutableList; - import javax.inject.Provider; /** A view to render channel banner. */ @@ -122,7 +118,6 @@ 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; @@ -270,12 +265,12 @@ public class ChannelBannerView extends FrameLayout mContentRatingsManager = mTvInputManagerHelper.getContentRatingsManager(); mNoProgram = - new ProgramImpl.Builder() + new Program.Builder() .setTitle(context.getString(R.string.channel_banner_no_title)) .setDescription(EMPTY_STRING) .build(); mLockedChannelProgram = - new ProgramImpl.Builder() + new Program.Builder() .setTitle(context.getString(R.string.channel_banner_locked_channel_title)) .setDescription(EMPTY_STRING) .build(); @@ -283,7 +278,8 @@ public class ChannelBannerView extends FrameLayout sClosedCaptionMark = context.getString(R.string.closed_caption); } mAutoHideScheduler = new AutoHideScheduler(context, this::hide); - mAccessibilityManager = context.getSystemService(AccessibilityManager.class); + context.getSystemService(AccessibilityManager.class) + .addAccessibilityStateChangeListener(mAutoHideScheduler); } @Override @@ -323,18 +319,6 @@ 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) { @@ -564,7 +548,7 @@ public class ChannelBannerView extends FrameLayout return new ImageLoaderCallback<ChannelBannerView>(channelBannerView) { @Override public void onBitmapLoaded(ChannelBannerView view, @Nullable Bitmap logo) { - if (!channel.equals(view.mCurrentChannel)) { + if (channel.equals(view.mCurrentChannel)) { // The logo is obsolete. return; } @@ -751,23 +735,15 @@ public class ChannelBannerView extends FrameLayout } else { ImmutableList<TvContentRating> ratings = (program == null) ? null : program.getContentRatings(); - int ratingsViewIndex = 0; - if (ratings != null) { - for (int i = 0; i < ratings.size(); i++) { - if (ratingsViewIndex < DISPLAYED_CONTENT_RATINGS_COUNT - && !TextUtils.isEmpty( - mContentRatingsManager.getDisplayNameForRating( - ratings.get(i)))) { - mContentRatingsTextViews[ratingsViewIndex].setText( - mContentRatingsManager.getDisplayNameForRating(ratings.get(i))); - mContentRatingsTextViews[ratingsViewIndex].setVisibility(View.VISIBLE); - ratingsViewIndex++; - } + for (int i = 0; i < DISPLAYED_CONTENT_RATINGS_COUNT; i++) { + if (ratings == null || ratings.size() <= i) { + mContentRatingsTextViews[i].setVisibility(View.GONE); + } else { + mContentRatingsTextViews[i].setText( + mContentRatingsManager.getDisplayNameForRating(ratings.get(i))); + mContentRatingsTextViews[i].setVisibility(View.VISIBLE); } } - while (ratingsViewIndex < DISPLAYED_CONTENT_RATINGS_COUNT) { - mContentRatingsTextViews[ratingsViewIndex++].setVisibility(View.GONE); - } } } diff --git a/src/com/android/tv/ui/DetailsActivity.java b/src/com/android/tv/ui/DetailsActivity.java index 92c13f57..80c0f64b 100644 --- a/src/com/android/tv/ui/DetailsActivity.java +++ b/src/com/android/tv/ui/DetailsActivity.java @@ -16,11 +16,12 @@ 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 androidx.leanback.app.DetailsFragment; +import android.support.v17.leanback.app.DetailsFragment; import android.transition.Transition; import android.transition.Transition.TransitionListener; import android.util.Log; @@ -34,12 +35,9 @@ 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 DaggerActivity - implements PinDialogFragment.OnPinCheckedListener { +public class DetailsActivity extends Activity implements PinDialogFragment.OnPinCheckedListener { private static final String TAG = "DetailsActivity"; private static final long INVALID_RECORD_ID = -1; @@ -208,15 +206,4 @@ public class DetailsActivity extends DaggerActivity } 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 3aba5d1d..9685b04b 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 androidx.leanback.app.GuidedStepFragment; -import androidx.leanback.widget.GuidedAction; -import androidx.leanback.widget.GuidedActionsStylist; +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidedAction; +import android.support.v17.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 703dc242..9b916afe 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 androidx.leanback.widget.VerticalGridView; +import android.support.v17.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 bfcebd7d..88a7b2ca 100644 --- a/src/com/android/tv/ui/ProgramDetailsFragment.java +++ b/src/com/android/tv/ui/ProgramDetailsFragment.java @@ -23,23 +23,21 @@ 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 android.text.TextUtils; - -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 com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrManager; @@ -66,7 +64,7 @@ public class ProgramDetailsFragment extends DetailsFragment protected DetailsViewBackgroundHelper mBackgroundHelper; private ArrayObjectAdapter mRowsAdapter; private DetailsOverviewRow mDetailsOverview; - private ProgramImpl mProgram; + private Program mProgram; private String mInputId; private ScheduledRecording mScheduledRecording; private DvrManager mDvrManager; @@ -139,7 +137,7 @@ public class ProgramDetailsFragment extends DetailsFragment * the detail activity and fragment will be ended. */ private boolean onLoadDetails(Bundle args) { - ProgramImpl program = args.getParcelable(DetailsActivity.PROGRAM); + Program program = args.getParcelable(DetailsActivity.PROGRAM); long channelId = args.getLong(DetailsActivity.CHANNEL_ID); String inputId = args.getString(DetailsActivity.INPUT_ID); if (program != null && channelId != Channel.INVALID_ID && !TextUtils.isEmpty(inputId)) { diff --git a/src/com/android/tv/ui/SelectInputView.java b/src/com/android/tv/ui/SelectInputView.java index a0cfad32..f4949f08 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 androidx.leanback.widget.VerticalGridView; -import androidx.recyclerview.widget.RecyclerView; +import android.support.v17.leanback.widget.VerticalGridView; +import android.support.v7.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 a736e79d..5ac6bd83 100644 --- a/src/com/android/tv/ui/TunableTvView.java +++ b/src/com/android/tv/ui/TunableTvView.java @@ -54,13 +54,11 @@ import android.view.View; import android.view.accessibility.AccessibilityManager; import android.widget.FrameLayout; import android.widget.ImageView; - import com.android.tv.InputSessionManager; 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; @@ -69,11 +67,11 @@ import com.android.tv.common.util.CommonUtils; import com.android.tv.common.util.Debug; import com.android.tv.common.util.DurationTimer; import com.android.tv.common.util.PermissionUtils; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; import com.android.tv.data.StreamInfo; import com.android.tv.data.WatchedHistoryManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.features.TvFeatures; import com.android.tv.parental.ContentRatingsManager; import com.android.tv.parental.ParentalControlSettings; @@ -83,9 +81,6 @@ 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; @@ -290,12 +285,12 @@ public class TunableTvView extends FrameLayout implements StreamInfo, TunableTvV if (mVideoWidth <= 0 || mVideoHeight <= 0) { mVideoDisplayAspectRatio = 0.0f; } else { - float videoPixelAspectRatio = + float VideoPixelAspectRatio = track.getVideoPixelAspectRatio(); - mVideoDisplayAspectRatio = (float) mVideoWidth - / mVideoHeight; - mVideoDisplayAspectRatio *= videoPixelAspectRatio > 0 ? - videoPixelAspectRatio : 1; + mVideoDisplayAspectRatio = + VideoPixelAspectRatio + * mVideoWidth + / mVideoHeight; } } else if (type == TvTrackInfo.TYPE_AUDIO) { mAudioChannelCount = track.getAudioChannelCount(); @@ -322,7 +317,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 TV app ends," + "Start up of Live TV ends," + " TunableTvView.onVideoAvailable resets timer"); Debug.getTimer(Debug.TAG_START_UP_TIMER).reset(); Debug.removeTimer(Debug.TAG_START_UP_TIMER); @@ -478,12 +473,8 @@ public class TunableTvView extends FrameLayout implements StreamInfo, TunableTvV } public void initialize( - ProgramDataManager programDataManager, - TvInputManagerHelper tvInputManagerHelper, - LegacyFlags mLegacyFlags) { + ProgramDataManager programDataManager, TvInputManagerHelper tvInputManagerHelper) { mTvView = findViewById(R.id.tv_view); - mTvView.setUseSecureSurface(!BuildConfig.ENG && !mLegacyFlags.enableDeveloperFeatures()); - mProgramDataManager = programDataManager; mInputManagerHelper = tvInputManagerHelper; mContentRatingsManager = tvInputManagerHelper.getContentRatingsManager(); @@ -562,9 +553,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo, TunableTvV } public void setMain() { - if (PermissionUtils.hasChangeHdmiCecActiveSource(getContext())) { - mTvView.setMain(); - } + mTvView.setMain(); } public void setWatchedHistoryManager(WatchedHistoryManager watchedHistoryManager) { @@ -664,22 +653,17 @@ public class TunableTvView extends FrameLayout implements StreamInfo, TunableTvV // To reduce the IPCs, unregister the callback here and register it when necessary. mTvView.setTimeShiftPositionCallback(null); setTimeShiftAvailable(false); + if (needSurfaceSizeUpdate && mFixedSurfaceWidth > 0 && mFixedSurfaceHeight > 0) { + // When the input is changed, TvView recreates its SurfaceView internally. + // So we need to call SurfaceHolder.setFixedSize for the new SurfaceView. + getSurfaceView().getHolder().setFixedSize(mFixedSurfaceWidth, mFixedSurfaceHeight); + } mVideoUnavailableReason = TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING; if (mTvViewSession != null) { mTvViewSession.tune(channel, params, listener); } else { mTvView.tune(mInputInfo.getId(), mCurrentChannel.getUri(), params); } - if (needSurfaceSizeUpdate && mFixedSurfaceWidth > 0 && mFixedSurfaceHeight > 0) { - // When the input is changed, TvView recreates its SurfaceView internally. - // So we need to call SurfaceHolder.setFixedSize for the new SurfaceView. - SurfaceView surfaceView = getSurfaceView(); - if (surfaceView != null) { - surfaceView.getHolder().setFixedSize(mFixedSurfaceWidth, mFixedSurfaceHeight); - } else { - Log.w(TAG, "Failed to set fixed size for surface view: Null surface view"); - } - } updateBlockScreenAndMuting(); if (mOnTuneListener != null) { mOnTuneListener.onStreamInfoChanged(this, true); diff --git a/src/com/android/tv/ui/TvOverlayManager.java b/src/com/android/tv/ui/TvOverlayManager.java index 0ab7c685..b2854a1f 100644 --- a/src/com/android/tv/ui/TvOverlayManager.java +++ b/src/com/android/tv/ui/TvOverlayManager.java @@ -33,7 +33,6 @@ import android.view.Gravity; import android.view.KeyEvent; import android.view.ViewGroup; import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; - import com.android.tv.ChannelTuner; import com.android.tv.MainActivity; import com.android.tv.MainActivity.KeyHandlerResultType; @@ -48,7 +47,6 @@ import com.android.tv.common.ui.setup.OnActionClickListener; import com.android.tv.common.ui.setup.SetupFragment; import com.android.tv.common.ui.setup.SetupMultiPaneFragment; import com.android.tv.data.ChannelDataManager; -import com.android.tv.data.ProgramDataManager; import com.android.tv.dialog.DvrHistoryDialogFragment; import com.android.tv.dialog.FullscreenDialogFragment; import com.android.tv.dialog.HalfSizedDialogFragment; @@ -70,12 +68,6 @@ 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.google.auto.factory.AutoFactory; -import com.google.auto.factory.Provided; - -import com.android.tv.common.flags.LegacyFlags; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -87,7 +79,6 @@ import java.util.Set; /** A class responsible for the life cycle and event handling of the pop-ups over TV view. */ @UiThread -@AutoFactory public class TvOverlayManager implements AccessibilityStateChangeListener { private static final String TAG = "TvOverlayManager"; private static final boolean DEBUG = false; @@ -225,7 +216,6 @@ 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; @@ -239,17 +229,12 @@ public class TvOverlayManager implements AccessibilityStateChangeListener { InputBannerView inputBannerView, SelectInputView selectInputView, ViewGroup sceneContainer, - ProgramGuideSearchFragment searchFragment, - @Provided LegacyFlags legacyFlags, - @Provided ChannelDataManager channelDataManager, - @Provided TvInputManagerHelper tvInputManager, - @Provided ProgramDataManager programDataManager) { + ProgramGuideSearchFragment searchFragment) { mMainActivity = mainActivity; mChannelTuner = channelTuner; TvSingletons singletons = TvSingletons.getSingletons(mainActivity); - mLegacyFlags = legacyFlags; - mChannelDataManager = channelDataManager; - mInputManager = tvInputManager; + mChannelDataManager = singletons.getChannelDataManager(); + mInputManager = singletons.getTvInputManagerHelper(); mTvView = tvView; mChannelBannerView = channelBannerView; mKeypadChannelSwitchView = keypadChannelSwitchView; @@ -286,7 +271,7 @@ public class TvOverlayManager implements AccessibilityStateChangeListener { tvView, optionsManager, menuView, - new MenuRowFactory(mainActivity, tvView, this.mLegacyFlags), + new MenuRowFactory(mainActivity, tvView), new Menu.OnMenuVisibilityChangeListener() { @Override public void onMenuVisibilityChange(boolean visible) { @@ -319,9 +304,9 @@ public class TvOverlayManager implements AccessibilityStateChangeListener { new ProgramGuide( mainActivity, channelTuner, - mInputManager, + singletons.getTvInputManagerHelper(), mChannelDataManager, - programDataManager, + singletons.getProgramDataManager(), dvrDataManager, singletons.getDvrScheduleManager(), singletons.getTracker(), diff --git a/src/com/android/tv/ui/ViewUtils.java b/src/com/android/tv/ui/ViewUtils.java index 431b3113..f64a70b2 100644 --- a/src/com/android/tv/ui/ViewUtils.java +++ b/src/com/android/tv/ui/ViewUtils.java @@ -18,11 +18,9 @@ package com.android.tv.ui; import android.animation.Animator; import android.animation.ValueAnimator; -import android.os.Build; import android.util.Log; import android.view.View; import android.view.ViewGroup.LayoutParams; - import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -35,9 +33,6 @@ public class ViewUtils { } public static void setTransitionAlpha(View v, float alpha) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - v.setTransitionAlpha(alpha); - } Method method; try { method = View.class.getDeclaredMethod("setTransitionAlpha", Float.TYPE); diff --git a/src/com/android/tv/ui/sidepanel/ChannelCheckItem.java b/src/com/android/tv/ui/sidepanel/ChannelCheckItem.java index de3ae751..2726839c 100644 --- a/src/com/android/tv/ui/sidepanel/ChannelCheckItem.java +++ b/src/com/android/tv/ui/sidepanel/ChannelCheckItem.java @@ -19,14 +19,13 @@ package com.android.tv.ui.sidepanel; import android.text.TextUtils; import android.view.View; import android.widget.TextView; - import com.android.tv.R; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.ChannelDataManager.ChannelListener; import com.android.tv.data.OnCurrentProgramUpdatedListener; +import com.android.tv.data.Program; import com.android.tv.data.ProgramDataManager; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; public abstract class ChannelCheckItem extends CompoundButtonItem { private final ChannelDataManager mChannelDataManager; diff --git a/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java b/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java index b62a57ee..62130b64 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 androidx.leanback.widget.VerticalGridView; +import android.support.v17.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 e43568c9..36ee5a2d 100644 --- a/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java +++ b/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java @@ -16,38 +16,29 @@ package com.android.tv.ui.sidepanel; +import android.accounts.Account; import android.app.Activity; - -import com.android.tv.MainActivity; +import android.support.annotation.NonNull; +import android.util.Log; +import android.widget.Toast; import com.android.tv.R; -import com.android.tv.common.BuildConfig; +import com.android.tv.TvSingletons; import com.android.tv.common.CommonPreferences; import com.android.tv.common.feature.CommonFeatures; -import com.android.tv.perf.PerformanceMonitor; +import com.android.tv.common.util.CommonUtils; + -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; +import java.util.ArrayList; +import java.util.List; /** 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(Activity activity) { - AndroidInjection.inject(this); - super.onAttach(activity); - } - @Override protected String getTitle() { return getString(R.string.menu_developer_options); @@ -59,15 +50,8 @@ public class DeveloperOptionFragment extends SideFragment { } @Override - protected ImmutableList<Item> getItemList() { - ImmutableList.Builder<Item> items = ImmutableList.builder(); - if (mAdditionalDeveloperItemsFactory.isPresent()) { - items.addAll( - mAdditionalDeveloperItemsFactory - .get() - .getAdditionalDevItems(getMainActivity())); - items.add(new DividerItem()); - } + protected List<Item> getItemList() { + List<Item> items = new ArrayList<>(); if (CommonFeatures.DVR.isEnabled(getContext())) { items.add( new ActionItem(getString(R.string.dev_item_dvr_history)) { @@ -77,7 +61,7 @@ public class DeveloperOptionFragment extends SideFragment { } }); } - if (BuildConfig.ENG || mLegacyFlags.enableDeveloperFeatures()) { + if (CommonUtils.isDeveloper()) { items.add( new ActionItem(getString(R.string.dev_item_watch_history)) { @Override @@ -103,21 +87,17 @@ public class DeveloperOptionFragment extends SideFragment { CommonPreferences.setStoreTsStream(getContext(), isChecked()); } }); - if (BuildConfig.ENG || mLegacyFlags.enableDeveloperFeatures()) { + if (CommonUtils.isDeveloper()) { items.add( new ActionItem(getString(R.string.dev_item_show_performance_monitor_log)) { @Override protected void onSelected() { - mPerformanceMonitor.startPerformanceMonitorEventDebugActivity( - getContext()); + TvSingletons.getSingletons(getContext()) + .getPerformanceMonitor() + .startPerformanceMonitorEventDebugActivity(getContext()); } }); } - return items.build(); - } - - /** Factory to create additional items. */ - public interface AdditionalDeveloperItemsFactory { - ImmutableList<Item> getAdditionalDevItems(MainActivity mainActivity); + return items; } } diff --git a/src/com/android/tv/ui/sidepanel/SettingsFragment.java b/src/com/android/tv/ui/sidepanel/SettingsFragment.java index 1c03b6a9..aa71fb75 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 TV app settings. */ +/** Shows Live TV 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 703b1e43..590f1300 100644 --- a/src/com/android/tv/ui/sidepanel/SideFragment.java +++ b/src/com/android/tv/ui/sidepanel/SideFragment.java @@ -20,27 +20,24 @@ import android.app.Fragment; import android.content.Context; import android.graphics.drawable.RippleDrawable; import android.os.Bundle; -import androidx.recyclerview.widget.RecyclerView; +import android.support.v17.leanback.widget.VerticalGridView; +import android.support.v7.widget.RecyclerView; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.TextView; - -import androidx.leanback.widget.VerticalGridView; - import com.android.tv.MainActivity; import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.analytics.HasTrackerLabel; import com.android.tv.analytics.Tracker; -import com.android.tv.common.dev.DeveloperPreferences; import com.android.tv.common.util.DurationTimer; +import com.android.tv.common.util.SystemProperties; import com.android.tv.data.ChannelDataManager; import com.android.tv.data.ProgramDataManager; import com.android.tv.util.ViewCache; - import java.util.List; public abstract class SideFragment<T extends Item> extends Fragment implements HasTrackerLabel { @@ -59,7 +56,7 @@ public abstract class SideFragment<T extends Item> extends Fragment implements H new RecyclerView.RecycledViewPool(); private VerticalGridView mListView; - private ItemAdapter<T> mAdapter; + private ItemAdapter mAdapter; private SideFragmentListener mListener; private ChannelDataManager mChannelDataManager; private ProgramDataManager mProgramDataManager; @@ -68,7 +65,6 @@ public abstract class SideFragment<T extends Item> extends Fragment implements H private final int mHideKey; private final int mDebugHideKey; - private Context mContext; public SideFragment() { this(KeyEvent.KEYCODE_UNKNOWN, KeyEvent.KEYCODE_UNKNOWN); @@ -77,7 +73,7 @@ public abstract class SideFragment<T extends Item> extends Fragment implements H /** * @param hideKey the KeyCode used to hide the fragment * @param debugHideKey the KeyCode used to hide the fragment if {@link - * DeveloperPreferences#USE_DEBUG_KEYS}. + * SystemProperties#USE_DEBUG_KEYS}. */ public SideFragment(int hideKey, int debugHideKey) { mHideKey = hideKey; @@ -87,7 +83,6 @@ public abstract class SideFragment<T extends Item> extends Fragment implements H @Override public void onAttach(Context context) { super.onAttach(context); - mContext = context; mChannelDataManager = getMainActivity().getChannelDataManager(); mProgramDataManager = getMainActivity().getProgramDataManager(); mTracker = TvSingletons.getSingletons(context).getTracker(); @@ -134,8 +129,7 @@ public abstract class SideFragment<T extends Item> extends Fragment implements H } public final boolean isHideKeyForThisPanel(int keyCode) { - boolean debugKeysEnabled = - DeveloperPreferences.USE_DEBUG_KEYS.getDefaultIfContextNull(mContext); + boolean debugKeysEnabled = SystemProperties.USE_DEBUG_KEYS.getValue(); return mHideKey != KeyEvent.KEYCODE_UNKNOWN && (mHideKey == keyCode || (debugKeysEnabled && mDebugHideKey == keyCode)); } diff --git a/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java b/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java index 620b7017..b14bf78d 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 androidx.leanback.widget.VerticalGridView; +import android.support.v17.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 60f8425f..d1ae4423 100644 --- a/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java +++ b/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingsFragment.java @@ -16,7 +16,6 @@ package com.android.tv.ui.sidepanel.parentalcontrols; -import android.app.Activity; import android.graphics.drawable.Drawable; import android.media.tv.TvContentRating; import android.os.Bundle; @@ -25,9 +24,9 @@ import android.util.SparseIntArray; import android.view.View; 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,28 +39,18 @@ import com.android.tv.ui.sidepanel.RadioButtonItem; 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; private static final SparseIntArray sDescriptionResourceIdMap; 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); @@ -112,7 +101,8 @@ public class RatingsFragment extends SideFragment { protected List<Item> getItemList() { List<Item> items = new ArrayList<>(); - if (mBlockUnratedItem != null && mLegacyFlags.enableUnratedContentSettings()) { + if (mBlockUnratedItem != null + && Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { items.add(mBlockUnratedItem); items.add(new DividerItem()); } @@ -168,13 +158,7 @@ public class RatingsFragment extends SideFragment { super.onCreate(savedInstanceState); mParentalControlSettings = getMainActivity().getParentalControlSettings(); mParentalControlSettings.loadRatings(); - } - - @Override - public void onAttach(Activity activity) { - AndroidInjection.inject(this); - super.onAttach(activity); - if (mLegacyFlags.enableUnratedContentSettings()) { + if (Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { mBlockUnratedItem = new CheckBoxItem( getResources().getString(R.string.option_block_unrated_programs)) { @@ -195,8 +179,6 @@ public class RatingsFragment extends SideFragment { } } }; - } else { - mBlockUnratedItem = null; } } @@ -253,7 +235,8 @@ public class RatingsFragment extends SideFragment { super.onSelected(); mParentalControlSettings.setContentRatingLevel( getMainActivity().getContentRatingsManager(), mRatingLevel); - if (mBlockUnratedItem != null && mLegacyFlags.enableUnratedContentSettings()) { + if (mBlockUnratedItem != null + && Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) { // set checked if UNRATED is blocked, and set unchecked otherwise. mBlockUnratedItem.setChecked( mParentalControlSettings.isRatingBlocked( diff --git a/src/com/android/tv/util/AsyncDbTask.java b/src/com/android/tv/util/AsyncDbTask.java index 2e9a1ea8..b3523952 100644 --- a/src/com/android/tv/util/AsyncDbTask.java +++ b/src/com/android/tv/util/AsyncDbTask.java @@ -28,23 +28,18 @@ import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; import android.util.Log; import android.util.Range; - import com.android.tv.TvSingletons; import com.android.tv.common.BuildConfig; import com.android.tv.common.SoftPreconditions; import com.android.tv.data.ChannelImpl; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; import com.android.tv.dvr.data.RecordedProgram; - import com.google.common.base.Predicate; - import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; - import javax.inject.Qualifier; /** @@ -128,7 +123,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> return null; } if (Utils.isProgramsUri(mUri) - && TvProviderUtils.checkSeriesIdColumn(context, Programs.CONTENT_URI)) { + && TvProviderUtils.checkSeriesIdColumn(context, Programs.CONTENT_URI)) { mProjection = TvProviderUtils.addExtraColumnsToProjection( mProjection, TvProviderUtils.EXTRA_PROGRAM_COLUMN_SERIES_ID); @@ -328,19 +323,10 @@ public abstract class AsyncDbTask<Params, Progress, Result> } } - /** - * Gets an {@link List} of {@link ProgramImpl}s from {@link TvContract.Programs#CONTENT_URI}. - */ + /** Gets an {@link List} of {@link Program}s from {@link TvContract.Programs#CONTENT_URI}. */ public abstract static class AsyncProgramQueryTask extends AsyncQueryListTask<Program> { public AsyncProgramQueryTask(Executor executor, Context context) { - super( - executor, - context, - Programs.CONTENT_URI, - ProgramImpl.PROJECTION, - null, - null, - null); + super(executor, context, Programs.CONTENT_URI, Program.PROJECTION, null, null, null); } public AsyncProgramQueryTask( @@ -355,7 +341,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> executor, context, uri, - ProgramImpl.PROJECTION, + Program.PROJECTION, selection, selectionArgs, sortOrder, @@ -364,7 +350,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> @Override protected final Program fromCursor(Cursor c) { - return ProgramImpl.fromCursor(c); + return Program.fromCursor(c); } } @@ -390,7 +376,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> } /** - * Gets an {@link List} of {@link ProgramImpl}s for a given channel and period {@link + * Gets an {@link List} of {@link Program}s for a given channel and period {@link * TvContract#buildProgramsUriForChannel(long, long, long)}. If the {@code period} is {@code * null}, then all the programs is queried. */ @@ -424,7 +410,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> } } - /** Gets a single {@link ProgramImpl} from {@link TvContract.Programs#CONTENT_URI}. */ + /** Gets a single {@link Program} from {@link TvContract.Programs#CONTENT_URI}. */ public static class AsyncQueryProgramTask extends AsyncQueryItemTask<Program> { public AsyncQueryProgramTask(Executor executor, Context context, long programId) { @@ -432,7 +418,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> executor, context, TvContract.buildProgramUri(programId), - ProgramImpl.PROJECTION, + Program.PROJECTION, null, null, null); @@ -440,7 +426,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> @Override protected Program fromCursor(Cursor c) { - return ProgramImpl.fromCursor(c); + return Program.fromCursor(c); } } diff --git a/src/com/android/tv/util/OnboardingUtils.java b/src/com/android/tv/util/OnboardingUtils.java index 4fae2f00..3b72e091 100644 --- a/src/com/android/tv/util/OnboardingUtils.java +++ b/src/com/android/tv/util/OnboardingUtils.java @@ -27,9 +27,7 @@ public final class OnboardingUtils { private static final String PREF_KEY_ONBOARDING_VERSION_CODE = "pref_onbaording_versionCode"; private static final int ONBOARDING_VERSION = 1; - // Replace as needed - private static final String MERCHANT_COLLECTION_URL_STRING = - "https://play.google.com/store/apps/collection/promotion_3001bf9_ATV_livechannels"; + private static final String MERCHANT_COLLECTION_URL_STRING = getMerchantCollectionUrl(); /** Intent to show merchant collection in online store. */ public static final Intent ONLINE_STORE_INTENT = @@ -71,5 +69,10 @@ 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 52b3e3e8..a9b67fa8 100644 --- a/src/com/android/tv/util/SetupUtils.java +++ b/src/com/android/tv/util/SetupUtils.java @@ -307,7 +307,8 @@ public class SetupUtils { } /** - * Called when TV app is launched. Once it is called, {@link #isFirstTune} will return false. + * Called when Live channels 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/SqlParams.java b/src/com/android/tv/util/SqlParams.java new file mode 100644 index 00000000..fa557ba2 --- /dev/null +++ b/src/com/android/tv/util/SqlParams.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2017 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.util; + +import android.database.DatabaseUtils; +import android.support.annotation.Nullable; +import java.util.Arrays; + +/** Convenience class for SQL operations. */ +public class SqlParams { + private String mTables; + private @Nullable String mSelection; + private @Nullable String[] mSelectionArgs; + + public SqlParams(String tables, @Nullable String selection, @Nullable String... selectionArgs) { + setTables(tables); + setWhere(selection, selectionArgs); + } + + public String getTables() { + return mTables; + } + + public @Nullable String getSelection() { + return mSelection; + } + + public @Nullable String[] getSelectionArgs() { + return mSelectionArgs; + } + + public void setTables(String tables) { + mTables = tables; + } + + public void setWhere(String selection, String... selectionArgs) { + mSelection = selection; + mSelectionArgs = selectionArgs; + } + + public void appendWhere(String selection, String... selectionArgs) { + mSelection = DatabaseUtils.concatenateWhere(mSelection, selection); + if (selectionArgs != null) { + mSelectionArgs = DatabaseUtils.appendSelectionArgs(mSelectionArgs, selectionArgs); + } + } + + public void appendWhereEquals(String name, String value) { + appendWhere(name + "=?", value); + } + + @Override + public String toString() { + return "tables " + + getTables() + + " where " + + getSelection() + + " with " + + Arrays.toString(getSelectionArgs()); + } +} diff --git a/src/com/android/tv/util/TvInputManagerHelper.java b/src/com/android/tv/util/TvInputManagerHelper.java index 23c9b494..cb7d9854 100644 --- a/src/com/android/tv/util/TvInputManagerHelper.java +++ b/src/com/android/tv/util/TvInputManagerHelper.java @@ -46,8 +46,6 @@ 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.google.common.collect.Ordering; -import com.android.tv.common.flags.LegacyFlags; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -129,7 +127,6 @@ 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"; @@ -161,10 +158,6 @@ 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 = { @@ -299,8 +292,8 @@ public class TvInputManagerHelper { private boolean mAllow3rdPartyInputs; @Inject - public TvInputManagerHelper(@ApplicationContext Context context, LegacyFlags legacyFlags) { - this(context, createTvInputManagerWrapper(context), legacyFlags); + public TvInputManagerHelper(@ApplicationContext Context context) { + this(context, createTvInputManagerWrapper(context)); } @Nullable @@ -312,14 +305,12 @@ public class TvInputManagerHelper { @VisibleForTesting protected TvInputManagerHelper( - Context context, - @Nullable TvInputManagerInterface tvInputManager, - LegacyFlags legacyFlags) { + Context context, @Nullable TvInputManagerInterface tvInputManager) { mContext = context.getApplicationContext(); mPackageManager = context.getPackageManager(); mTvInputManager = tvInputManager; mContentRatingsManager = new ContentRatingsManager(context, tvInputManager); - mParentalControlSettings = new ParentalControlSettings(context, legacyFlags); + mParentalControlSettings = new ParentalControlSettings(context); mTvInputInfoComparator = new InputComparatorInternal(this); mContentObserver = new ContentObserver(mHandler) { @@ -357,6 +348,7 @@ public class TvInputManagerHelper { updateAllow3rdPartyInputs(); mTvInputManager.registerCallback(mInternalCallback, mHandler); initInputMaps(); + mContentRatingsManager.update(); } public void stop() { @@ -454,12 +446,10 @@ public class TvInputManagerHelper { } /** Loads label of {@code info}. */ - @Nullable public String loadLabel(TvInputInfo info) { String label = mTvInputLabels.get(info.getId()); if (label == null) { - CharSequence labelSequence = info.loadLabel(mContext); - label = labelSequence == null ? null : labelSequence.toString(); + label = info.loadLabel(mContext).toString(); mTvInputLabels.put(info.getId(), label); } return label; @@ -713,8 +703,6 @@ public class TvInputManagerHelper { @VisibleForTesting static class InputComparatorInternal implements Comparator<TvInputInfo> { private final TvInputManagerHelper mInputManager; - private static final Ordering<Comparable> NULL_FIRST_STRING_ORDERING = - Ordering.natural().nullsFirst(); public InputComparatorInternal(TvInputManagerHelper inputManager) { mInputManager = inputManager; @@ -725,8 +713,7 @@ public class TvInputManagerHelper { if (mInputManager.isPartnerInput(lhs) != mInputManager.isPartnerInput(rhs)) { return mInputManager.isPartnerInput(lhs) ? -1 : 1; } - return NULL_FIRST_STRING_ORDERING.compare( - mInputManager.loadLabel(lhs), mInputManager.loadLabel(rhs)); + return mInputManager.loadLabel(lhs).compareTo(mInputManager.loadLabel(rhs)); } } @@ -808,7 +795,7 @@ public class TvInputManagerHelper { if (TextUtils.isEmpty(label)) { label = mTvInputManagerHelper.loadLabel(input); } - return label == null ? "" : label; + return label; } private int getPriority(TvInputInfo info) { diff --git a/src/com/android/tv/util/TvProviderUtils.java b/src/com/android/tv/util/TvProviderUtils.java index d931dcd5..6b5aaecc 100644 --- a/src/com/android/tv/util/TvProviderUtils.java +++ b/src/com/android/tv/util/TvProviderUtils.java @@ -27,7 +27,7 @@ import android.support.annotation.StringDef; import android.support.annotation.VisibleForTesting; import android.support.annotation.WorkerThread; import android.util.Log; -import com.android.tv.data.api.BaseProgram; +import com.android.tv.data.BaseProgram; import com.android.tv.features.PartnerFeatures; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -67,9 +67,6 @@ 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; } @@ -115,9 +112,6 @@ 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; } @@ -150,8 +144,8 @@ public final class TvProviderUtils { return TRUE.equals(sRecordedProgramHasStateColumn); } - public static String[] addExtraColumnsToProjection( - String[] projection, @TvProviderExtraColumn String column) { + public static String[] addExtraColumnsToProjection(String[] projection, + @TvProviderExtraColumn String column) { List<String> projectionList = new ArrayList<>(Arrays.asList(projection)); if (!projectionList.contains(column)) { projectionList.add(column); diff --git a/src/com/android/tv/util/TvTrackInfoUtils.java b/src/com/android/tv/util/TvTrackInfoUtils.java index ae30df11..4ec96c62 100644 --- a/src/com/android/tv/util/TvTrackInfoUtils.java +++ b/src/com/android/tv/util/TvTrackInfoUtils.java @@ -17,16 +17,9 @@ package com.android.tv.util; import android.content.Context; import android.media.tv.TvTrackInfo; -import android.os.Build; -import android.os.LocaleList; import android.text.TextUtils; import android.util.Log; - import com.android.tv.R; - -import com.google.common.collect.Iterables; - -import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; import java.util.List; @@ -45,19 +38,17 @@ public class TvTrackInfoUtils { private static final int AUDIO_CHANNEL_SURROUND_8 = 8; /** - * Compares how closely two {@link android.media.tv.TvTrackInfo}s match {@code languages}, - * {@code channelCount} and {@code id} in that precedence. A listed sorted with this comparator - * has the worst matches first. + * Compares how closely two {@link android.media.tv.TvTrackInfo}s match {@code language}, {@code + * channelCount} and {@code id} in that precedence. * * @param id The track id to match. - * @param languages The prioritized list of languages. Languages earlier in the list are a - * better match. + * @param language The language to match. * @param channelCount The channel count to match. * @return -1 if lhs is a worse match, 0 if lhs and rhs match equally and 1 if lhs is a better * match. */ public static Comparator<TvTrackInfo> createComparator( - final String id, final List<String> languages, final int channelCount) { + final String id, final String language, final int channelCount) { return (TvTrackInfo lhs, TvTrackInfo rhs) -> { if (Objects.equals(lhs, rhs)) { return 0; @@ -68,35 +59,26 @@ public class TvTrackInfoUtils { if (rhs == null) { return 1; } - // Find the first language that matches the lhs and rhs tracks. The earlier match is - // better. If there is no match set the index to the size of the language list since - // its the worst match. - int lhsLangIndex = - Iterables.indexOf(languages, s -> Utils.isEqualLanguage(lhs.getLanguage(), s)); - if (lhsLangIndex == -1) { - lhsLangIndex = languages.size(); - } - int rhsLangIndex = - Iterables.indexOf(languages, s -> Utils.isEqualLanguage(rhs.getLanguage(), s)); - if (rhsLangIndex == -1) { - rhsLangIndex = languages.size(); - } - if (lhsLangIndex != rhsLangIndex) { - // Return the track with lower index as best - return Integer.compare(rhsLangIndex, lhsLangIndex); - } - boolean lhsCountMatch = - lhs.getType() != TvTrackInfo.TYPE_AUDIO - || lhs.getAudioChannelCount() == channelCount; - boolean rhsCountMatch = - rhs.getType() != TvTrackInfo.TYPE_AUDIO - || rhs.getAudioChannelCount() == channelCount; - if (lhsCountMatch && rhsCountMatch) { - return Boolean.compare(lhs.getId().equals(id), rhs.getId().equals(id)); - } else if (lhsCountMatch || rhsCountMatch) { - return Boolean.compare(lhsCountMatch, rhsCountMatch); + // Assumes {@code null} language matches to any language since it means user hasn't + // selected any track before or selected a track without language information. + boolean lhsLangMatch = + language == null || Utils.isEqualLanguage(lhs.getLanguage(), language); + boolean rhsLangMatch = + language == null || Utils.isEqualLanguage(rhs.getLanguage(), language); + if (lhsLangMatch && rhsLangMatch) { + boolean lhsCountMatch = + lhs.getType() != TvTrackInfo.TYPE_AUDIO + || lhs.getAudioChannelCount() == channelCount; + boolean rhsCountMatch = + rhs.getType() != TvTrackInfo.TYPE_AUDIO + || rhs.getAudioChannelCount() == channelCount; + if (lhsCountMatch && rhsCountMatch) { + return Boolean.compare(lhs.getId().equals(id), rhs.getId().equals(id)); + } else { + return Boolean.compare(lhsCountMatch, rhsCountMatch); + } } else { - return Integer.compare(lhs.getAudioChannelCount(), rhs.getAudioChannelCount()); + return Boolean.compare(lhsLangMatch, rhsLangMatch); } }; } @@ -115,20 +97,7 @@ public class TvTrackInfoUtils { if (tracks == null) { return null; } - List<String> languages = new ArrayList<>(); - if (language == null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - LocaleList locales = LocaleList.getDefault(); - for (int i = 0; i < locales.size(); i++) { - languages.add(locales.get(i).getLanguage()); - } - } else { - languages.add(Locale.getDefault().getLanguage()); - } - } else { - languages.add(language); - } - Comparator<TvTrackInfo> comparator = createComparator(id, languages, channelCount); + Comparator<TvTrackInfo> comparator = createComparator(id, language, channelCount); TvTrackInfo best = null; for (TvTrackInfo track : tracks) { if (comparator.compare(track, best) > 0) { @@ -159,7 +128,11 @@ public class TvTrackInfoUtils { if (!TextUtils.isEmpty(track.getLanguage())) { language = new Locale(track.getLanguage()).getDisplayName(); } else { - Log.d(TAG, "No language information found for the audio track: " + toString(track)); + Log.d( + TAG, + "No language information found for the audio track: " + + toString(track) + ); } StringBuilder metadata = new StringBuilder(); @@ -234,31 +207,31 @@ public class TvTrackInfoUtils { public static String toString(TvTrackInfo info) { int trackType = info.getType(); return "TvTrackInfo{" - + "type=" - + trackTypeToString(trackType) - + ", id=" - + info.getId() - + ", language=" - + info.getLanguage() - + ", description=" - + info.getDescription() - + (trackType == TvTrackInfo.TYPE_AUDIO - ? (", audioChannelCount=" - + info.getAudioChannelCount() - + ", audioSampleRate=" - + info.getAudioSampleRate()) - : "") - + (trackType == TvTrackInfo.TYPE_VIDEO - ? (", videoWidth=" - + info.getVideoWidth() - + ", videoHeight=" - + info.getVideoHeight() - + ", videoFrameRate=" - + info.getVideoFrameRate() - + ", videoPixelAspectRatio=" - + info.getVideoPixelAspectRatio()) - : "") - + "}"; + + "type=" + + trackTypeToString(trackType) + + ", id=" + + info.getId() + + ", language=" + + info.getLanguage() + + ", description=" + + info.getDescription() + + (trackType == TvTrackInfo.TYPE_AUDIO + ? + (", audioChannelCount=" + + info.getAudioChannelCount() + + ", audioSampleRate=" + + info.getAudioSampleRate()) : "") + + (trackType == TvTrackInfo.TYPE_VIDEO + ? + (", videoWidth=" + + info.getVideoWidth() + + ", videoHeight=" + + info.getVideoHeight() + + ", videoFrameRate=" + + info.getVideoFrameRate() + + ", videoPixelAspectRatio=" + + info.getVideoPixelAspectRatio()) : "") + + "}"; } private TvTrackInfoUtils() {} diff --git a/src/com/android/tv/util/Utils.java b/src/com/android/tv/util/Utils.java index c1f9e935..51173739 100644 --- a/src/com/android/tv/util/Utils.java +++ b/src/com/android/tv/util/Utils.java @@ -39,19 +39,17 @@ import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; import android.view.View; - import com.android.tv.R; import com.android.tv.TvSingletons; import com.android.tv.common.BaseSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.util.Clock; import com.android.tv.data.GenreItems; -import com.android.tv.data.ProgramImpl; +import com.android.tv.data.Program; import com.android.tv.data.StreamInfo; import com.android.tv.data.api.Channel; -import com.android.tv.data.api.Program; - import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; @@ -326,7 +324,7 @@ public class Utils { TvContract.buildChannelUri(channelId), timeMs, timeMs); ContentResolver resolver = context.getContentResolver(); - String[] projection = ProgramImpl.PROJECTION; + String[] projection = Program.PROJECTION; if (TvProviderUtils.checkSeriesIdColumn(context, TvContract.Programs.CONTENT_URI)) { if (Utils.isProgramsUri(uri)) { projection = @@ -336,7 +334,7 @@ public class Utils { } try (Cursor cursor = resolver.query(uri, projection, null, null, null)) { if (cursor != null && cursor.moveToNext()) { - return ProgramImpl.fromCursor(cursor); + return Program.fromCursor(cursor); } } return null; @@ -605,7 +603,6 @@ public class Utils { } /** Returns the label for a given input. Returns the custom label, if any. */ - @Nullable public static String loadLabel(Context context, TvInputInfo input) { if (input == null) { return null; @@ -615,7 +612,7 @@ public class Utils { CharSequence customLabel = inputManager.loadCustomLabel(input); String label = (customLabel == null) ? null : customLabel.toString(); if (TextUtils.isEmpty(label)) { - label = inputManager.loadLabel(input); + label = inputManager.loadLabel(input).toString(); } return label; } @@ -717,6 +714,33 @@ public class Utils { return context.createConfigurationContext(config).getText(resourceId); } + /** Checks where there is any internal TV input. */ + public static boolean hasInternalTvInputs(Context context, boolean tunerInputOnly) { + for (TvInputInfo input : + TvSingletons.getSingletons(context) + .getTvInputManagerHelper() + .getTvInputInfos(true, tunerInputOnly)) { + if (isInternalTvInput(context, input.getId())) { + return true; + } + } + return false; + } + + /** Returns the internal TV inputs. */ + public static List<TvInputInfo> getInternalTvInputs(Context context, boolean tunerInputOnly) { + List<TvInputInfo> inputs = new ArrayList<>(); + for (TvInputInfo input : + TvSingletons.getSingletons(context) + .getTvInputManagerHelper() + .getTvInputInfos(true, tunerInputOnly)) { + if (isInternalTvInput(context, input.getId())) { + inputs.add(input); + } + } + return inputs; + } + /** Checks whether the input is internal or not. */ public static boolean isInternalTvInput(Context context, String inputId) { ComponentName unflattenInputId = ComponentName.unflattenFromString(inputId); diff --git a/src/com/android/tv/util/account/AccountHelper.java b/src/com/android/tv/util/account/AccountHelper.java index d54c2f56..e98b42ec 100644 --- a/src/com/android/tv/util/account/AccountHelper.java +++ b/src/com/android/tv/util/account/AccountHelper.java @@ -35,11 +35,4 @@ 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 e97cc3f2..58fbd27e 100644 --- a/src/com/android/tv/util/account/AccountHelperImpl.java +++ b/src/com/android/tv/util/account/AccountHelperImpl.java @@ -21,12 +21,8 @@ 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"; @@ -35,8 +31,7 @@ public class AccountHelperImpl implements com.android.tv.util.account.AccountHel @Nullable private Account mSelectedAccount; - @Inject - public AccountHelperImpl(@ApplicationContext Context context) { + public AccountHelperImpl(Context context) { mContext = context.getApplicationContext(); mDefaultPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); } @@ -103,9 +98,4 @@ 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 e026f26a..d2ad0eb1 100644 --- a/src/com/android/tv/util/images/ImageLoader.java +++ b/src/com/android/tv/util/images/ImageLoader.java @@ -29,13 +29,9 @@ 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; - import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Map; @@ -168,8 +164,8 @@ public final class ImageLoader { * @return {@code true} if the load is complete and the callback is executed. */ @UiThread - public static <T> boolean loadBitmap( - Context context, String uriString, ImageLoaderCallback<T> callback) { + public static boolean loadBitmap( + Context context, String uriString, ImageLoaderCallback callback) { return loadBitmap(context, uriString, Integer.MAX_VALUE, Integer.MAX_VALUE, callback); } @@ -182,12 +178,12 @@ public final class ImageLoader { * @return {@code true} if the load is complete and the callback is executed. */ @UiThread - public static <T> boolean loadBitmap( + public static boolean loadBitmap( Context context, String uriString, int maxWidth, int maxHeight, - ImageLoaderCallback<T> callback) { + ImageLoaderCallback callback) { if (DEBUG) { Log.d(TAG, "loadBitmap() " + uriString); } @@ -195,12 +191,12 @@ public final class ImageLoader { context, uriString, maxWidth, maxHeight, callback, IMAGE_THREAD_POOL_EXECUTOR); } - private static <T> boolean doLoadBitmap( + private static boolean doLoadBitmap( Context context, String uriString, int maxWidth, int maxHeight, - ImageLoaderCallback<T> callback, + ImageLoaderCallback callback, Executor executor) { // Check the cache before creating a Task. The cache will be checked again in doLoadBitmap // but checking a cache is much cheaper than creating an new task. @@ -226,8 +222,7 @@ public final class ImageLoader { * @return {@code true} if the load is complete and the callback is executed. */ @UiThread - public static <T> boolean loadBitmap( - ImageLoaderCallback<T> callback, LoadBitmapTask<T> loadBitmapTask) { + public static boolean loadBitmap(ImageLoaderCallback callback, LoadBitmapTask loadBitmapTask) { if (DEBUG) { Log.d(TAG, "loadBitmap() " + loadBitmapTask); } @@ -236,8 +231,8 @@ public final class ImageLoader { /** @return {@code true} if the load is complete and the callback is executed. */ @UiThread - private static <T> boolean doLoadBitmap( - ImageLoaderCallback<T> callback, Executor executor, LoadBitmapTask<T> loadBitmapTask) { + private static boolean doLoadBitmap( + ImageLoaderCallback callback, Executor executor, LoadBitmapTask loadBitmapTask) { ScaledBitmapInfo bitmapInfo = loadBitmapTask.getFromCache(); boolean needToReload = loadBitmapTask.isReloadNeeded(); if (bitmapInfo != null && !needToReload) { @@ -272,11 +267,11 @@ public final class ImageLoader { * * <p>Implement {@link #doGetBitmapInBackground} to do the actual loading. */ - public abstract static class LoadBitmapTask<T> extends AsyncTask<Void, Void, ScaledBitmapInfo> { + public abstract static class LoadBitmapTask extends AsyncTask<Void, Void, ScaledBitmapInfo> { protected final Context mAppContext; protected final int mMaxWidth; protected final int mMaxHeight; - private final Set<ImageLoaderCallback<T>> mCallbacks = new ArraySet<>(); + private final Set<ImageLoaderCallback> mCallbacks = new ArraySet<>(); private final ImageCache mImageCache; private final String mKey; @@ -358,7 +353,7 @@ public final class ImageLoader { public final void onPostExecute(ScaledBitmapInfo scaledBitmapInfo) { if (DEBUG) Log.d(ImageLoader.TAG, "Bitmap is loaded " + mKey); - for (ImageLoader.ImageLoaderCallback<T> callback : mCallbacks) { + for (ImageLoader.ImageLoaderCallback callback : mCallbacks) { callback.onBitmapLoaded(scaledBitmapInfo == null ? null : scaledBitmapInfo.bitmap); } ImageLoader.sPendingListMap.remove(mKey); @@ -381,7 +376,7 @@ public final class ImageLoader { } } - private static final class LoadBitmapFromUriTask<T> extends LoadBitmapTask<T> { + private static final class LoadBitmapFromUriTask extends LoadBitmapTask { private LoadBitmapFromUriTask( Context context, ImageCache imageCache, @@ -400,7 +395,7 @@ public final class ImageLoader { } /** Loads and caches the logo for a given {@link TvInputInfo} */ - public static final class LoadTvInputLogoTask<T> extends LoadBitmapTask<T> { + public static final class LoadTvInputLogoTask extends LoadBitmapTask { private final TvInputInfo mInfo; public LoadTvInputLogoTask(Context context, ImageCache cache, TvInputInfo info) { @@ -419,10 +414,9 @@ public final class ImageLoader { @Override public ScaledBitmapInfo doGetBitmapInBackground() { Drawable drawable = mInfo.loadIcon(mAppContext); - Bitmap bm = - drawable instanceof BitmapDrawable - ? ((BitmapDrawable) drawable).getBitmap() - : BitmapUtils.drawableToBitmap(drawable); + Bitmap bm = drawable instanceof BitmapDrawable + ? ((BitmapDrawable) drawable).getBitmap() + : BitmapUtils.drawableToBitmap(drawable); return bm == null ? null : BitmapUtils.createScaledBitmapInfo(getKey(), bm, mMaxWidth, mMaxHeight); @@ -434,46 +428,6 @@ 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()); |