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

Commit 36ae9189 authored by Weng Su's avatar Weng Su
Browse files

Show Hotspot informations in Network details settings

- Show Hotspot device type in hearder icon

- Show Hotspot device details informations.
  - Internet source (network type)
  - Battery

Bug: 297346368
Test: manual test
atest -c WifiNetworkDetailsFragmentTest \
         WifiDetailPreferenceController2Test
atest -c SharedConnectivityRepositoryTest \
         WifiNetworkDetailsViewModelTest

Merged-In: I4bd090e00681911c8fac469289fd818237b8c518
Change-Id: I4bd090e00681911c8fac469289fd818237b8c518
parent 32c75f49
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -1980,6 +1980,21 @@
    <!-- Wifi details preference category title for IPv6 information -->
    <string name="wifi_details_ipv6_address_header">IPv6 addresses</string>
    <!-- Hotspot device details preference category title in Network details [CHAR LIMIT=NONE]-->
    <string name="hotspot_device_details_category">Hotspot device details</string>
    <!-- Internet source preference in Hotspot device details preference category [CHAR LIMIT=NONE]-->
    <string name="hotspot_device_details_internet_source">Internet source</string>
    <!-- Wi-Fi summary in Internet source preference [CHAR LIMIT=NONE]-->
    <string name="internet_source_wifi">Wi\u2011Fi</string>
    <!-- Mobile data summary in Internet source preference [CHAR LIMIT=NONE]-->
    <string name="internet_source_mobile_data">Mobile data</string>
    <!-- Ethernet summary in Internet source preference [CHAR LIMIT=NONE]-->
    <string name="internet_source_ethernet">Ethernet</string>
    <!-- Hotspot device details preference category title in Network details [CHAR LIMIT=NONE]-->
    <string name="hotspot_connection_category">Hotspot connection</string>
    <!-- Connection strength preference in Hotspot connection preference category [CHAR LIMIT=NONE]-->
    <string name="hotspot_connection_strength">Connection strength</string>
    <!-- Wifi saved access points.  Used as a label under the shortcut icon that goes to Wifi saved access points. [CHAR LIMIT=20] -->
    <string name="wifi_saved_access_points_label">Saved networks</string>
    <!-- Tab title for showing subscribed WiFi access points. [CHAR LIMIT=20] -->
+24 −0
Original line number Diff line number Diff line
@@ -40,6 +40,30 @@
        android:key="buttons"
        android:selectable="false"/>

    <!-- Hotspot device details category -->
    <PreferenceCategory
        android:key="hotspot_device_details_category"
        android:title="@string/hotspot_device_details_category"
        settings:isPreferenceVisible="false">
        <Preference
            android:key="hotspot_device_details_internet_source"
            android:title="@string/hotspot_device_details_internet_source"
            android:selectable="false"
            settings:enableCopying="true"/>
        <Preference
            android:key="hotspot_device_details_battery"
            android:title="@string/power_usage_summary_title"
            android:selectable="false"
            settings:enableCopying="true"/>
    </PreferenceCategory>

    <!-- Hotspot connection category -->
    <PreferenceCategory
        android:key="hotspot_connection_category"
        android:title="@string/hotspot_connection_category"
        settings:isPreferenceVisible="false">
    </PreferenceCategory>

    <!-- General Details Preferences -->
    <Preference
        android:key="signal_strength"
+119 −1
Original line number Diff line number Diff line
@@ -15,14 +15,19 @@
 */
package com.android.settings.wifi.details;

import static com.android.settings.network.telephony.MobileNetworkUtils.NO_CELL_DATA_TYPE_ICON;
import static com.android.settings.wifi.WifiSettings.WIFI_DIALOG_ID;
import static com.android.settingslib.Utils.formatPercentage;

import android.app.Dialog;
import android.app.admin.DevicePolicyManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.net.wifi.sharedconnectivity.app.HotspotNetwork;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -32,19 +37,23 @@ import android.os.SimpleClock;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.telephony.SignalStrength;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;

