package me.shouheng.utils.device; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; import android.os.Environment; import android.os.PowerManager; import android.provider.Settings; import android.support.annotation.Nullable; import android.support.annotation.RequiresApi; import android.support.annotation.RequiresPermission; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.view.WindowManager; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.lang.reflect.Method; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Locale; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; import me.shouheng.utils.UtilsApp; import me.shouheng.utils.stability.L; import me.shouheng.utils.store.IOUtils; import static android.Manifest.permission.ACCESS_WIFI_STATE; import static android.Manifest.permission.INTERNET; import static android.Manifest.permission.READ_PHONE_STATE; /** * @author WngShhng * @version 2019-05-09 21:20 */ public final class DeviceUtils { private final static String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name"; private static final String KEY_FLYME_VERSION_NAME = "ro.build.display.id"; private final static String FLYME = "flyme"; private final static String ZTEC2016 = "zte c2016"; private final static String ZUKZ1 = "zuk z1"; private final static String ESSENTIAL = "essential"; private final static String MEIZUBOARD[] = {"m9", "M9", "mx", "MX"}; private static String sMiuiVersionName; private static String sFlymeVersionName; private static Boolean sIsTabletValue = null; private static final String BRAND = Build.BRAND.toLowerCase(); static { Properties properties = new Properties(); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { // android 8.0,读取 /system/uild.prop 会报 permission denied FileInputStream fileInputStream = null; try { fileInputStream = new FileInputStream(new File(Environment.getRootDirectory(), "build.prop")); properties.load(fileInputStream); } catch (Exception e) { L.e("read file error " + e); } finally { IOUtils.safeCloseAll(fileInputStream); } } Class<?> clzSystemProperties = null; try { clzSystemProperties = Class.forName("android.os.SystemProperties"); Method getMethod = clzSystemProperties.getDeclaredMethod("get", String.class); // miui sMiuiVersionName = getLowerCaseName(properties, getMethod, KEY_MIUI_VERSION_NAME); // flyme sFlymeVersionName = getLowerCaseName(properties, getMethod, KEY_FLYME_VERSION_NAME); } catch (Exception e) { L.e("read SystemProperties error " + e); } } /*---------------------------------- 信息查询 --------------------------------------*/ /** * 判断是否为平板设备 */ public static boolean isTablet(Context context) { if (sIsTabletValue != null) { return sIsTabletValue; } sIsTabletValue = isTabletInner(context); return sIsTabletValue; } /** * 判断是否是flyme系统 */ public static boolean isFlyme() { return !TextUtils.isEmpty(sFlymeVersionName) && sFlymeVersionName.contains(FLYME); } /** * 判断是否是MIUI系统 */ public static boolean isMIUI() { return !TextUtils.isEmpty(sMiuiVersionName); } public static boolean isMIUIV5() { return "v5".equals(sMiuiVersionName); } public static boolean isMIUIV6() { return "v6".equals(sMiuiVersionName); } public static boolean isMIUIV7() { return "v7".equals(sMiuiVersionName); } public static boolean isMIUIV8() { return "v8".equals(sMiuiVersionName); } public static boolean isMIUIV9() { return "v9".equals(sMiuiVersionName); } public static boolean isFlymeVersionHigher5_2_4() { //查不到默认高于5.2.4 boolean isHigher = true; if (sFlymeVersionName != null && !sFlymeVersionName.equals("")) { Pattern pattern = Pattern.compile("(\\d+\\.){2}\\d"); Matcher matcher = pattern.matcher(sFlymeVersionName); if (matcher.find()) { String versionString = matcher.group(); if (versionString != null && !versionString.equals("")) { String[] version = versionString.split("\\."); if (version.length == 3) { if (Integer.valueOf(version[0]) < 5) { isHigher = false; } else if (Integer.valueOf(version[0]) > 5) { isHigher = true; } else { if (Integer.valueOf(version[1]) < 2) { isHigher = false; } else if (Integer.valueOf(version[1]) > 2) { isHigher = true; } else { if (Integer.valueOf(version[2]) < 4) { isHigher = false; } else if (Integer.valueOf(version[2]) >= 5) { isHigher = true; } } } } } } } return isMeizu() && isHigher; } public static boolean isMeizu() { return isPhone() || isFlyme(); } /** * 判断是否为小米 * https://dev.mi.com/doc/?p=254 */ public static boolean isXiaomi() { return Build.MANUFACTURER.toLowerCase().equals("xiaomi"); } public static boolean isVivo() { return BRAND.contains("vivo") || BRAND.contains("bbk"); } public static boolean isOppo() { return BRAND.contains("oppo"); } public static boolean isHuawei() { return BRAND.contains("huawei") || BRAND.contains("honor"); } public static boolean isEssentialPhone(){ return BRAND.contains("essential"); } /** * 判断是否为 ZUK Z1 和 ZTK C2016。 * 两台设备的系统虽然为 android 6.0,但不支持状态栏icon颜色改变,因此经常需要对它们进行额外判断。 */ public static boolean isZUKZ1() { final String board = android.os.Build.MODEL; return board != null && board.toLowerCase().contains(ZUKZ1); } public static boolean isZTKC2016() { final String board = android.os.Build.MODEL; return board != null && board.toLowerCase().contains(ZTEC2016); } public static boolean isPhone() { TelephonyManager tm = (TelephonyManager) UtilsApp.getApp().getSystemService(Context.TELEPHONY_SERVICE); // noinspection ConstantConditions return tm.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE; } @SuppressLint("HardwareIds") @RequiresPermission(READ_PHONE_STATE) public static String getDeviceId() { TelephonyManager tm = (TelephonyManager) UtilsApp.getApp().getSystemService(Context.TELEPHONY_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //noinspection ConstantConditions String imei = tm.getImei(); if (!TextUtils.isEmpty(imei)) return imei; String meid = tm.getMeid(); return TextUtils.isEmpty(meid) ? "" : meid; } //noinspection ConstantConditions return tm.getDeviceId(); } @SuppressLint("HardwareIds") @RequiresPermission(READ_PHONE_STATE) public static String getSerial() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? Build.getSerial() : Build.SERIAL; } @SuppressLint("HardwareIds") @RequiresPermission(READ_PHONE_STATE) public static String getIMEI() { TelephonyManager tm = (TelephonyManager) UtilsApp.getApp().getSystemService(Context.TELEPHONY_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //noinspection ConstantConditions return tm.getImei(); } //noinspection ConstantConditions return tm.getDeviceId(); } @SuppressLint("HardwareIds") @RequiresPermission(READ_PHONE_STATE) public static String getMEID() { TelephonyManager tm = (TelephonyManager) UtilsApp.getApp().getSystemService(Context.TELEPHONY_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //noinspection ConstantConditions return tm.getMeid(); } //noinspection ConstantConditions return tm.getDeviceId(); } @SuppressLint("HardwareIds") @RequiresPermission(READ_PHONE_STATE) public static String getIMSI() { TelephonyManager tm = (TelephonyManager) UtilsApp.getApp().getSystemService(Context.TELEPHONY_SERVICE); //noinspection ConstantConditions return tm.getSubscriberId(); } /** * Returns the current phone type. * * @return the current phone type * <ul> * <li>{@link TelephonyManager#PHONE_TYPE_NONE}</li> * <li>{@link TelephonyManager#PHONE_TYPE_GSM }</li> * <li>{@link TelephonyManager#PHONE_TYPE_CDMA}</li> * <li>{@link TelephonyManager#PHONE_TYPE_SIP }</li> * </ul> */ public static int getPhoneType() { TelephonyManager tm = (TelephonyManager) UtilsApp.getApp().getSystemService(Context.TELEPHONY_SERVICE); //noinspection ConstantConditions return tm.getPhoneType(); } public static boolean isSimCardReady() { TelephonyManager tm = (TelephonyManager) UtilsApp.getApp().getSystemService(Context.TELEPHONY_SERVICE); //noinspection ConstantConditions return tm.getSimState() == TelephonyManager.SIM_STATE_READY; } public static String getSimOperatorName() { TelephonyManager tm = (TelephonyManager) UtilsApp.getApp().getSystemService(Context.TELEPHONY_SERVICE); //noinspection ConstantConditions return tm.getSimOperatorName(); } public static String getSimOperatorByMnc() { TelephonyManager tm = (TelephonyManager) UtilsApp.getApp().getSystemService(Context.TELEPHONY_SERVICE); //noinspection ConstantConditions String operator = tm.getSimOperator(); if (operator == null) return ""; switch (operator) { case "46000": case "46002": case "46007": case "46020": return "中国移动"; case "46001": case "46006": case "46009": return "中国联通"; case "46003": case "46005": case "46011": return "中国电信"; default: return operator; } } /** * Return the phone status. * <p>Must hold * {@code <uses-permission android:name="android.permission.READ_PHONE_STATE" />}</p> * * @return DeviceId = 99000311726612<br> * DeviceSoftwareVersion = 00<br> * Line1Number =<br> * NetworkCountryIso = cn<br> * NetworkOperator = 46003<br> * NetworkOperatorName = 中国电信<br> * NetworkType = 6<br> * PhoneType = 2<br> * SimCountryIso = cn<br> * SimOperator = 46003<br> * SimOperatorName = 中国电信<br> * SimSerialNumber = 89860315045710604022<br> * SimState = 5<br> * SubscriberId(IMSI) = 460030419724900<br> * VoiceMailNumber = *86<br> */ @SuppressLint("HardwareIds") @RequiresPermission(READ_PHONE_STATE) public static String getPhoneStatus() { TelephonyManager tm = (TelephonyManager) UtilsApp.getApp().getSystemService(Context.TELEPHONY_SERVICE); String str = ""; //noinspection ConstantConditions str += "DeviceId(IMEI) = " + tm.getDeviceId() + "\n"; str += "DeviceSoftwareVersion = " + tm.getDeviceSoftwareVersion() + "\n"; str += "Line1Number = " + tm.getLine1Number() + "\n"; str += "NetworkCountryIso = " + tm.getNetworkCountryIso() + "\n"; str += "NetworkOperator = " + tm.getNetworkOperator() + "\n"; str += "NetworkOperatorName = " + tm.getNetworkOperatorName() + "\n"; str += "NetworkType = " + tm.getNetworkType() + "\n"; str += "PhoneType = " + tm.getPhoneType() + "\n"; str += "SimCountryIso = " + tm.getSimCountryIso() + "\n"; str += "SimOperator = " + tm.getSimOperator() + "\n"; str += "SimOperatorName = " + tm.getSimOperatorName() + "\n"; str += "SimSerialNumber = " + tm.getSimSerialNumber() + "\n"; str += "SimState = " + tm.getSimState() + "\n"; str += "SubscriberId(IMSI) = " + tm.getSubscriberId() + "\n"; str += "VoiceMailNumber = " + tm.getVoiceMailNumber(); return str; } public static boolean isDeviceRooted() { String su = "su"; String[] locations = {"/system/bin/", "/system/xbin/", "/sbin/", "/system/sd/xbin/", "/system/bin/failsafe/", "/data/local/xbin/", "/data/local/bin/", "/data/local/"}; for (String location : locations) { if (new File(location + su).exists()) { return true; } } return false; } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) public static boolean isAdbEnabled() { return Settings.Secure.getInt( UtilsApp.getApp().getContentResolver(), Settings.Global.ADB_ENABLED, 0 ) > 0; } public static String getSDKVersionName() { return android.os.Build.VERSION.RELEASE; } public static int getSDKVersionCode() { return android.os.Build.VERSION.SDK_INT; } public static String getLanguage() { return Locale.getDefault().getLanguage(); } public static Locale[] getAvailableLanguages() { return Locale.getAvailableLocales(); } @SuppressLint("HardwareIds") public static String getAndroidID() { String id = Settings.Secure.getString( UtilsApp.getApp().getContentResolver(), Settings.Secure.ANDROID_ID ); return id == null ? "" : id; } @RequiresPermission(allOf = {ACCESS_WIFI_STATE, INTERNET}) public static String getMacAddress() { return getMacAddress((String[]) null); } @RequiresPermission(allOf = {ACCESS_WIFI_STATE, INTERNET}) public static String getMacAddress(final String... excepts) { String macAddress = getMacAddressByWifiInfo(); if (isAddressNotInExcepts(macAddress, excepts)) { return macAddress; } macAddress = getMacAddressByNetworkInterface(); if (isAddressNotInExcepts(macAddress, excepts)) { return macAddress; } macAddress = getMacAddressByInetAddress(); if (isAddressNotInExcepts(macAddress, excepts)) { return macAddress; } macAddress = getMacAddressByFile(); if (isAddressNotInExcepts(macAddress, excepts)) { return macAddress; } return ""; } /** * Return the manufacturer of the product/hardware. * <p>e.g. Xiaomi</p> * * @return the manufacturer of the product/hardware */ public static String getManufacturer() { return Build.MANUFACTURER; } /** * 手机型号 * <p>e.g. MI2SC</p> * * @return 手机型号 */ public static String getModel() { String model = Build.MODEL; if (model != null) { model = model.trim().replaceAll("\\s*", ""); } else { model = ""; } return model; } /** * 操作系统版本号 * * @return 操作系统版本号 */ public static String getRelease() { return Build.VERSION.RELEASE; } /** * 获取编译厂商 * * @return 编译厂商 */ public static String getBrand() { return Build.BRAND; } /** * 获取系统版本号 * * @return 系统版本号 */ public static String getDisplay() { return Build.DISPLAY; } /** * 获取硬件信息 * * @return 硬件信息 */ public static String getHardware() { return Build.HARDWARE; } /** * 获取产品信息 * * @return 产品信息 */ public static String getProduct() { return Build.PRODUCT; } /** * 获取设备信息 * * @return 设备信息 */ public static String getDevice() { return Build.DEVICE; } /** * 获取主板信息 * * @return 主板信息 */ public static String getBoard() { return Build.BOARD; } /** * 获取基带版本(无线电固件版本 Api14以上) * * @return 基带版本 */ public static String getRadioVersion() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH ? Build.getRadioVersion() : ""; } public static String[] getABIs() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return Build.SUPPORTED_ABIS; } else { if (!TextUtils.isEmpty(Build.CPU_ABI2)) { return new String[]{Build.CPU_ABI, Build.CPU_ABI2}; } return new String[]{Build.CPU_ABI}; } } public static int getCpuNumber() { try { File dir = new File("/sys/devices/system/cpu/"); File[] files = dir.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { return Pattern.matches("cpu[0-9]", pathname.getName()); } }); return files.length; } catch (Exception e) { e.printStackTrace(); return 1; } } public static int getPhoneWidth() { WindowManager wm = (WindowManager) UtilsApp.getApp().getSystemService(Context.WINDOW_SERVICE); return wm.getDefaultDisplay().getWidth(); } public static int getPhoneHeight() { WindowManager wm = (WindowManager) UtilsApp.getApp().getSystemService(Context.WINDOW_SERVICE); return wm.getDefaultDisplay().getHeight(); } /** * 获取所有安装的应用 * * @return 应用列表 */ public static List<PackageInfo> getInstalledApp() { PackageManager pm = UtilsApp.getApp().getPackageManager(); return pm.getInstalledPackages(0); } /** * 获取所有安装的非系统应用 * * @return 应用列表 */ public static List<PackageInfo> getUserInstalledApp() { List<PackageInfo> infos = getInstalledApp(); List<PackageInfo> apps = new ArrayList<>(); for (PackageInfo info : infos) { if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) <= 0) { apps.add(info); } } infos.clear(); return apps; } /*---------------------------------- 命令操作 --------------------------------------*/ public static void shutdown() { ShellUtils.execCmd("reboot -p", true); Intent intent = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN"); intent.putExtra("android.intent.extra.KEY_CONFIRM", false); UtilsApp.getApp().startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); } public static void reboot() { ShellUtils.execCmd("reboot", true); Intent intent = new Intent(Intent.ACTION_REBOOT); intent.putExtra("nowait", 1); intent.putExtra("interval", 1); intent.putExtra("window", 0); UtilsApp.getApp().sendBroadcast(intent); } public static void reboot(final String reason) { PowerManager pm = (PowerManager) UtilsApp.getApp().getSystemService(Context.POWER_SERVICE); // noinspection ConstantConditions pm.reboot(reason); } public static void reboot2Recovery() { ShellUtils.execCmd("reboot recovery", true); } public static void reboot2Bootloader() { ShellUtils.execCmd("reboot bootloader", true); } /*---------------------------------- inner methods --------------------------------------*/ private static boolean isAddressNotInExcepts(final String address, final String... excepts) { if (excepts == null || excepts.length == 0) { return !"02:00:00:00:00:00".equals(address); } for (String filter : excepts) { if (address.equals(filter)) { return false; } } return true; } @SuppressLint({"HardwareIds", "MissingPermission", "WifiManagerLeak"}) private static String getMacAddressByWifiInfo() { try { WifiManager wifi = (WifiManager) UtilsApp.getApp().getSystemService(Context.WIFI_SERVICE); if (wifi != null) { WifiInfo info = wifi.getConnectionInfo(); if (info != null) return info.getMacAddress(); } } catch (Exception e) { e.printStackTrace(); } return "02:00:00:00:00:00"; } private static String getMacAddressByNetworkInterface() { try { Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces(); while (nis.hasMoreElements()) { NetworkInterface ni = nis.nextElement(); if (ni == null || !ni.getName().equalsIgnoreCase("wlan0")) continue; byte[] macBytes = ni.getHardwareAddress(); if (macBytes != null && macBytes.length > 0) { StringBuilder sb = new StringBuilder(); for (byte b : macBytes) { sb.append(String.format("%02x:", b)); } return sb.substring(0, sb.length() - 1); } } } catch (Exception e) { e.printStackTrace(); } return "02:00:00:00:00:00"; } private static String getMacAddressByInetAddress() { try { InetAddress inetAddress = getInetAddress(); if (inetAddress != null) { NetworkInterface ni = NetworkInterface.getByInetAddress(inetAddress); if (ni != null) { byte[] macBytes = ni.getHardwareAddress(); if (macBytes != null && macBytes.length > 0) { StringBuilder sb = new StringBuilder(); for (byte b : macBytes) { sb.append(String.format("%02x:", b)); } return sb.substring(0, sb.length() - 1); } } } } catch (Exception e) { e.printStackTrace(); } return "02:00:00:00:00:00"; } private static InetAddress getInetAddress() { try { Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces(); while (nis.hasMoreElements()) { NetworkInterface ni = nis.nextElement(); // To prevent phone of xiaomi return "10.0.2.15" if (!ni.isUp()) continue; Enumeration<InetAddress> addresses = ni.getInetAddresses(); while (addresses.hasMoreElements()) { InetAddress inetAddress = addresses.nextElement(); if (!inetAddress.isLoopbackAddress()) { String hostAddress = inetAddress.getHostAddress(); if (hostAddress.indexOf(':') < 0) return inetAddress; } } } } catch (SocketException e) { e.printStackTrace(); } return null; } private static String getMacAddressByFile() { ShellUtils.CommandResult result = ShellUtils.execCmd("getprop wifi.interface", false); if (result.result == 0) { String name = result.successMsg; if (name != null) { result = ShellUtils.execCmd("cat /sys/class/net/" + name + "/address", false); if (result.result == 0) { String address = result.successMsg; if (address != null && address.length() > 0) { return address; } } } } return "02:00:00:00:00:00"; } private static boolean isTabletInner(Context context) { return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE; } @Nullable private static String getLowerCaseName(Properties p, Method get, String key) { String name = p.getProperty(key); if (name == null) { try { name = (String) get.invoke(null, key); } catch (Exception ignored) { } } if (name != null) name = name.toLowerCase(); return name; } private DeviceUtils() { throw new UnsupportedOperationException("u can't initialize me!"); } }