This commit moves knowledge of the upper / lower bounds for valid manual date suggestions to (internal) API calls. It adds a test to confirm the API calls are used to configure the date dialog. Further, it removes redundant filtering from the client that would prevent suggestion calls being made if the settings UI considers them invalid. Year bounds are already used to limit the UI entry, and the system server will return false from the service call if the suggestion is invalid, though the SettingsUI doesn't do anything (behaviorally) with the false before or after this change. After this change it is logged. The goal of this change is to allow users with devices that don't have the Y2038 issue to enter dates > 2037. This could have been done with a smaller change, but the use of the new internal class TimeDetectorHelper means that the bounds logic is in one place. The lower bound (on mobile devices) can now be changed relatively easily by touching one class. Bug: 228967927 Test: m RunSettingsRoboTests ROBOTEST_FILTER="com.android.settings.datetime" Change-Id: Iaf1ca8220e0e96773aa71b595da9c1ba1e50d59d
161 lines
5.8 KiB
Java
161 lines
5.8 KiB
Java
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.settings.datetime;
|
|
|
|
import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
|
|
|
|
import android.app.DatePickerDialog;
|
|
import android.app.time.TimeCapabilities;
|
|
import android.app.time.TimeManager;
|
|
import android.app.timedetector.ManualTimeSuggestion;
|
|
import android.app.timedetector.TimeDetector;
|
|
import android.app.timedetector.TimeDetectorHelper;
|
|
import android.content.Context;
|
|
import android.text.TextUtils;
|
|
import android.text.format.DateFormat;
|
|
import android.util.Log;
|
|
import android.widget.DatePicker;
|
|
|
|
import androidx.annotation.VisibleForTesting;
|
|
import androidx.preference.Preference;
|
|
|
|
import com.android.settings.core.PreferenceControllerMixin;
|
|
import com.android.settingslib.RestrictedPreference;
|
|
import com.android.settingslib.core.AbstractPreferenceController;
|
|
|
|
import java.util.Calendar;
|
|
|
|
public class DatePreferenceController extends AbstractPreferenceController
|
|
implements PreferenceControllerMixin, DatePickerDialog.OnDateSetListener {
|
|
|
|
public interface DatePreferenceHost extends UpdateTimeAndDateCallback {
|
|
void showDatePicker();
|
|
}
|
|
|
|
public static final int DIALOG_DATEPICKER = 0;
|
|
|
|
private static final String TAG = "DatePreferenceController";
|
|
private static final String KEY_DATE = "date";
|
|
|
|
private final DatePreferenceHost mHost;
|
|
private final TimeManager mTimeManager;
|
|
|
|
public DatePreferenceController(Context context, DatePreferenceHost host) {
|
|
super(context);
|
|
mHost = host;
|
|
mTimeManager = context.getSystemService(TimeManager.class);
|
|
}
|
|
|
|
@Override
|
|
public boolean isAvailable() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void updateState(Preference preference) {
|
|
if (!(preference instanceof RestrictedPreference)) {
|
|
return;
|
|
}
|
|
final Calendar now = Calendar.getInstance();
|
|
preference.setSummary(DateFormat.getLongDateFormat(mContext).format(now.getTime()));
|
|
if (!((RestrictedPreference) preference).isDisabledByAdmin()) {
|
|
boolean enableManualDateSelection = isEnabled();
|
|
preference.setEnabled(enableManualDateSelection);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean handlePreferenceTreeClick(Preference preference) {
|
|
if (!TextUtils.equals(preference.getKey(), KEY_DATE)) {
|
|
return false;
|
|
}
|
|
mHost.showDatePicker();
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public String getPreferenceKey() {
|
|
return KEY_DATE;
|
|
}
|
|
|
|
@Override
|
|
public void onDateSet(DatePicker view, int year, int month, int day) {
|
|
setDate(year, month, day);
|
|
mHost.updateTimeAndDateDisplay(mContext);
|
|
}
|
|
|
|
/**
|
|
* Builds a {@link DatePickerDialog} that can be used to request the current date from the user.
|
|
*/
|
|
public DatePickerDialog buildDatePicker(
|
|
Context parentContext, TimeDetectorHelper timeDetectorHelper) {
|
|
final Calendar calendar = Calendar.getInstance();
|
|
final DatePickerDialog dialog = new DatePickerDialog(
|
|
parentContext,
|
|
this,
|
|
calendar.get(Calendar.YEAR),
|
|
calendar.get(Calendar.MONTH),
|
|
calendar.get(Calendar.DAY_OF_MONTH));
|
|
|
|
// Limit the dates the user can pick to a sensible range.
|
|
DatePicker datePicker = dialog.getDatePicker();
|
|
|
|
calendar.clear();
|
|
int minYear = timeDetectorHelper.getManualDateSelectionYearMin();
|
|
calendar.set(minYear, Calendar.JANUARY, 1);
|
|
datePicker.setMinDate(calendar.getTimeInMillis());
|
|
|
|
int maxYear = timeDetectorHelper.getManualDateSelectionYearMax();
|
|
calendar.clear();
|
|
calendar.set(maxYear, Calendar.DECEMBER, 31);
|
|
datePicker.setMaxDate(calendar.getTimeInMillis());
|
|
return dialog;
|
|
}
|
|
|
|
@VisibleForTesting
|
|
void setDate(int year, int month, int day) {
|
|
Calendar c = Calendar.getInstance();
|
|
|
|
c.set(Calendar.YEAR, year);
|
|
c.set(Calendar.MONTH, month);
|
|
c.set(Calendar.DAY_OF_MONTH, day);
|
|
long when = c.getTimeInMillis();
|
|
|
|
TimeDetector timeDetector = mContext.getSystemService(TimeDetector.class);
|
|
ManualTimeSuggestion manualTimeSuggestion =
|
|
TimeDetector.createManualTimeSuggestion(when, "Settings: Set date");
|
|
boolean success = timeDetector.suggestManualTime(manualTimeSuggestion);
|
|
if (!success) {
|
|
// This implies the system server is applying tighter bounds than the settings app or
|
|
// the date/time cannot be set for other reasons, e.g. perhaps "auto time" is turned on.
|
|
Log.w(TAG, "Unable to set date with suggestion=" + manualTimeSuggestion);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns whether selecting the preference should prompt for the user to enter the date
|
|
* manually. Exposed as public so that the time controller can easily share the same logic as
|
|
* the rules are identical for time.
|
|
*/
|
|
public boolean isEnabled() {
|
|
TimeCapabilities timeZoneCapabilities =
|
|
mTimeManager.getTimeCapabilitiesAndConfig().getCapabilities();
|
|
int suggestManualTimeCapability = timeZoneCapabilities.getSuggestManualTimeCapability();
|
|
return suggestManualTimeCapability == CAPABILITY_POSSESSED;
|
|
}
|
|
}
|