1 /* 2 * Copyright (C) 2017 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.settings.system; 18 19 import android.app.timedetector.ManualTimeSuggestion; 20 import android.app.timedetector.TimeDetector; 21 import android.content.Context; 22 import android.os.Bundle; 23 import android.text.TextUtils; 24 import android.util.TypedValue; 25 import android.view.ContextThemeWrapper; 26 import android.view.LayoutInflater; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import android.widget.TextView; 30 31 import androidx.leanback.preference.LeanbackPreferenceDialogFragmentCompat; 32 import androidx.leanback.preference.LeanbackSettingsFragmentCompat; 33 import androidx.leanback.widget.picker.DatePicker; 34 import androidx.leanback.widget.picker.Picker; 35 import androidx.leanback.widget.picker.TimePicker; 36 import androidx.preference.DialogPreference; 37 38 import com.android.tv.settings.R; 39 import com.android.tv.twopanelsettings.TwoPanelSettingsFragment; 40 41 import java.util.Calendar; 42 43 /** 44 * A DialogFragment started for either setting date or setting time purposes. The type of 45 * fragment launched is controlled by the type of {@link LeanbackPickerDialogPreference} 46 * that's clicked. Launching of these two fragments is done inside 47 * {@link com.android.tv.settings.BaseSettingsFragment#onPreferenceDisplayDialog}. 48 */ 49 public class LeanbackPickerDialogFragment extends LeanbackPreferenceDialogFragmentCompat implements 50 TwoPanelSettingsFragment.NavigationCallback { 51 52 private static final String EXTRA_PICKER_TYPE = "LeanbackPickerDialogFragment.PickerType"; 53 private static final String TYPE_DATE = "date"; 54 private static final String TYPE_TIME = "time"; 55 private static final String SAVE_STATE_TITLE = "LeanbackPickerDialogFragment.title"; 56 57 private CharSequence mDialogTitle; 58 private Calendar mCalendar; 59 private Picker mPicker; 60 61 /** 62 * Generated a new DialogFragment displaying a Leanback DatePicker widget. 63 * 64 * @param key The preference key starting this DialogFragment. 65 * @return The fragment to be started displaying a DatePicker widget for setting date. 66 */ newDatePickerInstance(String key)67 public static LeanbackPickerDialogFragment newDatePickerInstance(String key) { 68 final Bundle args = new Bundle(1); 69 args.putString(ARG_KEY, key); 70 args.putString(EXTRA_PICKER_TYPE, TYPE_DATE); 71 72 final LeanbackPickerDialogFragment fragment = new LeanbackPickerDialogFragment(); 73 fragment.setArguments(args); 74 return fragment; 75 } 76 77 /** 78 * Generated a new DialogFragment displaying a Leanback TimePicker widget. 79 * 80 * @param key The preference key starting this DialogFragment. 81 * @return The fragment to be started displaying a TimePicker widget for setting time. 82 */ newTimePickerInstance(String key)83 public static LeanbackPickerDialogFragment newTimePickerInstance(String key) { 84 final Bundle args = new Bundle(1); 85 args.putString(ARG_KEY, key); 86 args.putString(EXTRA_PICKER_TYPE, TYPE_TIME); 87 88 final LeanbackPickerDialogFragment fragment = new LeanbackPickerDialogFragment(); 89 fragment.setArguments(args); 90 return fragment; 91 } 92 93 @Override onCreate(Bundle savedInstanceState)94 public void onCreate(Bundle savedInstanceState) { 95 super.onCreate(savedInstanceState); 96 97 if (savedInstanceState == null) { 98 final DialogPreference preference = getPreference(); 99 mDialogTitle = preference.getDialogTitle(); 100 } else { 101 mDialogTitle = savedInstanceState.getCharSequence(SAVE_STATE_TITLE); 102 } 103 mCalendar = Calendar.getInstance(); 104 } 105 106 @Override onSaveInstanceState(Bundle outState)107 public void onSaveInstanceState(Bundle outState) { 108 super.onSaveInstanceState(outState); 109 outState.putCharSequence(SAVE_STATE_TITLE, mDialogTitle); 110 } 111 112 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)113 public View onCreateView(LayoutInflater inflater, ViewGroup container, 114 Bundle savedInstanceState) { 115 final String pickerType = getArguments().getString(EXTRA_PICKER_TYPE); 116 117 final TypedValue tv = new TypedValue(); 118 getActivity().getTheme().resolveAttribute(R.attr.preferenceTheme, tv, true); 119 int theme = tv.resourceId; 120 if (theme == 0) { 121 // Fallback to default theme. 122 theme = R.style.PreferenceThemeOverlayLeanback; 123 } 124 Context styledContext = new ContextThemeWrapper(getActivity(), theme); 125 LayoutInflater styledInflater = inflater.cloneInContext(styledContext); 126 final View view = styledInflater.inflate(R.layout.picker_dialog_fragment, container, false); 127 ViewGroup pickerContainer = view.findViewById(R.id.picker_container); 128 if (pickerType.equals(TYPE_DATE)) { 129 styledInflater.inflate(R.layout.date_picker_widget, pickerContainer, true); 130 DatePicker datePicker = pickerContainer.findViewById(R.id.date_picker); 131 mPicker = datePicker; 132 if (getParentFragment() instanceof LeanbackSettingsFragmentCompat) { 133 datePicker.setActivated(true); 134 } 135 datePicker.setOnClickListener(v -> { 136 // Setting the new system date 137 long whenMillis = datePicker.getDate(); 138 TimeDetector timeDetector = getContext().getSystemService(TimeDetector.class); 139 ManualTimeSuggestion manualTimeSuggestion = TimeDetector.createManualTimeSuggestion( 140 whenMillis, "Settings: Set date"); 141 timeDetector.suggestManualTime(manualTimeSuggestion); 142 // a) Two Panel: Navigate back, setActivated(false) in the callback 143 // b) Side Panel: Finish the fragment/activity when clicked. 144 if (getParentFragment() instanceof TwoPanelSettingsFragment) { 145 ((TwoPanelSettingsFragment) getParentFragment()).navigateBack(); 146 } else if (!getFragmentManager().popBackStackImmediate()) { 147 getActivity().finish(); 148 } 149 }); 150 151 } else { 152 styledInflater.inflate(R.layout.time_picker_widget, pickerContainer, true); 153 TimePicker timePicker = pickerContainer.findViewById(R.id.time_picker); 154 if (getParentFragment() instanceof LeanbackSettingsFragmentCompat) { 155 timePicker.setActivated(true); 156 } 157 mPicker = timePicker; 158 timePicker.setOnClickListener(v -> { 159 // Setting the new system time 160 mCalendar.set(Calendar.HOUR_OF_DAY, timePicker.getHour()); 161 mCalendar.set(Calendar.MINUTE, timePicker.getMinute()); 162 mCalendar.set(Calendar.SECOND, 0); 163 mCalendar.set(Calendar.MILLISECOND, 0); 164 long whenMillis = mCalendar.getTimeInMillis(); 165 166 TimeDetector timeDetector = getContext().getSystemService(TimeDetector.class); 167 ManualTimeSuggestion manualTimeSuggestion = TimeDetector.createManualTimeSuggestion( 168 whenMillis, "Settings: Set time"); 169 timeDetector.suggestManualTime(manualTimeSuggestion); 170 // a) Two Panel: Navigate back, setActivated(false) in the callback. 171 // b) Side Panel: Finish the fragment/activity when clicked. 172 if (getParentFragment() instanceof TwoPanelSettingsFragment) { 173 ((TwoPanelSettingsFragment) getParentFragment()).navigateBack(); 174 } else if (!getFragmentManager().popBackStackImmediate()) { 175 getActivity().finish(); 176 } 177 }); 178 } 179 180 final CharSequence title = mDialogTitle; 181 if (!TextUtils.isEmpty(title)) { 182 final TextView titleView = view.findViewById(R.id.decor_title); 183 titleView.setText(title); 184 } 185 return view; 186 } 187 188 @Override canNavigateBackOnDPAD()189 public boolean canNavigateBackOnDPAD() { 190 if (mPicker.isActivated() && mPicker.hasFocus()) { 191 if (mPicker.getSelectedColumn() == 0) { 192 return true; 193 } 194 return false; 195 } 196 return true; 197 } 198 199 @Override onNavigateToPreview()200 public void onNavigateToPreview() { 201 mPicker.setActivated(true); 202 mPicker.requestFocus(); 203 } 204 205 @Override onNavigateBack()206 public void onNavigateBack() { 207 mPicker.setActivated(false); 208 } 209 } 210