• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.deviceconfig;
18 
19 import android.annotation.SuppressLint;
20 import android.annotation.TargetApi;
21 import android.content.Context;
22 import android.content.pm.FeatureInfo;
23 import android.content.pm.PackageManager;
24 import android.content.res.Configuration;
25 import android.content.res.Resources;
26 import android.hardware.Camera;
27 import android.hardware.Camera.CameraInfo;
28 import android.os.Build;
29 import android.os.Environment;
30 import android.os.StatFs;
31 import android.util.DisplayMetrics;
32 import android.util.Log;
33 import android.view.ViewConfiguration;
34 import android.widget.Toast;
35 
36 import org.w3c.dom.Document;
37 import org.w3c.dom.Element;
38 import org.w3c.dom.Text;
39 
40 import java.io.BufferedReader;
41 import java.io.File;
42 import java.io.FileNotFoundException;
43 import java.io.FileOutputStream;
44 import java.io.FileReader;
45 import java.io.IOException;
46 import java.util.ArrayList;
47 import java.util.Calendar;
48 import java.util.List;
49 
50 import javax.xml.XMLConstants;
51 import javax.xml.parsers.DocumentBuilderFactory;
52 import javax.xml.parsers.ParserConfigurationException;
53 import javax.xml.transform.OutputKeys;
54 import javax.xml.transform.Transformer;
55 import javax.xml.transform.TransformerConfigurationException;
56 import javax.xml.transform.TransformerException;
57 import javax.xml.transform.TransformerFactory;
58 import javax.xml.transform.TransformerFactoryConfigurationError;
59 import javax.xml.transform.dom.DOMSource;
60 import javax.xml.transform.stream.StreamResult;
61 
62 public class ConfigGenerator {
63     private Context mCtx;
64     private String mExtensions;
65 
66     public static final String NS_DEVICES_XSD = "http://schemas.android.com/sdk/devices/1";
67 
68     /**
69      * The "devices" element is the root element of this schema.
70      *
71      * It must contain one or more "device" elements that each define the
72      * hardware, software, and states for a given device.
73      */
74     public static final String NODE_DEVICES = "devices";
75 
76     /**
77      * A "device" element contains a "hardware" element, a "software" element
78      * for each API version it supports, and a "state" element for each possible
79      * state the device could be in.
80      */
81     public static final String NODE_DEVICE = "device";
82 
83     /**
84      * The "hardware" element contains all of the hardware information for a
85      * given device.
86      */
87     public static final String NODE_HARDWARE = "hardware";
88 
89     /**
90      * The "software" element contains all of the software information for an
91      * API version of the given device.
92      */
93     public static final String NODE_SOFTWARE = "software";
94 
95     /**
96      * The "state" element contains all of the parameters for a given state of
97      * the device. It's also capable of redefining hardware configurations if
98      * they change based on state.
99      */
100 
101     public static final String NODE_STATE = "state";
102 
103     public static final String NODE_KEYBOARD = "keyboard";
104     public static final String NODE_TOUCH = "touch";
105     public static final String NODE_GL_EXTENSIONS = "gl-extensions";
106     public static final String NODE_GL_VERSION = "gl-version";
107     public static final String NODE_NETWORKING = "networking";
108     public static final String NODE_REMOVABLE_STORAGE = "removable-storage";
109     public static final String NODE_FLASH = "flash";
110     public static final String NODE_LIVE_WALLPAPER_SUPPORT = "live-wallpaper-support";
111     public static final String NODE_BUTTONS = "buttons";
112     public static final String NODE_CAMERA = "camera";
113     public static final String NODE_LOCATION = "location";
114     public static final String NODE_GPU = "gpu";
115     public static final String NODE_DOCK = "dock";
116     public static final String NODE_YDPI = "ydpi";
117     public static final String NODE_POWER_TYPE = "power-type";
118     public static final String NODE_Y_DIMENSION = "y-dimension";
119     public static final String NODE_SCREEN_RATIO = "screen-ratio";
120     public static final String NODE_NAV_STATE = "nav-state";
121     public static final String NODE_MIC = "mic";
122     public static final String NODE_RAM = "ram";
123     public static final String NODE_XDPI = "xdpi";
124     public static final String NODE_DIMENSIONS = "dimensions";
125     public static final String NODE_ABI = "abi";
126     public static final String NODE_MECHANISM = "mechanism";
127     public static final String NODE_MULTITOUCH = "multitouch";
128     public static final String NODE_NAV = "nav";
129     public static final String NODE_PIXEL_DENSITY = "pixel-density";
130     public static final String NODE_SCREEN_ORIENTATION = "screen-orientation";
131     public static final String NODE_AUTOFOCUS = "autofocus";
132     public static final String NODE_SCREEN_SIZE = "screen-size";
133     public static final String NODE_DESCRIPTION = "description";
134     public static final String NODE_BLUETOOTH_PROFILES = "bluetooth-profiles";
135     public static final String NODE_SCREEN = "screen";
136     public static final String NODE_SENSORS = "sensors";
137     public static final String NODE_DIAGONAL_LENGTH = "diagonal-length";
138     public static final String NODE_SCREEN_TYPE = "screen-type";
139     public static final String NODE_KEYBOARD_STATE = "keyboard-state";
140     public static final String NODE_X_DIMENSION = "x-dimension";
141     public static final String NODE_CPU = "cpu";
142     public static final String NODE_INTERNAL_STORAGE = "internal-storage";
143     public static final String NODE_NAME = "name";
144     public static final String NODE_MANUFACTURER = "manufacturer";
145     public static final String NODE_API_LEVEL = "api-level";
146     public static final String ATTR_DEFAULT = "default";
147     public static final String ATTR_UNIT = "unit";
148     public static final String UNIT_BYTES = "B";
149     public static final String UNIT_KIBIBYTES = "KiB";
150     public static final String UNIT_MEBIBYTES = "MiB";
151     public static final String UNIT_GIBIBYTES = "GiB";
152     public static final String UNIT_TEBIBYTES = "TiB";
153     public static final String LOCAL_NS = "d";
154     public static final String PREFIX = LOCAL_NS + ":";
155 
156     private static final String TAG = "ConfigGenerator";
157 
ConfigGenerator(Context context, String extensions)158     public ConfigGenerator(Context context, String extensions) {
159         mCtx = context;
160         mExtensions = extensions;
161     }
162 
163     @SuppressLint("WorldReadableFiles")
generateConfig()164     public String generateConfig() {
165         Resources resources = mCtx.getResources();
166         PackageManager packageMgr = mCtx.getPackageManager();
167         DisplayMetrics metrics = resources.getDisplayMetrics();
168         Configuration config = resources.getConfiguration();
169 
170         try {
171             Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
172 
173             Element devices = doc.createElement(PREFIX + NODE_DEVICES);
174             devices.setAttribute(XMLConstants.XMLNS_ATTRIBUTE + ":xsi",
175                     XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
176             devices.setAttribute(XMLConstants.XMLNS_ATTRIBUTE + ":" + LOCAL_NS, NS_DEVICES_XSD);
177             doc.appendChild(devices);
178 
179             Element device = doc.createElement(PREFIX + NODE_DEVICE);
180             devices.appendChild(device);
181 
182             Element name = doc.createElement(PREFIX + NODE_NAME);
183             device.appendChild(name);
184             name.appendChild(doc.createTextNode(android.os.Build.MODEL));
185             Element manufacturer = doc.createElement(PREFIX + NODE_MANUFACTURER);
186             device.appendChild(manufacturer);
187             manufacturer.appendChild(doc.createTextNode(android.os.Build.MANUFACTURER));
188 
189             Element hardware = doc.createElement(PREFIX + NODE_HARDWARE);
190             device.appendChild(hardware);
191 
192             Element screen = doc.createElement(PREFIX + NODE_SCREEN);
193             hardware.appendChild(screen);
194 
195             Element screenSize = doc.createElement(PREFIX + NODE_SCREEN_SIZE);
196             screen.appendChild(screenSize);
197             Text screenSizeText;
198             switch (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) {
199             case Configuration.SCREENLAYOUT_SIZE_SMALL:
200                 screenSizeText = doc.createTextNode("small");
201                 break;
202             case Configuration.SCREENLAYOUT_SIZE_NORMAL:
203                 screenSizeText = doc.createTextNode("normal");
204                 break;
205             case Configuration.SCREENLAYOUT_SIZE_LARGE:
206                 screenSizeText = doc.createTextNode("large");
207                 break;
208             case Configuration.SCREENLAYOUT_SIZE_XLARGE:
209                 screenSizeText = doc.createTextNode("xlarge");
210                 break;
211             default:
212                 screenSizeText = doc.createTextNode(" ");
213                 break;
214             }
215             screenSize.appendChild(screenSizeText);
216 
217             Element diagonalLength = doc.createElement(PREFIX + NODE_DIAGONAL_LENGTH);
218             screen.appendChild(diagonalLength);
219             double xin = metrics.widthPixels / metrics.xdpi;
220             double yin = metrics.heightPixels / metrics.ydpi;
221             double diag = Math.sqrt(Math.pow(xin, 2) + Math.pow(yin, 2));
222             diagonalLength.appendChild(doc.createTextNode(String.format("%1$.2f", diag)));
223 
224             Element pixelDensity = doc.createElement(PREFIX + NODE_PIXEL_DENSITY);
225             screen.appendChild(pixelDensity);
226             Text pixelDensityText;
227             switch (metrics.densityDpi) {
228             case DisplayMetrics.DENSITY_LOW:
229                 pixelDensityText = doc.createTextNode("ldpi");
230                 break;
231             case DisplayMetrics.DENSITY_MEDIUM:
232                 pixelDensityText = doc.createTextNode("mdpi");
233                 break;
234             case DisplayMetrics.DENSITY_TV:
235                 pixelDensityText = doc.createTextNode("tvdpi");
236                 break;
237             case DisplayMetrics.DENSITY_HIGH:
238                 pixelDensityText = doc.createTextNode("hdpi");
239                 break;
240             case DisplayMetrics.DENSITY_XHIGH:
241                 pixelDensityText = doc.createTextNode("xhdpi");
242                 break;
243             default:
244                 pixelDensityText = doc.createTextNode(" ");
245             }
246             pixelDensity.appendChild(pixelDensityText);
247 
248             Element screenRatio = doc.createElement(PREFIX + NODE_SCREEN_RATIO);
249             screen.appendChild(screenRatio);
250             Text screenRatioText;
251             switch (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) {
252             case Configuration.SCREENLAYOUT_LONG_YES:
253                 screenRatioText = doc.createTextNode("long");
254                 break;
255             case Configuration.SCREENLAYOUT_LONG_NO:
256                 screenRatioText = doc.createTextNode("notlong");
257                 break;
258             default:
259                 screenRatioText = doc.createTextNode(" ");
260                 break;
261             }
262             screenRatio.appendChild(screenRatioText);
263 
264             Element dimensions = doc.createElement(PREFIX + NODE_DIMENSIONS);
265             screen.appendChild(dimensions);
266 
267             Element xDimension = doc.createElement(PREFIX + NODE_X_DIMENSION);
268             dimensions.appendChild(xDimension);
269             xDimension.appendChild(doc.createTextNode(Integer.toString(metrics.widthPixels)));
270 
271             Element yDimension = doc.createElement(PREFIX + NODE_Y_DIMENSION);
272             dimensions.appendChild(yDimension);
273             yDimension.appendChild(doc.createTextNode(Integer.toString(metrics.heightPixels)));
274 
275             Element xdpi = doc.createElement(PREFIX + NODE_XDPI);
276             screen.appendChild(xdpi);
277             xdpi.appendChild(doc.createTextNode(Double.toString(metrics.xdpi)));
278 
279             Element ydpi = doc.createElement(PREFIX + NODE_YDPI);
280             screen.appendChild(ydpi);
281             ydpi.appendChild(doc.createTextNode(Double.toString(metrics.ydpi)));
282 
283             Element touch = doc.createElement(PREFIX + NODE_TOUCH);
284             screen.appendChild(touch);
285 
286             Element multitouch = doc.createElement(PREFIX + NODE_MULTITOUCH);
287             touch.appendChild(multitouch);
288             Text multitouchText;
289             if (packageMgr
290                     .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND)) {
291                 multitouchText = doc.createTextNode("jazz-hands");
292             } else if (packageMgr
293                     .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)) {
294                 multitouchText = doc.createTextNode("distinct");
295             } else if (packageMgr.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)) {
296                 multitouchText = doc.createTextNode("basic");
297             } else {
298                 multitouchText = doc.createTextNode("none");
299             }
300             multitouch.appendChild(multitouchText);
301 
302             Element mechanism = doc.createElement(PREFIX + NODE_MECHANISM);
303             touch.appendChild(mechanism);
304             Text mechanismText;
305             switch (config.touchscreen) {
306             case Configuration.TOUCHSCREEN_STYLUS:
307                 mechanismText = doc.createTextNode("stylus");
308             case Configuration.TOUCHSCREEN_FINGER:
309                 mechanismText = doc.createTextNode("finger");
310             case Configuration.TOUCHSCREEN_NOTOUCH:
311                 mechanismText = doc.createTextNode("notouch");
312             default:
313                 mechanismText = doc.createTextNode(" ");
314             }
315             mechanism.appendChild(mechanismText);
316 
317             // Create an empty place holder node for screen-type since we can't
318             // actually determine it
319 
320             Element screenType = doc.createElement(PREFIX + NODE_SCREEN_TYPE);
321             touch.appendChild(screenType);
322             screenType.appendChild(doc.createTextNode(" "));
323 
324             Element networking = doc.createElement(PREFIX + NODE_NETWORKING);
325             hardware.appendChild(networking);
326             Text networkingText = doc.createTextNode("");
327             networking.appendChild(networkingText);
328             if (packageMgr.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
329                 networkingText.appendData("\nWifi");
330             }
331             if (packageMgr.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
332                 networkingText.appendData("\nBluetooth");
333             }
334             if (packageMgr.hasSystemFeature(PackageManager.FEATURE_NFC)) {
335                 networkingText.appendData("\nNFC");
336             }
337 
338             Element sensors = doc.createElement(PREFIX + NODE_SENSORS);
339             hardware.appendChild(sensors);
340             Text sensorsText = doc.createTextNode("");
341             sensors.appendChild(sensorsText);
342             if (packageMgr.hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER)) {
343                 sensorsText.appendData("\nAccelerometer");
344             }
345             if (packageMgr.hasSystemFeature(PackageManager.FEATURE_SENSOR_BAROMETER)) {
346                 sensorsText.appendData("\nBarometer");
347             }
348             if (packageMgr.hasSystemFeature(PackageManager.FEATURE_SENSOR_COMPASS)) {
349                 sensorsText.appendData("\nCompass");
350             }
351             if (packageMgr.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)) {
352                 sensorsText.appendData("\nGPS");
353             }
354             if (packageMgr.hasSystemFeature(PackageManager.FEATURE_SENSOR_GYROSCOPE)) {
355                 sensorsText.appendData("\nGyroscope");
356             }
357             if (packageMgr.hasSystemFeature(PackageManager.FEATURE_SENSOR_LIGHT)) {
358                 sensorsText.appendData("\nLightSensor");
359             }
360             if (packageMgr.hasSystemFeature(PackageManager.FEATURE_SENSOR_PROXIMITY)) {
361                 sensorsText.appendData("\nProximitySensor");
362             }
363 
364             Element mic = doc.createElement(PREFIX + NODE_MIC);
365             hardware.appendChild(mic);
366             Text micText;
367             if (packageMgr.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
368                 micText = doc.createTextNode("true");
369             } else {
370                 micText = doc.createTextNode("false");
371             }
372             mic.appendChild(micText);
373 
374             if (android.os.Build.VERSION.SDK_INT >= 9){
375                 List<Element> cameras = getCameraElements(doc);
376                 for (Element cam : cameras){
377                     hardware.appendChild(cam);
378                 }
379             } else {
380                 Camera c = Camera.open();
381                 Element camera = doc.createElement(PREFIX + NODE_CAMERA);
382                 hardware.appendChild(camera);
383                 Element location = doc.createElement(PREFIX + NODE_LOCATION);
384                 camera.appendChild(location);
385                 // All camera's before API 9 were on the back
386                 location.appendChild(doc.createTextNode("back"));
387                 Camera.Parameters cParams = c.getParameters();
388                 Element autofocus = doc.createElement(PREFIX + NODE_AUTOFOCUS);
389                 camera.appendChild(autofocus);
390                 List<String> foci = cParams.getSupportedFocusModes();
391                 if (foci == null) {
392                     autofocus.appendChild(doc.createTextNode(" "));
393                 } else if (foci.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
394                     autofocus.appendChild(doc.createTextNode("true"));
395                 } else {
396                     autofocus.appendChild(doc.createTextNode("false"));
397                 }
398 
399                 Element flash = doc.createElement(PREFIX + NODE_FLASH);
400                 camera.appendChild(flash);
401                 List<String> flashes = cParams.getSupportedFlashModes();
402                 if (flashes == null || !flashes.contains(Camera.Parameters.FLASH_MODE_ON)) {
403                     flash.appendChild(doc.createTextNode("false"));
404                 } else {
405                     flash.appendChild(doc.createTextNode("true"));
406                 }
407                 c.release();
408             }
409 
410 
411             Element keyboard = doc.createElement(PREFIX + NODE_KEYBOARD);
412             hardware.appendChild(keyboard);
413             Text keyboardText;
414             switch (config.keyboard) {
415             case Configuration.KEYBOARD_NOKEYS:
416                 keyboardText = doc.createTextNode("nokeys");
417                 break;
418             case Configuration.KEYBOARD_12KEY:
419                 keyboardText = doc.createTextNode("12key");
420                 break;
421             case Configuration.KEYBOARD_QWERTY:
422                 keyboardText = doc.createTextNode("qwerty");
423                 break;
424             default:
425                 keyboardText = doc.createTextNode(" ");
426             }
427             keyboard.appendChild(keyboardText);
428 
429             Element nav = doc.createElement(PREFIX + NODE_NAV);
430             hardware.appendChild(nav);
431             Text navText;
432             switch (config.navigation) {
433             case Configuration.NAVIGATION_DPAD:
434                 navText = doc.createTextNode("dpad");
435             case Configuration.NAVIGATION_TRACKBALL:
436                 navText = doc.createTextNode("trackball");
437             case Configuration.NAVIGATION_WHEEL:
438                 navText = doc.createTextNode("wheel");
439             case Configuration.NAVIGATION_NONAV:
440                 navText = doc.createTextNode("nonav");
441             default:
442                 navText = doc.createTextNode(" ");
443             }
444             nav.appendChild(navText);
445 
446             Element ram = doc.createElement(PREFIX + NODE_RAM);
447             hardware.appendChild(ram);
448             // totalMemory given in bytes, divide by 1048576 to get RAM in MiB
449             String line;
450             long ramAmount = 0;
451             String unit = UNIT_BYTES;
452             try {
453                 BufferedReader meminfo = new BufferedReader(new FileReader("/proc/meminfo"));
454                 while ((line = meminfo.readLine()) != null) {
455                     String[] vals = line.split("[\\s]+");
456                     if (vals[0].equals("MemTotal:")) {
457                         try {
458                             /*
459                              * We're going to want it as a string eventually,
460                              * but parsing it lets us validate it's actually a
461                              * number and something strange isn't going on
462                              */
463                             ramAmount = Long.parseLong(vals[1]);
464                             unit = vals[2];
465                             break;
466                         } catch (NumberFormatException e) {
467                             // Ignore
468                         }
469                     }
470                 }
471                 meminfo.close();
472             } catch (FileNotFoundException e) {
473                 // Ignore
474             }
475             if (ramAmount > 0) {
476                 if (unit.equals("B")) {
477                     unit = UNIT_BYTES;
478                 } else if (unit.equals("kB")) {
479                     unit = UNIT_KIBIBYTES;
480                 } else if (unit.equals("MB")) {
481                     unit = UNIT_MEBIBYTES;
482                 } else if (unit.equals("GB")) {
483                     unit = UNIT_GIBIBYTES;
484                 } else {
485                     unit = " ";
486                 }
487             }
488             ram.setAttribute(ATTR_UNIT, unit);
489             ram.appendChild(doc.createTextNode(Long.toString(ramAmount)));
490 
491             Element buttons = doc.createElement(PREFIX + NODE_BUTTONS);
492             hardware.appendChild(buttons);
493             Text buttonsText;
494             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
495                 buttonsText = doc.createTextNode(getButtonsType());
496             } else {
497                 buttonsText = doc.createTextNode("hard");
498             }
499             buttons.appendChild(buttonsText);
500 
501             Element internalStorage = doc.createElement(PREFIX + NODE_INTERNAL_STORAGE);
502             hardware.appendChild(internalStorage);
503             StatFs rootStat = new StatFs(Environment.getRootDirectory().getAbsolutePath());
504             long bytesAvailable = rootStat.getBlockSize() * rootStat.getBlockCount();
505             long internalStorageSize = bytesAvailable / (1024 * 1024);
506             internalStorage.appendChild(doc.createTextNode(Long.toString(internalStorageSize)));
507             internalStorage.setAttribute(ATTR_UNIT, UNIT_MEBIBYTES);
508 
509             Element externalStorage = doc.createElement(PREFIX + NODE_REMOVABLE_STORAGE);
510             hardware.appendChild(externalStorage);
511             externalStorage.appendChild(doc.createTextNode(" "));
512 
513 
514             // Don't know CPU, GPU types
515             Element cpu = doc.createElement(PREFIX + NODE_CPU);
516             hardware.appendChild(cpu);
517             cpu.appendChild(doc.createTextNode(" "));
518             Element gpu = doc.createElement(PREFIX + NODE_GPU);
519             hardware.appendChild(gpu);
520             gpu.appendChild(doc.createTextNode(" "));
521 
522             Element abi = doc.createElement(PREFIX + NODE_ABI);
523             hardware.appendChild(abi);
524             Text abiText = doc.createTextNode("");
525             abi.appendChild(abiText);
526             abiText.appendData("\n" + android.os.Build.CPU_ABI);
527             abiText.appendData("\n" + android.os.Build.CPU_ABI2);
528 
529             // Don't know about either the dock or plugged-in element
530             Element dock = doc.createElement(PREFIX + NODE_DOCK);
531             hardware.appendChild(dock);
532             dock.appendChild(doc.createTextNode(" "));
533 
534             Element pluggedIn = doc.createElement(PREFIX + NODE_POWER_TYPE);
535             hardware.appendChild(pluggedIn);
536             pluggedIn.appendChild(doc.createTextNode(" "));
537 
538             Element software = doc.createElement(PREFIX + NODE_SOFTWARE);
539             device.appendChild(software);
540 
541             Element apiLevel = doc.createElement(PREFIX + NODE_API_LEVEL);
542             software.appendChild(apiLevel);
543             apiLevel.appendChild(doc.createTextNode(Integer
544                     .toString(android.os.Build.VERSION.SDK_INT)));
545 
546             Element liveWallpaperSupport = doc.createElement(PREFIX + NODE_LIVE_WALLPAPER_SUPPORT);
547             software.appendChild(liveWallpaperSupport);
548             if (packageMgr.hasSystemFeature(PackageManager.FEATURE_LIVE_WALLPAPER)) {
549                 liveWallpaperSupport.appendChild(doc.createTextNode("true"));
550             } else {
551                 liveWallpaperSupport.appendChild(doc.createTextNode("flase"));
552             }
553 
554             Element bluetoothProfiles = doc.createElement(PREFIX + NODE_BLUETOOTH_PROFILES);
555             software.appendChild(bluetoothProfiles);
556             bluetoothProfiles.appendChild(doc.createTextNode(" "));
557 
558             Element glVersion = doc.createElement(PREFIX + NODE_GL_VERSION);
559             software.appendChild(glVersion);
560             String glVersionString = " ";
561 
562             FeatureInfo[] features = packageMgr.getSystemAvailableFeatures();
563             for (FeatureInfo feature : features) {
564                 if (feature.reqGlEsVersion > 0) {
565                     glVersionString = feature.getGlEsVersion();
566                     break;
567                 }
568             }
569 
570             glVersion.appendChild(doc.createTextNode(glVersionString));
571 
572             Element glExtensions = doc.createElement(PREFIX + NODE_GL_EXTENSIONS);
573             software.appendChild(glExtensions);
574             if (mExtensions != null && !mExtensions.trim().equals("")) {
575                 glExtensions.appendChild(doc.createTextNode(mExtensions));
576             } else {
577                 glExtensions.appendChild(doc.createTextNode(" "));
578             }
579 
580             Transformer tf = TransformerFactory.newInstance().newTransformer();
581             tf.setOutputProperty(OutputKeys.INDENT, "yes");
582             tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
583             DOMSource source = new DOMSource(doc);
584             String filename = String.format("devices_%1$tm_%1$td_%1$ty.xml", Calendar.getInstance()
585                     .getTime());
586             File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
587             File outFile = new File(dir, filename);
588             FileOutputStream out = new FileOutputStream(new File(dir, filename));
589             StreamResult result = new StreamResult(out);
590             tf.transform(source, result);
591             out.flush();
592             out.close();
593             return outFile.getAbsolutePath();
594         } catch (ParserConfigurationException e) {
595             error("Parser config exception", e);
596         } catch (TransformerConfigurationException e) {
597             error("Transformer config exception", e);
598         } catch (TransformerFactoryConfigurationError e) {
599             error("TransformerFactory config exception", e);
600         } catch (TransformerException e) {
601             error("Error transforming", e);
602         } catch (IOException e) {
603             error("I/O Error", e);
604         }
605         return null;
606     }
607 
608     @TargetApi(9)
getCameraElements(Document doc)609     private List<Element> getCameraElements(Document doc) {
610         List<Element> cList = new ArrayList<Element>();
611         for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
612             Element camera = doc.createElement(PREFIX + NODE_CAMERA);
613             cList.add(camera);
614             Element location = doc.createElement(PREFIX + NODE_LOCATION);
615             camera.appendChild(location);
616             Text locationText;
617             Camera.CameraInfo cInfo = new Camera.CameraInfo();
618             Camera.getCameraInfo(i, cInfo);
619             if (cInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
620                 locationText = doc.createTextNode("front");
621             } else if (cInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
622                 locationText = doc.createTextNode("back");
623             } else {
624                 locationText = doc.createTextNode(" ");
625             }
626             location.appendChild(locationText);
627 
628             Camera c = Camera.open(i);
629             Camera.Parameters cParams = c.getParameters();
630 
631             Element autofocus = doc.createElement(PREFIX + NODE_AUTOFOCUS);
632             camera.appendChild(autofocus);
633             List<String> foci = cParams.getSupportedFocusModes();
634             if (foci == null) {
635                 autofocus.appendChild(doc.createTextNode(" "));
636             } else if (foci.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
637                 autofocus.appendChild(doc.createTextNode("true"));
638             } else {
639                 autofocus.appendChild(doc.createTextNode("false"));
640             }
641 
642             Element flash = doc.createElement(PREFIX + NODE_FLASH);
643             camera.appendChild(flash);
644             List<String> flashes = cParams.getSupportedFlashModes();
645             if (flashes == null || !flashes.contains(Camera.Parameters.FLASH_MODE_ON)) {
646                 flash.appendChild(doc.createTextNode("false"));
647             } else {
648                 flash.appendChild(doc.createTextNode("true"));
649             }
650             c.release();
651         }
652         return cList;
653     }
654 
655     @TargetApi(14)
getButtonsType()656     private String getButtonsType() {
657         ViewConfiguration vConfig = ViewConfiguration.get(mCtx);
658 
659         if (vConfig.hasPermanentMenuKey()) {
660             return "hard";
661         } else {
662             return "soft";
663         }
664     }
665 
error(String err, Throwable e)666     private void error(String err, Throwable e) {
667         Toast.makeText(mCtx, "Error Generating Configuration", Toast.LENGTH_SHORT).show();
668         Log.e(TAG, err);
669         Log.e(TAG, e.getLocalizedMessage());
670     }
671 }
672