/* * Copyright (c) 2016 Hugo Matalonga & João Paulo Fernandes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hmatalonga.greenhub.models; import android.content.Context; import android.content.SharedPreferences; import android.os.Build; import android.preference.PreferenceManager; import com.hmatalonga.greenhub.Config; import com.hmatalonga.greenhub.models.data.Feature; import com.hmatalonga.greenhub.util.LogUtils; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.util.UUID; import static com.hmatalonga.greenhub.util.LogUtils.makeLogTag; /** * Specifications properties model. * <p> * Retrieves all information about the device specifications, such as ID, brand, build serial * number, kernel version, manufacturer, model, os version and product name. */ public class Specifications { private static final String TAG = makeLogTag(Specifications.class); private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID"; private static final String TYPE_UNKNOWN = "unknown"; private static final int UUID_LENGTH = 16; /** * Provides a {@link SharedPreferences} instance. * * @param context Context of the Application * @return {@link SharedPreferences} default instance */ private static SharedPreferences getSharedPreferences(final Context context) { return PreferenceManager.getDefaultSharedPreferences(context); } /** * Returns a randomly generated unique identifier that stays constant for * the lifetime of the current installation. (Changes if app is uninstalled). * There is also a known bug with a popular handset from a manufacturer where * every instance have the same ANDROID_ID. Clearly, the solution is not 100% reliable. * This is probably our best choice for a UUID across the Android landscape. * Since it is present, on both phones and non-phones. * * @return a String that uniquely identifies this app installation. */ public static synchronized String getAndroidId(final Context context) { SharedPreferences sp = getSharedPreferences(context); String id = sp.getString(PREF_UNIQUE_ID, null); if (id == null) { id = UUID.randomUUID().toString(); LogUtils.logD(TAG, "No Android ID Key on this device. Generating random one: " + id); setAndroidId(context, id); } return id; } /** * Sets a new ID for the current application installation. * * @param context Context of the Application * @param id Automatic ID generated by {@link UUID} */ private static void setAndroidId(final Context context, final String id) { SharedPreferences sp = getSharedPreferences(context); sp.edit().putString(PREF_UNIQUE_ID, id).apply(); LogUtils.logD(TAG, "Android ID Key of device set to: " + id); } /** * Returns the brand for which the device is customized, e.g. Verizon. * * @return the brand for which the device is customized, e.g. Verizon. */ public static String getBrand() { return android.os.Build.BRAND; } /** * Returns the build serial number. May only work for 2.3 and up. * * @return the build serial number. */ public static String getBuildSerial() { // TODO: Review this approach // return android.os.Build.Serial; // return System.getProperty("ro.serial", TYPE_UNKNOWN); return Build.SERIAL; } /** * Returns the kernel version, e.g. 3.4-1101. * * @return the kernel version, e.g. 3.4-1101. */ public static String getKernelVersion() { return System.getProperty("os.version", TYPE_UNKNOWN); } /** * Returns the manufacturer of the device running GreenHub, for example * "google" or "samsung". * * @return the manufacturer of the device running GreenHub, for example * "google" or "samsung". */ public static String getManufacturer() { return android.os.Build.MANUFACTURER; } /** * Returns the model of the device running GreenHub, for example "sdk" for the * emulator, Galaxy Nexus for Samsung Galaxy Nexus. * * @return the model of the device running GreenHub, for example "sdk" for the * emulator, Galaxy Nexus for Samsung Galaxy Nexus. */ public static String getModel() { return android.os.Build.MODEL; } /** * Returns the OS version of the device running GreenHub, for example 2.3.3 or * 4.0.2. * * @return the OS version of the device running GreenHub, for example 2.3.3 or * 4.0.2. */ public static String getOsVersion() { return android.os.Build.VERSION.RELEASE; } /** * Returns the product name. * * @return the product name. */ public static String getProductName() { return android.os.Build.PRODUCT; } /** * Get the java.vm.version system property as a Feature("vm", version). * * @return key "vm" and value of the "java.vm.version" system property. */ public static Feature getVmVersion() { Feature vmVersion = new Feature(); String vm = System.getProperty("java.vm.version"); if (vm == null) vm = ""; vmVersion.key = "vm"; vmVersion.value = vm; return vmVersion; } /** * Undocumented call to read a string value from system properties. * WARNING: Uses reflection, data might not always be available. * * @param context Application context * @param property Property name * @return Property value * @throws Exception */ public static String getSystemProperty(final Context context, String property) throws Exception { Class<?> systemProperties = Class.forName("android.os.SystemProperties"); Method get = systemProperties.getMethod("get", String.class); get.setAccessible(true); return ((String) get.invoke(context, property)); } /** * Retrieves service provider using an undocumented system properties call. * WARNING: Uses reflection, data might not always be available. * * @param context * @param property * @return */ public static String getStringFromSystemProperty(final Context context, String property) { try { String operator = getSystemProperty(context, property); if (operator != null && operator.length() > 0) { return operator; } } catch (Exception e) { if (Config.DEBUG && e != null && e.getLocalizedMessage() != null) { LogUtils.logD(TAG, "Failed getting service provider: " + e.getLocalizedMessage()); } } return null; } /** * Checks if the device is rooted. As seen at: * http://stackoverflow.com/a/8097801/29299 * * @return <code>true</code> if the device is rooted, <code>false</code> otherwise. */ public static boolean isRooted() { return checkRootMethod1() || checkRootMethod2() || checkRootMethod3(); } private static boolean checkRootMethod1() { String buildTags = android.os.Build.TAGS; return buildTags != null && buildTags.contains("test-keys"); } private static boolean checkRootMethod2() { String[] paths = { "/system/app/Superuser.apk", "/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su", "/system/bin/failsafe/su", "/data/local/su" }; for (String path : paths) { if (new File(path).exists()) return true; } return false; } private static boolean checkRootMethod3() { java.lang.Process process = null; try { process = Runtime.getRuntime().exec(new String[]{"/system/xbin/which", "su"}); BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())); return in.readLine() != null; } catch (Throwable t) { return false; } finally { if (process != null) process.destroy(); } } }