1 /* 2 * Copyright (C) 2019 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.car.settings.wifi; 18 19 import android.car.drivingstate.CarUxRestrictions; 20 import android.content.Context; 21 import android.content.SharedPreferences; 22 import android.net.wifi.SoftApConfiguration; 23 import android.text.InputType; 24 import android.text.TextUtils; 25 import android.util.Log; 26 27 import com.android.car.settings.R; 28 import com.android.car.settings.common.FragmentController; 29 import com.android.car.settings.common.ValidatedEditTextPreference; 30 31 import java.util.UUID; 32 33 /** 34 * Controls Wifi Hotspot password configuration. 35 * 36 * <p>Note: This controller uses {@link ValidatedEditTextPreference} as opposed to 37 * PasswordEditTextPreference because the input is not obscured by default, and the user is setting 38 * their own password, as opposed to entering password for authentication. 39 */ 40 public class WifiTetherPasswordPreferenceController extends 41 WifiTetherBasePreferenceController<ValidatedEditTextPreference> { 42 private static final String TAG = "CarWifiTetherApPwdPref"; 43 44 protected static final String SHARED_PREFERENCE_PATH = 45 "com.android.car.settings.wifi.WifiTetherPreferenceController"; 46 protected static final String KEY_SAVED_PASSWORD = 47 "com.android.car.settings.wifi.SAVED_PASSWORD"; 48 49 private static final int SHARED_SECURITY_TYPE_UNSET = -1; 50 51 private static final int HOTSPOT_PASSWORD_MIN_LENGTH = 8; 52 private static final int HOTSPOT_PASSWORD_MAX_LENGTH = 63; 53 private static final ValidatedEditTextPreference.Validator PASSWORD_VALIDATOR = 54 value -> value.length() >= HOTSPOT_PASSWORD_MIN_LENGTH 55 && value.length() <= HOTSPOT_PASSWORD_MAX_LENGTH; 56 57 private final SharedPreferences mSharedPreferences = 58 getContext().getSharedPreferences(SHARED_PREFERENCE_PATH, Context.MODE_PRIVATE); 59 60 private String mPassword; 61 private int mSecurityType; 62 WifiTetherPasswordPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)63 public WifiTetherPasswordPreferenceController(Context context, String preferenceKey, 64 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 65 super(context, preferenceKey, fragmentController, uxRestrictions); 66 } 67 68 @Override getPreferenceType()69 protected Class<ValidatedEditTextPreference> getPreferenceType() { 70 return ValidatedEditTextPreference.class; 71 } 72 73 @Override onCreateInternal()74 protected void onCreateInternal() { 75 super.onCreateInternal(); 76 getPreference().setValidator(PASSWORD_VALIDATOR); 77 mSecurityType = getCarSoftApConfig().getSecurityType(); 78 syncPassword(); 79 } 80 81 @Override onStartInternal()82 protected void onStartInternal() { 83 int newSecurityType = mSharedPreferences.getInt( 84 WifiTetherSecurityPreferenceController.KEY_SECURITY_TYPE, 85 /* defaultValue= */ SHARED_SECURITY_TYPE_UNSET); 86 if (mSecurityType != newSecurityType && newSecurityType != SHARED_SECURITY_TYPE_UNSET) { 87 // Security type has been changed - update ap configuration 88 mSecurityType = newSecurityType; 89 syncPassword(); 90 updateApSecurity(mPassword); 91 } 92 } 93 94 @Override handlePreferenceChanged(ValidatedEditTextPreference preference, Object newValue)95 protected boolean handlePreferenceChanged(ValidatedEditTextPreference preference, 96 Object newValue) { 97 if (!newValue.toString().equals(mPassword)) { 98 mPassword = newValue.toString(); 99 updateApSecurity(mPassword); 100 refreshUi(); 101 } 102 return true; 103 } 104 105 @Override updateState(ValidatedEditTextPreference preference)106 protected void updateState(ValidatedEditTextPreference preference) { 107 super.updateState(preference); 108 updatePasswordDisplay(); 109 if (TextUtils.isEmpty(mPassword)) { 110 preference.setSummaryInputType(InputType.TYPE_CLASS_TEXT); 111 } else { 112 preference.setSummaryInputType( 113 InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); 114 } 115 } 116 117 @Override getSummary()118 protected String getSummary() { 119 return mPassword; 120 } 121 122 @Override getDefaultSummary()123 protected String getDefaultSummary() { 124 return getContext().getString(R.string.default_password_summary); 125 } 126 syncPassword()127 private void syncPassword() { 128 mPassword = getSyncedPassword(); 129 refreshUi(); 130 } 131 getSyncedPassword()132 private String getSyncedPassword() { 133 if (mSecurityType == SoftApConfiguration.SECURITY_TYPE_OPEN) { 134 return null; 135 } 136 137 String passphrase = getCarSoftApConfig().getPassphrase(); 138 if (!TextUtils.isEmpty(passphrase)) { 139 return passphrase; 140 } 141 142 if (!TextUtils.isEmpty( 143 mSharedPreferences.getString(KEY_SAVED_PASSWORD, /* defaultValue= */ null))) { 144 return mSharedPreferences.getString(KEY_SAVED_PASSWORD, /* defaultValue= */ null); 145 } 146 147 return generateRandomPassword(); 148 } 149 generateRandomPassword()150 private static String generateRandomPassword() { 151 String randomUUID = UUID.randomUUID().toString(); 152 // First 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx 153 return randomUUID.substring(0, 8) + randomUUID.substring(9, 13); 154 } 155 156 /** 157 * If the password and/or security type has changed, update the ap configuration 158 */ updateApSecurity(String password)159 private void updateApSecurity(String password) { 160 String passwordOrNullIfOpen; 161 if (mSecurityType == SoftApConfiguration.SECURITY_TYPE_OPEN) { 162 passwordOrNullIfOpen = null; 163 Log.w(TAG, "Setting password on an open network!"); 164 } else { 165 passwordOrNullIfOpen = password; 166 } 167 SoftApConfiguration config = new SoftApConfiguration.Builder(getCarSoftApConfig()) 168 .setPassphrase(passwordOrNullIfOpen, mSecurityType) 169 .build(); 170 setCarSoftApConfig(config); 171 172 if (!TextUtils.isEmpty(password)) { 173 mSharedPreferences.edit().putString(KEY_SAVED_PASSWORD, password).commit(); 174 } 175 } 176 updatePasswordDisplay()177 private void updatePasswordDisplay() { 178 getPreference().setText(mPassword); 179 getPreference().setVisible(mSecurityType != SoftApConfiguration.SECURITY_TYPE_OPEN); 180 getPreference().setSummary(getSummary()); 181 } 182 183 } 184