/* * Copyright (C) 2012 The Android Open Source Project * * 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.example.android.deviceconfig; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Context; import android.content.pm.FeatureInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.hardware.Camera; import android.hardware.Camera.CameraInfo; import android.os.Build; import android.os.Environment; import android.os.StatFs; import android.util.DisplayMetrics; import android.util.Log; import android.view.ViewConfiguration; import android.widget.Toast; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Text; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.Locale; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; public class ConfigGenerator { private Context mCtx; private String mExtensions; public static final String NS_DEVICES_XSD = "http://schemas.android.com/sdk/devices/1"; /** * The "devices" element is the root element of this schema. * * It must contain one or more "device" elements that each define the * hardware, software, and states for a given device. */ public static final String NODE_DEVICES = "devices"; /** * A "device" element contains a "hardware" element, a "software" element * for each API version it supports, and a "state" element for each possible * state the device could be in. */ public static final String NODE_DEVICE = "device"; /** * The "hardware" element contains all of the hardware information for a * given device. */ public static final String NODE_HARDWARE = "hardware"; /** * The "software" element contains all of the software information for an * API version of the given device. */ public static final String NODE_SOFTWARE = "software"; /** * The "state" element contains all of the parameters for a given state of * the device. It's also capable of redefining hardware configurations if * they change based on state. */ public static final String NODE_STATE = "state"; public static final String NODE_KEYBOARD = "keyboard"; public static final String NODE_TOUCH = "touch"; public static final String NODE_GL_EXTENSIONS = "gl-extensions"; public static final String NODE_GL_VERSION = "gl-version"; public static final String NODE_NETWORKING = "networking"; public static final String NODE_REMOVABLE_STORAGE = "removable-storage"; public static final String NODE_FLASH = "flash"; public static final String NODE_LIVE_WALLPAPER_SUPPORT = "live-wallpaper-support"; public static final String NODE_BUTTONS = "buttons"; public static final String NODE_CAMERA = "camera"; public static final String NODE_LOCATION = "location"; public static final String NODE_GPU = "gpu"; public static final String NODE_DOCK = "dock"; public static final String NODE_YDPI = "ydpi"; public static final String NODE_POWER_TYPE = "power-type"; public static final String NODE_Y_DIMENSION = "y-dimension"; public static final String NODE_SCREEN_RATIO = "screen-ratio"; public static final String NODE_NAV_STATE = "nav-state"; public static final String NODE_MIC = "mic"; public static final String NODE_RAM = "ram"; public static final String NODE_XDPI = "xdpi"; public static final String NODE_DIMENSIONS = "dimensions"; public static final String NODE_ABI = "abi"; public static final String NODE_MECHANISM = "mechanism"; public static final String NODE_MULTITOUCH = "multitouch"; public static final String NODE_NAV = "nav"; public static final String NODE_PIXEL_DENSITY = "pixel-density"; public static final String NODE_SCREEN_ORIENTATION = "screen-orientation"; public static final String NODE_AUTOFOCUS = "autofocus"; public static final String NODE_SCREEN_SIZE = "screen-size"; public static final String NODE_DESCRIPTION = "description"; public static final String NODE_BLUETOOTH_PROFILES = "bluetooth-profiles"; public static final String NODE_SCREEN = "screen"; public static final String NODE_SENSORS = "sensors"; public static final String NODE_DIAGONAL_LENGTH = "diagonal-length"; public static final String NODE_SCREEN_TYPE = "screen-type"; public static final String NODE_KEYBOARD_STATE = "keyboard-state"; public static final String NODE_X_DIMENSION = "x-dimension"; public static final String NODE_CPU = "cpu"; public static final String NODE_INTERNAL_STORAGE = "internal-storage"; public static final String NODE_NAME = "name"; public static final String NODE_MANUFACTURER = "manufacturer"; public static final String NODE_API_LEVEL = "api-level"; public static final String ATTR_DEFAULT = "default"; public static final String ATTR_UNIT = "unit"; public static final String UNIT_BYTES = "B"; public static final String UNIT_KIBIBYTES = "KiB"; public static final String UNIT_MEBIBYTES = "MiB"; public static final String UNIT_GIBIBYTES = "GiB"; public static final String UNIT_TEBIBYTES = "TiB"; public static final String LOCAL_NS = "d"; public static final String PREFIX = LOCAL_NS + ":"; private static final String TAG = "ConfigGenerator"; public ConfigGenerator(Context context, String extensions) { mCtx = context; mExtensions = extensions; } @SuppressLint("WorldReadableFiles") public String generateConfig() { Resources resources = mCtx.getResources(); PackageManager packageMgr = mCtx.getPackageManager(); DisplayMetrics metrics = resources.getDisplayMetrics(); Configuration config = resources.getConfiguration(); try { Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); Element devices = doc.createElement(PREFIX + NODE_DEVICES); devices.setAttribute(XMLConstants.XMLNS_ATTRIBUTE + ":xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); devices.setAttribute(XMLConstants.XMLNS_ATTRIBUTE + ":" + LOCAL_NS, NS_DEVICES_XSD); doc.appendChild(devices); Element device = doc.createElement(PREFIX + NODE_DEVICE); devices.appendChild(device); Element name = doc.createElement(PREFIX + NODE_NAME); device.appendChild(name); name.appendChild(doc.createTextNode(android.os.Build.MODEL)); Element manufacturer = doc.createElement(PREFIX + NODE_MANUFACTURER); device.appendChild(manufacturer); manufacturer.appendChild(doc.createTextNode(android.os.Build.MANUFACTURER)); Element hardware = doc.createElement(PREFIX + NODE_HARDWARE); device.appendChild(hardware); Element screen = doc.createElement(PREFIX + NODE_SCREEN); hardware.appendChild(screen); Element screenSize = doc.createElement(PREFIX + NODE_SCREEN_SIZE); screen.appendChild(screenSize); Text screenSizeText; switch (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) { case Configuration.SCREENLAYOUT_SIZE_SMALL: screenSizeText = doc.createTextNode("small"); break; case Configuration.SCREENLAYOUT_SIZE_NORMAL: screenSizeText = doc.createTextNode("normal"); break; case Configuration.SCREENLAYOUT_SIZE_LARGE: screenSizeText = doc.createTextNode("large"); break; case Configuration.SCREENLAYOUT_SIZE_XLARGE: screenSizeText = doc.createTextNode("xlarge"); break; default: screenSizeText = doc.createTextNode(" "); break; } screenSize.appendChild(screenSizeText); Element diagonalLength = doc.createElement(PREFIX + NODE_DIAGONAL_LENGTH); screen.appendChild(diagonalLength); double xin = metrics.widthPixels / metrics.xdpi; double yin = metrics.heightPixels / metrics.ydpi; double diag = Math.sqrt(Math.pow(xin, 2) + Math.pow(yin, 2)); diagonalLength.appendChild(doc.createTextNode( String.format(Locale.US, "%1$.2f", diag))); Element pixelDensity = doc.createElement(PREFIX + NODE_PIXEL_DENSITY); screen.appendChild(pixelDensity); Text pixelDensityText; switch (metrics.densityDpi) { case DisplayMetrics.DENSITY_LOW: pixelDensityText = doc.createTextNode("ldpi"); break; case DisplayMetrics.DENSITY_MEDIUM: pixelDensityText = doc.createTextNode("mdpi"); break; case DisplayMetrics.DENSITY_TV: pixelDensityText = doc.createTextNode("tvdpi"); break; case DisplayMetrics.DENSITY_HIGH: pixelDensityText = doc.createTextNode("hdpi"); break; case DisplayMetrics.DENSITY_XHIGH: pixelDensityText = doc.createTextNode("xhdpi"); break; default: pixelDensityText = doc.createTextNode(" "); } pixelDensity.appendChild(pixelDensityText); Element screenRatio = doc.createElement(PREFIX + NODE_SCREEN_RATIO); screen.appendChild(screenRatio); Text screenRatioText; switch (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) { case Configuration.SCREENLAYOUT_LONG_YES: screenRatioText = doc.createTextNode("long"); break; case Configuration.SCREENLAYOUT_LONG_NO: screenRatioText = doc.createTextNode("notlong"); break; default: screenRatioText = doc.createTextNode(" "); break; } screenRatio.appendChild(screenRatioText); Element dimensions = doc.createElement(PREFIX + NODE_DIMENSIONS); screen.appendChild(dimensions); Element xDimension = doc.createElement(PREFIX + NODE_X_DIMENSION); dimensions.appendChild(xDimension); xDimension.appendChild(doc.createTextNode(Integer.toString(metrics.widthPixels))); Element yDimension = doc.createElement(PREFIX + NODE_Y_DIMENSION); dimensions.appendChild(yDimension); yDimension.appendChild(doc.createTextNode(Integer.toString(metrics.heightPixels))); Element xdpi = doc.createElement(PREFIX + NODE_XDPI); screen.appendChild(xdpi); xdpi.appendChild(doc.createTextNode(Double.toString(metrics.xdpi))); Element ydpi = doc.createElement(PREFIX + NODE_YDPI); screen.appendChild(ydpi); ydpi.appendChild(doc.createTextNode(Double.toString(metrics.ydpi))); Element touch = doc.createElement(PREFIX + NODE_TOUCH); screen.appendChild(touch); Element multitouch = doc.createElement(PREFIX + NODE_MULTITOUCH); touch.appendChild(multitouch); Text multitouchText; if (packageMgr .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND)) { multitouchText = doc.createTextNode("jazz-hands"); } else if (packageMgr .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)) { multitouchText = doc.createTextNode("distinct"); } else if (packageMgr.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)) { multitouchText = doc.createTextNode("basic"); } else { multitouchText = doc.createTextNode("none"); } multitouch.appendChild(multitouchText); Element mechanism = doc.createElement(PREFIX + NODE_MECHANISM); touch.appendChild(mechanism); Text mechanismText; switch (config.touchscreen) { case Configuration.TOUCHSCREEN_STYLUS: mechanismText = doc.createTextNode("stylus"); case Configuration.TOUCHSCREEN_FINGER: mechanismText = doc.createTextNode("finger"); case Configuration.TOUCHSCREEN_NOTOUCH: mechanismText = doc.createTextNode("notouch"); default: mechanismText = doc.createTextNode(" "); } mechanism.appendChild(mechanismText); // Create an empty place holder node for screen-type since we can't // actually determine it Element screenType = doc.createElement(PREFIX + NODE_SCREEN_TYPE); touch.appendChild(screenType); screenType.appendChild(doc.createTextNode(" ")); Element networking = doc.createElement(PREFIX + NODE_NETWORKING); hardware.appendChild(networking); Text networkingText = doc.createTextNode(""); networking.appendChild(networkingText); if (packageMgr.hasSystemFeature(PackageManager.FEATURE_WIFI)) { networkingText.appendData("\nWifi"); } if (packageMgr.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) { networkingText.appendData("\nBluetooth"); } if (packageMgr.hasSystemFeature(PackageManager.FEATURE_NFC)) { networkingText.appendData("\nNFC"); } Element sensors = doc.createElement(PREFIX + NODE_SENSORS); hardware.appendChild(sensors); Text sensorsText = doc.createTextNode(""); sensors.appendChild(sensorsText); if (packageMgr.hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER)) { sensorsText.appendData("\nAccelerometer"); } if (packageMgr.hasSystemFeature(PackageManager.FEATURE_SENSOR_BAROMETER)) { sensorsText.appendData("\nBarometer"); } if (packageMgr.hasSystemFeature(PackageManager.FEATURE_SENSOR_COMPASS)) { sensorsText.appendData("\nCompass"); } if (packageMgr.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)) { sensorsText.appendData("\nGPS"); } if (packageMgr.hasSystemFeature(PackageManager.FEATURE_SENSOR_GYROSCOPE)) { sensorsText.appendData("\nGyroscope"); } if (packageMgr.hasSystemFeature(PackageManager.FEATURE_SENSOR_LIGHT)) { sensorsText.appendData("\nLightSensor"); } if (packageMgr.hasSystemFeature(PackageManager.FEATURE_SENSOR_PROXIMITY)) { sensorsText.appendData("\nProximitySensor"); } Element mic = doc.createElement(PREFIX + NODE_MIC); hardware.appendChild(mic); Text micText; if (packageMgr.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) { micText = doc.createTextNode("true"); } else { micText = doc.createTextNode("false"); } mic.appendChild(micText); if (android.os.Build.VERSION.SDK_INT >= 9){ List<Element> cameras = getCameraElements(doc); for (Element cam : cameras){ hardware.appendChild(cam); } } else { Camera c = Camera.open(); Element camera = doc.createElement(PREFIX + NODE_CAMERA); hardware.appendChild(camera); Element location = doc.createElement(PREFIX + NODE_LOCATION); camera.appendChild(location); // All camera's before API 9 were on the back location.appendChild(doc.createTextNode("back")); Camera.Parameters cParams = c.getParameters(); Element autofocus = doc.createElement(PREFIX + NODE_AUTOFOCUS); camera.appendChild(autofocus); List<String> foci = cParams.getSupportedFocusModes(); if (foci == null) { autofocus.appendChild(doc.createTextNode(" ")); } else if (foci.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { autofocus.appendChild(doc.createTextNode("true")); } else { autofocus.appendChild(doc.createTextNode("false")); } Element flash = doc.createElement(PREFIX + NODE_FLASH); camera.appendChild(flash); List<String> flashes = cParams.getSupportedFlashModes(); if (flashes == null || !flashes.contains(Camera.Parameters.FLASH_MODE_ON)) { flash.appendChild(doc.createTextNode("false")); } else { flash.appendChild(doc.createTextNode("true")); } c.release(); } Element keyboard = doc.createElement(PREFIX + NODE_KEYBOARD); hardware.appendChild(keyboard); Text keyboardText; switch (config.keyboard) { case Configuration.KEYBOARD_NOKEYS: keyboardText = doc.createTextNode("nokeys"); break; case Configuration.KEYBOARD_12KEY: keyboardText = doc.createTextNode("12key"); break; case Configuration.KEYBOARD_QWERTY: keyboardText = doc.createTextNode("qwerty"); break; default: keyboardText = doc.createTextNode(" "); } keyboard.appendChild(keyboardText); Element nav = doc.createElement(PREFIX + NODE_NAV); hardware.appendChild(nav); Text navText; switch (config.navigation) { case Configuration.NAVIGATION_DPAD: navText = doc.createTextNode("dpad"); case Configuration.NAVIGATION_TRACKBALL: navText = doc.createTextNode("trackball"); case Configuration.NAVIGATION_WHEEL: navText = doc.createTextNode("wheel"); case Configuration.NAVIGATION_NONAV: navText = doc.createTextNode("nonav"); default: navText = doc.createTextNode(" "); } nav.appendChild(navText); Element ram = doc.createElement(PREFIX + NODE_RAM); hardware.appendChild(ram); // totalMemory given in bytes, divide by 1048576 to get RAM in MiB String line; long ramAmount = 0; String unit = UNIT_BYTES; try { BufferedReader meminfo = new BufferedReader(new FileReader("/proc/meminfo")); while ((line = meminfo.readLine()) != null) { String[] vals = line.split("[\\s]+"); if (vals[0].equals("MemTotal:")) { try { /* * We're going to want it as a string eventually, * but parsing it lets us validate it's actually a * number and something strange isn't going on */ ramAmount = Long.parseLong(vals[1]); unit = vals[2]; break; } catch (NumberFormatException e) { // Ignore } } } meminfo.close(); } catch (FileNotFoundException e) { // Ignore } if (ramAmount > 0) { if (unit.equals("B")) { unit = UNIT_BYTES; } else if (unit.equals("kB")) { unit = UNIT_KIBIBYTES; } else if (unit.equals("MB")) { unit = UNIT_MEBIBYTES; } else if (unit.equals("GB")) { unit = UNIT_GIBIBYTES; } else { unit = " "; } } ram.setAttribute(ATTR_UNIT, unit); ram.appendChild(doc.createTextNode(Long.toString(ramAmount))); Element buttons = doc.createElement(PREFIX + NODE_BUTTONS); hardware.appendChild(buttons); Text buttonsText; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { buttonsText = doc.createTextNode(getButtonsType()); } else { buttonsText = doc.createTextNode("hard"); } buttons.appendChild(buttonsText); Element internalStorage = doc.createElement(PREFIX + NODE_INTERNAL_STORAGE); hardware.appendChild(internalStorage); StatFs rootStat = new StatFs(Environment.getRootDirectory().getAbsolutePath()); long bytesAvailable = rootStat.getBlockSize() * rootStat.getBlockCount(); long internalStorageSize = bytesAvailable / (1024 * 1024); internalStorage.appendChild(doc.createTextNode(Long.toString(internalStorageSize))); internalStorage.setAttribute(ATTR_UNIT, UNIT_MEBIBYTES); Element externalStorage = doc.createElement(PREFIX + NODE_REMOVABLE_STORAGE); hardware.appendChild(externalStorage); externalStorage.appendChild(doc.createTextNode(" ")); // Don't know CPU, GPU types Element cpu = doc.createElement(PREFIX + NODE_CPU); hardware.appendChild(cpu); cpu.appendChild(doc.createTextNode(" ")); Element gpu = doc.createElement(PREFIX + NODE_GPU); hardware.appendChild(gpu); gpu.appendChild(doc.createTextNode(" ")); Element abi = doc.createElement(PREFIX + NODE_ABI); hardware.appendChild(abi); Text abiText = doc.createTextNode(""); abi.appendChild(abiText); abiText.appendData("\n" + android.os.Build.CPU_ABI); abiText.appendData("\n" + android.os.Build.CPU_ABI2); // Don't know about either the dock or plugged-in element Element dock = doc.createElement(PREFIX + NODE_DOCK); hardware.appendChild(dock); dock.appendChild(doc.createTextNode(" ")); Element pluggedIn = doc.createElement(PREFIX + NODE_POWER_TYPE); hardware.appendChild(pluggedIn); pluggedIn.appendChild(doc.createTextNode(" ")); Element software = doc.createElement(PREFIX + NODE_SOFTWARE); device.appendChild(software); Element apiLevel = doc.createElement(PREFIX + NODE_API_LEVEL); software.appendChild(apiLevel); apiLevel.appendChild(doc.createTextNode(Integer .toString(android.os.Build.VERSION.SDK_INT))); Element liveWallpaperSupport = doc.createElement(PREFIX + NODE_LIVE_WALLPAPER_SUPPORT); software.appendChild(liveWallpaperSupport); if (packageMgr.hasSystemFeature(PackageManager.FEATURE_LIVE_WALLPAPER)) { liveWallpaperSupport.appendChild(doc.createTextNode("true")); } else { liveWallpaperSupport.appendChild(doc.createTextNode("flase")); } Element bluetoothProfiles = doc.createElement(PREFIX + NODE_BLUETOOTH_PROFILES); software.appendChild(bluetoothProfiles); bluetoothProfiles.appendChild(doc.createTextNode(" ")); Element glVersion = doc.createElement(PREFIX + NODE_GL_VERSION); software.appendChild(glVersion); String glVersionString = " "; FeatureInfo[] features = packageMgr.getSystemAvailableFeatures(); for (FeatureInfo feature : features) { if (feature.reqGlEsVersion > 0) { glVersionString = feature.getGlEsVersion(); break; } } glVersion.appendChild(doc.createTextNode(glVersionString)); Element glExtensions = doc.createElement(PREFIX + NODE_GL_EXTENSIONS); software.appendChild(glExtensions); if (mExtensions != null && !mExtensions.trim().equals("")) { glExtensions.appendChild(doc.createTextNode(mExtensions)); } else { glExtensions.appendChild(doc.createTextNode(" ")); } Transformer tf = TransformerFactory.newInstance().newTransformer(); tf.setOutputProperty(OutputKeys.INDENT, "yes"); tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); DOMSource source = new DOMSource(doc); String filename = String.format("devices_%1$tm_%1$td_%1$ty.xml", Calendar.getInstance() .getTime()); File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); File outFile = new File(dir, filename); FileOutputStream out = new FileOutputStream(new File(dir, filename)); StreamResult result = new StreamResult(out); tf.transform(source, result); out.flush(); out.close(); return outFile.getAbsolutePath(); } catch (ParserConfigurationException e) { error("Parser config exception", e); } catch (TransformerConfigurationException e) { error("Transformer config exception", e); } catch (TransformerFactoryConfigurationError e) { error("TransformerFactory config exception", e); } catch (TransformerException e) { error("Error transforming", e); } catch (IOException e) { error("I/O Error", e); } return null; } @TargetApi(9) private List<Element> getCameraElements(Document doc) { List<Element> cList = new ArrayList<Element>(); for (int i = 0; i < Camera.getNumberOfCameras(); i++) { Element camera = doc.createElement(PREFIX + NODE_CAMERA); cList.add(camera); Element location = doc.createElement(PREFIX + NODE_LOCATION); camera.appendChild(location); Text locationText; Camera.CameraInfo cInfo = new Camera.CameraInfo(); Camera.getCameraInfo(i, cInfo); if (cInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { locationText = doc.createTextNode("front"); } else if (cInfo.facing == CameraInfo.CAMERA_FACING_BACK) { locationText = doc.createTextNode("back"); } else { locationText = doc.createTextNode(" "); } location.appendChild(locationText); Camera c = Camera.open(i); Camera.Parameters cParams = c.getParameters(); Element autofocus = doc.createElement(PREFIX + NODE_AUTOFOCUS); camera.appendChild(autofocus); List<String> foci = cParams.getSupportedFocusModes(); if (foci == null) { autofocus.appendChild(doc.createTextNode(" ")); } else if (foci.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { autofocus.appendChild(doc.createTextNode("true")); } else { autofocus.appendChild(doc.createTextNode("false")); } Element flash = doc.createElement(PREFIX + NODE_FLASH); camera.appendChild(flash); List<String> flashes = cParams.getSupportedFlashModes(); if (flashes == null || !flashes.contains(Camera.Parameters.FLASH_MODE_ON)) { flash.appendChild(doc.createTextNode("false")); } else { flash.appendChild(doc.createTextNode("true")); } c.release(); } return cList; } @TargetApi(14) private String getButtonsType() { ViewConfiguration vConfig = ViewConfiguration.get(mCtx); if (vConfig.hasPermanentMenuKey()) { return "hard"; } else { return "soft"; } } private void error(String err, Throwable e) { Toast.makeText(mCtx, "Error Generating Configuration", Toast.LENGTH_SHORT).show(); Log.e(TAG, err); Log.e(TAG, e.getLocalizedMessage()); } }