1 /* 2 * Copyright (C) 2008 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.android.settings; 18 19 import android.app.Activity; 20 import android.content.ComponentName; 21 import android.content.Intent; 22 import android.content.pm.PackageManager; 23 import android.content.pm.ResolveInfo; 24 import android.os.Build; 25 import android.os.Bundle; 26 import android.os.SystemClock; 27 import android.os.SystemProperties; 28 import android.preference.Preference; 29 import android.preference.PreferenceGroup; 30 import android.preference.PreferenceScreen; 31 import android.provider.Settings; 32 import android.util.Log; 33 34 import java.io.BufferedReader; 35 import java.io.FileReader; 36 import java.io.IOException; 37 import java.util.List; 38 import java.util.regex.Matcher; 39 import java.util.regex.Pattern; 40 41 public class DeviceInfoSettings extends SettingsPreferenceFragment { 42 43 private static final String LOG_TAG = "DeviceInfoSettings"; 44 45 private static final String FILENAME_PROC_VERSION = "/proc/version"; 46 private static final String FILENAME_MSV = "/sys/board_properties/soc/msv"; 47 48 private static final String KEY_CONTAINER = "container"; 49 private static final String KEY_TEAM = "team"; 50 private static final String KEY_CONTRIBUTORS = "contributors"; 51 private static final String KEY_TERMS = "terms"; 52 private static final String KEY_LICENSE = "license"; 53 private static final String KEY_COPYRIGHT = "copyright"; 54 private static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings"; 55 private static final String PROPERTY_URL_SAFETYLEGAL = "ro.url.safetylegal"; 56 private static final String KEY_KERNEL_VERSION = "kernel_version"; 57 private static final String KEY_BUILD_NUMBER = "build_number"; 58 private static final String KEY_DEVICE_MODEL = "device_model"; 59 private static final String KEY_BASEBAND_VERSION = "baseband_version"; 60 private static final String KEY_FIRMWARE_VERSION = "firmware_version"; 61 private static final String KEY_UPDATE_SETTING = "additional_system_update_settings"; 62 63 long[] mHits = new long[3]; 64 65 @Override 66 public void onCreate(Bundle icicle) { 67 super.onCreate(icicle); 68 69 addPreferencesFromResource(R.xml.device_info_settings); 70 71 setStringSummary(KEY_FIRMWARE_VERSION, Build.VERSION.RELEASE); 72 findPreference(KEY_FIRMWARE_VERSION).setEnabled(true); 73 setValueSummary(KEY_BASEBAND_VERSION, "gsm.version.baseband"); 74 setStringSummary(KEY_DEVICE_MODEL, Build.MODEL + getMsvSuffix()); 75 setStringSummary(KEY_BUILD_NUMBER, Build.DISPLAY); 76 findPreference(KEY_KERNEL_VERSION).setSummary(getFormattedKernelVersion()); 77 78 // Remove Safety information preference if PROPERTY_URL_SAFETYLEGAL is not set 79 removePreferenceIfPropertyMissing(getPreferenceScreen(), "safetylegal", 80 PROPERTY_URL_SAFETYLEGAL); 81 82 // Remove Baseband version if wifi-only device 83 if (Utils.isWifiOnly(getActivity())) { 84 getPreferenceScreen().removePreference(findPreference(KEY_BASEBAND_VERSION)); 85 } 86 87 /* 88 * Settings is a generic app and should not contain any device-specific 89 * info. 90 */ 91 final Activity act = getActivity(); 92 // These are contained in the "container" preference group 93 PreferenceGroup parentPreference = (PreferenceGroup) findPreference(KEY_CONTAINER); 94 Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference, KEY_TERMS, 95 Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY); 96 Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference, KEY_LICENSE, 97 Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY); 98 Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference, KEY_COPYRIGHT, 99 Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY); 100 Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference, KEY_TEAM, 101 Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY); 102 103 // These are contained by the root preference screen 104 parentPreference = getPreferenceScreen(); 105 Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference, 106 KEY_SYSTEM_UPDATE_SETTINGS, 107 Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY); 108 Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference, KEY_CONTRIBUTORS, 109 Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY); 110 111 // Read platform settings for additional system update setting 112 boolean isUpdateSettingAvailable = 113 getResources().getBoolean(R.bool.config_additional_system_update_setting_enable); 114 if (isUpdateSettingAvailable == false) { 115 getPreferenceScreen().removePreference(findPreference(KEY_UPDATE_SETTING)); 116 } 117 } 118 119 @Override 120 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 121 if (preference.getKey().equals(KEY_FIRMWARE_VERSION)) { 122 System.arraycopy(mHits, 1, mHits, 0, mHits.length-1); 123 mHits[mHits.length-1] = SystemClock.uptimeMillis(); 124 if (mHits[0] >= (SystemClock.uptimeMillis()-500)) { 125 Intent intent = new Intent(Intent.ACTION_MAIN); 126 intent.setClassName("android", 127 com.android.internal.app.PlatLogoActivity.class.getName()); 128 try { 129 startActivity(intent); 130 } catch (Exception e) { 131 Log.e(LOG_TAG, "Unable to start activity " + intent.toString()); 132 } 133 } 134 } 135 return super.onPreferenceTreeClick(preferenceScreen, preference); 136 } 137 138 private void removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup, 139 String preference, String property ) { 140 if (SystemProperties.get(property).equals("")) 141 { 142 // Property is missing so remove preference from group 143 try { 144 preferenceGroup.removePreference(findPreference(preference)); 145 } catch (RuntimeException e) { 146 Log.d(LOG_TAG, "Property '" + property + "' missing and no '" 147 + preference + "' preference"); 148 } 149 } 150 } 151 152 private void setStringSummary(String preference, String value) { 153 try { 154 findPreference(preference).setSummary(value); 155 } catch (RuntimeException e) { 156 findPreference(preference).setSummary( 157 getResources().getString(R.string.device_info_default)); 158 } 159 } 160 161 private void setValueSummary(String preference, String property) { 162 try { 163 findPreference(preference).setSummary( 164 SystemProperties.get(property, 165 getResources().getString(R.string.device_info_default))); 166 } catch (RuntimeException e) { 167 // No recovery 168 } 169 } 170 171 /** 172 * Reads a line from the specified file. 173 * @param filename the file to read from 174 * @return the first line, if any. 175 * @throws IOException if the file couldn't be read 176 */ 177 private String readLine(String filename) throws IOException { 178 BufferedReader reader = new BufferedReader(new FileReader(filename), 256); 179 try { 180 return reader.readLine(); 181 } finally { 182 reader.close(); 183 } 184 } 185 186 private String getFormattedKernelVersion() { 187 String procVersionStr; 188 189 try { 190 procVersionStr = readLine(FILENAME_PROC_VERSION); 191 192 final String PROC_VERSION_REGEX = 193 "\\w+\\s+" + /* ignore: Linux */ 194 "\\w+\\s+" + /* ignore: version */ 195 "([^\\s]+)\\s+" + /* group 1: 2.6.22-omap1 */ 196 "\\(([^\\s@]+(?:@[^\\s.]+)?)[^)]*\\)\\s+" + /* group 2: (xxxxxx (at) xxxxx.constant) */ 197 "\\((?:[^(]*\\([^)]*\\))?[^)]*\\)\\s+" + /* ignore: (gcc ..) */ 198 "([^\\s]+)\\s+" + /* group 3: #26 */ 199 "(?:PREEMPT\\s+)?" + /* ignore: PREEMPT (optional) */ 200 "(.+)"; /* group 4: date */ 201 202 Pattern p = Pattern.compile(PROC_VERSION_REGEX); 203 Matcher m = p.matcher(procVersionStr); 204 205 if (!m.matches()) { 206 Log.e(LOG_TAG, "Regex did not match on /proc/version: " + procVersionStr); 207 return "Unavailable"; 208 } else if (m.groupCount() < 4) { 209 Log.e(LOG_TAG, "Regex match on /proc/version only returned " + m.groupCount() 210 + " groups"); 211 return "Unavailable"; 212 } else { 213 return (new StringBuilder(m.group(1)).append("\n").append( 214 m.group(2)).append(" ").append(m.group(3)).append("\n") 215 .append(m.group(4))).toString(); 216 } 217 } catch (IOException e) { 218 Log.e(LOG_TAG, 219 "IO Exception when getting kernel version for Device Info screen", 220 e); 221 222 return "Unavailable"; 223 } 224 } 225 226 /** 227 * Returns " (ENGINEERING)" if the msv file has a zero value, else returns "". 228 * @return a string to append to the model number description. 229 */ 230 private String getMsvSuffix() { 231 // Production devices should have a non-zero value. If we can't read it, assume it's a 232 // production device so that we don't accidentally show that it's an ENGINEERING device. 233 try { 234 String msv = readLine(FILENAME_MSV); 235 // Parse as a hex number. If it evaluates to a zero, then it's an engineering build. 236 if (Long.parseLong(msv, 16) == 0) { 237 return " (ENGINEERING)"; 238 } 239 } catch (IOException ioe) { 240 // Fail quietly, as the file may not exist on some devices. 241 } catch (NumberFormatException nfe) { 242 // Fail quietly, returning empty string should be sufficient 243 } 244 return ""; 245 } 246 } 247