经常遇到客户在内网中使用无法与ntp服务器通讯导致系统时间错乱,他们想自己替换ntp地址要么是用adb命令要么是重新刷机,这样比较浪费客户的时间。
看了一下Android系统中选择ntp地址的逻辑,发现在framework中已经有了个ntp地址那么系统将会选择framework中默认的ntp服务器作为系统ntp服务器,如果framework中没有那么将会选择settings数据库中存储的ntp服务器作为系统ntp服务器
framework/base/core/java/android/util/NtpTrustedTime.java
根据上面逻辑咋们可以推断,是可以在app中通过写数据库的值来更改系统的ntp地址。
以下代码是在设置中添加UI来更改ntp地址(基于Android10)
vendor/mediatek/proprietary/packages/apps/MtkSettings/res/values-zh-rCN/strings.xml
+ <string name="date_and_time_ntp_server">NTP服务器</string>
vendor/mediatek/proprietary/packages/apps/MtkSettings/res/values/strings.xml
+ <string name="date_and_time_ntp_server">NTP server</string>
vendor/mediatek/proprietary/packages/apps/MtkSettings/res_ext/xml/date_time_ext_prefs.xml
+ <com.android.settings.widget.ValidatedEditTextPreference
+ android:key="ntp_server"
+ android:title="@string/date_and_time_ntp_server"
+ android:summary="@string/summary_placeholder"
+ settings:controller="com.android.settings.datetime.NtpServerPreferenceController"
+ settings:enableCopying="true"/>
新建文件
vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/datetime/NtpServerPreferenceController.java
package com.android.settings.datetime;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.text.SpannedString;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.widget.ValidatedEditTextPreference;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnCreate;
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
import android.util.Log;
public class NtpServerPreferenceController extends BasePreferenceController
implements ValidatedEditTextPreference.Validator,
Preference.OnPreferenceChangeListener,
LifecycleObserver,
OnSaveInstanceState{
private String defaultServer;
private String secureServer = null;
private String mPendingNtpName;
private ValidatedEditTextPreference mPreference;
private String TAG = "NtpServerPreferenceController";
public NtpServerPreferenceController(Context context, String key) {
super(context, key);
//Log.d(TAG,"NtpServerPreferenceController is run..");
initializeDeviceName();
}
private void initializeDeviceName(){
defaultServer = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.NTP_SERVER);
//Log.d(TAG,"defaultserver=" + defaultServer);
if(defaultServer == null){
Log.d(TAG,"defaultservr is null");
}
//Settings.Global.getString(resolver, Settings.Global.NTP_SERVER);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
final CharSequence ntpserverName = getSummary();
if(ntpserverName != null){
//Log.d(TAG,"ntpserverName=" + ntpserverName);
mPreference.setSummary(ntpserverName);
mPreference.setText(ntpserverName.toString());
mPreference.setValidator(this);
} else {
Log.d(TAG,"ntpserverName is null");
}
}
@Override
public CharSequence getSummary() {
return defaultServer;
}
public void updateDeviceName(boolean update) {
}
private void setSettingsGlobalDeviceName(String ntpserver) {
Settings.Global.putString(mContext.getContentResolver(), Settings.Global.NTP_SERVER,ntpserver);
//Log.d(TAG,"set ntpserver is:" + ntpserver);
}
@Override
public int getAvailabilityStatus() {
return 0;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
//Log.d(TAG,"newValue=" + newValue);
mPendingNtpName = (String) newValue;
setSettingsGlobalDeviceName(mPendingNtpName);
return true;
}
@Override
public boolean isTextValid(String deviceName) {
// BluetoothNameDialogFragment describes BT name filter as a 248 bytes long cap.
// Given the restrictions presented by the SSID name filter (32 char), I don't believe it is
// possible to construct an SSID that is not a valid Bluetooth name.
return true;
}
@Override
public void onSaveInstanceState(Bundle outState) {
}
}
实际效果如下:
设置ntp地址后需要重启系统新设置的ntp地址才有效
此功能实现并无难度,好在方便了用户使用。