• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.settings.deviceinfo;
18 
19 import android.bluetooth.BluetoothAdapter;
20 import android.content.Context;
21 import android.net.wifi.WifiConfiguration;
22 import android.net.wifi.WifiManager;
23 import android.os.Build;
24 import android.os.Bundle;
25 import android.provider.Settings;
26 import android.text.SpannedString;
27 
28 import androidx.preference.Preference;
29 import androidx.preference.PreferenceScreen;
30 
31 import com.android.settings.R;
32 import com.android.settings.bluetooth.BluetoothLengthDeviceNameFilter;
33 import com.android.settings.core.BasePreferenceController;
34 import com.android.settings.widget.ValidatedEditTextPreference;
35 import com.android.settings.wifi.tether.WifiDeviceNameTextValidator;
36 import com.android.settingslib.core.lifecycle.LifecycleObserver;
37 import com.android.settingslib.core.lifecycle.events.OnCreate;
38 import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
39 
40 public class DeviceNamePreferenceController extends BasePreferenceController
41         implements ValidatedEditTextPreference.Validator,
42         Preference.OnPreferenceChangeListener,
43         LifecycleObserver,
44         OnSaveInstanceState,
45         OnCreate {
46     private static final String KEY_PENDING_DEVICE_NAME = "key_pending_device_name";
47     private String mDeviceName;
48     protected WifiManager mWifiManager;
49     private final BluetoothAdapter mBluetoothAdapter;
50     private final WifiDeviceNameTextValidator mWifiDeviceNameTextValidator;
51     private ValidatedEditTextPreference mPreference;
52     private DeviceNamePreferenceHost mHost;
53     private String mPendingDeviceName;
54 
DeviceNamePreferenceController(Context context, String key)55     public DeviceNamePreferenceController(Context context, String key) {
56         super(context, key);
57 
58         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
59         mWifiDeviceNameTextValidator = new WifiDeviceNameTextValidator();
60         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
61 
62         initializeDeviceName();
63     }
64 
65     @Override
displayPreference(PreferenceScreen screen)66     public void displayPreference(PreferenceScreen screen) {
67         super.displayPreference(screen);
68         mPreference = screen.findPreference(getPreferenceKey());
69         final CharSequence deviceName = getSummary();
70         mPreference.setSummary(deviceName);
71         mPreference.setText(deviceName.toString());
72         mPreference.setValidator(this);
73     }
74 
initializeDeviceName()75     private void initializeDeviceName() {
76         mDeviceName = Settings.Global.getString(mContext.getContentResolver(),
77                 Settings.Global.DEVICE_NAME);
78         if (mDeviceName == null) {
79             mDeviceName = Build.MODEL;
80         }
81     }
82 
83     @Override
getSummary()84     public CharSequence getSummary() {
85         return mDeviceName;
86     }
87 
88     @Override
getAvailabilityStatus()89     public int getAvailabilityStatus() {
90         return mContext.getResources().getBoolean(R.bool.config_show_device_name)
91                 ? AVAILABLE
92                 : UNSUPPORTED_ON_DEVICE;
93     }
94 
95     @Override
onPreferenceChange(Preference preference, Object newValue)96     public boolean onPreferenceChange(Preference preference, Object newValue) {
97         mPendingDeviceName = (String) newValue;
98         if (mHost != null) {
99             mHost.showDeviceNameWarningDialog(mPendingDeviceName);
100         }
101         return true;
102     }
103 
104     @Override
isTextValid(String deviceName)105     public boolean isTextValid(String deviceName) {
106         // BluetoothNameDialogFragment describes BT name filter as a 248 bytes long cap.
107         // Given the restrictions presented by the SSID name filter (32 char), I don't believe it is
108         // possible to construct an SSID that is not a valid Bluetooth name.
109         return mWifiDeviceNameTextValidator.isTextValid(deviceName);
110     }
111 
updateDeviceName(boolean update)112     public void updateDeviceName(boolean update) {
113         if (update && mPendingDeviceName != null) {
114             setDeviceName(mPendingDeviceName);
115         } else {
116             mPreference.setText(getSummary().toString());
117         }
118     }
119 
setHost(DeviceNamePreferenceHost host)120     public void setHost(DeviceNamePreferenceHost host) {
121         mHost = host;
122     }
123 
124     /**
125      * This method presumes that security/validity checks have already been passed.
126      */
setDeviceName(String deviceName)127     private void setDeviceName(String deviceName) {
128         mDeviceName = deviceName;
129         setSettingsGlobalDeviceName(deviceName);
130         setBluetoothDeviceName(deviceName);
131         setTetherSsidName(deviceName);
132         mPreference.setSummary(getSummary());
133     }
134 
setSettingsGlobalDeviceName(String deviceName)135     private void setSettingsGlobalDeviceName(String deviceName) {
136         Settings.Global.putString(mContext.getContentResolver(), Settings.Global.DEVICE_NAME,
137                 deviceName);
138     }
139 
setBluetoothDeviceName(String deviceName)140     private void setBluetoothDeviceName(String deviceName) {
141         if (mBluetoothAdapter != null) {
142             mBluetoothAdapter.setName(getFilteredBluetoothString(deviceName));
143         }
144     }
145 
146     /**
147      * Using a UTF8ByteLengthFilter, we can filter a string to be compliant with the Bluetooth spec.
148      * For more information, see {@link com.android.settings.bluetooth.BluetoothNameDialogFragment}.
149      */
getFilteredBluetoothString(final String deviceName)150     private static final String getFilteredBluetoothString(final String deviceName) {
151         CharSequence filteredSequence = new BluetoothLengthDeviceNameFilter().filter(deviceName, 0,
152                 deviceName.length(),
153                 new SpannedString(""),
154                 0, 0);
155         // null -> use the original
156         if (filteredSequence == null) {
157             return deviceName;
158         }
159         return filteredSequence.toString();
160     }
161 
setTetherSsidName(String deviceName)162     private void setTetherSsidName(String deviceName) {
163         final WifiConfiguration config = mWifiManager.getWifiApConfiguration();
164         config.SSID = deviceName;
165         // TODO: If tether is running, turn off the AP and restart it after setting config.
166         mWifiManager.setWifiApConfiguration(config);
167     }
168 
169     @Override
onCreate(Bundle savedInstanceState)170     public void onCreate(Bundle savedInstanceState) {
171         if (savedInstanceState != null) {
172             mPendingDeviceName = savedInstanceState.getString(KEY_PENDING_DEVICE_NAME, null);
173         }
174     }
175 
176     @Override
onSaveInstanceState(Bundle outState)177     public void onSaveInstanceState(Bundle outState) {
178         outState.putString(KEY_PENDING_DEVICE_NAME, mPendingDeviceName);
179     }
180 
181     public interface DeviceNamePreferenceHost {
showDeviceNameWarningDialog(String deviceName)182         void showDeviceNameWarningDialog(String deviceName);
183     }
184 }