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.annotation.NonNull; 20 import android.car.drivingstate.CarUxRestrictions; 21 import android.content.Context; 22 import android.content.SharedPreferences; 23 import android.net.wifi.SoftApCapability; 24 import android.net.wifi.SoftApConfiguration; 25 import android.net.wifi.WifiManager; 26 27 import androidx.preference.ListPreference; 28 29 import com.android.car.settings.R; 30 import com.android.car.settings.common.FragmentController; 31 import com.android.car.settings.common.Logger; 32 33 import java.util.LinkedHashMap; 34 import java.util.Map; 35 36 /** 37 * Controls WiFi Hotspot Security Type configuration. 38 */ 39 public class WifiTetherSecurityPreferenceController extends 40 WifiTetherBasePreferenceController<ListPreference> implements WifiManager.SoftApCallback { 41 42 protected static final String KEY_SECURITY_TYPE = 43 "com.android.car.settings.wifi.KEY_SECURITY_TYPE"; 44 45 private static final Logger LOG = new Logger(WifiTetherSecurityPreferenceController.class); 46 47 private int mSecurityType; 48 49 private boolean mIsWpa3Supported = true; 50 51 private final SharedPreferences mSharedPreferences = getContext().getSharedPreferences( 52 WifiTetherPasswordPreferenceController.SHARED_PREFERENCE_PATH, 53 Context.MODE_PRIVATE); 54 55 private final Map<Integer, String> mSecurityMap = new LinkedHashMap<>(); 56 WifiTetherSecurityPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)57 public WifiTetherSecurityPreferenceController(Context context, String preferenceKey, 58 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 59 super(context, preferenceKey, fragmentController, uxRestrictions); 60 String[] securityNames = getContext().getResources().getStringArray( 61 R.array.wifi_tether_security); 62 String[] securityValues = getContext().getResources().getStringArray( 63 R.array.wifi_tether_security_values); 64 for (int i = 0; i < securityNames.length; i++) { 65 mSecurityMap.put(Integer.parseInt(securityValues[i]), securityNames[i]); 66 } 67 } 68 69 @Override getPreferenceType()70 protected Class<ListPreference> getPreferenceType() { 71 return ListPreference.class; 72 } 73 74 @Override onCreateInternal()75 protected void onCreateInternal() { 76 super.onCreateInternal(); 77 SoftApConfiguration config = getCarSoftApConfig(); 78 if (config != null) { 79 mSecurityType = config.getSecurityType(); 80 } 81 getCarWifiManager().registerSoftApCallback(getContext().getMainExecutor(), this); 82 updatePreferenceOptions(); 83 } 84 updatePreferenceOptions()85 private void updatePreferenceOptions() { 86 if (!mIsWpa3Supported) { 87 mSecurityMap.keySet() 88 .removeIf(key -> key > SoftApConfiguration.SECURITY_TYPE_WPA2_PSK); 89 } 90 91 getPreference().setEntries(mSecurityMap.values().toArray(new CharSequence[0])); 92 getPreference().setEntryValues( 93 mSecurityMap.keySet().stream().map(Object::toString).toArray(CharSequence[]::new)); 94 // Need to update the security type in case current mSecurityType 95 // is incompatible with the device 96 updateSecurityType(mSecurityType); 97 getPreference().setValue(String.valueOf(mSecurityType)); 98 } 99 100 @Override handlePreferenceChanged(ListPreference preference, Object newValue)101 protected boolean handlePreferenceChanged(ListPreference preference, 102 Object newValue) { 103 updateSecurityType(Integer.parseInt(newValue.toString())); 104 // Rather than updating the ap config here, we will only update the security type shared 105 // preference. When the user confirms their selection by going back, the config will be 106 // updated by the WifiTetherPasswordPreferenceController. By updating the config in that 107 // controller, we avoid running into a transient state where the (securityType, passphrase) 108 // pair is invalid due to not being updated simultaneously. 109 mSharedPreferences.edit().putInt(KEY_SECURITY_TYPE, mSecurityType).commit(); 110 refreshUi(); 111 return true; 112 } 113 updateSecurityType(int newValue)114 private void updateSecurityType(int newValue) { 115 mSecurityType = mSecurityMap.containsKey(newValue) 116 ? newValue : SoftApConfiguration.SECURITY_TYPE_WPA2_PSK; 117 } 118 119 @Override updateState(ListPreference preference)120 protected void updateState(ListPreference preference) { 121 super.updateState(preference); 122 preference.setValue(Integer.toString(mSecurityType)); 123 } 124 125 @Override getSummary()126 protected String getSummary() { 127 return mSecurityMap.containsKey(mSecurityType) ? mSecurityMap.get(mSecurityType) 128 : getContext().getString(R.string.wifi_hotspot_security_none); 129 } 130 131 @Override getDefaultSummary()132 protected String getDefaultSummary() { 133 return null; 134 } 135 136 @Override onCapabilityChanged(@onNull SoftApCapability softApCapability)137 public void onCapabilityChanged(@NonNull SoftApCapability softApCapability) { 138 boolean isWpa3Supported = 139 softApCapability.areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE); 140 if (!isWpa3Supported) { 141 LOG.i("WPA3 SAE is not supported on this device"); 142 } 143 if (mIsWpa3Supported != isWpa3Supported) { 144 mIsWpa3Supported = isWpa3Supported; 145 updatePreferenceOptions(); 146 } 147 getCarWifiManager().unregisterSoftApCallback(this); 148 } 149 } 150