1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tv.dvr.ui; 18 19 import android.annotation.TargetApi; 20 import android.app.FragmentManager; 21 import android.content.Context; 22 import android.graphics.Typeface; 23 import android.os.Build; 24 import android.os.Bundle; 25 import androidx.leanback.widget.GuidanceStylist.Guidance; 26 import androidx.leanback.widget.GuidedAction; 27 import androidx.leanback.widget.GuidedActionsStylist; 28 import android.view.View; 29 import android.widget.ImageView; 30 import android.widget.TextView; 31 import com.android.tv.R; 32 import com.android.tv.TvSingletons; 33 import com.android.tv.dvr.DvrDataManager; 34 import com.android.tv.dvr.DvrManager; 35 import com.android.tv.dvr.DvrScheduleManager; 36 import com.android.tv.dvr.data.SeriesRecording; 37 import java.util.ArrayList; 38 import java.util.List; 39 40 /** Fragment for DVR series recording settings. */ 41 @TargetApi(Build.VERSION_CODES.N) 42 @SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated 43 public class DvrPrioritySettingsFragment extends TrackedGuidedStepFragment { 44 /** Name of series recording id starting the fragment. Type: Long */ 45 public static final String COME_FROM_SERIES_RECORDING_ID = "series_recording_id"; 46 47 private static final int ONE_TIME_RECORDING_ID = 0; 48 // button action's IDs are negative. 49 private static final long ACTION_ID_SAVE = -100L; 50 51 private final List<SeriesRecording> mSeriesRecordings = new ArrayList<>(); 52 53 private SeriesRecording mSelectedRecording; 54 private SeriesRecording mComeFromSeriesRecording; 55 private float mSelectedActionElevation; 56 private int mActionColor; 57 private int mSelectedActionColor; 58 59 @Override onAttach(Context context)60 public void onAttach(Context context) { 61 super.onAttach(context); 62 mSeriesRecordings.clear(); 63 mSeriesRecordings.add( 64 new SeriesRecording.Builder() 65 .setTitle(getString(R.string.dvr_priority_action_one_time_recording)) 66 .setPriority(Long.MAX_VALUE) 67 .setId(ONE_TIME_RECORDING_ID) 68 .build()); 69 DvrDataManager dvrDataManager = TvSingletons.getSingletons(context).getDvrDataManager(); 70 long comeFromSeriesRecordingId = getArguments().getLong(COME_FROM_SERIES_RECORDING_ID, -1); 71 for (SeriesRecording series : dvrDataManager.getSeriesRecordings()) { 72 if (series.getState() == SeriesRecording.STATE_SERIES_NORMAL 73 || series.getId() == comeFromSeriesRecordingId) { 74 mSeriesRecordings.add(series); 75 } 76 } 77 mSeriesRecordings.sort(SeriesRecording.PRIORITY_COMPARATOR); 78 mComeFromSeriesRecording = dvrDataManager.getSeriesRecording(comeFromSeriesRecordingId); 79 mSelectedActionElevation = getResources().getDimension(R.dimen.card_elevation_normal); 80 mActionColor = getResources().getColor(R.color.dvr_guided_step_action_text_color, null); 81 mSelectedActionColor = 82 getResources().getColor(R.color.dvr_guided_step_action_text_color_selected, null); 83 } 84 85 @Override onResume()86 public void onResume() { 87 super.onResume(); 88 setSelectedActionPosition( 89 mComeFromSeriesRecording == null 90 ? 1 91 : mSeriesRecordings.indexOf(mComeFromSeriesRecording)); 92 } 93 94 @Override onCreateGuidance(Bundle savedInstanceState)95 public Guidance onCreateGuidance(Bundle savedInstanceState) { 96 String breadcrumb = 97 mComeFromSeriesRecording == null ? null : mComeFromSeriesRecording.getTitle(); 98 return new Guidance( 99 getString(R.string.dvr_priority_title), 100 getString(R.string.dvr_priority_description), 101 breadcrumb, 102 null); 103 } 104 105 @Override onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState)106 public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) { 107 int position = 0; 108 for (SeriesRecording seriesRecording : mSeriesRecordings) { 109 actions.add( 110 new GuidedAction.Builder(getActivity()) 111 .id(position++) 112 .title(seriesRecording.getTitle()) 113 .build()); 114 } 115 } 116 117 @Override onCreateButtonActions(List<GuidedAction> actions, Bundle savedInstanceState)118 public void onCreateButtonActions(List<GuidedAction> actions, Bundle savedInstanceState) { 119 actions.add( 120 new GuidedAction.Builder(getActivity()) 121 .id(ACTION_ID_SAVE) 122 .title(getString(R.string.dvr_priority_button_action_save)) 123 .build()); 124 actions.add( 125 new GuidedAction.Builder(getActivity()) 126 .clickAction(GuidedAction.ACTION_ID_CANCEL) 127 .build()); 128 } 129 130 @Override onTrackedGuidedActionClicked(GuidedAction action)131 public void onTrackedGuidedActionClicked(GuidedAction action) { 132 long actionId = action.getId(); 133 if (actionId == ACTION_ID_SAVE) { 134 DvrManager dvrManager = TvSingletons.getSingletons(getContext()).getDvrManager(); 135 int size = mSeriesRecordings.size(); 136 for (int i = 1; i < size; ++i) { 137 long priority = DvrScheduleManager.suggestSeriesPriority(size - i); 138 SeriesRecording seriesRecording = mSeriesRecordings.get(i); 139 if (seriesRecording.getPriority() != priority) { 140 dvrManager.updateSeriesRecording( 141 SeriesRecording.buildFrom(seriesRecording) 142 .setPriority(priority) 143 .build()); 144 } 145 } 146 FragmentManager fragmentManager = getFragmentManager(); 147 fragmentManager.popBackStack(); 148 } else if (actionId == GuidedAction.ACTION_ID_CANCEL) { 149 FragmentManager fragmentManager = getFragmentManager(); 150 fragmentManager.popBackStack(); 151 } else if (mSelectedRecording == null) { 152 mSelectedRecording = mSeriesRecordings.get((int) actionId); 153 for (int i = 0; i < mSeriesRecordings.size(); ++i) { 154 updateItem(i); 155 } 156 } else { 157 mSelectedRecording = null; 158 for (int i = 0; i < mSeriesRecordings.size(); ++i) { 159 updateItem(i); 160 } 161 } 162 } 163 164 @Override getTrackerPrefix()165 public String getTrackerPrefix() { 166 return "DvrPrioritySettingsFragment"; 167 } 168 169 @Override getTrackerLabelForGuidedAction(GuidedAction action)170 public String getTrackerLabelForGuidedAction(GuidedAction action) { 171 long actionId = action.getId(); 172 if (actionId == ACTION_ID_SAVE) { 173 return "save"; 174 } else { 175 return super.getTrackerLabelForGuidedAction(action); 176 } 177 } 178 179 @Override onGuidedActionFocused(GuidedAction action)180 public void onGuidedActionFocused(GuidedAction action) { 181 super.onGuidedActionFocused(action); 182 if (mSelectedRecording == null) { 183 return; 184 } 185 if (action.getId() < 0) { 186 mSelectedRecording = null; 187 for (int i = 0; i < mSeriesRecordings.size(); ++i) { 188 updateItem(i); 189 } 190 return; 191 } 192 int position = (int) action.getId(); 193 int previousPosition = mSeriesRecordings.indexOf(mSelectedRecording); 194 mSeriesRecordings.remove(mSelectedRecording); 195 mSeriesRecordings.add(position, mSelectedRecording); 196 updateItem(previousPosition); 197 updateItem(position); 198 notifyActionChanged(previousPosition); 199 notifyActionChanged(position); 200 } 201 202 @Override onCreateButtonActionsStylist()203 public GuidedActionsStylist onCreateButtonActionsStylist() { 204 return new DvrGuidedActionsStylist(true); 205 } 206 207 @Override onCreateActionsStylist()208 public GuidedActionsStylist onCreateActionsStylist() { 209 return new DvrGuidedActionsStylist(false) { 210 @Override 211 public void onBindViewHolder(ViewHolder vh, GuidedAction action) { 212 super.onBindViewHolder(vh, action); 213 updateItem(vh.itemView, (int) action.getId()); 214 } 215 216 @Override 217 public int onProvideItemLayoutId() { 218 return R.layout.priority_settings_action_item; 219 } 220 }; 221 } 222 223 private void updateItem(int position) { 224 View itemView = getActionItemView(position); 225 if (itemView == null) { 226 return; 227 } 228 updateItem(itemView, position); 229 } 230 231 private void updateItem(View itemView, int position) { 232 GuidedAction action = getActions().get(position); 233 action.setTitle(mSeriesRecordings.get(position).getTitle()); 234 boolean selected = 235 mSelectedRecording != null 236 && mSeriesRecordings.indexOf(mSelectedRecording) == position; 237 TextView titleView = (TextView) itemView.findViewById(R.id.guidedactions_item_title); 238 ImageView imageView = (ImageView) itemView.findViewById(R.id.guidedactions_item_tail_image); 239 if (position == 0) { 240 // one-time recording 241 itemView.setBackgroundResource(R.drawable.setup_selector_background); 242 imageView.setVisibility(View.GONE); 243 itemView.setFocusable(false); 244 itemView.setElevation(0); 245 // strings.xml <i> tag doesn't work. 246 titleView.setTypeface(titleView.getTypeface(), Typeface.ITALIC); 247 } else if (mSelectedRecording == null) { 248 titleView.setTextColor(mActionColor); 249 itemView.setBackgroundResource(R.drawable.setup_selector_background); 250 imageView.setImageResource(R.drawable.ic_draggable_white); 251 imageView.setVisibility(View.VISIBLE); 252 itemView.setFocusable(true); 253 itemView.setElevation(0); 254 titleView.setTypeface(titleView.getTypeface(), Typeface.NORMAL); 255 } else if (selected) { 256 titleView.setTextColor(mSelectedActionColor); 257 itemView.setBackgroundResource(R.drawable.priority_settings_action_item_selected); 258 imageView.setImageResource(R.drawable.ic_dragging_grey); 259 imageView.setVisibility(View.VISIBLE); 260 itemView.setFocusable(true); 261 itemView.setElevation(mSelectedActionElevation); 262 titleView.setTypeface(titleView.getTypeface(), Typeface.NORMAL); 263 } else { 264 titleView.setTextColor(mActionColor); 265 itemView.setBackgroundResource(R.drawable.setup_selector_background); 266 imageView.setVisibility(View.INVISIBLE); 267 itemView.setFocusable(true); 268 itemView.setElevation(0); 269 titleView.setTypeface(titleView.getTypeface(), Typeface.NORMAL); 270 } 271 } 272 } 273