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