import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.wifi.WifiConfigUiBase2;
import com.android.settings.wifi.WifiDialog2;
import com.android.settings.wifi.WifiUtils;
import com.android.settings.wifi.details2.AddDevicePreferenceController2;
import com.android.settings.wifi.details2.WifiAutoConnectPreferenceController2;
import com.android.settings.wifi.details2.WifiDetailPreferenceController2;
@@ -52,10 +61,12 @@ import com.android.settings.wifi.details2.WifiMeteredPreferenceController2;
import com.android.settings.wifi.details2.WifiPrivacyPreferenceController2;
import com.android.settings.wifi.details2.WifiSecondSummaryController2;
import com.android.settings.wifi.details2.WifiSubscriptionDetailPreferenceController2;
import com.android.settings.wifi.repository.SharedConnectivityRepository;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.graph.ThemedBatteryDrawable;
import com.android.wifitrackerlib.NetworkDetailsTracker;
import com.android.wifitrackerlib.WifiEntry;

@@ -78,6 +89,12 @@ public class WifiNetworkDetailsFragment extends RestrictedDashboardFragment impl
    // Key of a Bundle to save/restore the selected WifiEntry
    public static final String KEY_CHOSEN_WIFIENTRY_KEY = "key_chosen_wifientry_key";

    public static final String KEY_HOTSPOT_DEVICE_CATEGORY = "hotspot_device_details_category";
    public static final String KEY_HOTSPOT_DEVICE_INTERNET_SOURCE =
            "hotspot_device_details_internet_source";
    public static final String KEY_HOTSPOT_DEVICE_BATTERY = "hotspot_device_details_battery";
    public static final String KEY_HOTSPOT_CONNECTION_CATEGORY = "hotspot_connection_category";

    // Max age of tracked WifiEntries
    private static final long MAX_SCAN_AGE_MILLIS = 15_000;
    // Interval between initiating SavedNetworkTracker scans
