blob: c04881827469443fa35171959360f251f45f6a14 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.car.settings.wifi.details;
import android.content.Context;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.XmlRes;
import com.android.car.settings.R;
import com.android.car.settings.common.Logger;
import com.android.car.settings.common.SettingsFragment;
import com.android.car.settings.wifi.WifiUtil;
import com.android.car.ui.toolbar.MenuItem;
import com.android.settingslib.wifi.AccessPoint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Shows details about a wifi network, including actions related to the network,
* e.g. ignore, disconnect, etc. The intent should include information about
* access point, use that to render UI, e.g. show SSID etc.
*/
public class WifiDetailsFragment extends SettingsFragment
implements WifiInfoProvider.Listener {
private static final String EXTRA_AP_STATE = "extra_ap_state";
private static final Logger LOG = new Logger(WifiDetailsFragment.class);
private WifiManager mWifiManager;
private AccessPoint mAccessPoint;
private MenuItem mForgetButton;
private MenuItem mConnectButton;
private List<WifiDetailsBasePreferenceController> mControllers = new ArrayList<>();
private WifiInfoProvider mWifiInfoProvider;
private class ActionFailListener implements WifiManager.ActionListener {
@StringRes
private final int mMessageResId;
ActionFailListener(@StringRes int messageResId) {
mMessageResId = messageResId;
}
@Override
public void onSuccess() {
}
@Override
public void onFailure(int reason) {
Toast.makeText(getContext(), mMessageResId, Toast.LENGTH_SHORT).show();
}
}
/**
* Gets an instance of this class.
*/
public static WifiDetailsFragment getInstance(AccessPoint accessPoint) {
WifiDetailsFragment wifiDetailsFragment = new WifiDetailsFragment();
Bundle bundle = new Bundle();
Bundle accessPointState = new Bundle();
accessPoint.saveWifiState(accessPointState);
bundle.putBundle(EXTRA_AP_STATE, accessPointState);
wifiDetailsFragment.setArguments(bundle);
return wifiDetailsFragment;
}
@Override
public List<MenuItem> getToolbarMenuItems() {
return Arrays.asList(mForgetButton, mConnectButton);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mForgetButton = new MenuItem.Builder(getContext())
.setTitle(R.string.forget)
.setOnClickListener(i -> {
WifiUtil.forget(getContext(), mAccessPoint);
goBack();
})
.build();
mConnectButton = new MenuItem.Builder(getContext())
.setTitle(R.string.wifi_setup_connect)
.setOnClickListener(i -> {
mWifiManager.connect(mAccessPoint.getConfig(),
new ActionFailListener(R.string.wifi_failed_connect_message));
goBack();
})
.build();
}
@Override
@XmlRes
protected int getPreferenceScreenResId() {
return R.xml.wifi_detail_fragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mAccessPoint = new AccessPoint(getContext(), getArguments().getBundle(EXTRA_AP_STATE));
mWifiManager = context.getSystemService(WifiManager.class);
LOG.d("Creating WifiInfoProvider for " + mAccessPoint);
if (mWifiInfoProvider == null) {
mWifiInfoProvider = new WifiInfoProvider(getContext(), mAccessPoint);
}
getLifecycle().addObserver(mWifiInfoProvider);
LOG.d("Creating WifiInfoProvider.Listeners.");
mControllers.add(use(
WifiSignalStrengthPreferenceController.class, R.string.pk_wifi_signal_strength)
.init(mAccessPoint, mWifiInfoProvider));
mControllers.add(use(WifiFrequencyPreferenceController.class, R.string.pk_wifi_frequency)
.init(mAccessPoint, mWifiInfoProvider));
mControllers.add(use(WifiSecurityPreferenceController.class, R.string.pk_wifi_security)
.init(mAccessPoint, mWifiInfoProvider));
mControllers.add(use(WifiMacAddressPreferenceController.class, R.string.pk_wifi_mac_address)
.init(mAccessPoint, mWifiInfoProvider));
mControllers.add(use(WifiIpAddressPreferenceController.class, R.string.pk_wifi_ip).init(
mAccessPoint, mWifiInfoProvider));
mControllers.add(use(WifiGatewayPreferenceController.class, R.string.pk_wifi_gateway).init(
mAccessPoint, mWifiInfoProvider));
mControllers.add(use(WifiSubnetPreferenceController.class, R.string.pk_wifi_subnet_mask)
.init(mAccessPoint, mWifiInfoProvider));
mControllers.add(use(WifiDnsPreferenceController.class, R.string.pk_wifi_dns).init(
mAccessPoint, mWifiInfoProvider));
mControllers.add(use(WifiLinkSpeedPreferenceController.class, R.string.pk_wifi_link_speed)
.init(mAccessPoint, mWifiInfoProvider));
mControllers.add(use(WifiIpv6AddressPreferenceController.class, R.string.pk_wifi_ipv6).init(
mAccessPoint, mWifiInfoProvider));
LOG.d("Done init.");
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getToolbar().setTitle(mAccessPoint.getSsid());
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
enableRotaryScroll();
}
@Override
public void onStart() {
super.onStart();
mWifiInfoProvider.addListener(this);
updateUi();
}
@Override
public void onStop() {
super.onStop();
mWifiInfoProvider.removeListener(this);
}
@Override
public void onDetach() {
super.onDetach();
getLifecycle().removeObserver(mWifiInfoProvider);
}
@Override
public void onWifiChanged(NetworkInfo networkInfo, WifiInfo wifiInfo) {
updateUi();
}
@Override
public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
updateUi();
}
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
updateUi();
}
@Override
public void onLost(Network network) {
updateUi();
}
@Override
public void onWifiConfigurationChanged(WifiConfiguration wifiConfiguration,
NetworkInfo networkInfo, WifiInfo wifiInfo) {
updateUi();
}
private void updateUi() {
LOG.d("updating.");
// No need to fetch LinkProperties and NetworkCapabilities, they are updated by the
// callbacks. mNetwork doesn't change except in onResume.
if (mWifiInfoProvider.getNetwork() == null
|| mWifiInfoProvider.getNetworkInfo() == null
|| mWifiInfoProvider.getWifiInfo() == null) {
LOG.d("WIFI not available.");
mForgetButton.setVisible(false);
mConnectButton.setVisible(false);
return;
}
mForgetButton.setVisible(canForgetNetwork());
mConnectButton.setVisible(needConnect());
LOG.d("updated.");
}
private boolean needConnect() {
return mAccessPoint.isSaved() && !mAccessPoint.isActive();
}
/**
* Returns whether the network represented by this fragment can be forgotten.
*/
private boolean canForgetNetwork() {
return (mWifiInfoProvider.getWifiInfo() != null
&& mWifiInfoProvider.getWifiInfo().isEphemeral()) || canModifyNetwork();
}
/**
* Returns whether the network represented by this preference can be modified.
*/
private boolean canModifyNetwork() {
WifiConfiguration wifiConfig = mWifiInfoProvider.getNetworkConfiguration();
LOG.d("wifiConfig is: " + wifiConfig);
return wifiConfig != null && !WifiUtil.isNetworkLockedDown(getContext(), wifiConfig);
}
}