package com.mixpanel.android.mpmetrics; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import android.Manifest; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.telephony.TelephonyManager; import android.util.DisplayMetrics; import android.view.Display; import android.view.WindowManager; import com.mixpanel.android.util.MPLog; /** * Abstracts away possibly non-present system information classes, * and handles permission-dependent queries for default system information. */ /* package */ class SystemInformation { public SystemInformation(Context context) { mContext = context; PackageManager packageManager = mContext.getPackageManager(); String foundAppVersionName = null; Integer foundAppVersionCode = null; try { PackageInfo packageInfo = packageManager.getPackageInfo(mContext.getPackageName(), 0); foundAppVersionName = packageInfo.versionName; foundAppVersionCode = packageInfo.versionCode; } catch (NameNotFoundException e) { MPLog.w(LOGTAG, "System information constructed with a context that apparently doesn't exist."); } mAppVersionName = foundAppVersionName; mAppVersionCode = foundAppVersionCode; // We can't count on these features being available, since we need to // run on old devices. Thus, the reflection fandango below... Class<? extends PackageManager> packageManagerClass = packageManager.getClass(); Method hasSystemFeatureMethod = null; try { hasSystemFeatureMethod = packageManagerClass.getMethod("hasSystemFeature", String.class); } catch (NoSuchMethodException e) { // Nothing, this is an expected outcome } Boolean foundNFC = null; Boolean foundTelephony = null; if (null != hasSystemFeatureMethod) { try { foundNFC = (Boolean) hasSystemFeatureMethod.invoke(packageManager, "android.hardware.nfc"); foundTelephony = (Boolean) hasSystemFeatureMethod.invoke(packageManager, "android.hardware.telephony"); } catch (InvocationTargetException e) { MPLog.w(LOGTAG, "System version appeared to support PackageManager.hasSystemFeature, but we were unable to call it."); } catch (IllegalAccessException e) { MPLog.w(LOGTAG, "System version appeared to support PackageManager.hasSystemFeature, but we were unable to call it."); } } mHasNFC = foundNFC; mHasTelephony = foundTelephony; mDisplayMetrics = new DisplayMetrics(); Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); display.getMetrics(mDisplayMetrics); } public String getAppVersionName() { return mAppVersionName; } public Integer getAppVersionCode() { return mAppVersionCode; } public boolean hasNFC() { return mHasNFC; } public boolean hasTelephony() { return mHasTelephony; } public DisplayMetrics getDisplayMetrics() { return mDisplayMetrics; } public String getPhoneRadioType() { String ret = null; TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); if (null != telephonyManager) { switch(telephonyManager.getPhoneType()) { case 0x00000000: // TelephonyManager.PHONE_TYPE_NONE ret = "none"; break; case 0x00000001: // TelephonyManager.PHONE_TYPE_GSM ret = "gsm"; break; case 0x00000002: // TelephonyManager.PHONE_TYPE_CDMA ret = "cdma"; break; case 0x00000003: // TelephonyManager.PHONE_TYPE_SIP ret = "sip"; break; default: ret = null; } } return ret; } // Note this is the *current*, not the canonical network, because it // doesn't require special permissions to access. Unreliable for CDMA phones, // public String getCurrentNetworkOperator() { String ret = null; TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); if (null != telephonyManager) { ret = telephonyManager.getNetworkOperatorName(); } return ret; } public Boolean isWifiConnected() { Boolean ret = null; if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE)) { ConnectivityManager connManager = (ConnectivityManager) this.mContext.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connManager.getActiveNetworkInfo(); ret = (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI && networkInfo.isConnected()); } return ret; } @SuppressLint("MissingPermission") public Boolean isBluetoothEnabled() { Boolean isBluetoothEnabled = null; try { BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter != null) { isBluetoothEnabled = bluetoothAdapter.isEnabled(); } } catch (SecurityException e) { // do nothing since we don't have permissions } catch (NoClassDefFoundError e) { // Some phones doesn't have this class. Just ignore it } return isBluetoothEnabled; } public String getBluetoothVersion() { String bluetoothVersion = null; if (android.os.Build.VERSION.SDK_INT >= 8) { bluetoothVersion = "none"; if(android.os.Build.VERSION.SDK_INT >= 18 && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { bluetoothVersion = "ble"; } else if(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) { bluetoothVersion = "classic"; } } return bluetoothVersion; } private final Context mContext; // Unchanging facts private final Boolean mHasNFC; private final Boolean mHasTelephony; private final DisplayMetrics mDisplayMetrics; private final String mAppVersionName; private final Integer mAppVersionCode; private static final String LOGTAG = "MixpanelAPI.SysInfo"; }