Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e910c7af authored by Johnson Lu's avatar Johnson Lu Committed by Android (Google) Code Review
Browse files

Merge "Implement WifiNetworkListFragment"

parents f7e1a25e 0adba0aa
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@

            <include layout="@layout/wifi_dpp_fragment_header"/>

            <ListView android:id="@+id/saved_wifi_network_list"
            <LinearLayout android:id="@+id/wifi_network_list_container"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_constraintTop_toBottomOf="@+id/header"/>
+24 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
     Copyright (C) 2019 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.
-->

<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory
        android:key="access_points"
        android:layout="@layout/preference_category_no_label"/>
</PreferenceScreen>
 No newline at end of file
+14 −0
Original line number Diff line number Diff line
@@ -25,6 +25,9 @@ import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ListView;

import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;

@@ -33,6 +36,8 @@ import com.android.settings.R;
 * {@code WifiDppConfiguratorActivity} to start with this fragment to choose a saved Wi-Fi network.
 */
public class WifiDppChooseSavedWifiNetworkFragment extends WifiDppQrCodeBaseFragment {
    private static final String TAG_FRAGMENT_WIFI_NETWORK_LIST = "wifi_network_list_fragment";

    private ListView mSavedWifiNetworkList;
    private Button mButtonLeft;
    private Button mButtonRight;
@@ -50,6 +55,15 @@ public class WifiDppChooseSavedWifiNetworkFragment extends WifiDppQrCodeBaseFrag
        if (actionBar != null) {
            actionBar.hide();
        }

        /** Embeded WifiNetworkListFragment as child fragment within
         * WifiDppChooseSavedWifiNetworkFragment. */
        final FragmentManager fragmentManager = getChildFragmentManager();
        final WifiNetworkListFragment fragment = new WifiNetworkListFragment();
        final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.wifi_network_list_container, fragment,
                TAG_FRAGMENT_WIFI_NETWORK_LIST);
        fragmentTransaction.commit();
    }

    @Override
+10 −1
Original line number Diff line number Diff line
@@ -53,7 +53,9 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
        WifiDppQrCodeGeneratorFragment.OnQrCodeGeneratorFragmentAddButtonClickedListener,
        WifiDppQrCodeScannerFragment.OnScanWifiDppSuccessListener,
        WifiDppQrCodeScannerFragment.OnScanZxingWifiFormatSuccessListener,
        WifiDppAddDeviceFragment.OnClickChooseDifferentNetworkListener {
        WifiDppAddDeviceFragment.OnClickChooseDifferentNetworkListener,
        WifiNetworkListFragment.OnChooseNetworkListener {

    private static final String TAG = "WifiDppConfiguratorActivity";

    public static final String ACTION_CONFIGURATOR_QR_CODE_SCANNER =
@@ -329,4 +331,11 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements

        super.onSaveInstanceState(outState);
    }

    @Override
    public void onChooseNetwork(WifiNetworkConfig wifiNetworkConfig) {
        mWifiNetworkConfig = new WifiNetworkConfig(wifiNetworkConfig);

        showAddDeviceFragment(/* addToBackStack */ true);
    }
}
+317 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.settings.wifi.dpp;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.wifi.AddNetworkFragment;
import com.android.settingslib.wifi.AccessPoint;
import com.android.settingslib.wifi.AccessPointPreference;
import com.android.settingslib.wifi.WifiTracker;
import com.android.settingslib.wifi.WifiTrackerFactory;

import java.util.List;

import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;

