1 package com.android.tv.settings.library.about; 2 3 import android.annotation.ColorInt; 4 import android.annotation.Nullable; 5 import android.content.Context; 6 import android.content.Intent; 7 import android.content.pm.PackageInfo; 8 import android.content.pm.PackageManager; 9 import android.content.pm.PackageManager.NameNotFoundException; 10 import android.content.pm.Signature; 11 import android.content.res.ColorStateList; 12 import android.content.res.TypedArray; 13 import android.graphics.Bitmap; 14 import android.graphics.Canvas; 15 import android.graphics.Color; 16 import android.graphics.ColorFilter; 17 import android.graphics.ColorMatrix; 18 import android.graphics.ColorMatrixColorFilter; 19 import android.graphics.drawable.Drawable; 20 import android.media.AudioManager; 21 import android.net.NetworkCapabilities; 22 import android.net.vcn.VcnTransportInfo; 23 import android.net.wifi.WifiInfo; 24 import android.os.BatteryManager; 25 import android.telephony.AccessNetworkConstants; 26 import android.telephony.NetworkRegistrationInfo; 27 import android.telephony.ServiceState; 28 import android.telephony.TelephonyManager; 29 30 import androidx.annotation.NonNull; 31 import androidx.core.graphics.drawable.RoundedBitmapDrawable; 32 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; 33 34 import java.text.NumberFormat; 35 36 public class Utils { 37 38 /** Formats a double from 0.0..100.0 with an option to round **/ formatPercentage(double percentage, boolean round)39 public static String formatPercentage(double percentage, boolean round) { 40 final int localPercentage = round ? Math.round((float) percentage) : (int) percentage; 41 return formatPercentage(localPercentage); 42 } 43 44 /** Formats the ratio of amount/total as a percentage. */ formatPercentage(long amount, long total)45 public static String formatPercentage(long amount, long total) { 46 return formatPercentage(((double) amount) / total); 47 } 48 49 /** Formats an integer from 0..100 as a percentage. */ formatPercentage(int percentage)50 public static String formatPercentage(int percentage) { 51 return formatPercentage(((double) percentage) / 100.0); 52 } 53 54 /** Formats a double from 0.0..1.0 as a percentage. */ formatPercentage(double percentage)55 public static String formatPercentage(double percentage) { 56 return NumberFormat.getPercentInstance().format(percentage); 57 } 58 getBatteryLevel(Intent batteryChangedIntent)59 public static int getBatteryLevel(Intent batteryChangedIntent) { 60 int level = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); 61 int scale = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 100); 62 return (level * 100) / scale; 63 } 64 getColorAccent(Context context)65 public static ColorStateList getColorAccent(Context context) { 66 return getColorAttr(context, android.R.attr.colorAccent); 67 } 68 getColorError(Context context)69 public static ColorStateList getColorError(Context context) { 70 return getColorAttr(context, android.R.attr.colorError); 71 } 72 73 @ColorInt getColorAccentDefaultColor(Context context)74 public static int getColorAccentDefaultColor(Context context) { 75 return getColorAttrDefaultColor(context, android.R.attr.colorAccent); 76 } 77 78 @ColorInt getColorErrorDefaultColor(Context context)79 public static int getColorErrorDefaultColor(Context context) { 80 return getColorAttrDefaultColor(context, android.R.attr.colorError); 81 } 82 83 @ColorInt getColorStateListDefaultColor(Context context, int resId)84 public static int getColorStateListDefaultColor(Context context, int resId) { 85 final ColorStateList list = 86 context.getResources().getColorStateList(resId, context.getTheme()); 87 return list.getDefaultColor(); 88 } 89 90 /** 91 * This method computes disabled color from normal color 92 * 93 * @param context the context 94 * @param inputColor normal color. 95 * @return disabled color. 96 */ 97 @ColorInt getDisabled(Context context, int inputColor)98 public static int getDisabled(Context context, int inputColor) { 99 return applyAlphaAttr(context, android.R.attr.disabledAlpha, inputColor); 100 } 101 102 @ColorInt applyAlphaAttr(Context context, int attr, int inputColor)103 public static int applyAlphaAttr(Context context, int attr, int inputColor) { 104 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 105 float alpha = ta.getFloat(0, 0); 106 ta.recycle(); 107 return applyAlpha(alpha, inputColor); 108 } 109 110 @ColorInt applyAlpha(float alpha, int inputColor)111 public static int applyAlpha(float alpha, int inputColor) { 112 alpha *= Color.alpha(inputColor); 113 return Color.argb((int) (alpha), Color.red(inputColor), Color.green(inputColor), 114 Color.blue(inputColor)); 115 } 116 117 @ColorInt getColorAttrDefaultColor(Context context, int attr)118 public static int getColorAttrDefaultColor(Context context, int attr) { 119 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 120 @ColorInt int colorAccent = ta.getColor(0, 0); 121 ta.recycle(); 122 return colorAccent; 123 } 124 getColorAttr(Context context, int attr)125 public static ColorStateList getColorAttr(Context context, int attr) { 126 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 127 ColorStateList stateList = null; 128 try { 129 stateList = ta.getColorStateList(0); 130 } finally { 131 ta.recycle(); 132 } 133 return stateList; 134 } 135 getThemeAttr(Context context, int attr)136 public static int getThemeAttr(Context context, int attr) { 137 return getThemeAttr(context, attr, 0); 138 } 139 getThemeAttr(Context context, int attr, int defaultValue)140 public static int getThemeAttr(Context context, int attr, int defaultValue) { 141 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 142 int theme = ta.getResourceId(0, defaultValue); 143 ta.recycle(); 144 return theme; 145 } 146 getDrawable(Context context, int attr)147 public static Drawable getDrawable(Context context, int attr) { 148 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 149 Drawable drawable = ta.getDrawable(0); 150 ta.recycle(); 151 return drawable; 152 } 153 154 /** 155 * Create a color matrix suitable for a ColorMatrixColorFilter that modifies only the color but 156 * preserves the alpha for a given drawable 157 * 158 * @return a color matrix that uses the source alpha and given color 159 */ getAlphaInvariantColorMatrixForColor(@olorInt int color)160 public static ColorMatrix getAlphaInvariantColorMatrixForColor(@ColorInt int color) { 161 int r = Color.red(color); 162 int g = Color.green(color); 163 int b = Color.blue(color); 164 165 ColorMatrix cm = new ColorMatrix(new float[]{ 166 0, 0, 0, 0, r, 167 0, 0, 0, 0, g, 168 0, 0, 0, 0, b, 169 0, 0, 0, 1, 0}); 170 171 return cm; 172 } 173 174 /** 175 * Create a ColorMatrixColorFilter to tint a drawable but retain its alpha characteristics 176 * 177 * @return a ColorMatrixColorFilter which changes the color of the output but is invariant on 178 * the source alpha 179 */ getAlphaInvariantColorFilterForColor(@olorInt int color)180 public static ColorFilter getAlphaInvariantColorFilterForColor(@ColorInt int color) { 181 return new ColorMatrixColorFilter(getAlphaInvariantColorMatrixForColor(color)); 182 } 183 184 getFirstSignature(PackageInfo pkg)185 private static Signature getFirstSignature(PackageInfo pkg) { 186 if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) { 187 return pkg.signatures[0]; 188 } 189 return null; 190 } 191 getSystemSignature(PackageManager pm)192 private static Signature getSystemSignature(PackageManager pm) { 193 try { 194 final PackageInfo sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES); 195 return getFirstSignature(sys); 196 } catch (NameNotFoundException e) { 197 } 198 return null; 199 } 200 isWifiOnly(Context context)201 public static boolean isWifiOnly(Context context) { 202 return !context.getSystemService(TelephonyManager.class).isDataCapable(); 203 } 204 205 206 207 /** 208 * get that {@link AudioManager#getMode()} is in ringing/call/communication(VoIP) status. 209 */ isAudioModeOngoingCall(Context context)210 public static boolean isAudioModeOngoingCall(Context context) { 211 final AudioManager audioManager = context.getSystemService(AudioManager.class); 212 final int audioMode = audioManager.getMode(); 213 return audioMode == AudioManager.MODE_RINGTONE 214 || audioMode == AudioManager.MODE_IN_CALL 215 || audioMode == AudioManager.MODE_IN_COMMUNICATION; 216 } 217 218 /** 219 * Return the service state is in-service or not. 220 * To make behavior consistent with SystemUI and Settings/AboutPhone/SIM status UI 221 * 222 * @param serviceState Service state. {@link ServiceState} 223 */ isInService(ServiceState serviceState)224 public static boolean isInService(ServiceState serviceState) { 225 if (serviceState == null) { 226 return false; 227 } 228 int state = getCombinedServiceState(serviceState); 229 return state != ServiceState.STATE_POWER_OFF 230 && state != ServiceState.STATE_OUT_OF_SERVICE 231 && state != ServiceState.STATE_EMERGENCY_ONLY; 232 } 233 234 /** 235 * Return the combined service state. 236 * To make behavior consistent with SystemUI and Settings/AboutPhone/SIM status UI 237 * 238 * @param serviceState Service state. {@link ServiceState} 239 */ getCombinedServiceState(ServiceState serviceState)240 public static int getCombinedServiceState(ServiceState serviceState) { 241 if (serviceState == null) { 242 return ServiceState.STATE_OUT_OF_SERVICE; 243 } 244 245 // Consider the device to be in service if either voice or data 246 // service is available. Some SIM cards are marketed as data-only 247 // and do not support voice service, and on these SIM cards, we 248 // want to show signal bars for data service as well as the "no 249 // service" or "emergency calls only" text that indicates that voice 250 // is not available. Note that we ignore the IWLAN service state 251 // because that state indicates the use of VoWIFI and not cell service 252 final int state = serviceState.getState(); 253 final int dataState = serviceState.getDataRegistrationState(); 254 255 if (state == ServiceState.STATE_OUT_OF_SERVICE 256 || state == ServiceState.STATE_EMERGENCY_ONLY) { 257 if (dataState == ServiceState.STATE_IN_SERVICE && isNotInIwlan(serviceState)) { 258 return ServiceState.STATE_IN_SERVICE; 259 } 260 } 261 return state; 262 } 263 isNotInIwlan(ServiceState serviceState)264 private static boolean isNotInIwlan(ServiceState serviceState) { 265 final NetworkRegistrationInfo networkRegWlan = serviceState.getNetworkRegistrationInfo( 266 NetworkRegistrationInfo.DOMAIN_PS, 267 AccessNetworkConstants.TRANSPORT_TYPE_WLAN); 268 if (networkRegWlan == null) { 269 return true; 270 } 271 272 final boolean isInIwlan = (networkRegWlan.getRegistrationState() 273 == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) 274 || (networkRegWlan.getRegistrationState() 275 == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); 276 return !isInIwlan; 277 } 278 279 /** 280 * Returns a bitmap with rounded corner. 281 * 282 * @param context application context. 283 * @param source bitmap to apply round corner. 284 * @param cornerRadius corner radius value. 285 */ convertCornerRadiusBitmap(@onNull Context context, @NonNull Bitmap source, @NonNull float cornerRadius)286 public static Bitmap convertCornerRadiusBitmap(@NonNull Context context, 287 @NonNull Bitmap source, @NonNull float cornerRadius) { 288 final Bitmap roundedBitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(), 289 Bitmap.Config.ARGB_8888); 290 final RoundedBitmapDrawable drawable = 291 RoundedBitmapDrawableFactory.create(context.getResources(), source); 292 drawable.setAntiAlias(true); 293 drawable.setCornerRadius(cornerRadius); 294 final Canvas canvas = new Canvas(roundedBitmap); 295 drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 296 drawable.draw(canvas); 297 return roundedBitmap; 298 } 299 300 /** 301 * Returns the WifiInfo for the underlying WiFi network of the VCN network, returns null if the 302 * input NetworkCapabilities is not for a VCN network with underlying WiFi network. 303 * 304 * @param networkCapabilities NetworkCapabilities of the network. 305 */ 306 @Nullable tryGetWifiInfoForVcn(NetworkCapabilities networkCapabilities)307 public static WifiInfo tryGetWifiInfoForVcn(NetworkCapabilities networkCapabilities) { 308 if (networkCapabilities.getTransportInfo() == null 309 || !(networkCapabilities.getTransportInfo() instanceof VcnTransportInfo)) { 310 return null; 311 } 312 VcnTransportInfo vcnTransportInfo = 313 (VcnTransportInfo) networkCapabilities.getTransportInfo(); 314 return vcnTransportInfo.getWifiInfo(); 315 } 316 } 317