diff options
Diffstat (limited to 'src/com/android/tv/guide/ProgramTableAdapter.java')
-rw-r--r-- | src/com/android/tv/guide/ProgramTableAdapter.java | 172 |
1 files changed, 88 insertions, 84 deletions
diff --git a/src/com/android/tv/guide/ProgramTableAdapter.java b/src/com/android/tv/guide/ProgramTableAdapter.java index e4a67972..99f853b1 100644 --- a/src/com/android/tv/guide/ProgramTableAdapter.java +++ b/src/com/android/tv/guide/ProgramTableAdapter.java @@ -45,19 +45,21 @@ import android.view.ViewGroup; import android.view.ViewParent; import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.android.tv.R; import com.android.tv.TvApplication; +import com.android.tv.common.TvCommonUtils; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.data.Channel; import com.android.tv.data.Program; import com.android.tv.data.Program.CriticScore; import com.android.tv.dvr.DvrDataManager; import com.android.tv.dvr.DvrManager; -import com.android.tv.dvr.ScheduledRecording; +import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.guide.ProgramManager.TableEntriesUpdatedListener; import com.android.tv.parental.ParentalControlSettings; import com.android.tv.ui.HardwareLayerAnimatorListenerAdapter; @@ -73,7 +75,7 @@ import java.util.List; /** * Adapts the {@link ProgramListAdapter} list to the body of the program guide table. */ -public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.ProgramRowHolder> +class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.ProgramRowViewHolder> implements ProgramManager.TableEntryChangedListener { private static final String TAG = "ProgramTableAdapter"; private static final boolean DEBUG = false; @@ -112,8 +114,7 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte private final int mDvrPaddingStartWithTrack; private final int mDvrPaddingStartWithOutTrack; - public ProgramTableAdapter(Context context, ProgramManager programManager, - ProgramGuide programGuide) { + ProgramTableAdapter(Context context, ProgramGuide programGuide) { mContext = context; mAccessibilityManager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); @@ -125,8 +126,8 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte mDvrManager = null; mDvrDataManager = null; } - mProgramManager = programManager; mProgramGuide = programGuide; + mProgramManager = programGuide.getProgramManager(); Resources res = context.getResources(); mChannelLogoWidth = res.getDimensionPixelSize( @@ -193,7 +194,7 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte mProgramListAdapters.clear(); for (int i = 0; i < mProgramManager.getChannelCount(); i++) { ProgramListAdapter listAdapter = new ProgramListAdapter(mContext.getResources(), - mProgramManager, i); + mProgramGuide, i); mProgramManager.addTableEntriesUpdatedListener(listAdapter); mProgramListAdapters.add(listAdapter); } @@ -211,12 +212,12 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte } @Override - public void onBindViewHolder(ProgramRowHolder holder, int position) { + public void onBindViewHolder(ProgramRowViewHolder holder, int position) { holder.onBind(position); } @Override - public void onBindViewHolder(ProgramRowHolder holder, int position, List<Object> payloads) { + public void onBindViewHolder(ProgramRowViewHolder holder, int position, List<Object> payloads) { if (!payloads.isEmpty()) { holder.updateDetailView(); } else { @@ -225,11 +226,11 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte } @Override - public ProgramRowHolder onCreateViewHolder(ViewGroup parent, int viewType) { + public ProgramRowViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false); ProgramRow programRow = (ProgramRow) itemView.findViewById(R.id.row); programRow.setRecycledViewPool(mRecycledViewPool); - return new ProgramRowHolder(itemView); + return new ProgramRowViewHolder(itemView); } @Override @@ -241,18 +242,7 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte notifyItemChanged(channelIndex, true); } - @Override - public void onViewAttachedToWindow(ProgramRowHolder holder) { - holder.onAttachedToWindow(); - } - - @Override - public void onViewDetachedFromWindow(ProgramRowHolder holder) { - holder.onDetachedFromWindow(); - } - - // TODO: make it static - public class ProgramRowHolder extends RecyclerView.ViewHolder + class ProgramRowViewHolder extends RecyclerView.ViewHolder implements ProgramRow.ChildFocusListener { private final ViewGroup mContainer; @@ -269,6 +259,12 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte } } }; + private final Runnable mUpdateDetailViewRunnable = new Runnable() { + @Override + public void run() { + updateDetailView(); + } + }; private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() { @@ -282,8 +278,9 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte new ViewTreeObserver.OnGlobalFocusChangeListener() { @Override public void onGlobalFocusChanged(View oldFocus, View newFocus) { - onChildFocus(isChild(oldFocus) ? oldFocus : null, - isChild(newFocus) ? newFocus : null); + onChildFocus( + GuideUtils.isDescendant(mContainer, oldFocus) ? oldFocus : null, + GuideUtils.isDescendant(mContainer, newFocus) ? newFocus : null); } }; @@ -312,11 +309,38 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte private final ImageView mInputLogoView; private boolean mIsInputLogoVisible; + private AccessibilityStateChangeListener mAccessibilityStateChangeListener = + new AccessibilityManager.AccessibilityStateChangeListener() { + @Override + public void onAccessibilityStateChanged(boolean enable) { + enable &= !TvCommonUtils.isRunningInTest(); + mDetailView.setFocusable(enable); + mChannelHeaderView.setFocusable(enable); + } + }; - public ProgramRowHolder(View itemView) { + ProgramRowViewHolder(View itemView) { super(itemView); mContainer = (ViewGroup) itemView; + mContainer.addOnAttachStateChangeListener( + new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + mContainer.getViewTreeObserver() + .addOnGlobalFocusChangeListener(mGlobalFocusChangeListener); + mAccessibilityManager.addAccessibilityStateChangeListener( + mAccessibilityStateChangeListener); + } + + @Override + public void onViewDetachedFromWindow(View v) { + mContainer.getViewTreeObserver() + .removeOnGlobalFocusChangeListener(mGlobalFocusChangeListener); + mAccessibilityManager.removeAccessibilityStateChangeListener( + mAccessibilityStateChangeListener); + } + }); mProgramRow = (ProgramRow) mContainer.findViewById(R.id.row); mDetailView = (ViewGroup) mContainer.findViewById(R.id.detail); @@ -339,23 +363,18 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte mChannelLogoView = (ImageView) mContainer.findViewById(R.id.channel_logo); mChannelBlockView = (ImageView) mContainer.findViewById(R.id.channel_block); mInputLogoView = (ImageView) mContainer.findViewById(R.id.input_logo); - mDetailView.setFocusable(mAccessibilityManager.isEnabled()); - mChannelHeaderView.setFocusable(mAccessibilityManager.isEnabled()); - mAccessibilityManager.addAccessibilityStateChangeListener( - new AccessibilityManager.AccessibilityStateChangeListener() { - @Override - public void onAccessibilityStateChanged(boolean enable) { - mDetailView.setFocusable(enable); - mChannelHeaderView.setFocusable(enable); - } - }); + + boolean accessibilityEnabled = mAccessibilityManager.isEnabled() + && !TvCommonUtils.isRunningInTest(); + mDetailView.setFocusable(accessibilityEnabled); + mChannelHeaderView.setFocusable(accessibilityEnabled); } public void onBind(int position) { onBindChannel(mProgramManager.getChannel(position)); mProgramRow.swapAdapter(mProgramListAdapters.get(position), true); - mProgramRow.setProgramManager(mProgramManager); + mProgramRow.setProgramGuide(mProgramGuide); mProgramRow.setChannel(mProgramManager.getChannel(position)); mProgramRow.setChildFocusListener(this); mProgramRow.resetScroll(mProgramGuide.getTimelineRowScrollOffset()); @@ -416,24 +435,11 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte } } - public boolean isChild(View view) { - if (view == null) { - return false; - } - for (ViewParent p = view.getParent(); p != null; p = p.getParent()) { - if (p == mContainer) { - return true; - } - } - return false; - } - @Override public void onChildFocus(View oldFocus, View newFocus) { if (newFocus == null) { return; - } - // When the accessibility service is enabled, focus might be put on channel's header or + } // When the accessibility service is enabled, focus might be put on channel's header or // detail view, besides program items. if (newFocus == mChannelHeaderView) { mSelectedEntry = ((ProgramItemView) mProgramRow.getChildAt(0)).getTableEntry(); @@ -443,7 +449,15 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte mSelectedEntry = ((ProgramItemView) newFocus).getTableEntry(); } if (oldFocus == null) { - updateDetailView(); + // Focus moved from other row. + if (mProgramGuide.getProgramGrid().isInLayout()) { + // We need to post runnable to avoid updating detail view when + // the recycler view is in layout, which may cause detail view not + // laid out according to the updated contents. + mHandler.post(mUpdateDetailViewRunnable); + } else { + updateDetailView(); + } return; } @@ -508,16 +522,6 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte }); } - private void onAttachedToWindow() { - mContainer.getViewTreeObserver() - .addOnGlobalFocusChangeListener(mGlobalFocusChangeListener); - } - - private void onDetachedFromWindow() { - mContainer.getViewTreeObserver() - .removeOnGlobalFocusChangeListener(mGlobalFocusChangeListener); - } - private void updateDetailView() { if (mSelectedEntry == null) { // The view holder is never on focus before. @@ -556,10 +560,8 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte program.getStartTimeUtcMillis(), program.getEndTimeUtcMillis(), false)); - boolean trackMetaDataVisible = false; - trackMetaDataVisible |= - updateTextView(mAspectRatioView, Utils.getAspectRatioString( - program.getVideoWidth(), program.getVideoHeight())); + boolean trackMetaDataVisible = updateTextView(mAspectRatioView, Utils + .getAspectRatioString(program.getVideoWidth(), program.getVideoHeight())); int videoDefinitionLevel = Utils.getVideoDefinitionLevelFromSize( program.getVideoWidth(), program.getVideoHeight()); @@ -658,7 +660,9 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte if (TextUtils.isEmpty(name)) { return mContext.getString(R.string.program_guide_content_locked); } else { - return mContext.getString(R.string.program_guide_content_locked_format, name); + return TvContentRating.UNRATED.equals(blockedRating) + ? mContext.getString(R.string.program_guide_content_locked_unrated) + : mContext.getString(R.string.program_guide_content_locked_format, name); } } @@ -666,7 +670,7 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte * Update tv input logo. It should be called when the visible child item in ProgramGrid * changed. */ - public void updateInputLogo(int lastPosition, boolean forceShow) { + void updateInputLogo(int lastPosition, boolean forceShow) { if (mChannel == null) { mInputLogoView.setVisibility(View.GONE); mIsInputLogoVisible = false; @@ -731,7 +735,7 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte mInputLogoView.setVisibility(View.VISIBLE); } - private void updateCriticScoreView(ProgramRowHolder holder, final long programId, + private void updateCriticScoreView(ProgramRowViewHolder holder, final long programId, CriticScore criticScore, View view) { TextView criticScoreSource = (TextView) view.findViewById(R.id.critic_score_source); TextView criticScoreText = (TextView) view.findViewById(R.id.critic_score_score); @@ -759,11 +763,11 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte } } - private static ImageLoaderCallback<ProgramRowHolder> createCriticScoreLogoCallback( - ProgramRowHolder holder, final long programId, ImageView logoView) { - return new ImageLoaderCallback<ProgramRowHolder>(holder) { + private static ImageLoaderCallback<ProgramRowViewHolder> createCriticScoreLogoCallback( + ProgramRowViewHolder holder, final long programId, ImageView logoView) { + return new ImageLoaderCallback<ProgramRowViewHolder>(holder) { @Override - public void onBitmapLoaded(ProgramRowHolder holder, @Nullable Bitmap logoImage) { + public void onBitmapLoaded(ProgramRowViewHolder holder, @Nullable Bitmap logoImage) { if (logoImage == null || holder.mSelectedEntry == null || holder.mSelectedEntry.program == null || holder.mSelectedEntry.program.getId() != programId) { @@ -776,11 +780,11 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte }; } - private static ImageLoaderCallback<ProgramRowHolder> createProgramPosterArtCallback( - ProgramRowHolder holder, final Program program) { - return new ImageLoaderCallback<ProgramRowHolder>(holder) { + private static ImageLoaderCallback<ProgramRowViewHolder> createProgramPosterArtCallback( + ProgramRowViewHolder holder, final Program program) { + return new ImageLoaderCallback<ProgramRowViewHolder>(holder) { @Override - public void onBitmapLoaded(ProgramRowHolder holder, @Nullable Bitmap posterArt) { + public void onBitmapLoaded(ProgramRowViewHolder holder, @Nullable Bitmap posterArt) { if (posterArt == null || holder.mSelectedEntry == null || holder.mSelectedEntry.program == null) { return; @@ -794,11 +798,11 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte }; } - private static ImageLoaderCallback<ProgramRowHolder> createChannelLogoLoadedCallback( - ProgramRowHolder holder, final long channelId) { - return new ImageLoaderCallback<ProgramRowHolder>(holder) { + private static ImageLoaderCallback<ProgramRowViewHolder> createChannelLogoLoadedCallback( + ProgramRowViewHolder holder, final long channelId) { + return new ImageLoaderCallback<ProgramRowViewHolder>(holder) { @Override - public void onBitmapLoaded(ProgramRowHolder holder, @Nullable Bitmap logo) { + public void onBitmapLoaded(ProgramRowViewHolder holder, @Nullable Bitmap logo) { if (logo == null || holder.mChannel == null || holder.mChannel.getId() != channelId) { return; @@ -808,11 +812,11 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte }; } - private static ImageLoaderCallback<ProgramRowHolder> createTvInputLogoLoadedCallback( - final TvInputInfo info, ProgramRowHolder holder) { - return new ImageLoaderCallback<ProgramRowHolder>(holder) { + private static ImageLoaderCallback<ProgramRowViewHolder> createTvInputLogoLoadedCallback( + final TvInputInfo info, ProgramRowViewHolder holder) { + return new ImageLoaderCallback<ProgramRowViewHolder>(holder) { @Override - public void onBitmapLoaded(ProgramRowHolder holder, @Nullable Bitmap logo) { + public void onBitmapLoaded(ProgramRowViewHolder holder, @Nullable Bitmap logo) { if (logo != null && holder.mChannel != null && info.getId() .equals(holder.mChannel.getInputId())) { holder.updateInputLogoInternal(logo); |