Inspects a link Configuration through reflection API to generate a human readable String with values replaced with their constants names.
/*
* Copyright 2010 Emmanuel Astier & Kevin Gaudin
*
* 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 org.acra.util;
//import static org.acra.ACRA.LOG_TAG;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import android.content.res.Configuration;
import android.util.Log;
import android.util.SparseArray;
/**
* Inspects a {@link Configuration} object through reflection API in order to
* generate a human readable String with values replaced with their constants
* names. The {@link Configuration#toString()} method was not enough as values
* like 0, 1, 2 or 3 don't look readable to me. Using reflection API allows to
* retrieve hidden fields and can make us hope to be compatible with all Android
* API levels, even those which are not published yet.
*
* @author Kevin Gaudin
*
*/
final class ConfigurationInspector {
private static final String SUFFIX_MASK = "_MASK";
private static final String FIELD_SCREENLAYOUT = "screenLayout";
private static final String FIELD_UIMODE = "uiMode";
private static final String FIELD_MNC = "mnc";
private static final String FIELD_MCC = "mcc";
private static final String PREFIX_UI_MODE = "UI_MODE_";
private static final String PREFIX_TOUCHSCREEN = "TOUCHSCREEN_";
private static final String PREFIX_SCREENLAYOUT = "SCREENLAYOUT_";
private static final String PREFIX_ORIENTATION = "ORIENTATION_";
private static final String PREFIX_NAVIGATIONHIDDEN = "NAVIGATIONHIDDEN_";
private static final String PREFIX_NAVIGATION = "NAVIGATION_";
private static final String PREFIX_KEYBOARDHIDDEN = "KEYBOARDHIDDEN_";
private static final String PREFIX_KEYBOARD = "KEYBOARD_";
private static final String PREFIX_HARDKEYBOARDHIDDEN = "HARDKEYBOARDHIDDEN_";
private static SparseArray<String> mHardKeyboardHiddenValues = new SparseArray<String>();
private static SparseArray<String> mKeyboardValues = new SparseArray<String>();
private static SparseArray<String> mKeyboardHiddenValues = new SparseArray<String>();
private static SparseArray<String> mNavigationValues = new SparseArray<String>();
private static SparseArray<String> mNavigationHiddenValues = new SparseArray<String>();
private static SparseArray<String> mOrientationValues = new SparseArray<String>();
private static SparseArray<String> mScreenLayoutValues = new SparseArray<String>();
private static SparseArray<String> mTouchScreenValues = new SparseArray<String>();
private static SparseArray<String> mUiModeValues = new SparseArray<String>();
private static final HashMap<String, SparseArray<String>> mValueArrays = new HashMap<String, SparseArray<String>>();
// Static init
static {
mValueArrays.put(PREFIX_HARDKEYBOARDHIDDEN, mHardKeyboardHiddenValues);
mValueArrays.put(PREFIX_KEYBOARD, mKeyboardValues);
mValueArrays.put(PREFIX_KEYBOARDHIDDEN, mKeyboardHiddenValues);
mValueArrays.put(PREFIX_NAVIGATION, mNavigationValues);
mValueArrays.put(PREFIX_NAVIGATIONHIDDEN, mNavigationHiddenValues);
mValueArrays.put(PREFIX_ORIENTATION, mOrientationValues);
mValueArrays.put(PREFIX_SCREENLAYOUT, mScreenLayoutValues);
mValueArrays.put(PREFIX_TOUCHSCREEN, mTouchScreenValues);
mValueArrays.put(PREFIX_UI_MODE, mUiModeValues);
for (final Field f : Configuration.class.getFields()) {
if (Modifier.isStatic(f.getModifiers()) && Modifier.isFinal(f.getModifiers())) {
final String fieldName = f.getName();
try {
if (fieldName.startsWith(PREFIX_HARDKEYBOARDHIDDEN)) {
mHardKeyboardHiddenValues.put(f.getInt(null), fieldName);
} else if (fieldName.startsWith(PREFIX_KEYBOARD)) {
mKeyboardValues.put(f.getInt(null), fieldName);
} else if (fieldName.startsWith(PREFIX_KEYBOARDHIDDEN)) {
mKeyboardHiddenValues.put(f.getInt(null), fieldName);
} else if (fieldName.startsWith(PREFIX_NAVIGATION)) {
mNavigationValues.put(f.getInt(null), fieldName);
} else if (fieldName.startsWith(PREFIX_NAVIGATIONHIDDEN)) {
mNavigationHiddenValues.put(f.getInt(null), fieldName);
} else if (fieldName.startsWith(PREFIX_ORIENTATION)) {
mOrientationValues.put(f.getInt(null), fieldName);
} else if (fieldName.startsWith(PREFIX_SCREENLAYOUT)) {
mScreenLayoutValues.put(f.getInt(null), fieldName);
} else if (fieldName.startsWith(PREFIX_TOUCHSCREEN)) {
mTouchScreenValues.put(f.getInt(null), fieldName);
} else if (fieldName.startsWith(PREFIX_UI_MODE)) {
mUiModeValues.put(f.getInt(null), fieldName);
}
} catch (IllegalArgumentException e) {
// Log.w(LOG_TAG, "Error while inspecting device configuration: ", e);
} catch (IllegalAccessException e) {
// Log.w(LOG_TAG, "Error while inspecting device configuration: ", e);
}
}
}
}
/**
* Use this method to generate a human readable String listing all values
* from the provided Configuration instance.
*
* @param conf
* The Configuration to be described.
* @return A String describing all the fields of the given Configuration,
* with values replaced by constant names.
*/
public static String toString(Configuration conf) {
final StringBuilder result = new StringBuilder();
for (final Field f : conf.getClass().getFields()) {
try {
if (!Modifier.isStatic(f.getModifiers())) {
final String fieldName = f.getName();
result.append(fieldName).append('=');
if (f.getType().equals(int.class)) {
result.append(getFieldValueName(conf, f));
} else {
result.append(f.get(conf).toString());
}
result.append('\n');
}
} catch (IllegalArgumentException e) {
// Log.e(LOG_TAG, "Error while inspecting device configuration: ", e);
} catch (IllegalAccessException e) {
// Log.e(LOG_TAG, "Error while inspecting device configuration: ", e);
}
}
return result.toString();
}
/**
* Retrieve the name of the constant defined in the {@link Configuration}
* class which defines the value of a field in a {@link Configuration}
* instance.
*
* @param conf
* The instance of {@link Configuration} where the value is
* stored.
* @param f
* The {@link Field} to be inspected in the {@link Configuration}
* instance.
* @return The value of the field f in instance conf translated to its
* constant name.
* @throws IllegalAccessException if the supplied field is inaccessible.
*/
private static String getFieldValueName(Configuration conf, Field f) throws IllegalAccessException {
final String fieldName = f.getName();
if (fieldName.equals(FIELD_MCC) || fieldName.equals(FIELD_MNC)) {
return Integer.toString(f.getInt(conf));
} else if (fieldName.equals(FIELD_UIMODE)) {
return activeFlags(mValueArrays.get(PREFIX_UI_MODE), f.getInt(conf));
} else if (fieldName.equals(FIELD_SCREENLAYOUT)) {
return activeFlags(mValueArrays.get(PREFIX_SCREENLAYOUT), f.getInt(conf));
} else {
final SparseArray<String> values = mValueArrays.get(fieldName.toUpperCase() + '_');
if (values == null) {
// Unknown field, return the raw int as String
return Integer.toString(f.getInt(conf));
}
final String value = values.get(f.getInt(conf));
if (value == null) {
// Unknown value, return the raw int as String
return Integer.toString(f.getInt(conf));
}
return value;
}
}
/**
* Some fields contain multiple value types which can be isolated by
* applying a bitmask. That method returns the concatenation of active
* values.
*
* @param valueNames
* The array containing the different values and names for this
* field. Must contain mask values too.
* @param bitfield
* The bitfield to inspect.
* @return The names of the different values contained in the bitfield,
* separated by '+'.
*/
private static String activeFlags(SparseArray<String> valueNames, int bitfield) {
final StringBuilder result = new StringBuilder();
// Look for masks, apply it an retrieve the masked value
for (int i = 0; i < valueNames.size(); i++) {
final int maskValue = valueNames.keyAt(i);
if (valueNames.get(maskValue).endsWith(SUFFIX_MASK)) {
final int value = bitfield & maskValue;
if (value > 0) {
if (result.length() > 0) {
result.append('+');
}
result.append(valueNames.get(value));
}
}
}
return result.toString();
}
}
Related examples in the same category
1. | Split with | | |
2. | Split first with | | |
3. | split By Space and save result to a List | | |
4. | Space trim | | |
5. | truncate by length | | |
6. | Remove all blanks | | |
7. | Is a string a Number | | |
8. | Random string | | |
9. | Tokenizer. Why? Because StringTokenizer is not available in J2ME. | | |
10. | String resource | | |
11. | Shows creating text with links from HTML in the Java code, rather than from a string resource. Note that for a | | |
12. | Join a collection of strings by a seperator | | |
13. | Tests if a string is blank: null, emtpy, or only whitespace (" ", \r\n, \t, etc) | | |
14. | Tests if a string is numeric, i.e. contains only digit characters | | |
15. | Writer implementation that outputs to a StringBuilder | | |
16. | Gets the device's phone number as a String. | | |
17. | Returns a String representation of the content of a android.view.Display object. | | |
18. | Get String Element Value | | |
19. | Join strings | | |
20. | Find two consecutive newlines in a string. | | |
21. | Retrieve a boolean primitive type from a String. | | |
22. | Trim char from string | | |
23. | Returns true if the string does not fit in standard ASCII | | |
24. | Returns true if the given string is null or empty. | | |
25. | 4 octets in address string | | |
26. | Add space to CSV string | | |
27. | String fast Split | | |
28. | Split a String by a Character, i.e. Split lines by using '\n' | | |
29. | String Capitalizer | | |
30. | Count char in a string | | |
31. | Search char in a string from a starting position | | |
32. | load String From Raw Resource | | |
33. | Join Collection of String | | |
34. | Padding a string, truncate a string | | |
35. | Converts a string to title casing. | | |
36. | reversing String | | |
37. | load Resource To String | | |
38. | convert Duration to String | | |
39. | Convert string from one encoding to another | | |
40. | Object to String and String to Object | | |
41. | IP to String | | |
42. | Convert string to bumber and convert number to string | | |
43. | line string reader in J2ME | | |
44. | String to Map with token | | |
45. | Generate the client id, which is a fixed string of length 8 concatenated with 12 random bytes | | |
46. | StringBuilder Writer | | |
47. | Return a specific raw resource contents as a String value. | | |
48. | Returns the ISO 8601-format String corresponding to the given duration (measured in milliseconds). | | |
49. | Returns a string representation of the given number of nanoseconds. | | |
50. | Simple Tokenizer | | |
51. | split By Space | | |
52. | Pad Front | | |
53. | Count Occurrences | | |
54. | Padding Left | | |
55. | captalize Words | | |
56. | Tokenizer Utils | | |
57. | Returns space padding | | |
58. | Normalise Whitespace | | |
59. | Removes unwanted blank characters | | |
60. | Removes unwanted backslashes characters | | |
61. | equals Ignore Case | | |
62. | A method to decode/encode quoted printable encoded data | | |
63. | Title Name Parser | | |
64. | Split Camal Case | | |
65. | Split and combine by token | | |
66. | Shorten text for display in lists etc. | | |