1 /* 2 * Copyright (C) 2017 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 package com.android.car.settings.wifi; 17 18 import android.net.wifi.WifiConfiguration; 19 import android.net.wifi.WifiManager; 20 import android.os.Bundle; 21 import android.support.annotation.Nullable; 22 import android.view.View; 23 import android.widget.AdapterView; 24 import android.widget.Button; 25 import android.widget.Toast; 26 27 import com.android.car.list.EditTextLineItem; 28 import com.android.car.list.PasswordLineItem; 29 import com.android.car.list.SpinnerLineItem; 30 import com.android.car.list.TypedPagedListAdapter; 31 import com.android.car.settings.R; 32 import com.android.car.settings.common.ListSettingsFragment; 33 import com.android.car.settings.common.Logger; 34 import com.android.settingslib.wifi.AccessPoint; 35 36 import java.util.ArrayList; 37 import java.util.List; 38 import java.util.regex.Pattern; 39 40 /** 41 * Adds a wifi network, the network can be public or private. If ADD_NETWORK_MODE is not specified 42 * in the intent, then it needs to contain AccessPoint information, which is be use that to 43 * render UI, e.g. show SSID etc. 44 */ 45 public class AddWifiFragment extends ListSettingsFragment implements 46 AdapterView.OnItemSelectedListener { 47 public static final String EXTRA_AP_STATE = "extra_ap_state"; 48 49 private static final Logger LOG = new Logger(AddWifiFragment.class); 50 private static final Pattern HEX_PATTERN = Pattern.compile("^[0-9A-F]+$"); 51 private static final Pattern VALID_SSID_PATTERN = 52 Pattern.compile("^[A-Za-z]+[\\w\\-\\:\\.]*$"); 53 @Nullable 54 private AccessPoint mAccessPoint; 55 @Nullable 56 private SpinnerLineItem<AccessPointSecurity> mSpinnerLineItem; 57 private WifiManager mWifiManager; 58 private Button mAddWifiButton; 59 private final WifiManager.ActionListener mConnectionListener = 60 new WifiManager.ActionListener() { 61 @Override 62 public void onSuccess() { 63 } 64 65 @Override 66 public void onFailure(int reason) { 67 Toast.makeText(getContext(), 68 R.string.wifi_failed_connect_message, 69 Toast.LENGTH_SHORT).show(); 70 } 71 }; 72 private EditTextLineItem mWifiNameInput; 73 private EditTextLineItem mWifiPasswordInput; 74 75 private int mSelectedPosition = AccessPointSecurity.SECURITY_NONE_POSITION; 76 77 public static AddWifiFragment getInstance(AccessPoint accessPoint) { 78 AddWifiFragment addWifiFragment = new AddWifiFragment(); 79 Bundle bundle = ListSettingsFragment.getBundle(); 80 bundle.putInt(EXTRA_TITLE_ID, R.string.wifi_setup_add_network); 81 bundle.putInt(EXTRA_ACTION_BAR_LAYOUT, R.layout.action_bar_with_button); 82 Bundle accessPointState = new Bundle(); 83 if (accessPoint != null) { 84 accessPoint.saveWifiState(accessPointState); 85 bundle.putBundle(EXTRA_AP_STATE, accessPointState); 86 } 87 addWifiFragment.setArguments(bundle); 88 return addWifiFragment; 89 } 90 91 @Override 92 public void onCreate(Bundle savedInstanceState) { 93 super.onCreate(savedInstanceState); 94 if (getArguments().keySet().contains(EXTRA_AP_STATE)) { 95 mAccessPoint = new AccessPoint(getContext(), getArguments().getBundle(EXTRA_AP_STATE)); 96 } 97 mWifiManager = getContext().getSystemService(WifiManager.class); 98 } 99 100 @Override 101 public void onActivityCreated(Bundle savedInstanceState) { 102 super.onActivityCreated(savedInstanceState); 103 104 mAddWifiButton = getActivity().findViewById(R.id.action_button1); 105 mAddWifiButton.setText(R.string.wifi_setup_connect); 106 mAddWifiButton.setOnClickListener(v -> { 107 connectToAccessPoint(); 108 getFragmentController().goBack(); 109 }); 110 mAddWifiButton.setEnabled(mAccessPoint != null); 111 } 112 113 @Override 114 public ArrayList<TypedPagedListAdapter.LineItem> getLineItems() { 115 ArrayList<TypedPagedListAdapter.LineItem> lineItems = new ArrayList<>(); 116 if (mAccessPoint != null) { 117 mWifiNameInput = new EditTextLineItem( 118 getContext().getText(R.string.wifi_ssid), mAccessPoint.getSsid()); 119 mWifiNameInput.setTextType(EditTextLineItem.TextType.NONE); 120 } else { 121 mWifiNameInput = new EditTextLineItem( 122 getContext().getText(R.string.wifi_ssid)); 123 mWifiNameInput.setTextType(EditTextLineItem.TextType.TEXT); 124 mWifiNameInput.setTextChangeListener(s -> 125 mAddWifiButton.setEnabled(VALID_SSID_PATTERN.matcher(s).matches())); 126 } 127 lineItems.add(mWifiNameInput); 128 129 if (mAccessPoint == null) { 130 List<AccessPointSecurity> securities = 131 AccessPointSecurity.getSecurityTypes(getContext()); 132 mSpinnerLineItem = new SpinnerLineItem<>( 133 getContext(), 134 this, 135 securities, 136 getContext().getText(R.string.wifi_security), 137 mSelectedPosition); 138 lineItems.add(mSpinnerLineItem); 139 } 140 141 if (mAccessPoint != null 142 || mSelectedPosition != AccessPointSecurity.SECURITY_NONE_POSITION) { 143 mWifiPasswordInput = new PasswordLineItem(getContext().getText(R.string.wifi_password)); 144 lineItems.add(mWifiPasswordInput); 145 } 146 return lineItems; 147 } 148 149 @Override 150 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 151 if (position == mSelectedPosition) { 152 return; 153 } 154 mSelectedPosition = position; 155 mPagedListAdapter.setList(getLineItems()); 156 } 157 158 @Override 159 public void onNothingSelected(AdapterView<?> parent) { 160 } 161 162 private void connectToAccessPoint() { 163 WifiConfiguration wifiConfig = new WifiConfiguration(); 164 wifiConfig.SSID = String.format("\"%s\"", getSsId()); 165 wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); 166 wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP); 167 wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN); 168 wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA); 169 wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40); 170 wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104); 171 int security; 172 if (mAccessPoint == null) { 173 security = mSpinnerLineItem.getItem(mSelectedPosition).getSecurityType(); 174 wifiConfig.hiddenSSID = true; 175 } else { 176 security = mAccessPoint.getSecurity(); 177 } 178 switch (security) { 179 case AccessPoint.SECURITY_NONE: 180 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 181 wifiConfig.allowedAuthAlgorithms.clear(); 182 wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); 183 wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); 184 break; 185 case AccessPoint.SECURITY_WEP: 186 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 187 wifiConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); 188 wifiConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); 189 String password = mWifiPasswordInput.getInput(); 190 wifiConfig.wepKeys[0] = isHexString(password) ? password 191 : "\"" + password + "\""; 192 wifiConfig.wepTxKeyIndex = 0; 193 break; 194 case AccessPoint.SECURITY_PSK: 195 case AccessPoint.SECURITY_EAP: 196 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); 197 wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); 198 wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); 199 wifiConfig.preSharedKey = String.format( 200 "\"%s\"", mWifiPasswordInput.getInput()); 201 break; 202 default: 203 LOG.w("invalid security type: " + security); 204 break; 205 } 206 int netId = mWifiManager.addNetwork(wifiConfig); 207 if (netId == -1) { 208 Toast.makeText(getContext(), 209 R.string.wifi_failed_connect_message, 210 Toast.LENGTH_SHORT).show(); 211 } else { 212 mWifiManager.enableNetwork(netId, true); 213 } 214 } 215 216 private boolean isHexString(String password) { 217 return HEX_PATTERN.matcher(password).matches(); 218 } 219 220 // TODO: handle null case, show warning message etc. 221 private String getSsId() { 222 if (mAccessPoint == null) { 223 return mWifiNameInput.getInput(); 224 } else { 225 return mAccessPoint.getSsid().toString(); 226 } 227 } 228 } 229