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