@@ -88,10 +105,15 @@ public class WifiNetworkDetailsFragment extends RestrictedDashboardFragment impl
    @VisibleForTesting
    NetworkDetailsTracker mNetworkDetailsTracker;
    private HandlerThread mWorkerThread;
    private WifiDetailPreferenceController2 mWifiDetailPreferenceController2;
    @VisibleForTesting
    WifiDetailPreferenceController2 mWifiDetailPreferenceController2;
    private List<WifiDialog2.WifiDialog2Listener> mWifiDialogListeners = new ArrayList<>();
    @VisibleForTesting
    List<AbstractPreferenceController> mControllers;
    private boolean mIsInstantHotspotFeatureEnabled =
            SharedConnectivityRepository.isDeviceConfigEnabled();
    @VisibleForTesting
    WifiNetworkDetailsViewModel mWifiNetworkDetailsViewModel;

    public WifiNetworkDetailsFragment() {
        super(UserManager.DISALLOW_CONFIG_WIFI);
@@ -207,6 +229,10 @@ public class WifiNetworkDetailsFragment extends RestrictedDashboardFragment impl
        setupNetworksDetailTracker();
        final WifiEntry wifiEntry = mNetworkDetailsTracker.getWifiEntry();

        if (mIsInstantHotspotFeatureEnabled) {
            getWifiNetworkDetailsViewModel().setWifiEntry(wifiEntry);
        }

        final WifiSecondSummaryController2 wifiSecondSummaryController2 =
                new WifiSecondSummaryController2(context);
        wifiSecondSummaryController2.setWifiEntry(wifiEntry);
@@ -335,5 +361,97 @@ public class WifiNetworkDetailsFragment extends RestrictedDashboardFragment impl
            }
            controller.displayPreference(screen);
        }
        if (mIsInstantHotspotFeatureEnabled) {
            getWifiNetworkDetailsViewModel().setWifiEntry(mNetworkDetailsTracker.getWifiEntry());
        }
    }

    private WifiNetworkDetailsViewModel getWifiNetworkDetailsViewModel() {
        if (mWifiNetworkDetailsViewModel == null) {
            mWifiNetworkDetailsViewModel = FeatureFactory.getFactory(getContext())
                    .getWifiFeatureProvider().getWifiNetworkDetailsViewModel(this);
            mWifiNetworkDetailsViewModel.getHotspotNetworkData()
                    .observe(this, this::onHotspotNetworkChanged);
        }
        return mWifiNetworkDetailsViewModel;
    }

    @VisibleForTesting
    void onHotspotNetworkChanged(WifiNetworkDetailsViewModel.HotspotNetworkData data) {
        PreferenceScreen screen = getPreferenceScreen();
        if (screen == null) {
            return;
        }
        if (data == null) {
            screen.findPreference(KEY_HOTSPOT_DEVICE_CATEGORY).setVisible(false);
            screen.findPreference(KEY_HOTSPOT_CONNECTION_CATEGORY).setVisible(false);
            if (mWifiDetailPreferenceController2 != null) {
                mWifiDetailPreferenceController2.setSignalStrengthTitle(R.string.wifi_signal);
            }
            return;
        }
        screen.findPreference(KEY_HOTSPOT_DEVICE_CATEGORY).setVisible(true);
        updateInternetSource(data.getNetworkType(), data.getUpstreamConnectionStrength());
        updateBattery(data.isBatteryCharging(), data.getBatteryPercentage());

        screen.findPreference(KEY_HOTSPOT_CONNECTION_CATEGORY).setVisible(true);
        if (mWifiDetailPreferenceController2 != null) {
            mWifiDetailPreferenceController2
                    .setSignalStrengthTitle(R.string.hotspot_connection_strength);
        }
    }

    @VisibleForTesting
    void updateInternetSource(int networkType, int upstreamConnectionStrength) {
        Preference internetSource = getPreferenceScreen()
                .findPreference(KEY_HOTSPOT_DEVICE_INTERNET_SOURCE);
        Drawable drawable;
        if (networkType == HotspotNetwork.NETWORK_TYPE_WIFI) {
            internetSource.setSummary(R.string.internet_source_wifi);
            drawable = getContext().getDrawable(
                    WifiUtils.getInternetIconResource(upstreamConnectionStrength, false));
        } else if (networkType == HotspotNetwork.NETWORK_TYPE_CELLULAR) {
            internetSource.setSummary(R.string.internet_source_mobile_data);
            drawable = getMobileDataIcon(upstreamConnectionStrength);
        } else if (networkType == HotspotNetwork.NETWORK_TYPE_ETHERNET) {
            internetSource.setSummary(R.string.internet_source_ethernet);
            drawable = getContext().getDrawable(R.drawable.ic_settings_ethernet);
        } else {
            internetSource.setSummary(R.string.summary_placeholder);
            drawable = null;
        }
        if (drawable != null) {
            drawable.setTintList(
                    Utils.getColorAttr(getContext(), android.R.attr.colorControlNormal));
        }
        internetSource.setIcon(drawable);
    }

    @VisibleForTesting
    Drawable getMobileDataIcon(int level) {
        return MobileNetworkUtils.getSignalStrengthIcon(getContext(), level,
                SignalStrength.NUM_SIGNAL_STRENGTH_BINS, NO_CELL_DATA_TYPE_ICON, false, false);
    }

    @VisibleForTesting
    void updateBattery(boolean isChanging, int percentage) {
        Preference battery = getPreferenceScreen().findPreference(KEY_HOTSPOT_DEVICE_BATTERY);
        battery.setSummary(formatPercentage(percentage));
        ThemedBatteryDrawable drawable = getBatteryDrawable();
        if (drawable != null) {
            drawable.setCharging(isChanging);
            drawable.setBatteryLevel(percentage);
        }
        battery.setIcon(drawable);
    }

    @VisibleForTesting
    ThemedBatteryDrawable getBatteryDrawable() {
        int frameColor = getContext().getColor(R.color.meter_background_color);
        ThemedBatteryDrawable drawable = new ThemedBatteryDrawable(getContext(), frameColor);
        ColorFilter colorFilter = Utils.getAlphaInvariantColorFilterForColor(
                Utils.getColorAttrDefaultColor(getContext(), android.R.attr.colorControlNormal));
        drawable.setColorFilter(colorFilter);
        return drawable;
    }
}
+118 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.details;

