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 package com.android.car.settings.datetime;
17 
18 import android.app.timedetector.ManualTimeSuggestion;
19 import android.app.timedetector.TimeDetector;
20 import android.car.drivingstate.CarUxRestrictions;
21 import android.content.Intent;
22 import android.os.Bundle;
23 import android.view.ViewGroup;
24 import android.widget.DatePicker;
25 import android.widget.NumberPicker;
26 
27 import androidx.annotation.LayoutRes;
28 import androidx.annotation.StringRes;
29 
30 import com.android.car.settings.R;
31 import com.android.car.settings.common.BaseFragment;
32 import com.android.car.settings.common.rotary.DirectManipulationHandler;
33 import com.android.car.settings.common.rotary.DirectManipulationState;
34 import com.android.car.settings.common.rotary.NumberPickerNudgeHandler;
35 import com.android.car.settings.common.rotary.NumberPickerRotationHandler;
36 import com.android.car.settings.common.rotary.NumberPickerUtils;
37 
38 import java.util.ArrayList;
39 import java.util.Calendar;
40 import java.util.List;
41 
42 /**
43  * Sets the system date.
44  */
45 public class DatePickerFragment extends BaseFragment {
46     private static final int MILLIS_IN_SECOND = 1000;
47 
48     private DirectManipulationState mDirectManipulationMode;
49     private DatePicker mDatePicker;
50     private List<NumberPicker> mNumberPickers;
51 
52     @Override
onStop()53     public void onStop() {
54         super.onStop();
55         Calendar c = Calendar.getInstance();
56         c.set(Calendar.YEAR, mDatePicker.getYear());
57         c.set(Calendar.MONTH, mDatePicker.getMonth());
58         c.set(Calendar.DAY_OF_MONTH, mDatePicker.getDayOfMonth());
59         long when = Math.max(c.getTimeInMillis(), DatetimeSettingsFragment.MIN_DATE);
60         if (when / MILLIS_IN_SECOND < Integer.MAX_VALUE) {
61             TimeDetector timeDetector =
62                     getContext().getSystemService(TimeDetector.class);
63             ManualTimeSuggestion manualTimeSuggestion =
64                     TimeDetector.createManualTimeSuggestion(when, "Settings: Set date");
65             timeDetector.suggestManualTime(manualTimeSuggestion);
66             getContext().sendBroadcast(new Intent(Intent.ACTION_TIME_CHANGED));
67         }
68     }
69 
70     @Override
71     @LayoutRes
getLayoutId()72     protected int getLayoutId() {
73         return R.layout.date_picker;
74     }
75 
76     @Override
77     @StringRes
getTitleId()78     protected int getTitleId() {
79         return R.string.date_picker_title;
80     }
81 
82     @Override
onActivityCreated(Bundle savedInstanceState)83     public void onActivityCreated(Bundle savedInstanceState) {
84         super.onActivityCreated(savedInstanceState);
85 
86         mDirectManipulationMode = new DirectManipulationState();
87         mDatePicker = getView().findViewById(R.id.date_picker);
88         mDatePicker.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
89         mNumberPickers = new ArrayList<>();
90         NumberPickerUtils.getNumberPickerDescendants(mNumberPickers, mDatePicker);
91 
92         DirectManipulationHandler.setDirectManipulationHandler(mDatePicker,
93                 new DirectManipulationHandler.Builder(mDirectManipulationMode)
94                         // Use no-op nudge handler, since we never stay on this view in direct
95                         // manipulation mode.
96                         .setNudgeHandler((v, keyCode, event) -> true)
97                         .setCenterButtonHandler(inDirectManipulationMode -> {
98                             if (inDirectManipulationMode) {
99                                 return true;
100                             }
101 
102                             NumberPicker picker = mNumberPickers.get(0);
103                             if (picker != null) {
104                                 picker.requestFocus();
105                             }
106                             return true;
107                         })
108                         .setBackHandler(inDirectManipulationMode -> {
109                             // Only handle back if we weren't previously in direct manipulation
110                             // mode.
111                             if (!inDirectManipulationMode) {
112                                 onBackPressed();
113                             }
114                             return true;
115                         })
116                         .build());
117 
118         DirectManipulationHandler numberPickerListener =
119                 new DirectManipulationHandler.Builder(mDirectManipulationMode)
120                         .setNudgeHandler(new NumberPickerNudgeHandler())
121                         .setCenterButtonHandler(inDirectManipulationMode -> {
122                             if (!inDirectManipulationMode) {
123                                 return true;
124                             }
125 
126                             mDatePicker.requestFocus();
127                             return true;
128                         })
129                         .setBackHandler(inDirectManipulationMode -> {
130                             mDatePicker.requestFocus();
131                             return true;
132                         })
133                         .setRotationHandler(new NumberPickerRotationHandler())
134                         .build();
135 
136         for (int i = 0; i < mNumberPickers.size(); i++) {
137             DirectManipulationHandler.setDirectManipulationHandler(mNumberPickers.get(i),
138                     numberPickerListener);
139         }
140     }
141 
142     @Override
onUxRestrictionsChanged(CarUxRestrictions restrictionInfo)143     public void onUxRestrictionsChanged(CarUxRestrictions restrictionInfo) {
144         if (canBeShown(restrictionInfo)) {
145             return;
146         }
147         if (mDirectManipulationMode != null && mDirectManipulationMode.isActive()) {
148             mDirectManipulationMode.disable();
149         }
150     }
151 
152     @Override
onDestroy()153     public void onDestroy() {
154         DirectManipulationHandler.setDirectManipulationHandler(mDatePicker, /* handler= */ null);
155         for (int i = 0; i < mNumberPickers.size(); i++) {
156             DirectManipulationHandler.setDirectManipulationHandler(mNumberPickers.get(i),
157                     /* handler= */ null);
158         }
159 
160         super.onDestroy();
161     }
162 }
163