1 /* 2 * Copyright (C) 2020 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.details; 18 19 import static com.android.car.settings.common.ActionButtonsPreference.ActionButtons; 20 21 import android.annotation.SuppressLint; 22 import android.car.drivingstate.CarUxRestrictions; 23 import android.content.Context; 24 import android.net.Network; 25 import android.net.NetworkCapabilities; 26 import android.net.Uri; 27 import android.net.wifi.EasyConnectStatusCallback; 28 import android.net.wifi.WifiManager; 29 import android.os.Build; 30 import android.widget.Toast; 31 32 import androidx.annotation.NonNull; 33 34 import com.android.car.settings.Flags; 35 import com.android.car.settings.R; 36 import com.android.car.settings.common.ActionButtonsPreference; 37 import com.android.car.settings.common.FragmentController; 38 import com.android.car.settings.common.Logger; 39 import com.android.car.settings.wifi.WifiUtil; 40 import com.android.wifitrackerlib.WifiEntry; 41 42 /** 43 * Shows Wifi details action buttons (forget and connect). 44 */ 45 public class WifiDetailsActionButtonsPreferenceController 46 extends WifiDetailsBasePreferenceController<ActionButtonsPreference> 47 implements WifiEntry.ConnectCallback { 48 private static final Logger LOG = new Logger( 49 WifiDetailsActionButtonsPreferenceController.class); 50 private String mUri; 51 private boolean mSupportEasyConnect; 52 WifiDetailsActionButtonsPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)53 public WifiDetailsActionButtonsPreferenceController(Context context, 54 String preferenceKey, FragmentController fragmentController, 55 CarUxRestrictions uxRestrictions) { 56 super(context, preferenceKey, fragmentController, uxRestrictions); 57 } 58 59 @Override getPreferenceType()60 protected Class<ActionButtonsPreference> getPreferenceType() { 61 return ActionButtonsPreference.class; 62 } 63 64 @Override onCreateInternal()65 protected void onCreateInternal() { 66 super.onCreateInternal(); 67 mSupportEasyConnect = getCarWifiManager() != null 68 && getCarWifiManager().isEasyConnectSupported(); 69 if (mSupportEasyConnect) { 70 setUpSharePageInfo(); 71 } 72 } 73 74 @Override updateState(ActionButtonsPreference preference)75 protected void updateState(ActionButtonsPreference preference) { 76 getPreference() 77 .getButton(ActionButtons.BUTTON1) 78 .setText(R.string.forget) 79 .setIcon(R.drawable.ic_delete) 80 .setVisible(canForgetNetwork()) 81 .setOnClickListener(v -> { 82 getWifiEntry().forget(/* callback= */ null); 83 getFragmentController().goBack(); 84 }); 85 86 boolean canConnectOrDisconnect = getWifiEntry().canConnect() 87 || getWifiEntry().canDisconnect(); 88 preference 89 .getButton(ActionButtons.BUTTON2) 90 .setVisible(canConnectOrDisconnect || getWifiEntry().getConnectedState() 91 == WifiEntry.CONNECTED_STATE_CONNECTING) 92 .setEnabled(canConnectOrDisconnect) 93 .setText(getConnectDisconnectButtonTextResource()) 94 .setIcon(getConnectDisconnectButtonIconResource()) 95 .setOnClickListener(v -> connectOrDisconnect()); 96 97 preference.getButton(ActionButtons.BUTTON3) 98 .setVisible(mSupportEasyConnect && Flags.newFragmentForIntents()) 99 .setEnabled(mUri != null) 100 .setText(R.string.wifi_detail_share) 101 .setIcon(R.drawable.ic_qr) 102 .setOnClickListener(v -> openSharePage()); 103 } 104 105 @Override getDefaultAvailabilityStatus()106 protected int getDefaultAvailabilityStatus() { 107 if (!WifiUtil.isWifiAvailable(getContext())) { 108 return UNSUPPORTED_ON_DEVICE; 109 } 110 return AVAILABLE; 111 } 112 113 @Override onCapabilitiesChanged(Network network, NetworkCapabilities nc)114 public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { 115 refreshUi(); 116 } 117 118 @Override onConnectResult(@ifiEntry.ConnectCallback.ConnectStatus int status)119 public void onConnectResult(@WifiEntry.ConnectCallback.ConnectStatus int status) { 120 if (getWifiEntry().getLevel() == WifiEntry.WIFI_LEVEL_UNREACHABLE) { 121 Toast.makeText(getContext(), 122 R.string.wifi_not_in_range_message, 123 Toast.LENGTH_SHORT).show(); 124 } else if (status != WifiEntry.ConnectCallback.CONNECT_STATUS_SUCCESS) { 125 Toast.makeText(getContext(), 126 R.string.wifi_failed_connect_message, 127 Toast.LENGTH_SHORT).show(); 128 } 129 } 130 canForgetNetwork()131 private boolean canForgetNetwork() { 132 return getWifiEntry().canForget() 133 && !WifiUtil.isNetworkLockedDown(getContext(), 134 getWifiEntry().getWifiConfiguration()); 135 } 136 connectOrDisconnect()137 private void connectOrDisconnect() { 138 if (!WifiUtil.isWifiEntryConnectedOrConnecting(getWifiEntry())) { 139 getWifiEntry().connect(/* callback= */ this); 140 } else { 141 getWifiEntry().disconnect(/* callback= */ null); 142 } 143 } 144 getConnectDisconnectButtonTextResource()145 private int getConnectDisconnectButtonTextResource() { 146 switch (getWifiEntry().getConnectedState()) { 147 case WifiEntry.CONNECTED_STATE_DISCONNECTED: 148 return R.string.wifi_setup_connect; 149 case WifiEntry.CONNECTED_STATE_CONNECTED: 150 return R.string.disconnect; 151 case WifiEntry.CONNECTED_STATE_CONNECTING: 152 return R.string.wifi_connecting; 153 default: 154 throw new IllegalStateException("Invalid WifiEntry connected state"); 155 } 156 } 157 getConnectDisconnectButtonIconResource()158 private int getConnectDisconnectButtonIconResource() { 159 switch (getWifiEntry().getConnectedState()) { 160 case WifiEntry.CONNECTED_STATE_DISCONNECTED: 161 case WifiEntry.CONNECTED_STATE_CONNECTING: 162 return R.drawable.ic_settings_wifi; 163 case WifiEntry.CONNECTED_STATE_CONNECTED: 164 return R.drawable.ic_close; 165 default: 166 throw new IllegalStateException("Invalid WifiEntry connected state"); 167 } 168 } 169 170 @SuppressLint("MissingPermission") openSharePage()171 private void openSharePage() { 172 if (mUri != null) { 173 getFragmentController().launchFragment( 174 WifiDetailsShareFragment.getInstance(mUri)); 175 } 176 } 177 178 @SuppressLint("MissingPermission") setUpSharePageInfo()179 private void setUpSharePageInfo() { 180 getCarWifiManager().getWifiManager().startEasyConnectAsEnrolleeResponder( 181 Build.DEVICE, 182 WifiManager.EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1, 183 getContext().getMainExecutor(), 184 new SettingsEasyConnectStatusCallback()); 185 } 186 187 private class SettingsEasyConnectStatusCallback extends EasyConnectStatusCallback { 188 189 @Override onBootstrapUriGenerated(@onNull Uri dppUri)190 public void onBootstrapUriGenerated(@NonNull Uri dppUri) { 191 super.onBootstrapUriGenerated(dppUri); 192 if (!dppUri.toString().equals(mUri)) { 193 mUri = dppUri.toString(); 194 refreshUi(); 195 } 196 } 197 198 @Override onFailure(int code)199 public void onFailure(int code) { 200 super.onFailure(code); 201 LOG.w("Unable to generate Easy Connect Wifi QR code : " + code); 202 if (mUri != null) { 203 mUri = null; 204 refreshUi(); 205 } 206 } 207 208 @Override onEnrolleeSuccess(int newNetworkId)209 public void onEnrolleeSuccess(int newNetworkId) { 210 // Do nothing. 211 } 212 213 @Override onConfiguratorSuccess(int code)214 public void onConfiguratorSuccess(int code) { 215 // Do nothing. 216 } 217 218 @Override onProgress(int code)219 public void onProgress(int code) { 220 // Do nothing. 221 } 222 } 223 } 224