public class WifiNetworkListFragment extends SettingsPreferenceFragment implements
        WifiTracker.WifiListener, AccessPoint.AccessPointListener {
    private static final String TAG = "WifiNetworkListFragment";

    private static final String WIFI_CONFIG_KEY = "wifi_config_key";
    private static final String PREF_KEY_EMPTY_WIFI_LIST = "wifi_empty_list";
    private static final String PREF_KEY_ACCESS_POINTS = "access_points";

    static final int ADD_NETWORK_REQUEST = 1;

    private PreferenceCategory mAccessPointsPreferenceCategory;
    private AccessPointPreference.UserBadgeCache mUserBadgeCache;
    private Preference mAddPreference;

    private WifiManager mWifiManager;
    private WifiTracker mWifiTracker;

    private WifiManager.ActionListener mSaveListener;

    // Container Activity must implement this interface
    public interface OnChooseNetworkListener {
        public void onChooseNetwork(WifiNetworkConfig wifiNetworkConfig);
    }

    OnChooseNetworkListener mOnChooseNetworkListener;

    @Override
    public int getMetricsCategory() {
        return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (!(context instanceof OnChooseNetworkListener)) {
            throw new IllegalArgumentException("Invalid context type");
        }
        mOnChooseNetworkListener = (OnChooseNetworkListener) context;
    }

    @Override
    public void onDetach() {
        mOnChooseNetworkListener = null;
        super.onDetach();
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mWifiTracker = WifiTrackerFactory.create(getActivity(), this,
                getSettingsLifecycle(), /* includeSaved */true, /* includeSaved */ true);
        mWifiManager = mWifiTracker.getManager();

        mSaveListener = new WifiManager.ActionListener() {
            @Override
            public void onSuccess() {
                // Do nothing.
            }

            @Override
            public void onFailure(int reason) {
                Activity activity = getActivity();
                if (activity != null) {
                    Toast.makeText(activity,
                            R.string.wifi_failed_save_message,
                            Toast.LENGTH_SHORT).show();
                }
            }
        };
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == ADD_NETWORK_REQUEST) {
            if (resultCode == Activity.RESULT_OK) {
                handleAddNetworkSubmitEvent(data);
            }
            mWifiTracker.resumeScanning();
        }
    }

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        addPreferencesFromResource(R.xml.wifi_dpp_network_list);

        mAccessPointsPreferenceCategory = (PreferenceCategory) findPreference(
                PREF_KEY_ACCESS_POINTS);

        mAddPreference = new Preference(getPrefContext());
        mAddPreference.setIcon(R.drawable.ic_menu_add);
        mAddPreference.setTitle(R.string.wifi_add_network);

        mUserBadgeCache = new AccessPointPreference.UserBadgeCache(getPackageManager());
    }

    /** Called when the state of Wifi has changed. */
    @Override
    public void onWifiStateChanged(int state) {
        final int wifiState = mWifiManager.getWifiState();
        switch (wifiState) {
            case WifiManager.WIFI_STATE_ENABLED:
                updateAccessPointPreferences();
                break;

            case WifiManager.WIFI_STATE_ENABLING:
            case WifiManager.WIFI_STATE_DISABLING:
                removeAccessPointPreferences();
                break;
        }
    }

    /** Called when the connection state of wifi has changed. */
    @Override
    public void onConnectedChanged() {
        // Do nothing.
    }

    /**
     * Called to indicate the list of AccessPoints has been updated and
     * getAccessPoints should be called to get the latest information.
     */
    @Override
    public void onAccessPointsChanged() {
        updateAccessPointPreferences();
    }

    @Override
    public void onAccessPointChanged(final AccessPoint accessPoint) {
        Log.d(TAG, "onAccessPointChanged (singular) callback initiated");
        View view = getView();
        if (view != null) {
            view.post(() -> {
                final Object tag = accessPoint.getTag();
                if (tag != null) {
                    ((AccessPointPreference) tag).refresh();
                }
            });
        }
    }

    @Override
    public void onLevelChanged(AccessPoint accessPoint) {
        ((AccessPointPreference) accessPoint.getTag()).onLevelChanged();
    }

    @Override
    public boolean onPreferenceTreeClick(Preference preference) {
        if (preference instanceof AccessPointPreference) {
            final AccessPoint selectedAccessPoint =
                    ((AccessPointPreference) preference).getAccessPoint();
            if (selectedAccessPoint == null) {
                return false;
            }

            // Launch WifiDppAddDeviceFragment to start DPP in Configurator-Initiator role.
            final WifiConfiguration wifiConfig = selectedAccessPoint.getConfig();
            if (wifiConfig == null) {
                throw new IllegalArgumentException("Invalid access point");
            }
            final WifiNetworkConfig networkConfig = WifiNetworkConfig.getValidConfigOrNull(
                    selectedAccessPoint.getSecurityString(/* concise */ true),
                    wifiConfig.getPrintableSsid(), wifiConfig.preSharedKey, /* hiddenSsid */ false,
                    wifiConfig.networkId);
            if (mOnChooseNetworkListener != null) {
                mOnChooseNetworkListener.onChooseNetwork(networkConfig);
            }
        } else if (preference == mAddPreference) {
            launchAddNetworkFragment();
        } else {
            return super.onPreferenceTreeClick(preference);
        }
        return true;
    }

    private void handleAddNetworkSubmitEvent(Intent data) {
        final WifiConfiguration wifiConfiguration = data.getParcelableExtra(WIFI_CONFIG_KEY);
        if (wifiConfiguration != null) {
            mWifiManager.save(wifiConfiguration, mSaveListener);
        }
    }

    private boolean isValidForDppConfiguration(AccessPoint accessPoint) {
        final int security = accessPoint.getSecurity();

        // DPP 1.0 only support SAE and PSK.
        if (!(security == AccessPoint.SECURITY_PSK || security == AccessPoint.SECURITY_SAE)) {
            return false;
        }

        // Can only use saved network for DPP configuration. For ephemeral connections networkId
        // is invalid.
        if (!accessPoint.isSaved()) {
            return false;
        }

        // Ignore access points that are out of range.
        if (!accessPoint.isReachable()) {
            return false;
        }

        return true;
    }

    private void launchAddNetworkFragment() {
        new SubSettingLauncher(getContext())
                .setTitleRes(R.string.wifi_add_network)
                .setDestination(AddNetworkFragment.class.getName())
                .setSourceMetricsCategory(getMetricsCategory())
                .setResultListener(this, ADD_NETWORK_REQUEST)
                .launch();
    }

    private void removeAccessPointPreferences() {
        mAccessPointsPreferenceCategory.removeAll();
        mAccessPointsPreferenceCategory.setVisible(false);
    }

    private void updateAccessPointPreferences() {
        // in case state has changed
        if (!mWifiManager.isWifiEnabled()) {
            return;
        }

        // AccessPoints are sorted by the WifiTracker
        final List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();

        boolean hasAvailableAccessPoints = false;
        mAccessPointsPreferenceCategory.setVisible(true);

        cacheRemoveAllPrefs(mAccessPointsPreferenceCategory);

        int index = 0;
        for (; index < accessPoints.size(); index++) {
            AccessPoint accessPoint = accessPoints.get(index);
            // Check if this access point is valid for DPP.
            if (isValidForDppConfiguration(accessPoint)) {
                final String key = accessPoint.getKey();
                hasAvailableAccessPoints = true;
                final AccessPointPreference pref = (AccessPointPreference) getCachedPreference(key);
                if (pref != null) {
                    pref.setOrder(index);
                    continue;
                }
                final AccessPointPreference preference = createAccessPointPreference(accessPoint);
                preference.setKey(key);
                preference.setOrder(index);

                mAccessPointsPreferenceCategory.addPreference(preference);
                accessPoint.setListener(this);
                preference.refresh();
            }
        }
        removeCachedPrefs(mAccessPointsPreferenceCategory);
        mAddPreference.setOrder(index);
        mAccessPointsPreferenceCategory.addPreference(mAddPreference);

        if (!hasAvailableAccessPoints) {
            final Preference pref = new Preference(getPrefContext());
            pref.setSelectable(false);
            pref.setSummary(R.string.wifi_empty_list_wifi_on);
            pref.setOrder(index++);
            pref.setKey(PREF_KEY_EMPTY_WIFI_LIST);
            mAccessPointsPreferenceCategory.addPreference(pref);
        }
    }

    private AccessPointPreference createAccessPointPreference(AccessPoint accessPoint) {
        return new AccessPointPreference(accessPoint, getPrefContext(), mUserBadgeCache,
                R.drawable.ic_wifi_signal_0, /* forSavedNetworks */ false);
    }
}
Loading