import android.app.Application;

import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import com.android.settings.overlay.FeatureFactory;
import com.android.wifitrackerlib.HotspotNetworkEntry;
import com.android.wifitrackerlib.WifiEntry;

import org.jetbrains.annotations.NotNull;

/**
 * Wi-Fi Network Details ViewModel
 */
public class WifiNetworkDetailsViewModel extends AndroidViewModel {
    private static final String TAG = "WifiNetworkDetailsViewModel";

    @VisibleForTesting
    MutableLiveData<HotspotNetworkData> mHotspotNetworkData = new MutableLiveData<>();

    public WifiNetworkDetailsViewModel(@NotNull Application application) {
        super(application);
    }

    /** Sets the {@link WifiEntry} class */
    public void setWifiEntry(WifiEntry wifiEntry) {
        if (!(wifiEntry instanceof HotspotNetworkEntry)) {
            log("post HotspotNetworkData:null");
            mHotspotNetworkData.postValue(null);
            return;
        }
        HotspotNetworkEntry entry = (HotspotNetworkEntry) wifiEntry;
        HotspotNetworkData data = new HotspotNetworkData(
                entry.getNetworkType(),
                entry.getUpstreamConnectionStrength(),
                entry.getBatteryPercentage(),
                entry.isBatteryCharging());
        log("post HotspotNetworkData:" + data);
        mHotspotNetworkData.postValue(data);
    }

    /** Gets the {@link HotspotNetworkData} LiveData */
    public LiveData<HotspotNetworkData> getHotspotNetworkData() {
        return mHotspotNetworkData;
    }

    /** The {@link HotspotNetworkData} class */
    static class HotspotNetworkData {
        private int mNetworkType;
        private int mUpstreamConnectionStrength;
        private int mBatteryPercentage;
        private boolean mIsBatteryCharging;

        HotspotNetworkData(int networkType, int upstreamConnectionStrength,
                int batteryPercentage,
                boolean isBatteryCharging) {
            mNetworkType = networkType;
            mUpstreamConnectionStrength = upstreamConnectionStrength;
            mBatteryPercentage = batteryPercentage;
            mIsBatteryCharging = isBatteryCharging;
        }

        /** Gets the network type */
        public int getNetworkType() {
            return mNetworkType;
        }

        /** Gets the upstream connection strength */
        public int getUpstreamConnectionStrength() {
            return mUpstreamConnectionStrength;
        }

        /** Gets the battery percentage */
        public int getBatteryPercentage() {
            return mBatteryPercentage;
        }

        /** Returns true if the battery is charging */
        public boolean isBatteryCharging() {
            return mIsBatteryCharging;
        }

        @Override
        public String toString() {
            return getClass().getSimpleName()
                    + ":{networkType:" + mNetworkType
                    + ", upstreamConnectionStrength:" + mUpstreamConnectionStrength
                    + ", batteryPercentage:" + mBatteryPercentage
                    + ", isBatteryCharging:" + mIsBatteryCharging
                    + " }";
        }
    }

    private void log(String msg) {
        FeatureFactory.getFactory(getApplication().getApplicationContext()).getWifiFeatureProvider()
                .verboseLog(TAG, msg);
    }
}
+41 −12
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID;

