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