1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.settings.datausage; 16 17 import static android.net.ConnectivityManager.TYPE_WIFI; 18 19 import android.content.Context; 20 import android.net.ConnectivityManager; 21 import android.net.INetworkStatsService; 22 import android.net.INetworkStatsSession; 23 import android.net.NetworkTemplate; 24 import android.net.TrafficStats; 25 import android.os.RemoteException; 26 import android.os.ServiceManager; 27 import android.os.SystemProperties; 28 import android.telephony.SubscriptionInfo; 29 import android.telephony.SubscriptionManager; 30 import android.telephony.TelephonyManager; 31 import android.text.BidiFormatter; 32 import android.text.format.Formatter; 33 import android.text.format.Formatter.BytesResult; 34 35 import java.util.List; 36 37 /** 38 * Utility methods for data usage classes. 39 */ 40 public final class DataUsageUtils { 41 static final boolean TEST_RADIOS = false; 42 static final String TEST_RADIOS_PROP = "test.radios"; 43 private static final String ETHERNET = "ethernet"; 44 45 private DataUsageUtils() { 46 } 47 48 /** 49 * Format byte value to readable string using IEC units. 50 */ 51 public static CharSequence formatDataUsage(Context context, long byteValue) { 52 final BytesResult res = Formatter.formatBytes(context.getResources(), byteValue, 53 Formatter.FLAG_IEC_UNITS); 54 return BidiFormatter.getInstance().unicodeWrap(context.getString( 55 com.android.internal.R.string.fileSizeSuffix, res.value, res.units)); 56 } 57 58 /** 59 * Test if device has an ethernet network connection. 60 */ 61 public static boolean hasEthernet(Context context) { 62 if (DataUsageUtils.TEST_RADIOS) { 63 return SystemProperties.get(DataUsageUtils.TEST_RADIOS_PROP).contains(ETHERNET); 64 } 65 66 final ConnectivityManager conn = ConnectivityManager.from(context); 67 final boolean hasEthernet = conn.isNetworkSupported(ConnectivityManager.TYPE_ETHERNET); 68 69 final long ethernetBytes; 70 try { 71 INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( 72 ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); 73 74 INetworkStatsSession statsSession = statsService.openSession(); 75 if (statsSession != null) { 76 ethernetBytes = statsSession.getSummaryForNetwork( 77 NetworkTemplate.buildTemplateEthernet(), Long.MIN_VALUE, Long.MAX_VALUE) 78 .getTotalBytes(); 79 TrafficStats.closeQuietly(statsSession); 80 } else { 81 ethernetBytes = 0; 82 } 83 } catch (RemoteException e) { 84 throw new RuntimeException(e); 85 } 86 87 // only show ethernet when both hardware present and traffic has occurred 88 return hasEthernet && ethernetBytes > 0; 89 } 90 91 /** 92 * Returns whether device has mobile data. 93 * TODO: This is the opposite to Utils.isWifiOnly(), it should be refactored into 1 method. 94 */ 95 public static boolean hasMobileData(Context context) { 96 ConnectivityManager connectivityManager = ConnectivityManager.from(context); 97 return connectivityManager != null && connectivityManager 98 .isNetworkSupported(ConnectivityManager.TYPE_MOBILE); 99 } 100 101 /** 102 * Whether device has a Wi-Fi data radio. 103 */ 104 public static boolean hasWifiRadio(Context context) { 105 if (TEST_RADIOS) { 106 return SystemProperties.get(TEST_RADIOS_PROP).contains("wifi"); 107 } 108 109 ConnectivityManager connectivityManager = 110 context.getSystemService(ConnectivityManager.class); 111 return connectivityManager != null && connectivityManager.isNetworkSupported(TYPE_WIFI); 112 } 113 114 public static boolean hasSim(Context context) { 115 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 116 final int simState = telephonyManager.getSimState(); 117 // Note that pulling the SIM card returns UNKNOWN, not ABSENT. 118 return simState != TelephonyManager.SIM_STATE_ABSENT 119 && simState != TelephonyManager.SIM_STATE_UNKNOWN; 120 } 121 122 /** 123 * Returns the default subscription if available else returns 124 * SubscriptionManager#INVALID_SUBSCRIPTION_ID 125 */ 126 public static int getDefaultSubscriptionId(Context context) { 127 SubscriptionManager subManager = SubscriptionManager.from(context); 128 if (subManager == null) { 129 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 130 } 131 SubscriptionInfo subscriptionInfo = subManager.getDefaultDataSubscriptionInfo(); 132 if (subscriptionInfo == null) { 133 List<SubscriptionInfo> list = subManager.getAllSubscriptionInfoList(); 134 if (list.size() == 0) { 135 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 136 } 137 subscriptionInfo = list.get(0); 138 } 139 return subscriptionInfo.getSubscriptionId(); 140 } 141 142 /** 143 * Returns the default network template based on the availability of mobile data, Wifi. Returns 144 * ethernet template if both mobile data and Wifi are not available. 145 */ 146 static NetworkTemplate getDefaultTemplate(Context context, int defaultSubId) { 147 if (hasMobileData(context) && defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 148 TelephonyManager telephonyManager = TelephonyManager.from(context); 149 NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll( 150 telephonyManager.getSubscriberId(defaultSubId)); 151 return NetworkTemplate.normalize(mobileAll, 152 telephonyManager.getMergedSubscriberIds()); 153 } else if (hasWifiRadio(context)) { 154 return NetworkTemplate.buildTemplateWifiWildcard(); 155 } else { 156 return NetworkTemplate.buildTemplateEthernet(); 157 } 158 } 159 } 160