import static com.android.settingslib.wifi.WifiUtils.getHotspotIconResource;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.settings.SettingsEnums;
@@ -86,6 +88,7 @@ import com.android.settingslib.core.lifecycle.events.OnResume;
import com.android.settingslib.utils.StringUtil;
import com.android.settingslib.widget.ActionButtonsPreference;
import com.android.settingslib.widget.LayoutPreference;
import com.android.wifitrackerlib.HotspotNetworkEntry;
import com.android.wifitrackerlib.WifiEntry;
import com.android.wifitrackerlib.WifiEntry.ConnectCallback;
import com.android.wifitrackerlib.WifiEntry.DisconnectCallback;
@@ -172,7 +175,8 @@ public class WifiDetailPreferenceController2 extends AbstractPreferenceControlle

    // UI elements - in order of appearance
    private ActionButtonsPreference mButtonsPref;
    private EntityHeaderController mEntityHeaderController;
    @VisibleForTesting
    EntityHeaderController mEntityHeaderController;
    private Preference mSignalStrengthPref;
    private Preference mTxLinkSpeedPref;
    private Preference mRxLinkSpeedPref;
@@ -535,6 +539,8 @@ public class WifiDetailPreferenceController2 extends AbstractPreferenceControlle
    private void refreshPage() {
        Log.d(TAG, "Update UI!");

        // refresh header icon
        refreshEntryHeaderIcon();
        // refresh header
        refreshEntityHeader();

@@ -563,9 +569,33 @@ public class WifiDetailPreferenceController2 extends AbstractPreferenceControlle
        refreshWifiType();
    }

    private void refreshRssiViews() {
        final int signalLevel = mWifiEntry.getLevel();
    @VisibleForTesting
    void refreshEntryHeaderIcon() {
        if (mEntityHeaderController == null) {
            return;
        }
        Drawable drawable = getWifiDrawable(mWifiEntry);
        mEntityHeaderController
                .setIcon(redrawIconForHeader(drawable))
                .done(mFragment.getActivity(), true /* rebind */);
    }

    /**
     * Returns a Wi-Fi icon {@link Drawable}.
     *
     * @param wifiEntry {@link WifiEntry}
     */
    @VisibleForTesting
    Drawable getWifiDrawable(WifiEntry wifiEntry) {
        if (wifiEntry instanceof HotspotNetworkEntry) {
            int deviceType = ((HotspotNetworkEntry) wifiEntry).getDeviceType();
            return mContext.getDrawable(getHotspotIconResource(deviceType));
        }
        return mIconInjector.getIcon(wifiEntry.shouldShowXLevelIcon(), wifiEntry.getLevel());
    }

    private void refreshRssiViews() {
        int signalLevel = mWifiEntry.getLevel();
        // Disappears signal view if not in range. e.g. for saved networks.
        if (signalLevel == WifiEntry.WIFI_LEVEL_UNREACHABLE) {
            mSignalStrengthPref.setVisible(false);
@@ -573,21 +603,13 @@ public class WifiDetailPreferenceController2 extends AbstractPreferenceControlle
            return;
        }

        final boolean showX = mWifiEntry.shouldShowXLevelIcon();

        boolean showX = mWifiEntry.shouldShowXLevelIcon();
        if (mRssiSignalLevel == signalLevel && mShowX == showX) {
            return;
        }
        mRssiSignalLevel = signalLevel;
        mShowX = showX;
        Drawable wifiIcon = mIconInjector.getIcon(mShowX, mRssiSignalLevel);

        if (mEntityHeaderController != null) {
            mEntityHeaderController
                    .setIcon(redrawIconForHeader(wifiIcon)).done(mFragment.getActivity(),
                            true /* rebind */);
        }

        Drawable wifiIconDark = wifiIcon.getConstantState().newDrawable().mutate();
        wifiIconDark.setTintList(Utils.getColorAttr(mContext, android.R.attr.colorControlNormal));
        mSignalStrengthPref.setIcon(wifiIconDark);
@@ -1124,4 +1146,11 @@ public class WifiDetailPreferenceController2 extends AbstractPreferenceControlle
    public void onSignInResult(@SignInStatus int status) {
        refreshPage();
    }

    /** Sets signal strength title */
    public void setSignalStrengthTitle(int titleResId) {
        if (mSignalStrengthPref != null) {
            mSignalStrengthPref.setTitle(titleResId);
        }
    }
}
Loading