Utils.java revision a83a24f48a8286ee3d67acc5fdcfb723acc56ada
1/** 2 * Copyright (C) 2007 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 17package com.android.settings; 18 19import android.content.Context; 20import android.content.Intent; 21import android.content.pm.ApplicationInfo; 22import android.content.pm.PackageManager; 23import android.content.pm.PackageManager.NameNotFoundException; 24import android.content.pm.ResolveInfo; 25import android.content.res.Resources; 26import android.content.res.Resources.NotFoundException; 27import android.graphics.drawable.Drawable; 28import android.net.ConnectivityManager; 29import android.net.LinkProperties; 30import android.os.BatteryManager; 31import android.os.Bundle; 32import android.os.SystemProperties; 33import android.preference.Preference; 34import android.preference.PreferenceActivity.Header; 35import android.preference.PreferenceFrameLayout; 36import android.preference.PreferenceGroup; 37import android.telephony.TelephonyManager; 38import android.text.TextUtils; 39import android.view.View; 40import android.view.ViewGroup; 41import android.widget.ListView; 42import android.widget.TabWidget; 43 44import java.net.InetAddress; 45import java.util.Iterator; 46import java.util.List; 47import java.util.Locale; 48 49public class Utils { 50 51 /** 52 * Set the preference's title to the matching activity's label. 53 */ 54 public static final int UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY = 1; 55 56 /** 57 * Name of the meta-data item that should be set in the AndroidManifest.xml 58 * to specify the icon that should be displayed for the preference. 59 */ 60 private static final String META_DATA_PREFERENCE_ICON = "com.android.settings.icon"; 61 62 /** 63 * Name of the meta-data item that should be set in the AndroidManifest.xml 64 * to specify the title that should be displayed for the preference. 65 */ 66 private static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title"; 67 68 /** 69 * Name of the meta-data item that should be set in the AndroidManifest.xml 70 * to specify the summary text that should be displayed for the preference. 71 */ 72 private static final String META_DATA_PREFERENCE_SUMMARY = "com.android.settings.summary"; 73 74 /** 75 * Finds a matching activity for a preference's intent. If a matching 76 * activity is not found, it will remove the preference. 77 * 78 * @param context The context. 79 * @param parentPreferenceGroup The preference group that contains the 80 * preference whose intent is being resolved. 81 * @param preferenceKey The key of the preference whose intent is being 82 * resolved. 83 * @param flags 0 or one or more of 84 * {@link #UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY} 85 * . 86 * @return Whether an activity was found. If false, the preference was 87 * removed. 88 */ 89 public static boolean updatePreferenceToSpecificActivityOrRemove(Context context, 90 PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags) { 91 92 Preference preference = parentPreferenceGroup.findPreference(preferenceKey); 93 if (preference == null) { 94 return false; 95 } 96 97 Intent intent = preference.getIntent(); 98 if (intent != null) { 99 // Find the activity that is in the system image 100 PackageManager pm = context.getPackageManager(); 101 List<ResolveInfo> list = pm.queryIntentActivities(intent, 0); 102 int listSize = list.size(); 103 for (int i = 0; i < listSize; i++) { 104 ResolveInfo resolveInfo = list.get(i); 105 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) 106 != 0) { 107 108 // Replace the intent with this specific activity 109 preference.setIntent(new Intent().setClassName( 110 resolveInfo.activityInfo.packageName, 111 resolveInfo.activityInfo.name)); 112 113 if ((flags & UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY) != 0) { 114 // Set the preference title to the activity's label 115 preference.setTitle(resolveInfo.loadLabel(pm)); 116 } 117 118 return true; 119 } 120 } 121 } 122 123 // Did not find a matching activity, so remove the preference 124 parentPreferenceGroup.removePreference(preference); 125 126 return true; 127 } 128 129 /** 130 * Finds a matching activity for a preference's intent. If a matching 131 * activity is not found, it will remove the preference. The icon, title and 132 * summary of the preference will also be updated with the values retrieved 133 * from the activity's meta-data elements. If no meta-data elements are 134 * specified then the preference title will be set to match the label of the 135 * activity, an icon and summary text will not be displayed. 136 * 137 * @param context The context. 138 * @param parentPreferenceGroup The preference group that contains the 139 * preference whose intent is being resolved. 140 * @param preferenceKey The key of the preference whose intent is being 141 * resolved. 142 * 143 * @return Whether an activity was found. If false, the preference was 144 * removed. 145 * 146 * @see {@link #META_DATA_PREFERENCE_ICON} 147 * {@link #META_DATA_PREFERENCE_TITLE} 148 * {@link #META_DATA_PREFERENCE_SUMMARY} 149 */ 150 public static boolean updatePreferenceToSpecificActivityFromMetaDataOrRemove(Context context, 151 PreferenceGroup parentPreferenceGroup, String preferenceKey) { 152 153 IconPreferenceScreen preference = (IconPreferenceScreen)parentPreferenceGroup 154 .findPreference(preferenceKey); 155 if (preference == null) { 156 return false; 157 } 158 159 Intent intent = preference.getIntent(); 160 if (intent != null) { 161 // Find the activity that is in the system image 162 PackageManager pm = context.getPackageManager(); 163 List<ResolveInfo> list = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA); 164 int listSize = list.size(); 165 for (int i = 0; i < listSize; i++) { 166 ResolveInfo resolveInfo = list.get(i); 167 if ((resolveInfo.activityInfo.applicationInfo.flags 168 & ApplicationInfo.FLAG_SYSTEM) != 0) { 169 Drawable icon = null; 170 String title = null; 171 String summary = null; 172 173 // Get the activity's meta-data 174 try { 175 Resources res = pm 176 .getResourcesForApplication(resolveInfo.activityInfo.packageName); 177 Bundle metaData = resolveInfo.activityInfo.metaData; 178 179 if (res != null && metaData != null) { 180 icon = res.getDrawable(metaData.getInt(META_DATA_PREFERENCE_ICON)); 181 title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE)); 182 summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY)); 183 } 184 } catch (NameNotFoundException e) { 185 // Ignore 186 } catch (NotFoundException e) { 187 // Ignore 188 } 189 190 // Set the preference title to the activity's label if no 191 // meta-data is found 192 if (TextUtils.isEmpty(title)) { 193 title = resolveInfo.loadLabel(pm).toString(); 194 } 195 196 // Set icon, title and summary for the preference 197 preference.setIcon(icon); 198 preference.setTitle(title); 199 preference.setSummary(summary); 200 201 // Replace the intent with this specific activity 202 preference.setIntent(new Intent().setClassName( 203 resolveInfo.activityInfo.packageName, 204 resolveInfo.activityInfo.name)); 205 206 return true; 207 } 208 } 209 } 210 211 // Did not find a matching activity, so remove the preference 212 parentPreferenceGroup.removePreference(preference); 213 214 return false; 215 } 216 217 public static boolean updateHeaderToSpecificActivityFromMetaDataOrRemove(Context context, 218 List<Header> target, Header header) { 219 220 Intent intent = header.intent; 221 if (intent != null) { 222 // Find the activity that is in the system image 223 PackageManager pm = context.getPackageManager(); 224 List<ResolveInfo> list = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA); 225 int listSize = list.size(); 226 for (int i = 0; i < listSize; i++) { 227 ResolveInfo resolveInfo = list.get(i); 228 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) 229 != 0) { 230 Drawable icon = null; 231 String title = null; 232 String summary = null; 233 234 // Get the activity's meta-data 235 try { 236 Resources res = pm.getResourcesForApplication( 237 resolveInfo.activityInfo.packageName); 238 Bundle metaData = resolveInfo.activityInfo.metaData; 239 240 if (res != null && metaData != null) { 241 icon = res.getDrawable(metaData.getInt(META_DATA_PREFERENCE_ICON)); 242 title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE)); 243 summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY)); 244 } 245 } catch (NameNotFoundException e) { 246 // Ignore 247 } catch (NotFoundException e) { 248 // Ignore 249 } 250 251 // Set the preference title to the activity's label if no 252 // meta-data is found 253 if (TextUtils.isEmpty(title)) { 254 title = resolveInfo.loadLabel(pm).toString(); 255 } 256 257 // Set icon, title and summary for the preference 258 // TODO: 259 //header.icon = icon; 260 header.title = title; 261 header.summary = summary; 262 // Replace the intent with this specific activity 263 header.intent = new Intent().setClassName(resolveInfo.activityInfo.packageName, 264 resolveInfo.activityInfo.name); 265 266 return true; 267 } 268 } 269 } 270 271 // Did not find a matching activity, so remove the preference 272 if (target.remove(header)) System.err.println("Removed " + header.id); 273 274 return false; 275 } 276 277 /** 278 * Returns true if Monkey is running. 279 */ 280 public static boolean isMonkeyRunning() { 281 return SystemProperties.getBoolean("ro.monkey", false); 282 } 283 284 /** 285 * Returns whether the device is voice-capable (meaning, it is also a phone). 286 */ 287 public static boolean isVoiceCapable(Context context) { 288 TelephonyManager telephony = 289 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 290 return telephony != null && telephony.isVoiceCapable(); 291 } 292 293 public static boolean isWifiOnly(Context context) { 294 ConnectivityManager cm = (ConnectivityManager)context.getSystemService( 295 Context.CONNECTIVITY_SERVICE); 296 return (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false); 297 } 298 299 /** 300 * Returns the WIFI IP Addresses, if any, taking into account IPv4 and IPv6 style addresses. 301 * @param context the application context 302 * @return the formatted and comma-separated IP addresses, or null if none. 303 */ 304 public static String getWifiIpAddresses(Context context) { 305 ConnectivityManager cm = (ConnectivityManager) 306 context.getSystemService(Context.CONNECTIVITY_SERVICE); 307 LinkProperties prop = cm.getLinkProperties(ConnectivityManager.TYPE_WIFI); 308 if (prop == null) return null; 309 Iterator<InetAddress> iter = prop.getAddresses().iterator(); 310 // If there are no entries, return null 311 if (!iter.hasNext()) return null; 312 // Concatenate all available addresses, comma separated 313 String addresses = ""; 314 while (iter.hasNext()) { 315 addresses += iter.next().getHostAddress(); 316 if (iter.hasNext()) addresses += ", "; 317 } 318 return addresses; 319 } 320 321 public static Locale createLocaleFromString(String localeStr) { 322 // TODO: is there a better way to actually construct a locale that will match? 323 // The main problem is, on top of Java specs, locale.toString() and 324 // new Locale(locale.toString()).toString() do not return equal() strings in 325 // many cases, because the constructor takes the only string as the language 326 // code. So : new Locale("en", "US").toString() => "en_US" 327 // And : new Locale("en_US").toString() => "en_us" 328 if (null == localeStr) 329 return Locale.getDefault(); 330 String[] brokenDownLocale = localeStr.split("_", 3); 331 // split may not return a 0-length array. 332 if (1 == brokenDownLocale.length) { 333 return new Locale(brokenDownLocale[0]); 334 } else if (2 == brokenDownLocale.length) { 335 return new Locale(brokenDownLocale[0], brokenDownLocale[1]); 336 } else { 337 return new Locale(brokenDownLocale[0], brokenDownLocale[1], brokenDownLocale[2]); 338 } 339 } 340 341 public static String getBatteryPercentage(Intent batteryChangedIntent) { 342 int level = batteryChangedIntent.getIntExtra("level", 0); 343 int scale = batteryChangedIntent.getIntExtra("scale", 100); 344 return String.valueOf(level * 100 / scale) + "%"; 345 } 346 347 public static String getBatteryStatus(Resources res, Intent batteryChangedIntent) { 348 final Intent intent = batteryChangedIntent; 349 350 int plugType = intent.getIntExtra("plugged", 0); 351 int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN); 352 String statusString; 353 if (status == BatteryManager.BATTERY_STATUS_CHARGING) { 354 statusString = res.getString(R.string.battery_info_status_charging); 355 if (plugType > 0) { 356 statusString = statusString 357 + " " 358 + res.getString((plugType == BatteryManager.BATTERY_PLUGGED_AC) 359 ? R.string.battery_info_status_charging_ac 360 : R.string.battery_info_status_charging_usb); 361 } 362 } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) { 363 statusString = res.getString(R.string.battery_info_status_discharging); 364 } else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) { 365 statusString = res.getString(R.string.battery_info_status_not_charging); 366 } else if (status == BatteryManager.BATTERY_STATUS_FULL) { 367 statusString = res.getString(R.string.battery_info_status_full); 368 } else { 369 statusString = res.getString(R.string.battery_info_status_unknown); 370 } 371 372 return statusString; 373 } 374 375 /** 376 * Prepare a custom preferences layout, moving padding to {@link ListView} 377 * when outside scrollbars are requested. Usually used to display 378 * {@link ListView} and {@link TabWidget} with correct padding. 379 */ 380 public static void prepareCustomPreferencesList( 381 ViewGroup parent, View child, ListView list, boolean ignoreSidePadding) { 382 final boolean movePadding = list.getScrollBarStyle() == View.SCROLLBARS_OUTSIDE_OVERLAY; 383 if (movePadding && parent instanceof PreferenceFrameLayout) { 384 ((PreferenceFrameLayout.LayoutParams) child.getLayoutParams()).removeBorders = true; 385 386 final Resources res = list.getResources(); 387 final int paddingSide = res.getDimensionPixelSize( 388 com.android.internal.R.dimen.preference_fragment_padding_side); 389 final int paddingBottom = res.getDimensionPixelSize( 390 com.android.internal.R.dimen.preference_fragment_padding_bottom); 391 392 final int effectivePaddingSide = ignoreSidePadding ? 0 : paddingBottom; 393 list.setPadding(effectivePaddingSide, 0, effectivePaddingSide, paddingBottom); 394 } 395 } 396 397 /** 398 * Return string resource that best describes combination of tethering 399 * options available on this device. 400 */ 401 public static int getTetheringLabel(ConnectivityManager cm) { 402 String[] usbRegexs = cm.getTetherableUsbRegexs(); 403 String[] wifiRegexs = cm.getTetherableWifiRegexs(); 404 String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs(); 405 406 boolean usbAvailable = usbRegexs.length != 0; 407 boolean wifiAvailable = wifiRegexs.length != 0; 408 boolean bluetoothAvailable = bluetoothRegexs.length != 0; 409 410 if (wifiAvailable && usbAvailable && bluetoothAvailable) { 411 return R.string.tether_settings_title_all; 412 } else if (wifiAvailable && usbAvailable) { 413 return R.string.tether_settings_title_all; 414 } else if (wifiAvailable && bluetoothAvailable) { 415 return R.string.tether_settings_title_all; 416 } else if (wifiAvailable) { 417 return R.string.tether_settings_title_wifi; 418 } else if (usbAvailable && bluetoothAvailable) { 419 return R.string.tether_settings_title_usb_bluetooth; 420 } else if (usbAvailable) { 421 return R.string.tether_settings_title_usb; 422 } else { 423 return R.string.tether_settings_title_bluetooth; 424 } 425 } 426} 427