喜好

喜好检索

生活 蔬菜

蔬菜大全

思考

见闻与录

BT技术

BT蓝牙技术

标签

wifi列表字符summary显示流程 2021年04月12日

    简介

    文件

    frameworks/base/packages/SettingsLib/res/values/

    <string name="no_internet_access_text">This network has no internet access. Stay connected?</string>
    
    <string name="wifi_connected_no_internet" >"已连接,但无法访问互联网"</string> 
    <!-- Summary for Connected wifi network without internet --> 
    <string name="wifi_connected_no_internet">Connected, no internet</string>
    

    WifiSettings.java

    updateAccessPointPreferences()

        private void updateAccessPointPreferences() {
            // in case state has changed
            if (!mWifiManager.isWifiEnabled()) {
                return;
            }
            // AccessPoints are sorted by the WifiTracker
            final List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
            if (isVerboseLoggingEnabled()) {
                Log.i(TAG, "updateAccessPoints called for: " + accessPoints);
            }
    
            boolean hasAvailableAccessPoints = false;
            mAccessPointsPreferenceCategory.removePreference(mStatusMessagePreference);
            cacheRemoveAllPrefs(mAccessPointsPreferenceCategory);
    
            int index =
                    configureConnectedAccessPointPreferenceCategory(accessPoints) ? 1 : 0;
            int numAccessPoints = accessPoints.size();
            for (; index < numAccessPoints; index++) {
                AccessPoint accessPoint = accessPoints.get(index);
                // Ignore access points that are out of range.
                if (accessPoint.isReachable()) {
                    String key = accessPoint.getKey();
                    hasAvailableAccessPoints = true;
                    LongPressAccessPointPreference pref =
                            (LongPressAccessPointPreference) getCachedPreference(key);
                    if (pref != null) {
                        pref.setOrder(index);
                        continue;
                    }
                    LongPressAccessPointPreference preference =
                            createLongPressAccessPointPreference(accessPoint);
                    preference.setKey(key);
                    preference.setOrder(index);
                    if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr())
                            && accessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
                        if (!accessPoint.isSaved() || isDisabledByWrongPassword(accessPoint)) {
    			
                            onPreferenceTreeClick(preference);
                            mOpenSsid = null;
                        }
                    }
                    mAccessPointsPreferenceCategory.addPreference(preference);
                    accessPoint.setListener(WifiSettings.this);
                    preference.refresh();
                }
            }
            removeCachedPrefs(mAccessPointsPreferenceCategory);
            mAddPreference.setOrder(index);
            mAccessPointsPreferenceCategory.addPreference(mAddPreference);
            setAdditionalSettingsSummaries();
    
            if (!hasAvailableAccessPoints) {
                setProgressBarVisible(true);
                Preference pref = new Preference(getPrefContext());
                pref.setSelectable(false);
                pref.setSummary(R.string.wifi_empty_list_wifi_on);
     //  <string name="wifi_empty_list_wifi_on" >"正在搜索WLAN网络…"</string>
                pref.setOrder(index++);
                pref.setKey(PREF_KEY_EMPTY_WIFI_LIST);
                mAccessPointsPreferenceCategory.addPreference(pref);
            } else {
                // Continuing showing progress bar for an additional delay to overlap with animation
                getView().postDelayed(mHideProgressBarRunnable, 1700 /* delay millis */);
            }
        }
    
    
    

    WifiUtils.java

    frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java

    // 创建 Summary 详情
       public static String buildLoggingSummary(AccessPoint accessPoint, WifiConfiguration config) {
            final StringBuilder summary = new StringBuilder();
            final WifiInfo info = accessPoint.getInfo();  // 1.获得 WifiInfo
            // Add RSSI/band information for this config, what was seen up to 6 seconds ago
            // verbose WiFi Logging is only turned on thru developers settings
            if (accessPoint.isActive() && info != null) {    // 2.获得 频率   isActive 标识能扫描得到的
                summary.append(" f=" + Integer.toString(info.getFrequency()));
            }
            summary.append(" " + getVisibilityStatus(accessPoint));
            if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) {
                summary.append(" (" + config.getNetworkSelectionStatus().getNetworkStatusString());
                if (config.getNetworkSelectionStatus().getDisableTime() > 0) {
                    long now = System.currentTimeMillis();
                    long diff = (now - config.getNetworkSelectionStatus().getDisableTime()) / 1000;
                    long sec = diff % 60; //seconds
                    long min = (diff / 60) % 60; //minutes
                    long hour = (min / 60) % 60; //hours
                    summary.append(", ");
                    if (hour > 0) summary.append(Long.toString(hour) + "h ");
                    summary.append(Long.toString(min) + "m ");
                    summary.append(Long.toString(sec) + "s ");
                }
                summary.append(")");
            }
    
            if (config != null) {
                WifiConfiguration.NetworkSelectionStatus networkStatus =
                        config.getNetworkSelectionStatus();
                for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
                        index < WifiConfiguration.NetworkSelectionStatus
                                .NETWORK_SELECTION_DISABLED_MAX; index++) {
                    if (networkStatus.getDisableReasonCounter(index) != 0) {
                        summary.append(" " + WifiConfiguration.NetworkSelectionStatus
                                .getNetworkDisableReasonString(index) + "="
                                + networkStatus.getDisableReasonCounter(index));
                    }
                }
            }
    
            return summary.toString();
        }
    
    
    

    AccessPoint.java

    /frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java

        public String getSavedNetworkSummary() {
            WifiConfiguration config = mConfig;
            if (config != null) {
                PackageManager pm = mContext.getPackageManager();
                String systemName = pm.getNameForUid(android.os.Process.SYSTEM_UID);
                int userId = UserHandle.getUserId(config.creatorUid);
                ApplicationInfo appInfo = null;
                if (config.creatorName != null && config.creatorName.equals(systemName)) {
                    appInfo = mContext.getApplicationInfo();
                } else {
                    try {
                        IPackageManager ipm = AppGlobals.getPackageManager();
                        appInfo = ipm.getApplicationInfo(config.creatorName, 0 /* flags */, userId);
                    } catch (RemoteException rex) {
                    }
                }
                if (appInfo != null &&
                        !appInfo.packageName.equals(mContext.getString(R.string.settings_package)) &&
                        !appInfo.packageName.equals(
                        mContext.getString(R.string.certinstaller_package)) &&
                        !appInfo.packageName.equals(mContext.getString(R.string.WpaConfigApp_package))) {
    					// <string name="saved_network" >"由“<xliff:g id="NAME">%1$s</xliff:g>”保存"</string>
                    return mContext.getString(R.string.saved_network, appInfo.loadLabel(pm));
                }
            }
            return "";
        }
    
    	public static String getSummary(Context context, DetailedState state, boolean isEphemeral) {
            return getSummary(context, null, state, isEphemeral, null);
        }
    
        public static String getSummary(Context context, DetailedState state, boolean isEphemeral, String passpointProvider) {
            return getSummary(context, null, state, isEphemeral, passpointProvider);
        }
    	
        public String getSummary() {
            return getSettingsSummary(mConfig);
        }
    
        public String getSettingsSummary() {
            return getSettingsSummary(mConfig);
        }
    
        private String getSettingsSummary(WifiConfiguration config) {
            // Update to new summary
            StringBuilder summary = new StringBuilder();
    
            if (isActive() && config != null && config.isPasspoint()) {
                // This is the active connection on passpoint
                summary.append(getSummary(mContext, getDetailedState(),false, config.providerFriendlyName));
            } else if (isActive() && config != null && getDetailedState() == DetailedState.CONNECTED  && mIsCarrierAp) {
                summary.append(String.format(mContext.getString(R.string.connected_via_carrier), mCarrierName));
    			//  <string name="connected_via_carrier" >"已通过%1$s连接"</string>
            } else if (isActive()) {
                // This is the active connection on non-passpoint network
                summary.append(getSummary(mContext, getDetailedState(), mInfo != null && mInfo.isEphemeral()));  // 三参数
            } else if (config != null && config.isPasspoint()
                    && config.getNetworkSelectionStatus().isNetworkEnabled()) {
                String format = mContext.getString(R.string.available_via_passpoint);
    			// <string name="available_via_passpoint" >"可通过%1$s连接"</string>
                summary.append(String.format(format, config.providerFriendlyName));
            } else if (config != null && config.hasNoInternetAccess()) {
                int messageID = config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()
                        ? R.string.wifi_no_internet_no_reconnect
                        : R.string.wifi_no_internet;
    					//<string name="wifi_no_internet_no_reconnect" >"无法自动连接"</string>
    					//<string name="wifi_no_internet" >"无法访问互联网"</string>
    				
                summary.append(mContext.getString(messageID));
            } else if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) {
                WifiConfiguration.NetworkSelectionStatus networkStatus =
                        config.getNetworkSelectionStatus();
                switch (networkStatus.getNetworkSelectionDisableReason()) {
                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE:
                        summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
                     // <string name="wifi_disabled_password_failure" >"身份验证出现问题"</string>
                        break;
                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD:
                        summary.append(mContext.getString(R.string.wifi_check_password_try_again));
    					//  <string name="wifi_check_password_try_again" >"请检查密码,然后重试"</string>
                        break;
                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE:
                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_DNS_FAILURE:
                        summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
    					//<string name="wifi_disabled_network_failure" >"IP 配置失败"</string>
                        break;
                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION:
                        summary.append(mContext.getString(R.string.wifi_disabled_generic));
    					// <string name="wifi_disabled_generic" >"已停用"</string>
                        break;
                }
            } else if (config != null && config.getNetworkSelectionStatus().isNotRecommended()) {
                summary.append(mContext.getString(R.string.wifi_disabled_by_recommendation_provider));
    			//<string name="wifi_disabled_by_recommendation_provider" >"网络质量较差,因此未连接"</string>
            } else if (mIsCarrierAp) {
                summary.append(String.format(mContext.getString(R.string.available_via_carrier), mCarrierName));
    			//<string name="available_via_carrier" >"可通过%1$s连接"</string>
            } else if (!isReachable()) { // Wifi out of range
                summary.append(mContext.getString(R.string.wifi_not_in_range));
    			//<string name="wifi_not_in_range" >"不在范围内"</string>
            } else { // In range, not disabled.
                if (config != null) { // Is saved network
                    // Last attempt to connect to this failed. Show reason why
                    switch (config.recentFailure.getAssociationStatus()) {
                        case WifiConfiguration.RecentFailure.STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
                            summary.append(mContext.getString(R.string.wifi_ap_unable_to_handle_new_sta));
    						// <string name="wifi_ap_unable_to_handle_new_sta" >"接入点暂时满载"</string>
                            break;
                        default:
                            // "Saved"   
                            summary.append(mContext.getString(R.string.wifi_remembered));
    						// <string name="wifi_remembered" >"已保存"</string>
                            break;
                    }
                }
            }
    
            if (isVerboseLoggingEnabled()) {
                summary.append(WifiUtils.buildLoggingSummary(this, config));
            }
    
            if (config != null && (WifiUtils.isMeteredOverridden(config) || config.meteredHint)) {
    //  <string name="preference_summary_default_combination" >"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
                return mContext.getResources().getString(
                        R.string.preference_summary_default_combination,
                        WifiUtils.getMeteredLabel(mContext, config),
                        summary.toString());
            }
    
            // If Speed label and summary are both present, use the preference combination to combine
            // the two, else return the non-null one.
            if (getSpeedLabel() != null && summary.length() != 0) {
    //  <string name="preference_summary_default_combination" >"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
                return mContext.getResources().getString(
                        R.string.preference_summary_default_combination,
                        getSpeedLabel(),
                        summary.toString());
            } else if (getSpeedLabel() != null) {
                return getSpeedLabel();
            } else {
                return summary.toString();
            }
        }
    
     // 五参数
    public static String getSummary(Context context, String ssid, DetailedState state, boolean isEphemeral, String passpointProvider) {
            if (state == DetailedState.CONNECTED && ssid == null) {
                if (TextUtils.isEmpty(passpointProvider) == false) {
                    // Special case for connected + passpoint networks.
                    String format = context.getString(R.string.connected_via_passpoint);
    				//  <string name="connected_via_passpoint" >"已通过%1$s连接"</string>
                    return String.format(format, passpointProvider);
                } else if (isEphemeral) {
                    // Special case for connected + ephemeral networks.
                    final NetworkScoreManager networkScoreManager = context.getSystemService(
                            NetworkScoreManager.class);
                    NetworkScorerAppData scorer = networkScoreManager.getActiveScorer();
                    if (scorer != null && scorer.getRecommendationServiceLabel() != null) {
                        String format = context.getString(R.string.connected_via_network_scorer);
                        return String.format(format, scorer.getRecommendationServiceLabel());
                    } else {
                        return context.getString(R.string.connected_via_network_scorer_default);
                    }
                }
            }
    
            // Case when there is wifi connected without internet connectivity.  当网络没有internet能力的时候  ▲
            final ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            if (state == DetailedState.CONNECTED) {
                IWifiManager wifiManager = IWifiManager.Stub.asInterface(ServiceManager.getService(Context.WIFI_SERVICE));
                NetworkCapabilities nc = null;
    
                try {
                    nc = cm.getNetworkCapabilities(wifiManager.getCurrentNetwork()); // 依据networkId 获取网络能力
                } catch (RemoteException e) {}
    
                if (nc != null) {
                    if (nc.hasCapability(nc.NET_CAPABILITY_CAPTIVE_PORTAL)) {  // Portal 网络
                        int id = context.getResources().getIdentifier("network_available_sign_in", "string", "android");
    					// <string name="network_available_sign_in" >"登录到网络"</string>
    					
                        return context.getString(id);
                    } else if (!nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
    				//  <string name="wifi_connected_no_internet">Connected, no internet</string>
    				//  <string name="wifi_connected_no_internet" >"已连接,但无法访问互联网"</string>
                        return context.getString(R.string.wifi_connected_no_internet);
    					
                    }
                } else {
                    return "";
                }
            }
            if (state == null) {
                Log.w(TAG, "state is null, returning empty summary");
                return "";
            }
            String[] formats = context.getResources().getStringArray((ssid == null) ? R.array.wifi_status : R.array.wifi_status_with_ssid);
            int index = state.ordinal();
    
            if (index >= formats.length || formats[index].length() == 0) {
                return "";
            }
            return String.format(formats[index], ssid);
        }
    
      <string-array name="wifi_status">
        <item ></item>
        <item >"正在扫描..."</item>
        <item >"正在连接..."</item>
        <item >"正在验证身份…"</item>
        <item >"正在获取IP地址..."</item>
        <item >"已连接"</item>
        <item >"已暂停"</item>
        <item >"正在断开连接..."</item>
        <item >"已断开连接"</item>
        <item >"失败"</item>
        <item >"已停用"</item>
        <item >"暂时关闭(网络状况不佳)"</item>
      </string-array>
    
    
      <string-array name="wifi_status_with_ssid">
        <item ></item>
        <item >"正在扫描..."</item>
        <item >"正在连接到 <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
        <item >"正在通过 <xliff:g id="NETWORK_NAME">%1$s</xliff:g> 进行身份验证..."</item>
        <item >"正在从<xliff:g id="NETWORK_NAME">%1$s</xliff:g>获取IP地址..."</item>
        <item >"已连接到 <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
        <item >"已暂停"</item>
        <item >"正在断开与 <xliff:g id="NETWORK_NAME">%1$s</xliff:g> 的连接..."</item>
        <item >"已断开连接"</item>
        <item >"失败"</item>
        <item >"已停用"</item>
        <item >"暂时关闭(网络状况不佳)"</item>
      </string-array>
    
    

    AccessPointPreference.java

    public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,boolean forSavedNetworks) {
    setWidgetLayoutResource(R.layout.access_point_friction_widget);  // 图标布局文件为  access_point_friction_widget.xml
    
    
     setSummary(mForSavedNetworks ? mAccessPoint.getSavedNetworkSummary(): mAccessPoint.getSettingsSummary());  // ▲
    
    }
    		
    
    

    ConnectivityManager.java

    frameworks/base/core/java/android/net/ConnectivityManager.java getNetworkCapabilities

        public NetworkCapabilities getNetworkCapabilities(Network network) {
            try {
                return mService.getNetworkCapabilities(network);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    
    
    

    ConnectivityService.java

    frameworks/base/services/core/java/com/android/server/ConnectivityService.java

        @Override
        public NetworkCapabilities getNetworkCapabilities(Network network) {
            enforceAccessPermission();   //  检查权限
            return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
        }
    	
    	
        private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
            if (nai != null) {
                synchronized (nai) {
                    if (nai.networkCapabilities != null) {
                        return networkCapabilitiesRestrictedForCallerPermissions(
                                nai.networkCapabilities,
                                Binder.getCallingPid(), Binder.getCallingUid());
                    }
                }
            }
            return null;
        }
    
    
    	    private NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions( NetworkCapabilities nc, int callerPid, int callerUid) {
            final NetworkCapabilities newNc = new NetworkCapabilities(nc);
            if (!checkSettingsPermission(callerPid, callerUid)) {
                newNc.setUids(null);
                newNc.setSSID(null);
            }
            return newNc;
        }
    	
    	
        private NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
            if (network == null) {
                return null;
            }
            return getNetworkAgentInfoForNetId(network.netId);
        }
    
    	
    	
    	  private NetworkAgentInfo getNetworkAgentInfoForNetId(int netId) {
            synchronized (mNetworkForNetId) {
                return mNetworkForNetId.get(netId);
            }
        }
    	
    

    NetworkAgentInfo.java

    /frameworks/base/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java NetworkAgentInfo.networkCapabilities android.net.NetworkCapabilities;

    
      public NetworkCapabilities networkCapabilities;
    
      
          public String toString() {
            return "NetworkAgentInfo{ ni{" + networkInfo + "}  " +
                    "network{" + network + "}  nethandle{" + network.getNetworkHandle() + "}  " +
                    "lp{" + linkProperties + "}  " +
                    "nc{" + networkCapabilities + "}  Score{" + getCurrentScore() + "}  " +
                    "everValidated{" + everValidated + "}  lastValidated{" + lastValidated + "}  " +
                    "created{" + created + "} lingering{" + isLingering() + "} " +
                    "explicitlySelected{" + networkMisc.explicitlySelected + "} " +
                    "acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} " +
                    "everCaptivePortalDetected{" + everCaptivePortalDetected + "} " +
                    "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} " +
                    "clat{" + clatd + "} " +
                    "}";
        }
    	
    

    NetworkCapabilities.java

    /frameworks/base/core/java/android/net/NetworkCapabilities.java

    
    public final class NetworkCapabilities implements Parcelable {
        private static final String TAG = "NetworkCapabilities";
        private static final int INVALID_UID = -1;
    
    	
    	public NetworkCapabilities() {
            clearAll();
            mNetworkCapabilities = DEFAULT_CAPABILITIES;
        }
    	
        public NetworkCapabilities(NetworkCapabilities nc) {
            if (nc != null) {
                set(nc);
            }
        }
    
    	    public void clearAll() {
            mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0;
            mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
            mNetworkSpecifier = null;
            mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
            mUids = null;
            mEstablishingVpnAppUid = INVALID_UID;
            mSSID = null;
        }
    	
        public void set(NetworkCapabilities nc) {
            mNetworkCapabilities = nc.mNetworkCapabilities;
            mTransportTypes = nc.mTransportTypes;
            mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
            mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
            mNetworkSpecifier = nc.mNetworkSpecifier;
            mSignalStrength = nc.mSignalStrength;
            setUids(nc.mUids); // Will make the defensive copy
            mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
            mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
            mSSID = nc.mSSID;
        }
    	
    	
    	
    	
        public static final int NET_CAPABILITY_MMS            = 0;   // 发MMS 短信息的功能
        public static final int NET_CAPABILITY_SUPL           = 1; // 能访问运营商的 SUPL server服务器 得到 GPS位置信息的功能
    
    	// Dial Up Networking拨号网络的简称 
    	//用于执行一个拨号网络网桥,使载体能知道拨号网络流量的应用程序,此连接能与default连接同时使用
        public static final int NET_CAPABILITY_DUN            = 2;  // 能拨号上网的能力
        public static final int NET_CAPABILITY_FOTA           = 3;   // Firmware Over-The-Air  能连接到运营商的FOTA 进行升级
    
    	// IMS(IP Multimedia Subsystem)是IP多媒体子系统 
        public static final int NET_CAPABILITY_IMS            = 4; // 连接到运营商IMS服务器的能力
    
    	// Cloud Service Broker  云服务?
        public static final int NET_CAPABILITY_CBS            = 5;  // 连接到运营商CBS服务器的能力
        public static final int NET_CAPABILITY_WIFI_P2P       = 6; // 标记当前网络是WIFI P2P的网络    【】
        public static final int NET_CAPABILITY_IA             = 7;  // Initial Attach servers IA服务器
        public static final int NET_CAPABILITY_RCS            = 8;  //  RCS servers  运营商RCS服务器
    
        public static final int NET_CAPABILITY_XCAP           = 9;  // 运营商 XCAP 服务器     配置和控制
        public static final int NET_CAPABILITY_EIMS           = 10;  // Emergency IMS  EIMS servers  紧急通信服务
        public static final int NET_CAPABILITY_NOT_METERED    = 11;   // 标记当前网络未测量  【】
        public static final int NET_CAPABILITY_INTERNET       = 12;  //   标记当前网络有访问互联网的能力 【】 true:可访问互联网   false 不可访问互联网
    
        public static final int NET_CAPABILITY_NOT_RESTRICTED = 13;  // 可以正常使用的网络 【】
    
    	 // sim 卡选择的网络   相互连接的BT设备,   用户主动加入的网络  ,  不信任的网络仅限于未知网络 【】
        public static final int NET_CAPABILITY_TRUSTED        = 14;  // 标识用户对该网络隐式信任  【】
        public static final int NET_CAPABILITY_NOT_VPN        = 15;  //  默认的   不是VPN的网络   【】
    	
    	
    //  <string name="wifi_connected_no_internet">Connected, no internet</string>
    //  <string name="wifi_connected_no_internet" >"已连接,但无法访问互联网"</string>
        public static final int NET_CAPABILITY_VALIDATED      = 16; // 标识在该网络成功认证 true:认证成功  false: 认证失败 已连接无网络
        public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17;  // 指示该网络是 Portal网络 captive portal    【】
        public static final int NET_CAPABILITY_NOT_ROAMING = 18;    // 指示该网络没有 漫游    【】
        public static final int NET_CAPABILITY_FOREGROUND = 19; // 表示该网络可供应用程序使用 前台网络    【】
        public static final int NET_CAPABILITY_NOT_CONGESTED = 20;   // 指示当前网络具有推迟发送 防止拥挤的能力
    
    	 // 网络挂起 IP地址和网络连接保持有效 但是网络暂时无法发送数据
    	 // 窝蜂网络暂时丢失信号 
        public static final int NET_CAPABILITY_NOT_SUSPENDED = 21;    // 指示当前网络不会挂起  会一直传输数据 【】
    
        public static final int NET_CAPABILITY_OEM_PAID = 22; // 指示通过此网络的流量由oem支付  免流
    	
    	
    	
    	   // 能改变的性能指标
    	   private static final long MUTABLE_CAPABILITIES =
                (1 << NET_CAPABILITY_TRUSTED)
                | (1 << NET_CAPABILITY_VALIDATED)
                | (1 << NET_CAPABILITY_CAPTIVE_PORTAL)
                | (1 << NET_CAPABILITY_NOT_ROAMING)
                | (1 << NET_CAPABILITY_FOREGROUND)
                | (1 << NET_CAPABILITY_NOT_CONGESTED)
                | (1 << NET_CAPABILITY_NOT_SUSPENDED);
    
    
    		// 默认构造 NetworkCapabilities 对象时设置为true的标识
    		private static final long DEFAULT_CAPABILITIES =
                (1 << NET_CAPABILITY_NOT_RESTRICTED) |
                (1 << NET_CAPABILITY_TRUSTED) |
                (1 << NET_CAPABILITY_NOT_VPN);
    			
    }
    	
    	
    nc{[ Transports: WIFI Capabilities: NOT_METERED&INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&NOT_ROAMING&FOREGROUND&NOT_CONGESTED&NOT_SUSPENDED 
    
        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder("[");
            if (0 != mTransportTypes) {
                sb.append(" Transports: ");
                appendStringRepresentationOfBitMaskToStringBuilder(sb, mTransportTypes,
                        NetworkCapabilities::transportNameOf, "|");
            }
            if (0 != mNetworkCapabilities) {
                sb.append(" Capabilities: ");
                appendStringRepresentationOfBitMaskToStringBuilder(sb, mNetworkCapabilities,
                        NetworkCapabilities::capabilityNameOf, "&");
            }
            if (0 != mNetworkCapabilities) {
                sb.append(" Unwanted: ");
                appendStringRepresentationOfBitMaskToStringBuilder(sb, mUnwantedNetworkCapabilities,
                        NetworkCapabilities::capabilityNameOf, "&");
            }
            if (mLinkUpBandwidthKbps > 0) {
                sb.append(" LinkUpBandwidth>=").append(mLinkUpBandwidthKbps).append("Kbps");
            }
            if (mLinkDownBandwidthKbps > 0) {
                sb.append(" LinkDnBandwidth>=").append(mLinkDownBandwidthKbps).append("Kbps");
            }
            if (mNetworkSpecifier != null) {
                sb.append(" Specifier: <").append(mNetworkSpecifier).append(">");
            }
            if (hasSignalStrength()) {
                sb.append(" SignalStrength: ").append(mSignalStrength);
            }
    
            if (null != mUids) {
                if ((1 == mUids.size()) && (mUids.valueAt(0).count() == 1)) {
                    sb.append(" Uid: ").append(mUids.valueAt(0).start);
                } else {
                    sb.append(" Uids: <").append(mUids).append(">");
                }
            }
            if (mEstablishingVpnAppUid != INVALID_UID) {
                sb.append(" EstablishingAppUid: ").append(mEstablishingVpnAppUid);
            }
    
            if (null != mSSID) {
                sb.append(" SSID: ").append(mSSID);
            }
    
            sb.append("]");
            return sb.toString();
        }
    
    
    	
    	    public static String capabilityNameOf(@NetCapability int capability) {
            switch (capability) {
                case NET_CAPABILITY_MMS:            return "MMS";
                case NET_CAPABILITY_SUPL:           return "SUPL";
                case NET_CAPABILITY_DUN:            return "DUN";
                case NET_CAPABILITY_FOTA:           return "FOTA";
                case NET_CAPABILITY_IMS:            return "IMS";
                case NET_CAPABILITY_CBS:            return "CBS";
                case NET_CAPABILITY_WIFI_P2P:       return "WIFI_P2P";
                case NET_CAPABILITY_IA:             return "IA";
                case NET_CAPABILITY_RCS:            return "RCS";
                case NET_CAPABILITY_XCAP:           return "XCAP";
                case NET_CAPABILITY_EIMS:           return "EIMS";
                case NET_CAPABILITY_NOT_METERED:    return "NOT_METERED";
                case NET_CAPABILITY_INTERNET:       return "INTERNET";
                case NET_CAPABILITY_NOT_RESTRICTED: return "NOT_RESTRICTED";
                case NET_CAPABILITY_TRUSTED:        return "TRUSTED";
                case NET_CAPABILITY_NOT_VPN:        return "NOT_VPN";
                case NET_CAPABILITY_VALIDATED:      return "VALIDATED";
                case NET_CAPABILITY_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL";
                case NET_CAPABILITY_NOT_ROAMING:    return "NOT_ROAMING";
                case NET_CAPABILITY_FOREGROUND:     return "FOREGROUND";
                case NET_CAPABILITY_NOT_CONGESTED:  return "NOT_CONGESTED";
                case NET_CAPABILITY_NOT_SUSPENDED:  return "NOT_SUSPENDED";
                case NET_CAPABILITY_OEM_PAID:       return "OEM_PAID";
                default:                            return Integer.toString(capability);
            }
    		
    	
     public static void appendStringRepresentationOfBitMaskToStringBuilder(StringBuilder sb,long bitMask, NameOf nameFetcher, String separator) {
            int bitPos = 0;
            boolean firstElementAdded = false;
            while (bitMask != 0) {
                if ((bitMask & 1) != 0) {
                    if (firstElementAdded) {
                        sb.append(separator);
                    } else {
                        firstElementAdded = true;
                    }
                    sb.append(nameFetcher.nameOf(bitPos));
                }
                bitMask >>= 1;
                ++bitPos;
            }
        }
    	
    	
    	
    WIFI Capabilities: NOT_METERED&INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&NOT_ROAMING&FOREGROUND&NOT_CONGESTED&NOT_SUSPENDED
    WIFI CAPABILITIES: NOT_METERED&INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&VALIDATED&NOT_ROAMING&FOREGROUND&NOT_CONGESTED&NOT_SUSPENDED
    
    
    
    	
    

    access_point_friction_widget.xml

    SettingsLib/res/layout/access_point_friction_widget.xml WIFI 图标ImageView

    <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/friction_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:contentDescription="@null" />
    	
    	
    AccessPointPreference.java
     private final StateListDrawable mFrictionSld;
     ImageView frictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
     bindFrictionImage(frictionImageView);
     
     
         /**
         * Binds the friction icon drawable using a StateListDrawable.
         *
         * <p>Friction icons will be rebound when notifyChange() is called, and therefore
         * do not need to be managed in refresh()</p>.
         */
        private void bindFrictionImage(ImageView frictionImageView) {
            if (frictionImageView == null || mFrictionSld == null) {
                return;
            }
            if (mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
                mFrictionSld.setState(STATE_SECURED);
            } else if (mAccessPoint.isMetered()) {
                mFrictionSld.setState(STATE_METERED);
            }
            Drawable drawable = mFrictionSld.getCurrent();
            frictionImageView.setImageDrawable(drawable);
        }
    	
    	
    	 getFrictionStateListDrawable(context)
    	 
    	 
    	     private static StateListDrawable getFrictionStateListDrawable(Context context) {
            TypedArray frictionSld;
            try {
                frictionSld = context.getTheme().obtainStyledAttributes(FRICTION_ATTRS); // { R.attr.wifi_friction }
            } catch (Resources.NotFoundException e) {
                // Fallback for platforms that do not need friction icon resources.
                frictionSld = null;
            }
            return frictionSld != null ? (StateListDrawable) frictionSld.getDrawable(0) : null;
        }
    	
    	    private static final int[] FRICTION_ATTRS = {
                R.attr.wifi_friction
        };
    	
    /SettingsLib/res/values/attrs.xml  <attr name="wifi_friction" format="reference" />
    /packages/apps/Settings/res/values/themes.xml      <item name="wifi_friction">@drawable/wifi_friction</item>
    
    packages/apps/Settings/res/drawable/wifi_friction.xml	
    

    wifi_friction.xml

    packages/apps/Settings/res/drawable/wifi_friction.xml

    <?xml version="1.0" encoding="utf-8"?>
    packages/apps/Settings/res/drawable/wifi_friction.xml	
    <selector xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
        <item
            settings:state_encrypted="true"
            android:drawable="@drawable/ic_friction_lock_closed"/>
        <item
            settings:state_metered="true"
            android:drawable="@drawable/ic_friction_money"/>
    </selector>
    
    
    packages/apps/Settings/res/drawable/ic_friction_lock_closed.xml	
    <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
            android:viewportWidth="48"
            android:viewportHeight="48"
            android:width="18dp"
            android:height="18dp">
        <path
            android:pathData="M36 16l-2 0 0 -4C34 6.48 29.52 2 24 2 18.48 2 14 6.48 14 12l0 4 -2 0c-2.21 0 -4 1.79 -4 4l0 20c0 2.21 1.79 4 4 4l24 0c2.21 0 4 -1.79 4 -4l0 -20c0 -2.21 -1.79 -4 -4 -4zM24 34c-2.21 0 -4 -1.79 -4 -4 0 -2.21 1.79 -4 4 -4 2.21 0 4 1.79 4 4 0 2.21 -1.79 4 -4 4zm6.2 -18l-12.4 0 0 -4c0 -3.42 2.78 -6.2 6.2 -6.2 3.42 0 6.2 2.78 6.2 6.2l0 4z"
            android:fillColor="?android:attr/colorForeground"
            android:fillAlpha="0.54" />
    </vector>
    
    
    packages/apps/Settings/res/drawable/ic_friction_money.xml
    <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
            android:viewportWidth="18"
            android:viewportHeight="18"
            android:width="18dp"
            android:height="18dp">
    
        <path android:fillColor="?android:attr/colorForeground"
              android:fillAlpha="0.54"
              android:pathData="M9.56 8.1c-1.6-.51-2.66-.71-2.66-1.88 0-.83 .72 -1.62 2.1-1.62 1.59 0 2.1 .88
              2.1 1.94H13c0-1.79-1.17-3.09-3-3.44V1H8v2.11c-1.58 .32 -3 1.37-3 3.12 0 2.25
              1.78 2.8 4 3.52 1.88 .61 2.25 1.04 2.25 2.09 0 .9-.67 1.56-2.25 1.56-1.2
              0-2.25-.84-2.25-2.06h-2c0 1.88 1.38 3.2 3.25 3.56V17h2v-2.07c2.04-.29 3.2-1.49
              3.2-3.1 0-1.87-.94-2.87-3.64-3.73z" />
        <path android:pathData="M0 0h18v18H0z" />
    </vector>
    
    

    < img src=”ic_friction_lock_closed” /> < img src=”ic_friction_money” />

    preference.xml

    /frameworks/base/core/res/res/layout/preference.xml Acesspoint热点布局

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="?android:attr/listPreferredItemHeight"
        android:gravity="center_vertical"
        android:paddingEnd="?android:attr/scrollbarSize"
        android:background="?android:attr/selectableItemBackground" >
    
        <ImageView
            android:id="@+android:id/icon"   // 显示  wifi信号质量的图标
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            />
    
        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="15dip"
            android:layout_marginEnd="6dip"
            android:layout_marginTop="6dip"
            android:layout_marginBottom="6dip"
            android:layout_weight="1">
    
            <TextView android:id="@+android:id/title"   // 显示  WIFI 热点  名字
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:ellipsize="marquee"
                android:fadingEdge="horizontal" />
    
            <TextView android:id="@+android:id/summary"   //   显示 热点 简要
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@android:id/title"
                android:layout_alignStart="@android:id/title"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:textColor="?android:attr/textColorSecondary"
                android:maxLines="4" />
    
        </RelativeLayout>
    
        <!-- Preference should place its actual preference widget here. -->  
        <LinearLayout android:id="@+android:id/widget_frame"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center_vertical"
            android:orientation="vertical" />
    
    </LinearLayout>
    
    
    

    Log

    	
    WIFI Capabilities: NOT_METERED&INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&NOT_ROAMING&FOREGROUND&NOT_CONGESTED&NOT_SUSPENDED
    WIFI CAPABILITIES: NOT_METERED&INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&VALIDATED&NOT_ROAMING&FOREGROUND&NOT_CONGESTED&NOT_SUSPENDED