summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/android/settings/AccessibilitySettings.java99
-rw-r--r--src/com/android/settings/ActivityPicker.java169
-rw-r--r--src/com/android/settings/AppWidgetPickActivity.java1
-rw-r--r--src/com/android/settings/ApplicationSettings.java72
-rw-r--r--src/com/android/settings/BandMode.java2
-rw-r--r--src/com/android/settings/BrightnessPreference.java1
-rw-r--r--src/com/android/settings/ChooseLockGeneric.java198
-rw-r--r--src/com/android/settings/ChooseLockPassword.java360
-rw-r--r--src/com/android/settings/ChooseLockPattern.java117
-rw-r--r--src/com/android/settings/ChooseLockPatternExample.java29
-rw-r--r--src/com/android/settings/ChooseLockPatternTutorial.java25
-rw-r--r--src/com/android/settings/ChooseLockSettingsHelper.java96
-rw-r--r--src/com/android/settings/ConfirmLockPassword.java131
-rw-r--r--src/com/android/settings/ConfirmLockPattern.java8
-rw-r--r--src/com/android/settings/CredentialInstaller.java26
-rw-r--r--src/com/android/settings/DeviceAdminAdd.java284
-rw-r--r--src/com/android/settings/DeviceAdminSettings.java189
-rw-r--r--src/com/android/settings/DeviceInfoSettings.java2
-rw-r--r--src/com/android/settings/DisplaySettings.java205
-rw-r--r--src/com/android/settings/DockSettings.java51
-rw-r--r--src/com/android/settings/InstalledAppDetails.java489
-rw-r--r--src/com/android/settings/LanguageSettings.java35
-rw-r--r--src/com/android/settings/LauncherAppWidgetBinder.java225
-rw-r--r--src/com/android/settings/LocalePicker.java25
-rw-r--r--src/com/android/settings/ManageApplications.java303
-rw-r--r--src/com/android/settings/MasterClear.java59
-rw-r--r--src/com/android/settings/MediaFormat.java45
-rw-r--r--src/com/android/settings/PrivacySettings.java163
-rw-r--r--src/com/android/settings/RadioInfo.java332
-rw-r--r--src/com/android/settings/RingerVolumePreference.java114
-rw-r--r--src/com/android/settings/RunningServices.java397
-rw-r--r--src/com/android/settings/SdCardIntentReceiver.java70
-rw-r--r--src/com/android/settings/SdCardSettings.java202
-rw-r--r--src/com/android/settings/SecuritySettings.java372
-rw-r--r--src/com/android/settings/SettingsSafetyLegalActivity.java12
-rw-r--r--src/com/android/settings/SoundSettings.java (renamed from src/com/android/settings/SoundAndDisplaySettings.java)257
-rw-r--r--src/com/android/settings/TetherSettings.java322
-rw-r--r--src/com/android/settings/TextToSpeechSettings.java393
-rw-r--r--src/com/android/settings/UserDictionarySettings.java6
-rw-r--r--src/com/android/settings/VoiceInputOutputSettings.java228
-rw-r--r--src/com/android/settings/WirelessSettings.java134
-rw-r--r--src/com/android/settings/bluetooth/BluetoothEnabler.java134
-rw-r--r--src/com/android/settings/bluetooth/BluetoothEventRedirector.java16
-rw-r--r--src/com/android/settings/bluetooth/BluetoothSettings.java37
-rw-r--r--src/com/android/settings/bluetooth/CachedBluetoothDevice.java67
-rw-r--r--src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java1
-rw-r--r--src/com/android/settings/bluetooth/DockEventReceiver.java53
-rw-r--r--src/com/android/settings/bluetooth/DockService.java99
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothManager.java19
-rw-r--r--src/com/android/settings/bluetooth/RequestPermissionActivity.java53
-rw-r--r--src/com/android/settings/deviceinfo/Memory.java188
-rw-r--r--src/com/android/settings/deviceinfo/Status.java9
-rw-r--r--src/com/android/settings/fuelgauge/PowerUsageDetail.java120
-rw-r--r--src/com/android/settings/fuelgauge/PowerUsageSummary.java15
-rw-r--r--src/com/android/settings/vpn/VpnSettings.java2
-rw-r--r--src/com/android/settings/widget/SettingsAppWidgetProvider.java528
-rw-r--r--src/com/android/settings/wifi/AccessPoint.java225
-rw-r--r--src/com/android/settings/wifi/AccessPointDialog.java807
-rw-r--r--src/com/android/settings/wifi/AccessPointPreference.java105
-rw-r--r--src/com/android/settings/wifi/AccessPointState.java898
-rw-r--r--src/com/android/settings/wifi/AdvancedSettings.java35
-rw-r--r--src/com/android/settings/wifi/Summary.java40
-rw-r--r--src/com/android/settings/wifi/WifiAPITest.java146
-rw-r--r--src/com/android/settings/wifi/WifiApDialog.java189
-rw-r--r--src/com/android/settings/wifi/WifiApEnabler.java214
-rw-r--r--src/com/android/settings/wifi/WifiApSettings.java138
-rw-r--r--src/com/android/settings/wifi/WifiConfigInfo.java63
-rw-r--r--src/com/android/settings/wifi/WifiDialog.java370
-rw-r--r--src/com/android/settings/wifi/WifiEnabler.java215
-rw-r--r--src/com/android/settings/wifi/WifiInfo.java36
-rw-r--r--src/com/android/settings/wifi/WifiLayer.java1316
-rw-r--r--src/com/android/settings/wifi/WifiSettings.java663
-rw-r--r--src/com/android/settings/wifi/WifiStatus.java102
-rw-r--r--src/com/android/settings/wifi/WifiStatusTest.java407
74 files changed, 7558 insertions, 6000 deletions
diff --git a/src/com/android/settings/AccessibilitySettings.java b/src/com/android/settings/AccessibilitySettings.java
index 6199e50..d78d2d8 100644
--- a/src/com/android/settings/AccessibilitySettings.java
+++ b/src/com/android/settings/AccessibilitySettings.java
@@ -19,15 +19,24 @@ package com.android.settings;
import android.app.AlertDialog;
import android.app.Service;
import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
+import android.net.Uri;
import android.os.Bundle;
+import android.os.SystemProperties;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
+import android.preference.PreferenceCategory;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.text.TextUtils;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
import android.view.accessibility.AccessibilityManager;
import java.util.HashSet;
@@ -39,14 +48,26 @@ import java.util.Map;
* Activity with the accessibility settings.
*/
public class AccessibilitySettings extends PreferenceActivity {
+ private static final String DEFAULT_SCREENREADER_MARKET_LINK =
+ "market://search?q=pname:com.google.android.marvin.talkback";
+
private final String TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX =
"toggle_accessibility_service_checkbox";
private static final String ACCESSIBILITY_SERVICES_CATEGORY =
"accessibility_services_category";
+ private static final String POWER_BUTTON_CATEGORY =
+ "power_button_category";
+
+ private final String POWER_BUTTON_ENDS_CALL_CHECKBOX =
+ "power_button_ends_call";
+
private CheckBoxPreference mToggleCheckBox;
+ private PreferenceCategory mPowerButtonCategory;
+ private CheckBoxPreference mPowerButtonEndsCallCheckBox;
+
private Map<String, ServiceInfo> mAccessibilityServices =
new LinkedHashMap<String, ServiceInfo>();
@@ -63,6 +84,10 @@ public class AccessibilitySettings extends PreferenceActivity {
mToggleCheckBox = (CheckBoxPreference) findPreference(
TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX);
+ mPowerButtonCategory = (PreferenceCategory) findPreference(POWER_BUTTON_CATEGORY);
+ mPowerButtonEndsCallCheckBox = (CheckBoxPreference) findPreference(
+ POWER_BUTTON_ENDS_CALL_CHECKBOX);
+
addAccessibilitServicePreferences();
}
@@ -105,9 +130,27 @@ public class AccessibilitySettings extends PreferenceActivity {
// no service and accessibility is enabled => disable
Settings.Secure.putInt(getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 0);
- setAccessibilityServicePreferencesState(false);
}
mToggleCheckBox.setEnabled(false);
+ // Notify user that they do not have any accessibility apps
+ // installed and direct them to Market to get TalkBack
+ displayNoAppsAlert();
+ }
+
+ if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)) {
+ int incallPowerBehavior = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+ Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT);
+ // The checkbox is labeled "Power button ends call"; thus the in-call
+ // Power button behavior is INCALL_POWER_BUTTON_BEHAVIOR_HANGUP if
+ // checked, and INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF if unchecked.
+ boolean powerButtonCheckboxEnabled =
+ (incallPowerBehavior == Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP);
+ mPowerButtonEndsCallCheckBox.setChecked(powerButtonCheckboxEnabled);
+ mPowerButtonEndsCallCheckBox.setEnabled(true);
+ } else {
+ // No POWER key on the current device; this entire category is irrelevant.
+ getPreferenceScreen().removePreference(mPowerButtonCategory);
}
}
@@ -119,7 +162,8 @@ public class AccessibilitySettings extends PreferenceActivity {
}
/**
- * Sets the state of the preferences for enabling/disabling AccessibilityServices.
+ * Sets the state of the preferences for enabling/disabling
+ * AccessibilityServices.
*
* @param isEnabled If to enable or disable the preferences.
*/
@@ -132,9 +176,6 @@ public class AccessibilitySettings extends PreferenceActivity {
for (int i = 0; i < count; i++) {
Preference pref = mAccessibilityServicesCategory.getPreference(i);
pref.setEnabled(isEnabled);
- if (!isEnabled){
- ((CheckBoxPreference) pref).setChecked(false);
- }
}
}
@@ -145,6 +186,15 @@ public class AccessibilitySettings extends PreferenceActivity {
if (TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX.equals(key)) {
boolean isChecked = ((CheckBoxPreference) preference).isChecked();
handleEnableAccessibilityStateChange((CheckBoxPreference) preference);
+ } else if (POWER_BUTTON_ENDS_CALL_CHECKBOX.equals(key)) {
+ boolean isChecked = ((CheckBoxPreference) preference).isChecked();
+ // The checkbox is labeled "Power button ends call"; thus the in-call
+ // Power button behavior is INCALL_POWER_BUTTON_BEHAVIOR_HANGUP if
+ // checked, and INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF if unchecked.
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+ (isChecked ? Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP
+ : Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF));
} else if (preference instanceof CheckBoxPreference) {
handleEnableAccessibilityServiceStateChange((CheckBoxPreference) preference);
}
@@ -274,4 +324,43 @@ public class AccessibilitySettings extends PreferenceActivity {
mAccessibilityServicesCategory.addPreference(preference);
}
}
+
+ /**
+ * Displays a message telling the user that they do not have any accessibility
+ * related apps installed and that they can get TalkBack (Google's free screen
+ * reader) from Market.
+ */
+ private void displayNoAppsAlert() {
+ try {
+ PackageManager pm = getPackageManager();
+ ApplicationInfo info = pm.getApplicationInfo("com.android.vending", 0);
+ } catch (NameNotFoundException e) {
+ // This is a no-op if the user does not have Android Market
+ return;
+ }
+ AlertDialog.Builder noAppsAlert = new AlertDialog.Builder(this);
+ noAppsAlert.setTitle(R.string.accessibility_service_no_apps_title);
+ noAppsAlert.setMessage(R.string.accessibility_service_no_apps_message);
+
+ noAppsAlert.setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ String screenreaderMarketLink =
+ SystemProperties.get("ro.screenreader.market",
+ DEFAULT_SCREENREADER_MARKET_LINK);
+ Uri marketUri = Uri.parse(screenreaderMarketLink);
+ Intent marketIntent = new Intent(Intent.ACTION_VIEW, marketUri);
+ startActivity(marketIntent);
+ finish();
+ }
+ });
+
+ noAppsAlert.setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ }
+ });
+
+ noAppsAlert.show();
+ }
}
diff --git a/src/com/android/settings/ActivityPicker.java b/src/com/android/settings/ActivityPicker.java
index 4b0469c..d984adb 100644
--- a/src/com/android/settings/ActivityPicker.java
+++ b/src/com/android/settings/ActivityPicker.java
@@ -16,6 +16,7 @@
package com.android.settings;
+import android.graphics.ColorFilter;
import android.util.DisplayMetrics;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
@@ -349,68 +350,124 @@ public class ActivityPicker extends AlertActivity implements
int width = mIconWidth;
int height = mIconHeight;
- if (icon instanceof PaintDrawable) {
- PaintDrawable painter = (PaintDrawable) icon;
- painter.setIntrinsicWidth(width);
- painter.setIntrinsicHeight(height);
- } else if (icon instanceof BitmapDrawable) {
- // Ensure the bitmap has a density.
- BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
- Bitmap bitmap = bitmapDrawable.getBitmap();
- if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
- bitmapDrawable.setTargetDensity(mMetrics);
- }
+ if (icon == null) {
+ return new EmptyDrawable(width, height);
}
- int iconWidth = icon.getIntrinsicWidth();
- int iconHeight = icon.getIntrinsicHeight();
-
- if (iconWidth > 0 && iconHeight > 0) {
- if (width < iconWidth || height < iconHeight) {
- final float ratio = (float) iconWidth / iconHeight;
-
- if (iconWidth > iconHeight) {
- height = (int) (width / ratio);
- } else if (iconHeight > iconWidth) {
- width = (int) (height * ratio);
+
+ try {
+ if (icon instanceof PaintDrawable) {
+ PaintDrawable painter = (PaintDrawable) icon;
+ painter.setIntrinsicWidth(width);
+ painter.setIntrinsicHeight(height);
+ } else if (icon instanceof BitmapDrawable) {
+ // Ensure the bitmap has a density.
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
+ Bitmap bitmap = bitmapDrawable.getBitmap();
+ if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
+ bitmapDrawable.setTargetDensity(mMetrics);
}
-
- final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ?
- Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
- final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
- final Canvas canvas = mCanvas;
- canvas.setBitmap(thumb);
- // Copy the old bounds to restore them later
- // If we were to do oldBounds = icon.getBounds(),
- // the call to setBounds() that follows would
- // change the same instance and we would lose the
- // old bounds
- mOldBounds.set(icon.getBounds());
- final int x = (mIconWidth - width) / 2;
- final int y = (mIconHeight - height) / 2;
- icon.setBounds(x, y, x + width, y + height);
- icon.draw(canvas);
- icon.setBounds(mOldBounds);
- //noinspection deprecation
- icon = new BitmapDrawable(thumb);
- ((BitmapDrawable) icon).setTargetDensity(mMetrics);
- } else if (iconWidth < width && iconHeight < height) {
- final Bitmap.Config c = Bitmap.Config.ARGB_8888;
- final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
- final Canvas canvas = mCanvas;
- canvas.setBitmap(thumb);
- mOldBounds.set(icon.getBounds());
- final int x = (width - iconWidth) / 2;
- final int y = (height - iconHeight) / 2;
- icon.setBounds(x, y, x + iconWidth, y + iconHeight);
- icon.draw(canvas);
- icon.setBounds(mOldBounds);
- //noinspection deprecation
- icon = new BitmapDrawable(thumb);
- ((BitmapDrawable) icon).setTargetDensity(mMetrics);
}
+ int iconWidth = icon.getIntrinsicWidth();
+ int iconHeight = icon.getIntrinsicHeight();
+
+ if (iconWidth > 0 && iconHeight > 0) {
+ if (width < iconWidth || height < iconHeight) {
+ final float ratio = (float) iconWidth / iconHeight;
+
+ if (iconWidth > iconHeight) {
+ height = (int) (width / ratio);
+ } else if (iconHeight > iconWidth) {
+ width = (int) (height * ratio);
+ }
+
+ final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ?
+ Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
+ final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
+ final Canvas canvas = mCanvas;
+ canvas.setBitmap(thumb);
+ // Copy the old bounds to restore them later
+ // If we were to do oldBounds = icon.getBounds(),
+ // the call to setBounds() that follows would
+ // change the same instance and we would lose the
+ // old bounds
+ mOldBounds.set(icon.getBounds());
+ final int x = (mIconWidth - width) / 2;
+ final int y = (mIconHeight - height) / 2;
+ icon.setBounds(x, y, x + width, y + height);
+ icon.draw(canvas);
+ icon.setBounds(mOldBounds);
+ //noinspection deprecation
+ icon = new BitmapDrawable(thumb);
+ ((BitmapDrawable) icon).setTargetDensity(mMetrics);
+ } else if (iconWidth < width && iconHeight < height) {
+ final Bitmap.Config c = Bitmap.Config.ARGB_8888;
+ final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
+ final Canvas canvas = mCanvas;
+ canvas.setBitmap(thumb);
+ mOldBounds.set(icon.getBounds());
+ final int x = (width - iconWidth) / 2;
+ final int y = (height - iconHeight) / 2;
+ icon.setBounds(x, y, x + iconWidth, y + iconHeight);
+ icon.draw(canvas);
+ icon.setBounds(mOldBounds);
+ //noinspection deprecation
+ icon = new BitmapDrawable(thumb);
+ ((BitmapDrawable) icon).setTargetDensity(mMetrics);
+ }
+ }
+
+ } catch (Throwable t) {
+ icon = new EmptyDrawable(width, height);
}
return icon;
}
}
+
+ private static class EmptyDrawable extends Drawable {
+ private final int mWidth;
+ private final int mHeight;
+
+ EmptyDrawable(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mHeight;
+ }
+
+ @Override
+ public int getMinimumWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getMinimumHeight() {
+ return mHeight;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+ }
}
diff --git a/src/com/android/settings/AppWidgetPickActivity.java b/src/com/android/settings/AppWidgetPickActivity.java
index cddc687..176ac80 100644
--- a/src/com/android/settings/AppWidgetPickActivity.java
+++ b/src/com/android/settings/AppWidgetPickActivity.java
@@ -167,6 +167,7 @@ public class AppWidgetPickActivity extends ActivityPicker {
*/
void putAppWidgetItems(List<AppWidgetProviderInfo> appWidgets,
List<Bundle> customExtras, List<PickAdapter.Item> items) {
+ if (appWidgets == null) return;
final int size = appWidgets.size();
for (int i = 0; i < size; i++) {
AppWidgetProviderInfo info = appWidgets.get(i);
diff --git a/src/com/android/settings/ApplicationSettings.java b/src/com/android/settings/ApplicationSettings.java
index 1df85dc..a919ae8 100644
--- a/src/com/android/settings/ApplicationSettings.java
+++ b/src/com/android/settings/ApplicationSettings.java
@@ -21,21 +21,35 @@ import android.content.DialogInterface;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
+import android.preference.Preference.OnPreferenceChangeListener;
import android.provider.Settings;
public class ApplicationSettings extends PreferenceActivity implements
DialogInterface.OnClickListener {
private static final String KEY_TOGGLE_INSTALL_APPLICATIONS = "toggle_install_applications";
+ private static final String KEY_APP_INSTALL_LOCATION = "app_install_location";
private static final String KEY_QUICK_LAUNCH = "quick_launch";
- private CheckBoxPreference mToggleAppInstallation;
+ // App installation location. Default is ask the user.
+ private static final int APP_INSTALL_AUTO = 0;
+ private static final int APP_INSTALL_DEVICE = 1;
+ private static final int APP_INSTALL_SDCARD = 2;
- private DialogInterface mWarnInstallApps;
+ private static final String APP_INSTALL_DEVICE_ID = "device";
+ private static final String APP_INSTALL_SDCARD_ID = "sdcard";
+ private static final String APP_INSTALL_AUTO_ID = "auto";
+ private CheckBoxPreference mToggleAppInstallation;
+
+ private ListPreference mInstallLocation;
+
+ private DialogInterface mWarnInstallApps;
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -45,6 +59,23 @@ public class ApplicationSettings extends PreferenceActivity implements
mToggleAppInstallation = (CheckBoxPreference) findPreference(KEY_TOGGLE_INSTALL_APPLICATIONS);
mToggleAppInstallation.setChecked(isNonMarketAppsAllowed());
+ mInstallLocation = (ListPreference) findPreference(KEY_APP_INSTALL_LOCATION);
+ // Is app default install location set?
+ boolean userSetInstLocation = (Settings.System.getInt(getContentResolver(),
+ Settings.Secure.SET_INSTALL_LOCATION, 0) != 0);
+ if (!userSetInstLocation) {
+ getPreferenceScreen().removePreference(mInstallLocation);
+ } else {
+ mInstallLocation.setValue(getAppInstallLocation());
+ mInstallLocation.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ String value = (String) newValue;
+ handleUpdateAppInstallLocation(value);
+ return false;
+ }
+ });
+ }
+
if (getResources().getConfiguration().keyboard == Configuration.KEYBOARD_NOKEYS) {
// No hard keyboard, remove the setting for quick launch
Preference quickLaunchSetting = findPreference(KEY_QUICK_LAUNCH);
@@ -52,6 +83,24 @@ public class ApplicationSettings extends PreferenceActivity implements
}
}
+ protected void handleUpdateAppInstallLocation(final String value) {
+ if(APP_INSTALL_DEVICE_ID.equals(value)) {
+ Settings.System.putInt(getContentResolver(),
+ Settings.Secure.DEFAULT_INSTALL_LOCATION, APP_INSTALL_DEVICE);
+ } else if (APP_INSTALL_SDCARD_ID.equals(value)) {
+ Settings.System.putInt(getContentResolver(),
+ Settings.Secure.DEFAULT_INSTALL_LOCATION, APP_INSTALL_SDCARD);
+ } else if (APP_INSTALL_AUTO_ID.equals(value)) {
+ Settings.System.putInt(getContentResolver(),
+ Settings.Secure.DEFAULT_INSTALL_LOCATION, APP_INSTALL_AUTO);
+ } else {
+ // Should not happen, default to prompt...
+ Settings.System.putInt(getContentResolver(),
+ Settings.Secure.DEFAULT_INSTALL_LOCATION, APP_INSTALL_AUTO);
+ }
+ mInstallLocation.setValue(value);
+ }
+
@Override
protected void onDestroy() {
super.onDestroy();
@@ -70,7 +119,7 @@ public class ApplicationSettings extends PreferenceActivity implements
setNonMarketAppsAllowed(false);
}
}
-
+
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
@@ -92,6 +141,21 @@ public class ApplicationSettings extends PreferenceActivity implements
Settings.Secure.INSTALL_NON_MARKET_APPS, 0) > 0;
}
+ private String getAppInstallLocation() {
+ int selectedLocation = Settings.System.getInt(getContentResolver(),
+ Settings.Secure.DEFAULT_INSTALL_LOCATION, APP_INSTALL_AUTO);
+ if (selectedLocation == APP_INSTALL_DEVICE) {
+ return APP_INSTALL_DEVICE_ID;
+ } else if (selectedLocation == APP_INSTALL_SDCARD) {
+ return APP_INSTALL_SDCARD_ID;
+ } else if (selectedLocation == APP_INSTALL_AUTO) {
+ return APP_INSTALL_AUTO_ID;
+ } else {
+ // Default value, should not happen.
+ return APP_INSTALL_AUTO_ID;
+ }
+ }
+
private void warnAppInstallation() {
mWarnInstallApps = new AlertDialog.Builder(this)
.setTitle(getString(R.string.error_title))
@@ -101,6 +165,4 @@ public class ApplicationSettings extends PreferenceActivity implements
.setNegativeButton(android.R.string.no, null)
.show();
}
-
-
}
diff --git a/src/com/android/settings/BandMode.java b/src/com/android/settings/BandMode.java
index a8c7833..4c7663e 100644
--- a/src/com/android/settings/BandMode.java
+++ b/src/com/android/settings/BandMode.java
@@ -62,7 +62,7 @@ public class BandMode extends Activity {
setContentView(R.layout.band_mode);
setTitle(getString(R.string.band_mode_title));
- getWindow().setLayout(WindowManager.LayoutParams.FILL_PARENT,
+ getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT);
mPhone = PhoneFactory.getDefaultPhone();
diff --git a/src/com/android/settings/BrightnessPreference.java b/src/com/android/settings/BrightnessPreference.java
index fe3b997..7494e2f 100644
--- a/src/com/android/settings/BrightnessPreference.java
+++ b/src/com/android/settings/BrightnessPreference.java
@@ -55,6 +55,7 @@ public class BrightnessPreference extends SeekBarPreference implements
com.android.internal.R.bool.config_automatic_brightness_available);
setDialogLayoutResource(R.layout.preference_dialog_brightness);
+ setDialogIcon(R.drawable.ic_settings_display);
}
@Override
diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java
new file mode 100644
index 0000000..0672ad9
--- /dev/null
+++ b/src/com/android/settings/ChooseLockGeneric.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceScreen;
+
+public class ChooseLockGeneric extends PreferenceActivity {
+ private static final int MIN_PASSWORD_LENGTH = 4;
+ private static final String KEY_UNLOCK_SET_NONE = "unlock_set_none";
+ private static final String KEY_UNLOCK_SET_PIN = "unlock_set_pin";
+ private static final String KEY_UNLOCK_SET_PASSWORD = "unlock_set_password";
+ private static final String KEY_UNLOCK_SET_PATTERN = "unlock_set_pattern";
+ private static final int CONFIRM_EXISTING_REQUEST = 100;
+ private static final String PASSWORD_CONFIRMED = "password_confirmed";
+ private static final String CONFIRM_CREDENTIALS = "confirm_credentials";
+
+ private ChooseLockSettingsHelper mChooseLockSettingsHelper;
+ private DevicePolicyManager mDPM;
+ private boolean mPasswordConfirmed = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
+
+ if (savedInstanceState != null) {
+ mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
+ }
+
+ if (!mPasswordConfirmed) {
+ ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(this);
+ if (!helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST, null, null)) {
+ mPasswordConfirmed = true; // no password set, so no need to confirm
+ updatePreferencesOrFinish();
+ }
+ } else {
+ updatePreferencesOrFinish();
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
+ Preference preference) {
+ final String key = preference.getKey();
+ boolean handled = true;
+ if (KEY_UNLOCK_SET_NONE.equals(key)) {
+ updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+ } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
+ updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ } else if (KEY_UNLOCK_SET_PIN.equals(key)) {
+ updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
+ } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) {
+ updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
+ } else {
+ handled = false;
+ }
+ return handled;
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == RESULT_OK) {
+ mPasswordConfirmed = true;
+ updatePreferencesOrFinish();
+ } else {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ // Saved so we don't force user to re-enter their password if configuration changes
+ outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
+ }
+
+ private void updatePreferencesOrFinish() {
+ int quality = getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
+ if (quality == -1) {
+ // If caller didn't specify password quality, show the UI and allow the user to choose.
+ quality = mChooseLockSettingsHelper.utils().getKeyguardStoredPasswordQuality();
+ final PreferenceScreen prefScreen = getPreferenceScreen();
+ if (prefScreen != null) {
+ prefScreen.removeAll();
+ }
+ addPreferencesFromResource(R.xml.security_settings_picker);
+ disableUnusablePreferences(mDPM.getPasswordQuality(null));
+ } else {
+ updateUnlockMethodAndFinish(quality);
+ }
+ }
+
+ /***
+ * Disables preferences that are less secure than required quality.
+ *
+ * @param quality the requested quality.
+ */
+ private void disableUnusablePreferences(final int quality) {
+ final Preference picker = getPreferenceScreen().findPreference("security_picker_category");
+ final PreferenceCategory cat = (PreferenceCategory) picker;
+ final int preferenceCount = cat.getPreferenceCount();
+ for (int i = 0; i < preferenceCount; i++) {
+ Preference pref = cat.getPreference(i);
+ if (pref instanceof PreferenceScreen) {
+ final String key = ((PreferenceScreen) pref).getKey();
+ boolean enabled = true;
+ if (KEY_UNLOCK_SET_NONE.equals(key)) {
+ enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
+ enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+ } else if (KEY_UNLOCK_SET_PIN.equals(key)) {
+ enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+ } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) {
+ enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+ }
+ if (!enabled) {
+ pref.setSummary(R.string.unlock_set_unlock_disabled_summary);
+ pref.setEnabled(false);
+ }
+ }
+ }
+ }
+
+ /**
+ * Invokes an activity to change the user's pattern, password or PIN based on given quality
+ * and minimum quality specified by DevicePolicyManager. If quality is
+ * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared.
+ *
+ * @param quality the desired quality. Ignored if DevicePolicyManager requires more security.
+ */
+ void updateUnlockMethodAndFinish(int quality) {
+ // Sanity check. We should never get here without confirming user's existing password first.
+ if (!mPasswordConfirmed) {
+ throw new IllegalStateException("Tried to update password without confirming first");
+ }
+
+ // Compare minimum allowed password quality and launch appropriate security setting method
+ int minQuality = mDPM.getPasswordQuality(null);
+ if (quality < minQuality) {
+ quality = minQuality;
+ }
+ if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
+ int minLength = mDPM.getPasswordMinimumLength(null);
+ if (minLength < MIN_PASSWORD_LENGTH) {
+ minLength = MIN_PASSWORD_LENGTH;
+ }
+ final int maxLength = mDPM.getPasswordMaximumLength(quality);
+ Intent intent = new Intent().setClass(this, ChooseLockPassword.class);
+ intent.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, quality);
+ intent.putExtra(ChooseLockPassword.PASSWORD_MIN_KEY, minLength);
+ intent.putExtra(ChooseLockPassword.PASSWORD_MAX_KEY, maxLength);
+ intent.putExtra(CONFIRM_CREDENTIALS, false);
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
+ } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
+ boolean showTutorial = !mChooseLockSettingsHelper.utils().isPatternEverChosen();
+ Intent intent = new Intent();
+ intent.setClass(this, showTutorial
+ ? ChooseLockPatternTutorial.class
+ : ChooseLockPattern.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ intent.putExtra("key_lock_method", "pattern");
+ intent.putExtra(CONFIRM_CREDENTIALS, false);
+ startActivity(intent);
+ } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ mChooseLockSettingsHelper.utils().clearLock();
+ setResult(RESULT_OK);
+ }
+ finish();
+ }
+}
diff --git a/src/com/android/settings/ChooseLockPassword.java b/src/com/android/settings/ChooseLockPassword.java
new file mode 100644
index 0000000..b5e72d7
--- /dev/null
+++ b/src/com/android/settings/ChooseLockPassword.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.PasswordEntryKeyboardHelper;
+import com.android.internal.widget.PasswordEntryKeyboardView;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.Intent;
+import android.inputmethodservice.KeyboardView;
+import android.os.Bundle;
+import android.os.Handler;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.View.OnClickListener;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+
+public class ChooseLockPassword extends Activity implements OnClickListener, OnEditorActionListener,
+ TextWatcher {
+ private static final String KEY_FIRST_PIN = "first_pin";
+ private static final String KEY_UI_STAGE = "ui_stage";
+ private TextView mPasswordEntry;
+ private int mPasswordMinLength = 4;
+ private int mPasswordMaxLength = 16;
+ private LockPatternUtils mLockPatternUtils;
+ private int mRequestedQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+ private ChooseLockSettingsHelper mChooseLockSettingsHelper;
+ private com.android.settings.ChooseLockPassword.Stage mUiStage = Stage.Introduction;
+ private TextView mHeaderText;
+ private String mFirstPin;
+ private KeyboardView mKeyboardView;
+ private PasswordEntryKeyboardHelper mKeyboardHelper;
+ private boolean mIsAlphaMode;
+ private Button mCancelButton;
+ private Button mNextButton;
+ public static final String PASSWORD_MIN_KEY = "lockscreen.password_min";
+ public static final String PASSWORD_MAX_KEY = "lockscreen.password_max";
+ private static Handler mHandler = new Handler();
+ private static final int CONFIRM_EXISTING_REQUEST = 58;
+ static final int RESULT_FINISHED = RESULT_FIRST_USER;
+ private static final long ERROR_MESSAGE_TIMEOUT = 3000;
+
+ /**
+ * Keep track internally of where the user is in choosing a pattern.
+ */
+ protected enum Stage {
+
+ Introduction(R.string.lockpassword_choose_your_password_header,
+ R.string.lockpassword_choose_your_pin_header,
+ R.string.lockpassword_continue_label),
+
+ NeedToConfirm(R.string.lockpassword_confirm_your_password_header,
+ R.string.lockpassword_confirm_your_pin_header,
+ R.string.lockpassword_ok_label),
+
+ ConfirmWrong(R.string.lockpassword_confirm_passwords_dont_match,
+ R.string.lockpassword_confirm_pins_dont_match,
+ R.string.lockpassword_continue_label);
+
+ /**
+ * @param headerMessage The message displayed at the top.
+ */
+ Stage(int hintInAlpha, int hintInNumeric, int nextButtonText) {
+ this.alphaHint = hintInAlpha;
+ this.numericHint = hintInNumeric;
+ this.buttonText = nextButtonText;
+ }
+
+ public final int alphaHint;
+ public final int numericHint;
+ public final int buttonText;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mLockPatternUtils = new LockPatternUtils(this);
+ mRequestedQuality = getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, mRequestedQuality);
+ mPasswordMinLength = getIntent().getIntExtra(PASSWORD_MIN_KEY, mPasswordMinLength);
+ mPasswordMaxLength = getIntent().getIntExtra(PASSWORD_MAX_KEY, mPasswordMaxLength);
+
+ final boolean confirmCredentials = getIntent().getBooleanExtra("confirm_credentials", true);
+ int minMode = mLockPatternUtils.getRequestedPasswordQuality();
+ if (mRequestedQuality < minMode) {
+ mRequestedQuality = minMode;
+ }
+ int minLength = mLockPatternUtils.getRequestedMinimumPasswordLength();
+ if (mPasswordMinLength < minLength) {
+ mPasswordMinLength = minLength;
+ }
+ initViews();
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
+ if (savedInstanceState == null) {
+ updateStage(Stage.Introduction);
+ if (confirmCredentials) {
+ mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
+ null, null);
+ }
+ }
+ }
+
+ private void initViews() {
+ setContentView(R.layout.choose_lock_password);
+ // Disable IME on our window since we provide our own keyboard
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+ WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+
+ mCancelButton = (Button) findViewById(R.id.cancel_button);
+ mCancelButton.setOnClickListener(this);
+ mNextButton = (Button) findViewById(R.id.next_button);
+ mNextButton.setOnClickListener(this);
+
+ mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
+ mPasswordEntry = (TextView) findViewById(R.id.password_entry);
+ mPasswordEntry.setOnEditorActionListener(this);
+ mPasswordEntry.addTextChangedListener(this);
+
+ mIsAlphaMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == mRequestedQuality
+ || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == mRequestedQuality;
+ mKeyboardHelper = new PasswordEntryKeyboardHelper(this, mKeyboardView, mPasswordEntry);
+ mKeyboardHelper.setKeyboardMode(mIsAlphaMode ?
+ PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
+ : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
+
+ mHeaderText = (TextView) findViewById(R.id.headerText);
+ mKeyboardView.requestFocus();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ updateStage(mUiStage);
+ mKeyboardView.requestFocus();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putString(KEY_UI_STAGE, mUiStage.name());
+ outState.putString(KEY_FIRST_PIN, mFirstPin);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ String state = savedInstanceState.getString(KEY_UI_STAGE);
+ mFirstPin = savedInstanceState.getString(KEY_FIRST_PIN);
+ if (state != null) {
+ mUiStage = Stage.valueOf(state);
+ updateStage(mUiStage);
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case CONFIRM_EXISTING_REQUEST:
+ if (resultCode != Activity.RESULT_OK) {
+ setResult(RESULT_FINISHED);
+ finish();
+ }
+ break;
+ }
+ }
+
+ protected void updateStage(Stage stage) {
+ mUiStage = stage;
+ updateUi();
+ }
+
+ /**
+ * Validates PIN and returns a message to display if PIN fails test.
+ * @param password the raw password the user typed in
+ * @return error message to show to user or null if password is OK
+ */
+ private String validatePassword(String password) {
+ if (password.length() < mPasswordMinLength) {
+ return getString(mIsAlphaMode ?
+ R.string.lockpassword_password_too_short
+ : R.string.lockpassword_pin_too_short, mPasswordMinLength);
+ }
+ if (password.length() > mPasswordMaxLength) {
+ return getString(mIsAlphaMode ?
+ R.string.lockpassword_password_too_long
+ : R.string.lockpassword_pin_too_long, mPasswordMaxLength);
+ }
+ boolean hasAlpha = false;
+ boolean hasDigit = false;
+ boolean hasSymbol = false;
+ for (int i = 0; i < password.length(); i++) {
+ char c = password.charAt(i);
+ // allow non white space Latin-1 characters only
+ if (c <= 32 || c > 127) {
+ return getString(R.string.lockpassword_illegal_character);
+ }
+ if (c >= '0' && c <= '9') {
+ hasDigit = true;
+ } else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
+ hasAlpha = true;
+ } else {
+ hasSymbol = true;
+ }
+ }
+ if (DevicePolicyManager.PASSWORD_QUALITY_NUMERIC == mRequestedQuality
+ && (hasAlpha | hasSymbol)) {
+ // This shouldn't be possible unless user finds some way to bring up soft keyboard
+ return getString(R.string.lockpassword_pin_contains_non_digits);
+ } else {
+ final boolean alphabetic = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
+ == mRequestedQuality;
+ final boolean alphanumeric = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
+ == mRequestedQuality;
+ final boolean symbolic = false; // not yet
+ if ((alphabetic || alphanumeric) && !hasAlpha) {
+ return getString(R.string.lockpassword_password_requires_alpha);
+ }
+ if (alphanumeric && !hasDigit) {
+ return getString(R.string.lockpassword_password_requires_digit);
+ }
+ if (symbolic && !hasSymbol) {
+ return getString(R.string.lockpassword_password_requires_symbol);
+ }
+ }
+ return null;
+ }
+
+ private void handleNext() {
+ final String pin = mPasswordEntry.getText().toString();
+ if (TextUtils.isEmpty(pin)) {
+ return;
+ }
+ String errorMsg = null;
+ if (mUiStage == Stage.Introduction) {
+ errorMsg = validatePassword(pin);
+ if (errorMsg == null) {
+ mFirstPin = pin;
+ updateStage(Stage.NeedToConfirm);
+ mPasswordEntry.setText("");
+ }
+ } else if (mUiStage == Stage.NeedToConfirm) {
+ if (mFirstPin.equals(pin)) {
+ mLockPatternUtils.clearLock();
+ mLockPatternUtils.saveLockPassword(pin, mRequestedQuality);
+ finish();
+ } else {
+ updateStage(Stage.ConfirmWrong);
+ CharSequence tmp = mPasswordEntry.getText();
+ if (tmp != null) {
+ Selection.setSelection((Spannable) tmp, 0, tmp.length());
+ }
+ }
+ }
+ if (errorMsg != null) {
+ showError(errorMsg, mUiStage);
+ }
+ }
+
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.next_button:
+ handleNext();
+ break;
+
+ case R.id.cancel_button:
+ finish();
+ break;
+ }
+ }
+
+ private void showError(String msg, final Stage next) {
+ mHeaderText.setText(msg);
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ updateStage(next);
+ }
+ }, ERROR_MESSAGE_TIMEOUT);
+ }
+
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ // Check if this was the result of hitting the enter key
+ if (actionId == EditorInfo.IME_NULL) {
+ handleNext();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Update the hint based on current Stage and length of password entry
+ */
+ private void updateUi() {
+ String password = mPasswordEntry.getText().toString();
+ final int length = password.length();
+ if (mUiStage == Stage.Introduction && length > 0) {
+ if (length < mPasswordMinLength) {
+ String msg = getString(mIsAlphaMode ? R.string.lockpassword_password_too_short
+ : R.string.lockpassword_pin_too_short, mPasswordMinLength);
+ mHeaderText.setText(msg);
+ mNextButton.setEnabled(false);
+ } else {
+ String error = validatePassword(password);
+ if (error != null) {
+ mHeaderText.setText(error);
+ mNextButton.setEnabled(false);
+ } else {
+ mHeaderText.setText(R.string.lockpassword_press_continue);
+ mNextButton.setEnabled(true);
+ }
+ }
+ } else {
+ mHeaderText.setText(mIsAlphaMode ? mUiStage.alphaHint : mUiStage.numericHint);
+ mNextButton.setEnabled(length > 0);
+ }
+ mNextButton.setText(mUiStage.buttonText);
+ }
+
+ public void afterTextChanged(Editable s) {
+ // Changing the text while error displayed resets to NeedToConfirm state
+ if (mUiStage == Stage.ConfirmWrong) {
+ mUiStage = Stage.NeedToConfirm;
+ }
+ updateUi();
+ }
+
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+
+ }
+}
diff --git a/src/com/android/settings/ChooseLockPattern.java b/src/com/android/settings/ChooseLockPattern.java
index f103c6b..b5c0e80 100644
--- a/src/com/android/settings/ChooseLockPattern.java
+++ b/src/com/android/settings/ChooseLockPattern.java
@@ -45,7 +45,6 @@ import java.util.List;
* - saves chosen password when confirmed
*/
public class ChooseLockPattern extends Activity implements View.OnClickListener{
-
/**
* Used by the choose lock pattern wizard to indicate the wizard is
* finished, and each activity in the wizard should finish.
@@ -56,7 +55,9 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
* result.
*/
static final int RESULT_FINISHED = RESULT_FIRST_USER;
-
+
+ public static final int CONFIRM_EXISTING_REQUEST = 55;
+
// how long after a confirmation message is shown before moving on
static final int INFORMATION_MSG_TIMEOUT_MS = 3000;
@@ -65,29 +66,38 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
private static final int ID_EMPTY_MESSAGE = -1;
-
protected TextView mHeaderText;
protected LockPatternView mLockPatternView;
protected TextView mFooterText;
private TextView mFooterLeftButton;
private TextView mFooterRightButton;
-
protected List<LockPatternView.Cell> mChosenPattern = null;
- protected LockPatternUtils mLockPatternUtils;
-
/**
* The patten used during the help screen to show how to draw a pattern.
*/
private final List<LockPatternView.Cell> mAnimatePattern =
- Collections.unmodifiableList(
- Lists.newArrayList(
- LockPatternView.Cell.of(0, 0),
- LockPatternView.Cell.of(0, 1),
- LockPatternView.Cell.of(1, 1),
- LockPatternView.Cell.of(2, 1)
- ));
+ Collections.unmodifiableList(Lists.newArrayList(
+ LockPatternView.Cell.of(0, 0),
+ LockPatternView.Cell.of(0, 1),
+ LockPatternView.Cell.of(1, 1),
+ LockPatternView.Cell.of(2, 1)
+ ));
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case CONFIRM_EXISTING_REQUEST:
+ if (resultCode != Activity.RESULT_OK) {
+ setResult(RESULT_FINISHED);
+ finish();
+ }
+ updateStage(Stage.Introduction);
+ break;
+ }
+ }
/**
* The pattern listener that responds according to a user choosing a new
@@ -125,7 +135,7 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
}
}
- public void onPatternCellAdded(List<Cell> pattern) {
+ public void onPatternCellAdded(List<Cell> pattern) {
}
@@ -250,19 +260,19 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
}
};
+ private ChooseLockSettingsHelper mChooseLockSettingsHelper;
+
private static final String KEY_UI_STAGE = "uiStage";
private static final String KEY_PATTERN_CHOICE = "chosenPattern";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- mLockPatternUtils = new LockPatternUtils(getContentResolver());
-
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setupViews();
-
+
// make it so unhandled touch events within the unlock screen go to the
// lock pattern view.
final LinearLayoutWithDefaultTouchRecepient topLayout
@@ -270,12 +280,22 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
R.id.topLayout);
topLayout.setDefaultTouchRecepient(mLockPatternView);
+ final boolean confirmCredentials = getIntent().getBooleanExtra("confirm_credentials", true);
+
if (savedInstanceState == null) {
- // first launch
- updateStage(Stage.Introduction);
- if (mLockPatternUtils.savedPatternExists()) {
- confirmPattern();
- }
+ if (confirmCredentials) {
+ // first launch. As a security measure, we're in NeedToConfirm mode until we know
+ // there isn't an existing password or the user confirms their password.
+ updateStage(Stage.NeedToConfirm);
+ boolean launchedConfirmationActivity =
+ mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
+ null, null);
+ if (!launchedConfirmationActivity) {
+ updateStage(Stage.Introduction);
+ }
+ } else {
+ updateStage(Stage.Introduction);
+ }
} else {
// restore from previous state
final String patternString = savedInstanceState.getString(KEY_PATTERN_CHOICE);
@@ -285,19 +305,20 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
updateStage(Stage.values()[savedInstanceState.getInt(KEY_UI_STAGE)]);
}
}
-
+
/**
* Keep all "find view" related stuff confined to this function since in
* case someone needs to subclass and customize.
*/
protected void setupViews() {
setContentView(R.layout.choose_lock_pattern);
-
+
mHeaderText = (TextView) findViewById(R.id.headerText);
mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);
mLockPatternView.setOnPatternListener(mChooseNewLockPatternListener);
- mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
+ mLockPatternView.setTactileFeedbackEnabled(
+ mChooseLockSettingsHelper.utils().isTactileFeedbackEnabled());
mFooterText = (TextView) findViewById(R.id.footerText);
@@ -364,35 +385,6 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
return super.onKeyDown(keyCode, event);
}
- /**
- * Launch screen to confirm the existing lock pattern.
- * @see #onActivityResult(int, int, android.content.Intent)
- */
- protected void confirmPattern() {
- final Intent intent = new Intent();
- intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPattern");
- startActivityForResult(intent, 55);
- }
-
- /**
- * @see #confirmPattern
- */
- @Override
- protected void onActivityResult(int requestCode, int resultCode,
- Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
-
- if (requestCode != 55) {
- return;
- }
-
- if (resultCode != Activity.RESULT_OK) {
- setResult(RESULT_FINISHED);
- finish();
- }
- updateStage(Stage.Introduction);
- }
-
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@@ -414,7 +406,7 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
mUiStage = stage;
- // header text, footer text, visibility and
+ // header text, footer text, visibility and
// enabled state all known from the stage
if (stage == Stage.ChoiceTooShort) {
mHeaderText.setText(
@@ -486,16 +478,17 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
}
private void saveChosenPatternAndFinish() {
- final boolean lockVirgin = !mLockPatternUtils.isPatternEverChosen();
+ LockPatternUtils utils = mChooseLockSettingsHelper.utils();
+ final boolean lockVirgin = !utils.isPatternEverChosen();
- mLockPatternUtils.saveLockPattern(mChosenPattern);
- mLockPatternUtils.setLockPatternEnabled(true);
+ utils.saveLockPattern(mChosenPattern);
+ utils.setLockPatternEnabled(true);
if (lockVirgin) {
- mLockPatternUtils.setVisiblePatternEnabled(true);
- mLockPatternUtils.setTactileFeedbackEnabled(false);
+ utils.setVisiblePatternEnabled(true);
+ utils.setTactileFeedbackEnabled(false);
}
-
+
setResult(RESULT_FINISHED);
finish();
}
diff --git a/src/com/android/settings/ChooseLockPatternExample.java b/src/com/android/settings/ChooseLockPatternExample.java
index 77517b9..cba88b0 100644
--- a/src/com/android/settings/ChooseLockPatternExample.java
+++ b/src/com/android/settings/ChooseLockPatternExample.java
@@ -25,7 +25,6 @@ import android.view.View;
import android.widget.ImageView;
public class ChooseLockPatternExample extends Activity implements View.OnClickListener {
- private static final int REQUESTCODE_CHOOSE = 1;
private static final long START_DELAY = 1000;
protected static final String TAG = "Settings";
private View mNextButton;
@@ -38,26 +37,26 @@ public class ChooseLockPatternExample extends Activity implements View.OnClickLi
startAnimation(mAnimation);
}
};
-
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.choose_lock_pattern_example);
initViews();
}
-
+
@Override
protected void onResume() {
super.onResume();
mHandler.postDelayed(mRunnable, START_DELAY);
}
-
+
@Override
protected void onPause() {
super.onPause();
stopAnimation(mAnimation);
}
-
+
public void onClick(View v) {
if (v == mSkipButton) {
// Canceling, so finish all
@@ -66,37 +65,31 @@ public class ChooseLockPatternExample extends Activity implements View.OnClickLi
} else if (v == mNextButton) {
stopAnimation(mAnimation);
Intent intent = new Intent(this, ChooseLockPattern.class);
- startActivityForResult(intent, REQUESTCODE_CHOOSE);
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQUESTCODE_CHOOSE && resultCode == ChooseLockPattern.RESULT_FINISHED) {
- setResult(resultCode);
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
finish();
}
}
-
+
private void initViews() {
mNextButton = findViewById(R.id.next_button);
mNextButton.setOnClickListener(this);
-
+
mSkipButton = findViewById(R.id.skip_button);
mSkipButton.setOnClickListener(this);
-
+
mImageView = (ImageView) findViewById(R.id.lock_anim);
mImageView.setBackgroundResource(R.drawable.lock_anim);
mImageView.setOnClickListener(this);
mAnimation = (AnimationDrawable) mImageView.getBackground();
}
-
+
protected void startAnimation(final AnimationDrawable animation) {
if (animation != null && !animation.isRunning()) {
animation.run();
}
}
-
+
protected void stopAnimation(final AnimationDrawable animation) {
if (animation != null && animation.isRunning()) animation.stop();
}
diff --git a/src/com/android/settings/ChooseLockPatternTutorial.java b/src/com/android/settings/ChooseLockPatternTutorial.java
index 6e92ca8..ee0019f 100644
--- a/src/com/android/settings/ChooseLockPatternTutorial.java
+++ b/src/com/android/settings/ChooseLockPatternTutorial.java
@@ -24,26 +24,24 @@ import android.os.Bundle;
import android.view.View;
public class ChooseLockPatternTutorial extends Activity implements View.OnClickListener {
- private static final int REQUESTCODE_EXAMPLE = 1;
-
private View mNextButton;
private View mSkipButton;
-
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Don't show the tutorial if the user has seen it before.
- LockPatternUtils lockPatternUtils = new LockPatternUtils(getContentResolver());
+ LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
if (savedInstanceState == null && lockPatternUtils.isPatternEverChosen()) {
- Intent intent = new Intent();
- intent.setClassName("com.android.settings", "com.android.settings.ChooseLockPattern");
+ Intent intent = new Intent(this, ChooseLockPattern.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
startActivity(intent);
finish();
} else {
initViews();
}
}
-
+
private void initViews() {
setContentView(R.layout.choose_lock_pattern_tutorial);
mNextButton = findViewById(R.id.next_button);
@@ -58,18 +56,11 @@ public class ChooseLockPatternTutorial extends Activity implements View.OnClickL
setResult(ChooseLockPattern.RESULT_FINISHED);
finish();
} else if (v == mNextButton) {
- startActivityForResult(new Intent(this, ChooseLockPatternExample.class),
- REQUESTCODE_EXAMPLE);
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQUESTCODE_EXAMPLE && resultCode == ChooseLockPattern.RESULT_FINISHED) {
- setResult(resultCode);
+ Intent intent = new Intent(this, ChooseLockPatternExample.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
finish();
}
}
-
}
diff --git a/src/com/android/settings/ChooseLockSettingsHelper.java b/src/com/android/settings/ChooseLockSettingsHelper.java
new file mode 100644
index 0000000..ba83f8e
--- /dev/null
+++ b/src/com/android/settings/ChooseLockSettingsHelper.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.Intent;
+
+import com.android.internal.widget.LockPatternUtils;
+
+public class ChooseLockSettingsHelper {
+ private LockPatternUtils mLockPatternUtils;
+ private Activity mActivity;
+
+ public ChooseLockSettingsHelper(Activity activity) {
+ mActivity = activity;
+ mLockPatternUtils = new LockPatternUtils(activity);
+ }
+
+ public LockPatternUtils utils() {
+ return mLockPatternUtils;
+ }
+
+ /**
+ * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
+ * @param message optional message to display about the action about to be done
+ * @param details optional detail message to display
+ * @return true if one exists and we launched an activity to confirm it
+ * @see #onActivityResult(int, int, android.content.Intent)
+ */
+ protected boolean launchConfirmationActivity(int request,
+ CharSequence message, CharSequence details) {
+ boolean launched = false;
+ switch (mLockPatternUtils.getKeyguardStoredPasswordQuality()) {
+ case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
+ launched = confirmPattern(request, message, details);
+ break;
+ case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
+ case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
+ case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
+ // TODO: update UI layout for ConfirmPassword to show message and details
+ launched = confirmPassword(request);
+ break;
+ }
+ return launched;
+ }
+
+ /**
+ * Launch screen to confirm the existing lock pattern.
+ * @param message shown in header of ConfirmLockPattern if not null
+ * @param details shown in footer of ConfirmLockPattern if not null
+ * @see #onActivityResult(int, int, android.content.Intent)
+ * @return true if we launched an activity to confirm pattern
+ */
+ private boolean confirmPattern(int request, CharSequence message, CharSequence details) {
+ if (!mLockPatternUtils.isLockPatternEnabled() || !mLockPatternUtils.savedPatternExists()) {
+ return false;
+ }
+ final Intent intent = new Intent();
+ // supply header and footer text in the intent
+ intent.putExtra(ConfirmLockPattern.HEADER_TEXT, message);
+ intent.putExtra(ConfirmLockPattern.FOOTER_TEXT, details);
+ intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPattern");
+ mActivity.startActivityForResult(intent, request);
+ return true;
+ }
+
+ /**
+ * Launch screen to confirm the existing lock password.
+ * @see #onActivityResult(int, int, android.content.Intent)
+ * @return true if we launched an activity to confirm password
+ */
+ private boolean confirmPassword(int request) {
+ if (!mLockPatternUtils.isLockPasswordEnabled()) return false;
+ final Intent intent = new Intent();
+ intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPassword");
+ mActivity.startActivityForResult(intent, request);
+ return true;
+ }
+
+
+}
diff --git a/src/com/android/settings/ConfirmLockPassword.java b/src/com/android/settings/ConfirmLockPassword.java
new file mode 100644
index 0000000..6bc135b
--- /dev/null
+++ b/src/com/android/settings/ConfirmLockPassword.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.PasswordEntryKeyboardHelper;
+import com.android.internal.widget.PasswordEntryKeyboardView;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.text.Editable;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.View.OnClickListener;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+public class ConfirmLockPassword extends Activity implements OnClickListener,
+ OnEditorActionListener {
+ private static final long ERROR_MESSAGE_TIMEOUT = 3000;
+ private TextView mPasswordEntry;
+ private LockPatternUtils mLockPatternUtils;
+ private TextView mHeaderText;
+ private Handler mHandler = new Handler();
+ private PasswordEntryKeyboardHelper mKeyboardHelper;
+ private PasswordEntryKeyboardView mKeyboardView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mLockPatternUtils = new LockPatternUtils(this);
+ initViews();
+ }
+
+ private void initViews() {
+ final int storedQuality = mLockPatternUtils.getKeyguardStoredPasswordQuality();
+ setContentView(R.layout.confirm_lock_password);
+ // Disable IME on our window since we provide our own keyboard
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+ WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+
+ findViewById(R.id.cancel_button).setOnClickListener(this);
+ findViewById(R.id.next_button).setOnClickListener(this);
+ mPasswordEntry = (TextView) findViewById(R.id.password_entry);
+ mPasswordEntry.setOnEditorActionListener(this);
+ mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
+ mHeaderText = (TextView) findViewById(R.id.headerText);
+ final boolean isAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == storedQuality
+ || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == storedQuality;
+ mHeaderText.setText(isAlpha ? R.string.lockpassword_confirm_your_password_header
+ : R.string.lockpassword_confirm_your_pin_header);
+ mKeyboardHelper = new PasswordEntryKeyboardHelper(this, mKeyboardView, mPasswordEntry);
+ mKeyboardHelper.setKeyboardMode(isAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
+ : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
+ mKeyboardView.requestFocus();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mKeyboardView.requestFocus();
+ }
+
+ @Override
+ protected void onResume() {
+ // TODO Auto-generated method stub
+ super.onResume();
+ mKeyboardView.requestFocus();
+ }
+
+ private void handleNext() {
+ final String pin = mPasswordEntry.getText().toString();
+ if (mLockPatternUtils.checkPassword(pin)) {
+ setResult(RESULT_OK);
+ finish();
+ } else {
+ showError(R.string.lockpattern_need_to_unlock_wrong);
+ }
+ }
+
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.next_button:
+ handleNext();
+ break;
+
+ case R.id.cancel_button:
+ setResult(RESULT_CANCELED);
+ finish();
+ break;
+ }
+ }
+
+ private void showError(int msg) {
+ mHeaderText.setText(msg);
+ mPasswordEntry.setText(null);
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mHeaderText.setText(R.string.lockpassword_confirm_your_password_header);
+ }
+ }, ERROR_MESSAGE_TIMEOUT);
+ }
+
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ // Check if this was the result of hitting the enter key
+ if (actionId == EditorInfo.IME_NULL) {
+ handleNext();
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/com/android/settings/ConfirmLockPattern.java b/src/com/android/settings/ConfirmLockPattern.java
index a91b45f..eb9a4d8 100644
--- a/src/com/android/settings/ConfirmLockPattern.java
+++ b/src/com/android/settings/ConfirmLockPattern.java
@@ -80,7 +80,7 @@ public class ConfirmLockPattern extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mLockPatternUtils = new LockPatternUtils(getContentResolver());
+ mLockPatternUtils = new LockPatternUtils(this);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.confirm_lock_pattern);
@@ -94,7 +94,7 @@ public class ConfirmLockPattern extends Activity {
final LinearLayoutWithDefaultTouchRecepient topLayout
= (LinearLayoutWithDefaultTouchRecepient) findViewById(
R.id.topLayout);
- topLayout.setDefaultTouchRecepient(mLockPatternView);
+ topLayout.setDefaultTouchRecepient(mLockPatternView);
Intent intent = getIntent();
if (intent != null) {
@@ -161,7 +161,7 @@ public class ConfirmLockPattern extends Activity {
} else {
mFooterTextView.setText(R.string.lockpattern_need_to_unlock_footer);
}
-
+
mLockPatternView.setEnabled(true);
mLockPatternView.enableInput();
break;
@@ -176,7 +176,7 @@ public class ConfirmLockPattern extends Activity {
} else {
mFooterTextView.setText(R.string.lockpattern_need_to_unlock_wrong_footer);
}
-
+
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
mLockPatternView.setEnabled(true);
mLockPatternView.enableInput();
diff --git a/src/com/android/settings/CredentialInstaller.java b/src/com/android/settings/CredentialInstaller.java
index 5a457d7..7c63b1c 100644
--- a/src/com/android/settings/CredentialInstaller.java
+++ b/src/com/android/settings/CredentialInstaller.java
@@ -32,6 +32,7 @@ import android.util.Log;
*/
public class CredentialInstaller extends Activity {
private static final String TAG = "CredentialInstaller";
+ private static final String UNLOCKING = "ulck";
private KeyStore mKeyStore = KeyStore.getInstance();
private boolean mUnlocking = false;
@@ -42,15 +43,26 @@ public class CredentialInstaller extends Activity {
if (!"com.android.certinstaller".equals(getCallingPackage())) finish();
- if (!isKeyStoreLocked()) {
+ if (isKeyStoreUnlocked()) {
install();
- finish();
} else if (!mUnlocking) {
mUnlocking = true;
Credentials.getInstance().unlock(this);
- } else {
- finish();
+ return;
}
+ finish();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outStates) {
+ super.onSaveInstanceState(outStates);
+ outStates.putBoolean(UNLOCKING, mUnlocking);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedStates) {
+ super.onRestoreInstanceState(savedStates);
+ mUnlocking = savedStates.getBoolean(UNLOCKING);
}
private void install() {
@@ -61,13 +73,13 @@ public class CredentialInstaller extends Activity {
byte[] data = bundle.getByteArray(key);
if (data == null) continue;
boolean success = mKeyStore.put(key.getBytes(), data);
- Log.v(TAG, "install " + key + ": " + data.length + " success? " + success);
+ Log.d(TAG, "install " + key + ": " + data.length + " success? " + success);
if (!success) return;
}
setResult(RESULT_OK);
}
- private boolean isKeyStoreLocked() {
- return (mKeyStore.test() != KeyStore.NO_ERROR);
+ private boolean isKeyStoreUnlocked() {
+ return (mKeyStore.test() == KeyStore.NO_ERROR);
}
}
diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java
new file mode 100644
index 0000000..4760277
--- /dev/null
+++ b/src/com/android/settings/DeviceAdminAdd.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteCallback;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AppSecurityPermissions;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+public class DeviceAdminAdd extends Activity {
+ static final String TAG = "DeviceAdminAdd";
+
+ static final int DIALOG_WARNING = 1;
+
+ Handler mHandler;
+
+ DevicePolicyManager mDPM;
+ DeviceAdminInfo mDeviceAdmin;
+ CharSequence mAddMsgText;
+
+ TextView mTitle;
+ ImageView mAdminIcon;
+ TextView mAdminName;
+ TextView mAdminDescription;
+ TextView mAddMsg;
+ TextView mAdminWarning;
+ ViewGroup mAdminPolicies;
+ Button mActionButton;
+ Button mCancelButton;
+
+ View mSelectLayout;
+
+ final ArrayList<View> mAddingPolicies = new ArrayList<View>();
+ final ArrayList<View> mActivePolicies = new ArrayList<View>();
+
+ boolean mAdding;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mHandler = new Handler(getMainLooper());
+
+ mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+ if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+ Log.w(TAG, "Can now start ADD_DEVICE_ADMIN as a new task");
+ finish();
+ return;
+ }
+
+ ComponentName cn = (ComponentName)getIntent().getParcelableExtra(
+ DevicePolicyManager.EXTRA_DEVICE_ADMIN);
+ if (cn == null) {
+ Log.w(TAG, "No component specified in " + getIntent().getAction());
+ finish();
+ return;
+ }
+ if (DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN.equals(getIntent().getAction())) {
+ // If this was an add request, then just exit immediately if the
+ // given component is already added.
+ if (mDPM.isAdminActive(cn)) {
+ setResult(Activity.RESULT_OK);
+ finish();
+ return;
+ }
+ }
+
+ ActivityInfo ai;
+ try {
+ ai = getPackageManager().getReceiverInfo(cn,
+ PackageManager.GET_META_DATA);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Unable to retrieve device policy " + cn, e);
+ finish();
+ return;
+ }
+
+ ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo = ai;
+ try {
+ mDeviceAdmin= new DeviceAdminInfo(this, ri);
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "Unable to retrieve device policy " + cn, e);
+ finish();
+ return;
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to retrieve device policy " + cn, e);
+ finish();
+ return;
+ }
+
+ mAddMsgText = getIntent().getCharSequenceExtra(
+ DevicePolicyManager.EXTRA_ADD_EXPLANATION);
+
+ setContentView(R.layout.device_admin_add);
+
+ mTitle = (TextView)findViewById(R.id.title);
+ mAdminIcon = (ImageView)findViewById(R.id.admin_icon);
+ mAdminName = (TextView)findViewById(R.id.admin_name);
+ mAdminDescription = (TextView)findViewById(R.id.admin_description);
+ mAddMsg = (TextView)findViewById(R.id.add_msg);
+ mAdminWarning = (TextView)findViewById(R.id.admin_warning);
+ mAdminPolicies = (ViewGroup)findViewById(R.id.admin_policies);
+ mCancelButton = (Button)findViewById(R.id.cancel_button);
+ mCancelButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ finish();
+ }
+ });
+ mActionButton = (Button)findViewById(R.id.action_button);
+ mActionButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ if (mAdding) {
+ try {
+ mDPM.setActiveAdmin(mDeviceAdmin.getComponent());
+ setResult(Activity.RESULT_OK);
+ } catch (RuntimeException e) {
+ // Something bad happened... could be that it was
+ // already set, though.
+ Log.w(TAG, "Exception trying to activate admin "
+ + mDeviceAdmin.getComponent(), e);
+ if (mDPM.isAdminActive(mDeviceAdmin.getComponent())) {
+ setResult(Activity.RESULT_OK);
+ }
+ }
+ finish();
+ } else {
+ mDPM.getRemoveWarning(mDeviceAdmin.getComponent(),
+ new RemoteCallback(mHandler) {
+ @Override
+ protected void onResult(Bundle bundle) {
+ CharSequence msg = bundle != null
+ ? bundle.getCharSequence(
+ DeviceAdminReceiver.EXTRA_DISABLE_WARNING)
+ : null;
+ if (msg == null) {
+ mDPM.removeActiveAdmin(mDeviceAdmin.getComponent());
+ finish();
+ } else {
+ Bundle args = new Bundle();
+ args.putCharSequence(
+ DeviceAdminReceiver.EXTRA_DISABLE_WARNING, msg);
+ showDialog(DIALOG_WARNING, args);
+ }
+ }
+ });
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ updateInterface();
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id, Bundle args) {
+ switch (id) {
+ case DIALOG_WARNING: {
+ CharSequence msg = args.getCharSequence(DeviceAdminReceiver.EXTRA_DISABLE_WARNING);
+ AlertDialog.Builder builder = new AlertDialog.Builder(
+ DeviceAdminAdd.this);
+ builder.setMessage(msg);
+ builder.setPositiveButton(R.string.dlg_ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mDPM.removeActiveAdmin(mDeviceAdmin.getComponent());
+ finish();
+ }
+ });
+ builder.setNegativeButton(R.string.dlg_cancel, null);
+ return builder.create();
+ }
+ default:
+ return super.onCreateDialog(id, args);
+
+ }
+ }
+
+ static void setViewVisibility(ArrayList<View> views, int visibility) {
+ final int N = views.size();
+ for (int i=0; i<N; i++) {
+ views.get(i).setVisibility(visibility);
+ }
+ }
+
+ void updateInterface() {
+ mAdminIcon.setImageDrawable(mDeviceAdmin.loadIcon(getPackageManager()));
+ mAdminName.setText(mDeviceAdmin.loadLabel(getPackageManager()));
+ try {
+ mAdminDescription.setText(
+ mDeviceAdmin.loadDescription(getPackageManager()));
+ mAdminDescription.setVisibility(View.VISIBLE);
+ } catch (Resources.NotFoundException e) {
+ mAdminDescription.setVisibility(View.GONE);
+ }
+ if (mAddMsgText != null) {
+ mAddMsg.setText(mAddMsgText);
+ mAddMsg.setVisibility(View.VISIBLE);
+ } else {
+ mAddMsg.setVisibility(View.GONE);
+ }
+ if (mDPM.isAdminActive(mDeviceAdmin.getComponent())) {
+ if (mActivePolicies.size() == 0) {
+ ArrayList<DeviceAdminInfo.PolicyInfo> policies = mDeviceAdmin.getUsedPolicies();
+ for (int i=0; i<policies.size(); i++) {
+ DeviceAdminInfo.PolicyInfo pi = policies.get(i);
+ View view = AppSecurityPermissions.getPermissionItemView(
+ this, getText(pi.label), "", true);
+ mActivePolicies.add(view);
+ mAdminPolicies.addView(view);
+ }
+ }
+ setViewVisibility(mActivePolicies, View.VISIBLE);
+ setViewVisibility(mAddingPolicies, View.GONE);
+ mAdminWarning.setText(getString(R.string.device_admin_status,
+ mDeviceAdmin.getActivityInfo().applicationInfo.loadLabel(getPackageManager())));
+ mTitle.setText(getText(R.string.active_device_admin_msg));
+ mActionButton.setText(getText(R.string.remove_device_admin));
+ mAdding = false;
+ } else {
+ if (mAddingPolicies.size() == 0) {
+ ArrayList<DeviceAdminInfo.PolicyInfo> policies = mDeviceAdmin.getUsedPolicies();
+ for (int i=0; i<policies.size(); i++) {
+ DeviceAdminInfo.PolicyInfo pi = policies.get(i);
+ View view = AppSecurityPermissions.getPermissionItemView(
+ this, getText(pi.label), getText(pi.description), true);
+ mAddingPolicies.add(view);
+ mAdminPolicies.addView(view);
+ }
+ }
+ setViewVisibility(mAddingPolicies, View.VISIBLE);
+ setViewVisibility(mActivePolicies, View.GONE);
+ mAdminWarning.setText(getString(R.string.device_admin_warning,
+ mDeviceAdmin.getActivityInfo().applicationInfo.loadLabel(getPackageManager())));
+ mTitle.setText(getText(R.string.add_device_admin_msg));
+ mActionButton.setText(getText(R.string.add_device_admin));
+ mAdding = true;
+ }
+ }
+
+}
diff --git a/src/com/android/settings/DeviceAdminSettings.java b/src/com/android/settings/DeviceAdminSettings.java
new file mode 100644
index 0000000..c3c74b6
--- /dev/null
+++ b/src/com/android/settings/DeviceAdminSettings.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ListActivity;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteCallback;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+public class DeviceAdminSettings extends ListActivity {
+ static final String TAG = "DeviceAdminSettings";
+
+ static final int DIALOG_WARNING = 1;
+
+ DevicePolicyManager mDPM;
+ final HashSet<ComponentName> mActiveAdmins = new HashSet<ComponentName>();
+ final ArrayList<DeviceAdminInfo> mAvailableAdmins = new ArrayList<DeviceAdminInfo>();
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+ setContentView(R.layout.device_admin_settings);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ updateList();
+ }
+
+ void updateList() {
+ mActiveAdmins.clear();
+ List<ComponentName> cur = mDPM.getActiveAdmins();
+ if (cur != null) {
+ for (int i=0; i<cur.size(); i++) {
+ mActiveAdmins.add(cur.get(i));
+ }
+ }
+
+ mAvailableAdmins.clear();
+ List<ResolveInfo> avail = getPackageManager().queryBroadcastReceivers(
+ new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
+ PackageManager.GET_META_DATA);
+ int count = avail == null ? 0 : avail.size();
+ for (int i=0; i<count; i++) {
+ ResolveInfo ri = avail.get(i);
+ try {
+ DeviceAdminInfo dpi = new DeviceAdminInfo(this, ri);
+ if (dpi.isVisible() || mActiveAdmins.contains(dpi.getComponent())) {
+ mAvailableAdmins.add(dpi);
+ }
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "Skipping " + ri.activityInfo, e);
+ } catch (IOException e) {
+ Log.w(TAG, "Skipping " + ri.activityInfo, e);
+ }
+ }
+
+ getListView().setAdapter(new PolicyListAdapter());
+ }
+
+ @Override
+ protected void onListItemClick(ListView l, View v, int position, long id) {
+ DeviceAdminInfo dpi = (DeviceAdminInfo)l.getAdapter().getItem(position);
+ Intent intent = new Intent();
+ intent.setClass(this, DeviceAdminAdd.class);
+ intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, dpi.getComponent());
+ startActivity(intent);
+ }
+
+ static class ViewHolder {
+ ImageView icon;
+ TextView name;
+ CheckBox checkbox;
+ TextView description;
+ }
+
+ class PolicyListAdapter extends BaseAdapter {
+ final LayoutInflater mInflater;
+
+ PolicyListAdapter() {
+ mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ public int getCount() {
+ return mAvailableAdmins.size();
+ }
+
+ public Object getItem(int position) {
+ return mAvailableAdmins.get(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+
+ public boolean isEnabled(int position) {
+ return true;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View v;
+ if (convertView == null) {
+ v = newView(parent);
+ } else {
+ v = convertView;
+ }
+ bindView(v, position);
+ return v;
+ }
+
+ public View newView(ViewGroup parent) {
+ View v = mInflater.inflate(R.layout.device_admin_item, parent, false);
+ ViewHolder h = new ViewHolder();
+ h.icon = (ImageView)v.findViewById(R.id.icon);
+ h.name = (TextView)v.findViewById(R.id.name);
+ h.checkbox = (CheckBox)v.findViewById(R.id.checkbox);
+ h.description = (TextView)v.findViewById(R.id.description);
+ v.setTag(h);
+ return v;
+ }
+
+ public void bindView(View view, int position) {
+ ViewHolder vh = (ViewHolder) view.getTag();
+ DeviceAdminInfo item = mAvailableAdmins.get(position);
+ vh.icon.setImageDrawable(item.loadIcon(getPackageManager()));
+ vh.name.setText(item.loadLabel(getPackageManager()));
+ vh.checkbox.setChecked(mActiveAdmins.contains(item.getComponent()));
+ try {
+ vh.description.setText(item.loadDescription(getPackageManager()));
+ } catch (Resources.NotFoundException e) {
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/DeviceInfoSettings.java b/src/com/android/settings/DeviceInfoSettings.java
index 82b7f28..a769c38 100644
--- a/src/com/android/settings/DeviceInfoSettings.java
+++ b/src/com/android/settings/DeviceInfoSettings.java
@@ -140,7 +140,7 @@ public class DeviceInfoSettings extends PreferenceActivity {
"\\w+\\s+" + /* ignore: version */
"([^\\s]+)\\s+" + /* group 1: 2.6.22-omap1 */
"\\(([^\\s@]+(?:@[^\\s.]+)?)[^)]*\\)\\s+" + /* group 2: (xxxxxx@xxxxx.constant) */
- "\\(.*?(?:\\(.*?\\)).*?\\)\\s+" + /* ignore: (gcc ..) */
+ "\\((?:[^(]*\\([^)]*\\))?[^)]*\\)\\s+" + /* ignore: (gcc ..) */
"([^\\s]+)\\s+" + /* group 3: #26 */
"(?:PREEMPT\\s+)?" + /* ignore: PREEMPT (optional) */
"(.+)"; /* group 4: date */
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
new file mode 100644
index 0000000..fbb07c1
--- /dev/null
+++ b/src/com/android/settings/DisplaySettings.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings;
+
+import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+
+import java.util.ArrayList;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.IWindowManager;
+
+public class DisplaySettings extends PreferenceActivity implements
+ Preference.OnPreferenceChangeListener {
+ private static final String TAG = "DisplaySettings";
+
+ /** If there is no setting in the provider, use this. */
+ private static final int FALLBACK_SCREEN_TIMEOUT_VALUE = 30000;
+
+ private static final String KEY_SCREEN_TIMEOUT = "screen_timeout";
+ private static final String KEY_ANIMATIONS = "animations";
+ private static final String KEY_ACCELEROMETER = "accelerometer";
+
+ private ListPreference mAnimations;
+ private CheckBoxPreference mAccelerometer;
+ private float[] mAnimationScales;
+
+ private IWindowManager mWindowManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ContentResolver resolver = getContentResolver();
+ mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
+
+ addPreferencesFromResource(R.xml.display_settings);
+
+ mAnimations = (ListPreference) findPreference(KEY_ANIMATIONS);
+ mAnimations.setOnPreferenceChangeListener(this);
+ mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);
+ mAccelerometer.setPersistent(false);
+
+ ListPreference screenTimeoutPreference =
+ (ListPreference) findPreference(KEY_SCREEN_TIMEOUT);
+ screenTimeoutPreference.setValue(String.valueOf(Settings.System.getInt(
+ resolver, SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE)));
+ screenTimeoutPreference.setOnPreferenceChangeListener(this);
+ disableUnusableTimeouts(screenTimeoutPreference);
+ }
+
+ private void disableUnusableTimeouts(ListPreference screenTimeoutPreference) {
+ final DevicePolicyManager dpm =
+ (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+ final long maxTimeout = dpm != null ? dpm.getMaximumTimeToLock(null) : 0;
+ if (maxTimeout == 0) {
+ return; // policy not enforced
+ }
+ final CharSequence[] entries = screenTimeoutPreference.getEntries();
+ final CharSequence[] values = screenTimeoutPreference.getEntryValues();
+ ArrayList<CharSequence> revisedEntries = new ArrayList<CharSequence>();
+ ArrayList<CharSequence> revisedValues = new ArrayList<CharSequence>();
+ for (int i = 0; i < values.length; i++) {
+ long timeout = Long.valueOf(values[i].toString());
+ if (timeout <= maxTimeout) {
+ revisedEntries.add(entries[i]);
+ revisedValues.add(values[i]);
+ }
+ }
+ if (revisedEntries.size() != entries.length || revisedValues.size() != values.length) {
+ screenTimeoutPreference.setEntries(
+ revisedEntries.toArray(new CharSequence[revisedEntries.size()]));
+ screenTimeoutPreference.setEntryValues(
+ revisedValues.toArray(new CharSequence[revisedValues.size()]));
+ final int userPreference = Integer.valueOf(screenTimeoutPreference.getValue());
+ if (userPreference <= maxTimeout) {
+ screenTimeoutPreference.setValue(String.valueOf(userPreference));
+ } else {
+ // There will be no highlighted selection since nothing in the list matches
+ // maxTimeout. The user can still select anything less than maxTimeout.
+ // TODO: maybe append maxTimeout to the list and mark selected.
+ }
+ }
+ screenTimeoutPreference.setEnabled(revisedEntries.size() > 0);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ updateState(true);
+ }
+
+ private void updateState(boolean force) {
+ int animations = 0;
+ try {
+ mAnimationScales = mWindowManager.getAnimationScales();
+ } catch (RemoteException e) {
+ }
+ if (mAnimationScales != null) {
+ if (mAnimationScales.length >= 1) {
+ animations = ((int)(mAnimationScales[0]+.5f)) % 10;
+ }
+ if (mAnimationScales.length >= 2) {
+ animations += (((int)(mAnimationScales[1]+.5f)) & 0x7) * 10;
+ }
+ }
+ int idx = 0;
+ int best = 0;
+ CharSequence[] aents = mAnimations.getEntryValues();
+ for (int i=0; i<aents.length; i++) {
+ int val = Integer.parseInt(aents[i].toString());
+ if (val <= animations && val > best) {
+ best = val;
+ idx = i;
+ }
+ }
+ mAnimations.setValueIndex(idx);
+ updateAnimationsSummary(mAnimations.getValue());
+ mAccelerometer.setChecked(Settings.System.getInt(
+ getContentResolver(),
+ Settings.System.ACCELEROMETER_ROTATION, 0) != 0);
+ }
+
+ private void updateAnimationsSummary(Object value) {
+ CharSequence[] summaries = getResources().getTextArray(R.array.animations_summaries);
+ CharSequence[] values = mAnimations.getEntryValues();
+ for (int i=0; i<values.length; i++) {
+ //Log.i("foo", "Comparing entry "+ values[i] + " to current "
+ // + mAnimations.getValue());
+ if (values[i].equals(value)) {
+ mAnimations.setSummary(summaries[i]);
+ break;
+ }
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (preference == mAccelerometer) {
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.ACCELEROMETER_ROTATION,
+ mAccelerometer.isChecked() ? 1 : 0);
+ }
+ return true;
+ }
+
+ public boolean onPreferenceChange(Preference preference, Object objValue) {
+ final String key = preference.getKey();
+ if (KEY_ANIMATIONS.equals(key)) {
+ try {
+ int value = Integer.parseInt((String) objValue);
+ if (mAnimationScales.length >= 1) {
+ mAnimationScales[0] = value%10;
+ }
+ if (mAnimationScales.length >= 2) {
+ mAnimationScales[1] = (value/10)%10;
+ }
+ try {
+ mWindowManager.setAnimationScales(mAnimationScales);
+ } catch (RemoteException e) {
+ }
+ updateAnimationsSummary(objValue);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "could not persist animation setting", e);
+ }
+
+ }
+ if (KEY_SCREEN_TIMEOUT.equals(key)) {
+ int value = Integer.parseInt((String) objValue);
+ try {
+ Settings.System.putInt(getContentResolver(),
+ SCREEN_OFF_TIMEOUT, value);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "could not persist screen timeout setting", e);
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/com/android/settings/DockSettings.java b/src/com/android/settings/DockSettings.java
index fe9aeb7..0d46ce9 100644
--- a/src/com/android/settings/DockSettings.java
+++ b/src/com/android/settings/DockSettings.java
@@ -18,15 +18,18 @@ package com.android.settings;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
+import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
+import android.provider.Settings;
import com.android.settings.bluetooth.DockEventReceiver;
@@ -34,7 +37,9 @@ public class DockSettings extends PreferenceActivity {
private static final int DIALOG_NOT_DOCKED = 1;
private static final String KEY_AUDIO_SETTINGS = "dock_audio";
+ private static final String KEY_DOCK_SOUNDS = "dock_sounds";
private Preference mAudioSettings;
+ private CheckBoxPreference mDockSounds;
private Intent mDockIntent;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -71,28 +76,47 @@ public class DockSettings extends PreferenceActivity {
}
private void initDockSettings() {
+ ContentResolver resolver = getContentResolver();
+
mAudioSettings = findPreference(KEY_AUDIO_SETTINGS);
if (mAudioSettings != null) {
mAudioSettings.setSummary(R.string.dock_audio_summary_none);
}
+
+ mDockSounds = (CheckBoxPreference) findPreference(KEY_DOCK_SOUNDS);
+ mDockSounds.setPersistent(false);
+ mDockSounds.setChecked(Settings.System.getInt(resolver,
+ Settings.System.DOCK_SOUNDS_ENABLED, 0) != 0);
}
private void handleDockChange(Intent intent) {
if (mAudioSettings != null) {
int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 0);
- mDockIntent = intent;
- int resId = R.string.dock_audio_summary_unknown;
- switch (dockState) {
- case Intent.EXTRA_DOCK_STATE_CAR:
- resId = R.string.dock_audio_summary_car;
- break;
- case Intent.EXTRA_DOCK_STATE_DESK:
- resId = R.string.dock_audio_summary_desk;
- break;
- case Intent.EXTRA_DOCK_STATE_UNDOCKED:
- resId = R.string.dock_audio_summary_none;
+
+ boolean isBluetooth = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) != null;
+
+ if (!isBluetooth) {
+ // No dock audio if not on Bluetooth.
+ mAudioSettings.setEnabled(false);
+ mAudioSettings.setSummary(R.string.dock_audio_summary_unknown);
+ } else {
+ mAudioSettings.setEnabled(true);
+
+ mDockIntent = intent;
+ int resId = R.string.dock_audio_summary_unknown;
+ switch (dockState) {
+ case Intent.EXTRA_DOCK_STATE_CAR:
+ resId = R.string.dock_audio_summary_car;
+ break;
+ case Intent.EXTRA_DOCK_STATE_DESK:
+ resId = R.string.dock_audio_summary_desk;
+ break;
+ case Intent.EXTRA_DOCK_STATE_UNDOCKED:
+ resId = R.string.dock_audio_summary_none;
+ }
+ mAudioSettings.setSummary(resId);
}
- mAudioSettings.setSummary(resId);
+
if (dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
// remove undocked dialog if currently showing.
try {
@@ -118,6 +142,9 @@ public class DockSettings extends PreferenceActivity {
i.setClass(this, DockEventReceiver.class);
sendBroadcast(i);
}
+ } else if (preference == mDockSounds) {
+ Settings.System.putInt(getContentResolver(), Settings.System.DOCK_SOUNDS_ENABLED,
+ mDockSounds.isChecked() ? 1 : 0);
}
return true;
diff --git a/src/com/android/settings/InstalledAppDetails.java b/src/com/android/settings/InstalledAppDetails.java
index d05014b..0ca35b8 100644
--- a/src/com/android/settings/InstalledAppDetails.java
+++ b/src/com/android/settings/InstalledAppDetails.java
@@ -18,30 +18,36 @@
package com.android.settings;
+import com.android.internal.content.PackageHelper;
import com.android.settings.R;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageManager;
+import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
import android.content.pm.PackageStats;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.storage.IMountService;
import android.text.format.Formatter;
-import android.util.Config;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
@@ -62,11 +68,13 @@ import android.widget.TextView;
* For non-system applications, there is no option to clear data. Instead there is an option to
* uninstall the application.
*/
-public class InstalledAppDetails extends Activity implements View.OnClickListener, DialogInterface.OnClickListener {
+public class InstalledAppDetails extends Activity implements View.OnClickListener {
private static final String TAG="InstalledAppDetails";
private static final int _UNKNOWN_APP=R.string.unknown;
private ApplicationInfo mAppInfo;
- private Button mAppButton;
+ private Button mUninstallButton;
+ private boolean mMoveInProgress = false;
+ private boolean mUpdatedSysApp = false;
private Button mActivitiesButton;
private boolean localLOGV = false;
private TextView mAppVersion;
@@ -76,15 +84,17 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
private PkgSizeObserver mSizeObserver;
private ClearUserDataObserver mClearDataObserver;
// Views related to cache info
- private View mCachePanel;
private TextView mCacheSize;
private Button mClearCacheButton;
private ClearCacheObserver mClearCacheObserver;
private Button mForceStopButton;
+ private Button mClearDataButton;
+ private Button mMoveAppButton;
+ private int mMoveErrorCode;
PackageStats mSizeInfo;
- private Button mManageSpaceButton;
private PackageManager mPm;
+ private PackageMoveObserver mPackageMoveObserver;
//internal constants used in Handler
private static final int OP_SUCCESSFUL = 1;
@@ -92,6 +102,7 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
private static final int CLEAR_USER_DATA = 1;
private static final int GET_PKG_SIZE = 2;
private static final int CLEAR_CACHE = 3;
+ private static final int PACKAGE_MOVE = 4;
private static final String ATTR_PACKAGE_STATS="PackageStats";
// invalid size value used initially and also when size retrieval through PackageManager
@@ -101,7 +112,6 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
// Resource strings
private CharSequence mInvalidSizeStr;
private CharSequence mComputingStr;
- private CharSequence mAppButtonText;
// Dialog identifiers used in showDialog
private static final int DLG_BASE = 0;
@@ -109,18 +119,15 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
private static final int DLG_FACTORY_RESET = DLG_BASE + 2;
private static final int DLG_APP_NOT_FOUND = DLG_BASE + 3;
private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 4;
-
- // Possible btn states
- private enum AppButtonStates {
- CLEAR_DATA,
- UNINSTALL,
- FACTORY_RESET,
- NONE
- }
- private AppButtonStates mAppButtonState;
+ private static final int DLG_FORCE_STOP = DLG_BASE + 5;
+ private static final int DLG_MOVE_FAILED = DLG_BASE + 6;
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
+ // If the activity is gone, don't process any more messages.
+ if (isFinishing()) {
+ return;
+ }
switch (msg.what) {
case CLEAR_USER_DATA:
processClearMsg(msg);
@@ -132,6 +139,9 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
// Refresh size info
mPm.getPackageSizeInfo(mAppInfo.packageName, mSizeObserver);
break;
+ case PACKAGE_MOVE:
+ processMoveMsg(msg);
+ break;
default:
break;
}
@@ -147,7 +157,6 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
}
class PkgSizeObserver extends IPackageStatsObserver.Stub {
- public int idx;
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) {
Message msg = mHandler.obtainMessage(GET_PKG_SIZE);
Bundle data = new Bundle();
@@ -161,10 +170,18 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
class ClearCacheObserver extends IPackageDataObserver.Stub {
public void onRemoveCompleted(final String packageName, final boolean succeeded) {
final Message msg = mHandler.obtainMessage(CLEAR_CACHE);
- msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
+ msg.arg1 = succeeded ? OP_SUCCESSFUL:OP_FAILED;
mHandler.sendMessage(msg);
}
}
+
+ class PackageMoveObserver extends IPackageMoveObserver.Stub {
+ public void packageMoved(String packageName, int returnCode) throws RemoteException {
+ final Message msg = mHandler.obtainMessage(PACKAGE_MOVE);
+ msg.arg1 = returnCode;
+ mHandler.sendMessage(msg);
+ }
+ }
private String getSizeStr(long size) {
if (size == SIZE_INVALID) {
@@ -173,31 +190,142 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
return Formatter.formatFileSize(this, size);
}
+ private void initDataButtons() {
+ if (mAppInfo.manageSpaceActivityName != null) {
+ mClearDataButton.setText(R.string.manage_space_text);
+ } else {
+ mClearDataButton.setText(R.string.clear_user_data_text);
+ }
+ mClearDataButton.setOnClickListener(this);
+ }
+
+ private CharSequence getMoveErrMsg(int errCode) {
+ switch (errCode) {
+ case PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE:
+ return getString(R.string.insufficient_storage);
+ case PackageManager.MOVE_FAILED_DOESNT_EXIST:
+ return getString(R.string.does_not_exist);
+ case PackageManager.MOVE_FAILED_FORWARD_LOCKED:
+ return getString(R.string.app_forward_locked);
+ case PackageManager.MOVE_FAILED_INVALID_LOCATION:
+ return getString(R.string.invalid_location);
+ case PackageManager.MOVE_FAILED_SYSTEM_PACKAGE:
+ return getString(R.string.system_package);
+ case PackageManager.MOVE_FAILED_INTERNAL_ERROR:
+ return "";
+ }
+ return "";
+ }
+
+ private void initMoveButton() {
+ String pkgName = mAppInfo.packageName;
+ boolean dataOnly = false;
+ ApplicationInfo info1 = null;
+ PackageInfo pkgInfo = null;
+
+ try {
+ info1 = mPm.getApplicationInfo(pkgName, 0);
+ pkgInfo = mPm.getPackageInfo(mAppInfo.packageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ } catch (NameNotFoundException e) {
+ }
+ dataOnly = (info1 == null) && (mAppInfo != null);
+ boolean moveDisable = true;
+ if (dataOnly) {
+ mMoveAppButton.setText(R.string.move_app);
+ } else if ((mAppInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+ mMoveAppButton.setText(R.string.move_app_to_internal);
+ // Always let apps move to internal storage from sdcard.
+ moveDisable = false;
+ } else {
+ mMoveAppButton.setText(R.string.move_app_to_sdcard);
+ if ((mAppInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0 &&
+ (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0 &&
+ pkgInfo != null) {
+ if (pkgInfo.installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL ||
+ pkgInfo.installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
+ moveDisable = false;
+ } else if (pkgInfo.installLocation == PackageInfo.INSTALL_LOCATION_UNSPECIFIED) {
+ IPackageManager ipm = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ int loc;
+ try {
+ loc = ipm.getInstallLocation();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Is Pakage Manager running?");
+ return;
+ }
+ if (loc == PackageHelper.APP_INSTALL_EXTERNAL) {
+ // For apps with no preference and the default value set
+ // to install on sdcard.
+ moveDisable = false;
+ }
+ }
+ }
+ }
+ if (moveDisable) {
+ mMoveAppButton.setEnabled(false);
+ } else {
+ mMoveAppButton.setOnClickListener(this);
+ mMoveAppButton.setEnabled(true);
+ }
+ }
+
+ private void initUninstallButtons() {
+ mUpdatedSysApp = (mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+ boolean enabled = true;
+ if (mUpdatedSysApp) {
+ mUninstallButton.setText(R.string.app_factory_reset);
+ } else {
+ if ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0){
+ // Disable button for system applications.
+ enabled = false;
+ }
+ mUninstallButton.setText(R.string.uninstall_text);
+ }
+ mUninstallButton.setEnabled(enabled);
+ if (enabled) {
+ // Register listener
+ mUninstallButton.setOnClickListener(this);
+ }
+ }
+
+ private boolean initAppInfo(String packageName) {
+ try {
+ mAppInfo = mPm.getApplicationInfo(packageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ return true;
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Exception when retrieving package: " + packageName, e);
+ showDialogInner(DLG_APP_NOT_FOUND);
+ return false;
+ }
+ }
+
/** Called when the activity is first created. */
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
+
// Get package manager
mPm = getPackageManager();
+
// Get application's name from intent
Intent intent = getIntent();
final String packageName = intent.getStringExtra(ManageApplications.APP_PKG_NAME);
- mComputingStr = getText(R.string.computing_size);
+ if (! initAppInfo(packageName)) {
+ return; // could not find package, finish called
+ }
+
// Try retrieving package stats again
CharSequence totalSizeStr, appSizeStr, dataSizeStr;
+ mComputingStr = getText(R.string.computing_size);
totalSizeStr = appSizeStr = dataSizeStr = mComputingStr;
if(localLOGV) Log.i(TAG, "Have to compute package sizes");
mSizeObserver = new PkgSizeObserver();
- try {
- mAppInfo = mPm.getApplicationInfo(packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Exception when retrieving package:"+packageName, e);
- showDialogInner(DLG_APP_NOT_FOUND);
- return;
- }
setContentView(R.layout.installed_app_details);
//TODO download str and download url
+
// Set default values on sizes
mTotalSize = (TextView)findViewById(R.id.total_size_text);
mTotalSize.setText(totalSizeStr);
@@ -205,24 +333,28 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
mAppSize.setText(appSizeStr);
mDataSize = (TextView)findViewById(R.id.data_size_text);
mDataSize.setText(dataSizeStr);
- // Get AppButton
- mAppButton = ((Button)findViewById(R.id.uninstall_button));
- // Get ManageSpaceButton
- mManageSpaceButton = (Button)findViewById(R.id.manage_space_button);
- if(mAppInfo.manageSpaceActivityName != null) {
- mManageSpaceButton.setVisibility(View.VISIBLE);
- mManageSpaceButton.setOnClickListener(this);
- }
+
+ // Get Control button panel
+ View btnPanel = findViewById(R.id.control_buttons_panel);
+ mForceStopButton = (Button) btnPanel.findViewById(R.id.left_button);
+ mForceStopButton.setText(R.string.force_stop);
+ mUninstallButton = (Button)btnPanel.findViewById(R.id.right_button);
+ mForceStopButton.setEnabled(false);
+
+ // Initialize clear data and move install location buttons
+ View data_buttons_panel = findViewById(R.id.data_buttons_panel);
+ mClearDataButton = (Button) data_buttons_panel.findViewById(R.id.left_button);
+ mMoveAppButton = (Button) data_buttons_panel.findViewById(R.id.right_button);
+
// Cache section
- mCachePanel = findViewById(R.id.cache_panel);
mCacheSize = (TextView) findViewById(R.id.cache_size_text);
mCacheSize.setText(mComputingStr);
mClearCacheButton = (Button) findViewById(R.id.clear_cache_button);
- mForceStopButton = (Button) findViewById(R.id.force_stop_button);
- mForceStopButton.setOnClickListener(this);
+
// Get list of preferred activities
mActivitiesButton = (Button)findViewById(R.id.clear_activities_button);
List<ComponentName> prefActList = new ArrayList<ComponentName>();
+
// Intent list cannot be null. so pass empty list
List<IntentFilter> intentList = new ArrayList<IntentFilter>();
mPm.getPreferredActivities(intentList, prefActList, packageName);
@@ -250,95 +382,65 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
permsView.setVisibility(View.GONE);
}
}
-
- private void refreshAppAttributes(PackageInfo pkgInfo) {
- setAppLabelAndIcon();
- // Version number of application
- setAppVersion(pkgInfo);
- setAppBtnState();
- // Refresh size info
- if (mAppInfo != null && mAppInfo.packageName != null) {
- mPm.getPackageSizeInfo(mAppInfo.packageName, mSizeObserver);
- }
- }
-
+
// Utility method to set applicaiton label and icon.
- private void setAppLabelAndIcon() {
- ((ImageView)findViewById(R.id.app_icon)).setImageDrawable(mAppInfo.loadIcon(mPm));
- //set application name TODO version
- CharSequence appName = mAppInfo.loadLabel(mPm);
- if(appName == null) {
- appName = getString(_UNKNOWN_APP);
- }
- ((TextView)findViewById(R.id.app_name)).setText(appName);
- }
-
- // Utility method to set application version
- private void setAppVersion(PackageInfo pkgInfo) {
+ private void setAppLabelAndIcon(PackageInfo pkgInfo) {
+ View appSnippet = findViewById(R.id.app_snippet);
+ ImageView icon = (ImageView) appSnippet.findViewById(R.id.app_icon);
+ icon.setImageDrawable(mAppInfo.loadIcon(mPm));
+ // Set application name.
+ TextView label = (TextView) appSnippet.findViewById(R.id.app_name);
+ label.setText(mAppInfo.loadLabel(mPm));
// Version number of application
- mAppVersion = ((TextView)findViewById(R.id.app_version));
- if (pkgInfo != null) {
+ mAppVersion = (TextView) appSnippet.findViewById(R.id.app_size);
+
+ if (pkgInfo != null && pkgInfo.versionName != null) {
mAppVersion.setVisibility(View.VISIBLE);
mAppVersion.setText(getString(R.string.version_text,
- String.valueOf(pkgInfo.versionCode)));
+ String.valueOf(pkgInfo.versionName)));
} else {
- mAppVersion.setVisibility(View.GONE);
+ mAppVersion.setVisibility(View.INVISIBLE);
}
}
- // Utility method to set button state
- private void setAppBtnState() {
- boolean visible = true;
- if ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- if ((mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
- mAppButtonState = AppButtonStates.FACTORY_RESET;
- mAppButtonText = getText(R.string.app_factory_reset);
- } else {
- if ((mAppInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
- // Hide button if diableClearUserData is set
- mAppButtonState = AppButtonStates.NONE;
- visible = false;
- } else {
- mAppButtonState = AppButtonStates.CLEAR_DATA;
- mAppButtonText = getText(R.string.clear_user_data_text);
- }
- }
- } else {
- mAppButtonState = AppButtonStates.UNINSTALL;
- mAppButtonText = getText(R.string.uninstall_text);
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ if (mAppInfo == null) {
+ setIntentAndFinish(true, true);
+ return; // onCreate must have failed, make sure to exit
}
- if(visible) {
- mAppButton.setText(mAppButtonText);
- mAppButton.setVisibility(View.VISIBLE);
- } else {
- mAppButton.setVisibility(View.GONE);
+ if (! initAppInfo(mAppInfo.packageName)) {
+ return; // could not find package, finish called
}
- }
-
- @Override
- public void onStart() {
- super.onStart();
- PackageInfo pkgInfo;
+
+ PackageInfo pkgInfo = null;
// Get application info again to refresh changed properties of application
try {
- mAppInfo = mPm.getApplicationInfo(mAppInfo.packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
pkgInfo = mPm.getPackageInfo(mAppInfo.packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
} catch (NameNotFoundException e) {
Log.e(TAG, "Exception when retrieving package:" + mAppInfo.packageName, e);
showDialogInner(DLG_APP_NOT_FOUND);
- return;
+ return; // could not find package, finish called
+ }
+
+ checkForceStop();
+ setAppLabelAndIcon(pkgInfo);
+ refreshButtons();
+
+ // Refresh size info
+ if (mAppInfo != null && mAppInfo.packageName != null) {
+ mPm.getPackageSizeInfo(mAppInfo.packageName, mSizeObserver);
}
- refreshAppAttributes(pkgInfo);
}
-
+
private void setIntentAndFinish(boolean finish, boolean appChanged) {
if(localLOGV) Log.i(TAG, "appChanged="+appChanged);
Intent intent = new Intent();
intent.putExtra(ManageApplications.APP_CHG, appChanged);
setResult(ManageApplications.RESULT_OK, intent);
- mAppButton.setEnabled(false);
if(finish) {
finish();
}
@@ -383,18 +485,11 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
mSizeInfo = newPs;
}
}
-
- long data = mSizeInfo.dataSize;
- // Disable button if data is 0
- if(mAppButtonState != AppButtonStates.NONE){
- mAppButton.setText(mAppButtonText);
- if((mAppButtonState == AppButtonStates.CLEAR_DATA) && (data == 0)) {
- mAppButton.setEnabled(false);
- } else {
- mAppButton.setEnabled(true);
- mAppButton.setOnClickListener(this);
- }
+ // If data size is zero disable clear data button
+ if (newPs.dataSize == 0) {
+ mClearDataButton.setEnabled(false);
}
+ long data = mSizeInfo.dataSize;
refreshCacheInfo(newPs.cacheSize);
}
@@ -415,24 +510,57 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
private void processClearMsg(Message msg) {
int result = msg.arg1;
String packageName = mAppInfo.packageName;
+ mClearDataButton.setText(R.string.clear_user_data_text);
if(result == OP_SUCCESSFUL) {
- Log.i(TAG, "Cleared user data for system package:"+packageName);
+ Log.i(TAG, "Cleared user data for package : "+packageName);
mPm.getPackageSizeInfo(packageName, mSizeObserver);
} else {
- mAppButton.setText(R.string.clear_user_data_text);
- mAppButton.setEnabled(true);
+ mClearDataButton.setEnabled(true);
}
}
-
+
+ private void refreshButtons() {
+ if (!mMoveInProgress) {
+ initUninstallButtons();
+ initDataButtons();
+ initMoveButton();
+ } else {
+ mMoveAppButton.setText(R.string.moving);
+ mMoveAppButton.setEnabled(false);
+ mUninstallButton.setEnabled(false);
+ }
+ }
+
+ private void processMoveMsg(Message msg) {
+ int result = msg.arg1;
+ String packageName = mAppInfo.packageName;
+ // Refresh the button attributes.
+ mMoveInProgress = false;
+ if(result == PackageManager.MOVE_SUCCEEDED) {
+ Log.i(TAG, "Moved resources for " + packageName);
+ // Refresh size information again.
+ mPm.getPackageSizeInfo(packageName, mSizeObserver);
+ } else {
+ mMoveErrorCode = result;
+ showDialogInner(DLG_MOVE_FAILED);
+ }
+
+ if (! initAppInfo(packageName)) {
+ return; // could not find package, finish called
+ }
+
+ refreshButtons();
+ }
+
/*
* Private method to initiate clearing user data when the user clicks the clear data
* button for a system package
*/
- private void initiateClearUserDataForSysPkg() {
- mAppButton.setEnabled(false);
- //invoke uninstall or clear user data based on sysPackage
+ private void initiateClearUserData() {
+ mClearDataButton.setEnabled(false);
+ // Invoke uninstall or clear user data based on sysPackage
String packageName = mAppInfo.packageName;
- Log.i(TAG, "Clearing user data for system package");
+ Log.i(TAG, "Clearing user data for package : " + packageName);
if(mClearDataObserver == null) {
mClearDataObserver = new ClearUserDataObserver();
}
@@ -443,7 +571,7 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
showDialogInner(DLG_CANNOT_CLEAR_DATA);
} else {
- mAppButton.setText(R.string.recompute_size);
+ mClearDataButton.setText(R.string.recompute_size);
}
}
@@ -453,23 +581,35 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
}
@Override
- public Dialog onCreateDialog(int id) {
+ public Dialog onCreateDialog(int id, Bundle args) {
switch (id) {
case DLG_CLEAR_DATA:
return new AlertDialog.Builder(this)
.setTitle(getString(R.string.clear_data_dlg_title))
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(getString(R.string.clear_data_dlg_text))
- .setPositiveButton(R.string.dlg_ok, this)
- .setNegativeButton(R.string.dlg_cancel, this)
+ .setPositiveButton(R.string.dlg_ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Clear user data here
+ initiateClearUserData();
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
.create();
case DLG_FACTORY_RESET:
return new AlertDialog.Builder(this)
.setTitle(getString(R.string.app_factory_reset_dlg_title))
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(getString(R.string.app_factory_reset_dlg_text))
- .setPositiveButton(R.string.dlg_ok, this)
- .setNegativeButton(R.string.dlg_cancel, this)
+ .setPositiveButton(R.string.dlg_ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Clear user data here
+ uninstallPkg(mAppInfo.packageName);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
.create();
case DLG_APP_NOT_FOUND:
return new AlertDialog.Builder(this)
@@ -492,11 +632,35 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
.setNeutralButton(R.string.dlg_ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
+ mClearDataButton.setEnabled(false);
//force to recompute changed value
setIntentAndFinish(false, false);
}
})
.create();
+ case DLG_FORCE_STOP:
+ return new AlertDialog.Builder(this)
+ .setTitle(getString(R.string.force_stop_dlg_title))
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(getString(R.string.force_stop_dlg_text))
+ .setPositiveButton(R.string.dlg_ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Force stop
+ forceStopPackage(mAppInfo.packageName);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ case DLG_MOVE_FAILED:
+ CharSequence msg = getString(R.string.move_app_failed_dlg_text,
+ getMoveErrMsg(mMoveErrorCode));
+ return new AlertDialog.Builder(this)
+ .setTitle(getString(R.string.move_app_failed_dlg_title))
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(msg)
+ .setNeutralButton(R.string.dlg_ok, null)
+ .create();
}
return null;
}
@@ -509,27 +673,53 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
setIntentAndFinish(true, true);
}
+ private void forceStopPackage(String pkgName) {
+ ActivityManager am = (ActivityManager)getSystemService(
+ Context.ACTIVITY_SERVICE);
+ am.forceStopPackage(pkgName);
+ checkForceStop();
+ }
+
+ private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mForceStopButton.setEnabled(getResultCode() != RESULT_CANCELED);
+ mForceStopButton.setOnClickListener(InstalledAppDetails.this);
+ }
+ };
+
+ private void checkForceStop() {
+ Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
+ Uri.fromParts("package", mAppInfo.packageName, null));
+ intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppInfo.packageName });
+ intent.putExtra(Intent.EXTRA_UID, mAppInfo.uid);
+ sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
+ Activity.RESULT_CANCELED, null, null);
+ }
+
/*
* Method implementing functionality of buttons clicked
* @see android.view.View.OnClickListener#onClick(android.view.View)
*/
public void onClick(View v) {
String packageName = mAppInfo.packageName;
- if(v == mAppButton) {
- if (mAppButtonState == AppButtonStates.CLEAR_DATA) {
- showDialogInner(DLG_CLEAR_DATA);
- } else if (mAppButtonState == AppButtonStates.FACTORY_RESET) {
+ if(v == mUninstallButton) {
+ if (mUpdatedSysApp) {
showDialogInner(DLG_FACTORY_RESET);
- } else if (mAppButtonState == AppButtonStates.UNINSTALL) {
+ } else {
uninstallPkg(packageName);
}
} else if(v == mActivitiesButton) {
mPm.clearPackagePreferredActivities(packageName);
mActivitiesButton.setEnabled(false);
- } else if(v == mManageSpaceButton) {
- Intent intent = new Intent(Intent.ACTION_DEFAULT);
- intent.setClassName(mAppInfo.packageName, mAppInfo.manageSpaceActivityName);
- startActivityForResult(intent, -1);
+ } else if(v == mClearDataButton) {
+ if (mAppInfo.manageSpaceActivityName != null) {
+ Intent intent = new Intent(Intent.ACTION_DEFAULT);
+ intent.setClassName(mAppInfo.packageName, mAppInfo.manageSpaceActivityName);
+ startActivityForResult(intent, -1);
+ } else {
+ showDialogInner(DLG_CLEAR_DATA);
+ }
} else if (v == mClearCacheButton) {
// Lazy initialization of observer
if (mClearCacheObserver == null) {
@@ -537,23 +727,16 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
}
mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver);
} else if (v == mForceStopButton) {
- ActivityManager am = (ActivityManager)getSystemService(
- Context.ACTIVITY_SERVICE);
- am.restartPackage(packageName);
- }
- }
-
- public void onClick(DialogInterface dialog, int which) {
- if(which == AlertDialog.BUTTON_POSITIVE) {
- if (mAppButtonState == AppButtonStates.CLEAR_DATA) {
- // Invoke uninstall or clear user data based on sysPackage
- initiateClearUserDataForSysPkg();
- } else if (mAppButtonState == AppButtonStates.FACTORY_RESET) {
- // Initiate package installer to delete package
- uninstallPkg(mAppInfo.packageName);
+ forceStopPackage(mAppInfo.packageName);
+ } else if (v == mMoveAppButton) {
+ if (mPackageMoveObserver == null) {
+ mPackageMoveObserver = new PackageMoveObserver();
}
- } else {
- //cancel do nothing just retain existing screen
+ int moveFlags = (mAppInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ?
+ PackageManager.MOVE_INTERNAL : PackageManager.MOVE_EXTERNAL_MEDIA;
+ mMoveInProgress = true;
+ refreshButtons();
+ mPm.movePackage(mAppInfo.packageName, mPackageMoveObserver, moveFlags);
}
}
}
diff --git a/src/com/android/settings/LanguageSettings.java b/src/com/android/settings/LanguageSettings.java
index 1b9f0c1..91d260c 100644
--- a/src/com/android/settings/LanguageSettings.java
+++ b/src/com/android/settings/LanguageSettings.java
@@ -43,10 +43,12 @@ import java.util.List;
public class LanguageSettings extends PreferenceActivity {
+ private static final String KEY_PHONE_LANGUAGE = "phone_language";
private boolean mHaveHardKeyboard;
private List<InputMethodInfo> mInputMethodProperties;
private List<CheckBoxPreference> mCheckboxes;
+ private Preference mLanguagePref;
final TextUtils.SimpleStringSplitter mStringColonSplitter
= new TextUtils.SimpleStringSplitter(':');
@@ -67,6 +69,8 @@ public class LanguageSettings extends PreferenceActivity {
if (getAssets().getLocales().length == 1) {
getPreferenceScreen().
removePreference(findPreference("language_category"));
+ } else {
+ mLanguagePref = findPreference(KEY_PHONE_LANGUAGE);
}
Configuration config = getResources().getConfiguration();
@@ -116,7 +120,11 @@ public class LanguageSettings extends PreferenceActivity {
// If setting activity is available, add a setting screen entry.
if (null != property.getSettingsActivity()) {
PreferenceScreen prefScreen = new PreferenceScreen(this, null);
- prefScreen.setKey(property.getSettingsActivity());
+ String settingsActivity = property.getSettingsActivity();
+ if (settingsActivity.lastIndexOf("/") < 0) {
+ settingsActivity = property.getPackageName() + "/" + settingsActivity;
+ }
+ prefScreen.setKey(settingsActivity);
prefScreen.setTitle(label);
if (N == 1) {
prefScreen.setSummary(getString(R.string.onscreen_keyboard_settings_summary));
@@ -156,6 +164,15 @@ public class LanguageSettings extends PreferenceActivity {
}
}
mLastTickedInputMethodId = null;
+
+ if (mLanguagePref != null) {
+ Configuration conf = getResources().getConfiguration();
+ String locale = conf.locale.getDisplayName(conf.locale);
+ if (locale != null && locale.length() > 1) {
+ locale = Character.toUpperCase(locale.charAt(0)) + locale.substring(1);
+ mLanguagePref.setSummary(locale);
+ }
+ }
}
@Override
@@ -163,7 +180,8 @@ public class LanguageSettings extends PreferenceActivity {
super.onPause();
StringBuilder builder = new StringBuilder(256);
-
+ StringBuilder disabledSysImes = new StringBuilder(256);
+
int firstEnabled = -1;
int N = mInputMethodProperties.size();
for (int i = 0; i < N; ++i) {
@@ -182,6 +200,12 @@ public class LanguageSettings extends PreferenceActivity {
} else if (hasIt) {
mLastInputMethodId = mLastTickedInputMethodId;
}
+ // If it's a disabled system ime, add it to the disabled list so that it
+ // doesn't get enabled automatically on any changes to the package list
+ if (pref != null && !pref.isChecked() && systemIme && mHaveHardKeyboard) {
+ if (disabledSysImes.length() > 0) disabledSysImes.append(":");
+ disabledSysImes.append(id);
+ }
}
// If the last input method is unset, set it as the first enabled one.
@@ -196,6 +220,8 @@ public class LanguageSettings extends PreferenceActivity {
Settings.Secure.putString(getContentResolver(),
Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
Settings.Secure.putString(getContentResolver(),
+ Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, disabledSysImes.toString());
+ Settings.Secure.putString(getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD,
mLastInputMethodId != null ? mLastInputMethodId : "");
}
@@ -261,6 +287,11 @@ public class LanguageSettings extends PreferenceActivity {
String activityName = pref.getKey();
String packageName = activityName.substring(0, activityName
.lastIndexOf("."));
+ int slash = activityName.indexOf("/");
+ if (slash > 0) {
+ packageName = activityName.substring(0, slash);
+ activityName = activityName.substring(slash + 1);
+ }
if (activityName.length() > 0) {
Intent i = new Intent(Intent.ACTION_MAIN);
i.setClassName(packageName, activityName);
diff --git a/src/com/android/settings/LauncherAppWidgetBinder.java b/src/com/android/settings/LauncherAppWidgetBinder.java
deleted file mode 100644
index 98ea246..0000000
--- a/src/com/android/settings/LauncherAppWidgetBinder.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * 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 com.android.settings;
-
-import android.app.Activity;
-import android.appwidget.AppWidgetManager;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Intent;
-import android.content.ComponentName;
-import android.database.Cursor;
-import android.database.SQLException;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.BaseColumns;
-import android.util.Log;
-
-import java.util.ArrayList;
-
-public class LauncherAppWidgetBinder extends Activity {
- private static final String TAG = "LauncherAppWidgetBinder";
- private static final boolean LOGD = true;
-
- static final String AUTHORITY = "com.android.launcher.settings";
- static final String TABLE_FAVORITES = "favorites";
-
- static final String EXTRA_BIND_SOURCES = "com.android.launcher.settings.bindsources";
- static final String EXTRA_BIND_TARGETS = "com.android.launcher.settings.bindtargets";
-
- static final String EXTRA_APPWIDGET_BITMAPS = "com.android.camera.appwidgetbitmaps";
-
- /**
- * {@link ContentProvider} constants pulled over from Launcher
- */
- static final class LauncherProvider implements BaseColumns {
- static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + TABLE_FAVORITES);
-
- static final String ITEM_TYPE = "itemType";
- static final String APPWIDGET_ID = "appWidgetId";
- static final String ICON = "icon";
-
- static final int ITEM_TYPE_APPWIDGET = 4;
- static final int ITEM_TYPE_WIDGET_CLOCK = 1000;
- static final int ITEM_TYPE_WIDGET_SEARCH = 1001;
- static final int ITEM_TYPE_WIDGET_PHOTO_FRAME = 1002;
- }
-
- static final String[] BIND_PROJECTION = new String[] {
- LauncherProvider._ID,
- LauncherProvider.ITEM_TYPE,
- LauncherProvider.APPWIDGET_ID,
- LauncherProvider.ICON,
- };
-
- static final int INDEX_ID = 0;
- static final int INDEX_ITEM_TYPE = 1;
- static final int INDEX_APPWIDGET_ID = 2;
- static final int INDEX_ICON = 3;
-
- static final ComponentName BIND_PHOTO_APPWIDGET = new ComponentName("com.android.camera",
- "com.android.camera.PhotoAppWidgetBind");
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- finish();
-
- // This helper reaches into the Launcher database and binds any unlinked
- // widgets. If will remove any items that can't be bound successfully.
- // We protect this binder at the manifest level by asserting the caller
- // has the Launcher WRITE_SETTINGS permission.
-
- final Intent intent = getIntent();
- final Bundle extras = intent.getExtras();
-
- int[] bindSources = null;
- ArrayList<ComponentName> bindTargets = null;
- Exception exception = null;
-
- try {
- bindSources = extras.getIntArray(EXTRA_BIND_SOURCES);
- bindTargets = intent.getParcelableArrayListExtra(EXTRA_BIND_TARGETS);
- } catch (ClassCastException ex) {
- exception = ex;
- }
-
- if (exception != null || bindSources == null || bindTargets == null ||
- bindSources.length != bindTargets.size()) {
- Log.w(TAG, "Problem reading incoming bind request, or invalid request", exception);
- return;
- }
-
- final String selectWhere = buildOrWhereString(LauncherProvider.ITEM_TYPE, bindSources);
-
- final ContentResolver resolver = getContentResolver();
- final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
-
- boolean foundPhotoAppWidgets = false;
- final ArrayList<Integer> photoAppWidgetIds = new ArrayList<Integer>();
- final ArrayList<Bitmap> photoBitmaps = new ArrayList<Bitmap>();
-
- Cursor c = null;
-
- try {
- c = resolver.query(LauncherProvider.CONTENT_URI,
- BIND_PROJECTION, selectWhere, null, null);
-
- if (LOGD) Log.d(TAG, "found bind cursor count="+c.getCount());
-
- final ContentValues values = new ContentValues();
- while (c != null && c.moveToNext()) {
- long favoriteId = c.getLong(INDEX_ID);
- int itemType = c.getInt(INDEX_ITEM_TYPE);
- int appWidgetId = c.getInt(INDEX_APPWIDGET_ID);
- byte[] iconData = c.getBlob(INDEX_ICON);
-
- // Find the binding target for this type
- ComponentName targetAppWidget = null;
- for (int i = 0; i < bindSources.length; i++) {
- if (bindSources[i] == itemType) {
- targetAppWidget = bindTargets.get(i);
- break;
- }
- }
-
- if (LOGD) Log.d(TAG, "found matching targetAppWidget="+targetAppWidget.toString()+" for favoriteId="+favoriteId);
-
- boolean bindSuccess = false;
- try {
- appWidgetManager.bindAppWidgetId(appWidgetId, targetAppWidget);
- bindSuccess = true;
- } catch (RuntimeException ex) {
- Log.w(TAG, "Problem binding widget", ex);
- }
-
- // Handle special case of photo widget by loading bitmap and
- // preparing for later binding
- if (bindSuccess && iconData != null &&
- itemType == LauncherProvider.ITEM_TYPE_WIDGET_PHOTO_FRAME) {
- Bitmap bitmap = BitmapFactory.decodeByteArray(iconData, 0, iconData.length);
-
- photoAppWidgetIds.add(appWidgetId);
- photoBitmaps.add(bitmap);
- foundPhotoAppWidgets = true;
- }
-
- if (LOGD) Log.d(TAG, "after finished, success="+bindSuccess);
-
- // Depending on success, update launcher or remove item
- Uri favoritesUri = ContentUris.withAppendedId(LauncherProvider.CONTENT_URI, favoriteId);
- if (bindSuccess) {
- values.clear();
- values.put(LauncherProvider.ITEM_TYPE, LauncherProvider.ITEM_TYPE_APPWIDGET);
- values.putNull(LauncherProvider.ICON);
- resolver.update(favoritesUri, values, null, null);
- } else {
- resolver.delete(favoritesUri, null, null);
- }
-
- }
- } catch (SQLException ex) {
- Log.w(TAG, "Problem while binding appWidgetIds for Launcher", ex);
- } finally {
- if (c != null) {
- c.close();
- }
- }
-
- if (foundPhotoAppWidgets) {
- // Convert appWidgetIds into int[]
- final int N = photoAppWidgetIds.size();
- final int[] photoAppWidgetIdsArray = new int[N];
- for (int i = 0; i < N; i++) {
- photoAppWidgetIdsArray[i] = photoAppWidgetIds.get(i);
- }
-
- // Launch intent over to handle bitmap binding, but we don't need to
- // wait around for the result.
- final Intent bindIntent = new Intent();
- bindIntent.setComponent(BIND_PHOTO_APPWIDGET);
-
- final Bundle bindExtras = new Bundle();
- bindExtras.putIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS, photoAppWidgetIdsArray);
- bindExtras.putParcelableArrayList(EXTRA_APPWIDGET_BITMAPS, photoBitmaps);
- bindIntent.putExtras(bindExtras);
-
- startActivity(bindIntent);
- }
-
- if (LOGD) Log.d(TAG, "completely finished with binding for Launcher");
- }
-
- /**
- * Build a query string that will match any row where the column matches
- * anything in the values list.
- */
- static String buildOrWhereString(String column, int[] values) {
- StringBuilder selectWhere = new StringBuilder();
- for (int i = values.length - 1; i >= 0; i--) {
- selectWhere.append(column).append("=").append(values[i]);
- if (i > 0) {
- selectWhere.append(" OR ");
- }
- }
- return selectWhere.toString();
- }
-
-}
diff --git a/src/com/android/settings/LocalePicker.java b/src/com/android/settings/LocalePicker.java
index d31e82c..dcd6141 100644
--- a/src/com/android/settings/LocalePicker.java
+++ b/src/com/android/settings/LocalePicker.java
@@ -19,7 +19,7 @@ package com.android.settings;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.ListActivity;
-import android.backup.BackupManager;
+import android.app.backup.BackupManager;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.RemoteException;
@@ -37,6 +37,7 @@ import java.util.Locale;
public class LocalePicker extends ListActivity {
private static final String TAG = "LocalePicker";
+ private static final boolean DEBUG = false;
Loc[] mLocales;
String[] mSpecialLocaleCodes;
@@ -90,8 +91,9 @@ public class LocalePicker extends ListActivity {
Locale l = new Locale(language, country);
if (finalSize == 0) {
- Log.v(TAG, "adding initial "+
- toTitleCase(l.getDisplayLanguage(l)));
+ if (DEBUG) {
+ Log.v(TAG, "adding initial "+ toTitleCase(l.getDisplayLanguage(l)));
+ }
preprocess[finalSize++] =
new Loc(toTitleCase(l.getDisplayLanguage(l)), l);
} else {
@@ -101,13 +103,16 @@ public class LocalePicker extends ListActivity {
// diff lang -> insert ours with lang-only name
if (preprocess[finalSize-1].locale.getLanguage().equals(
language)) {
- Log.v(TAG, "backing up and fixing "+
- preprocess[finalSize-1].label+" to "+
- getDisplayName(preprocess[finalSize-1].locale));
+ if (DEBUG) {
+ Log.v(TAG, "backing up and fixing "+
+ preprocess[finalSize-1].label+" to "+
+ getDisplayName(preprocess[finalSize-1].locale));
+ }
preprocess[finalSize-1].label = toTitleCase(
getDisplayName(preprocess[finalSize-1].locale));
- Log.v(TAG, " and adding "+
- toTitleCase(getDisplayName(l)));
+ if (DEBUG) {
+ Log.v(TAG, " and adding "+ toTitleCase(getDisplayName(l)));
+ }
preprocess[finalSize++] =
new Loc(toTitleCase(getDisplayName(l)), l);
} else {
@@ -117,7 +122,9 @@ public class LocalePicker extends ListActivity {
} else {
displayName = toTitleCase(l.getDisplayLanguage(l));
}
- Log.v(TAG, "adding "+displayName);
+ if (DEBUG) {
+ Log.v(TAG, "adding "+displayName);
+ }
preprocess[finalSize++] = new Loc(displayName, l);
}
}
diff --git a/src/com/android/settings/ManageApplications.java b/src/com/android/settings/ManageApplications.java
index 9cd6e23..dfff8c9 100644
--- a/src/com/android/settings/ManageApplications.java
+++ b/src/com/android/settings/ManageApplications.java
@@ -17,11 +17,11 @@
package com.android.settings;
import com.android.settings.R;
+
import android.app.ActivityManager;
-import android.app.AlertDialog;
import android.app.Dialog;
-import android.app.ListActivity;
import android.app.ProgressDialog;
+import android.app.TabActivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -42,7 +42,6 @@ import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.text.format.Formatter;
-import android.util.Config;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -56,6 +55,7 @@ import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.ListView;
+import android.widget.TabHost;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
@@ -81,42 +81,46 @@ import java.util.concurrent.CountDownLatch;
* options to uninstall/delete user data for system applications. This activity
* can be launched through Settings or via the ACTION_MANAGE_PACKAGE_STORAGE
* intent.
- * Initially a compute in progress message is displayed while the application retrieves
- * the list of application information from the PackageManager. The size information
- * for each package is refreshed to the screen. The resource(app description and
- * icon) information for each package is not available yet, so some default values for size
- * icon and descriptions are used initially. Later the resource information for each
- * application is retrieved and dynamically updated on the screen.
- * A Broadcast receiver registers for package additions or deletions when the activity is
- * in focus. If the user installs or deletes packages when the activity has focus, the receiver
- * gets notified and proceeds to add/delete these packages from the list on the screen.
- * This is an unlikely scenario but could happen. The entire list gets created every time
- * the activity's onStart gets invoked. This is to avoid having the receiver for the entire
- * life cycle of the application.
- * The applications can be sorted either alphabetically or
- * based on size(descending). If this activity gets launched under low memory
- * situations(A low memory notification dispatches intent
- * ACTION_MANAGE_PACKAGE_STORAGE) the list is sorted per size.
- * If the user selects an application, extended info(like size, uninstall/clear data options,
- * permissions info etc.,) is displayed via the InstalledAppDetails activity.
+ *
+ * Initially a compute in progress message is displayed while the application retrieves
+ * the list of application information from the PackageManager. The size information
+ * for each package is refreshed to the screen. The resource (app description and
+ * icon) information for each package is not available yet, so some default values for size
+ * icon and descriptions are used initially. Later the resource information for each
+ * application is retrieved and dynamically updated on the screen.
+ *
+ * A Broadcast receiver registers for package additions or deletions when the activity is
+ * in focus. If the user installs or deletes packages when the activity has focus, the receiver
+ * gets notified and proceeds to add/delete these packages from the list on the screen.
+ * This is an unlikely scenario but could happen. The entire list gets created every time
+ * the activity's onStart gets invoked. This is to avoid having the receiver for the entire
+ * life cycle of the application.
+ *
+ * The applications can be sorted either alphabetically or
+ * based on size (descending). If this activity gets launched under low memory
+ * situations (a low memory notification dispatches intent
+ * ACTION_MANAGE_PACKAGE_STORAGE) the list is sorted per size.
+ *
+ * If the user selects an application, extended info (like size, uninstall/clear data options,
+ * permissions info etc.,) is displayed via the InstalledAppDetails activity.
*/
-public class ManageApplications extends ListActivity implements
+public class ManageApplications extends TabActivity implements
OnItemClickListener, DialogInterface.OnCancelListener,
- DialogInterface.OnClickListener {
+ TabHost.TabContentFactory,
+ TabHost.OnTabChangeListener {
// TAG for this activity
private static final String TAG = "ManageApplications";
private static final String PREFS_NAME = "ManageAppsInfo.prefs";
private static final String PREF_DISABLE_CACHE = "disableCache";
// Log information boolean
- private boolean localLOGV = Config.LOGV || false;
+ private boolean localLOGV = false;
private static final boolean DEBUG_SIZE = false;
private static final boolean DEBUG_TIME = false;
// attributes used as keys when passing values to InstalledAppDetails activity
- public static final String APP_PKG_PREFIX = "com.android.settings.";
- public static final String APP_PKG_NAME = APP_PKG_PREFIX+"ApplicationPkgName";
- public static final String APP_CHG = APP_PKG_PREFIX+"changed";
+ public static final String APP_PKG_NAME = "pkg";
+ public static final String APP_CHG = "chg";
// attribute name used in receiver for tagging names of added/deleted packages
private static final String ATTR_PKG_NAME="p";
@@ -138,11 +142,10 @@ public class ManageApplications extends ListActivity implements
public static final int FILTER_APPS_ALL = MENU_OPTIONS_BASE + 0;
public static final int FILTER_APPS_RUNNING = MENU_OPTIONS_BASE + 1;
public static final int FILTER_APPS_THIRD_PARTY = MENU_OPTIONS_BASE + 2;
- public static final int FILTER_OPTIONS = MENU_OPTIONS_BASE + 3;
+ public static final int FILTER_APPS_SDCARD = MENU_OPTIONS_BASE + 3;
+
public static final int SORT_ORDER_ALPHA = MENU_OPTIONS_BASE + 4;
public static final int SORT_ORDER_SIZE = MENU_OPTIONS_BASE + 5;
- // Alert Dialog presented to user to find out the filter option
- private AlertDialog mAlertDlg;
// sort order
private int mSortOrder = SORT_ORDER_ALPHA;
// Filter value
@@ -174,7 +177,7 @@ public class ManageApplications extends ListActivity implements
private PackageIntentReceiver mReceiver;
// atomic variable used to track if computing pkg sizes is in progress. should be volatile?
- private boolean mComputeSizes = false;
+ private boolean mComputeSizesFinished = false;
// default icon thats used when displaying applications initially before resource info is
// retrieved
private static Drawable mDefaultAppIcon;
@@ -207,13 +210,13 @@ public class ManageApplications extends ListActivity implements
ResourceLoaderThread mResourceThread;
private TaskRunner mSizeComputor;
- String mCurrentPkgName;
+ private String mCurrentPkgName;
// Cache application attributes
private AppInfoCache mCache = new AppInfoCache();
// Boolean variables indicating state
- private boolean mLoadLabels = false;
+ private boolean mLoadLabelsFinished = false;
private boolean mSizesFirst = false;
// ListView used to display list
private ListView mListView;
@@ -225,33 +228,38 @@ public class ManageApplications extends ListActivity implements
private boolean mSetListViewLater = true;
/*
- * Handler class to handle messages for various operations
+ * Handler class to handle messages for various operations.
* Most of the operations that effect Application related data
* are posted as messages to the handler to avoid synchronization
* when accessing these structures.
+ *
* When the size retrieval gets kicked off for the first time, a COMPUTE_PKG_SIZE_START
- * message is posted to the handler which invokes the getSizeInfo for the pkg at index 0
+ * message is posted to the handler which invokes the getSizeInfo for the pkg at index 0.
+ *
* When the PackageManager's asynchronous call back through
* PkgSizeObserver.onGetStatsCompleted gets invoked, the application resources like
- * label, description, icon etc., is loaded in the same thread and these values are
- * set on the observer. The observer then posts a COMPUTE_PKG_SIZE_DONE message
- * to the handler. This information is updated on the AppInfoAdapter associated with
+ * label, description, icon etc., are loaded in the same thread and these values are
+ * set on the observer. The observer then posts a COMPUTE_PKG_SIZE_DONE message
+ * to the handler. This information is updated on the AppInfoAdapter associated with
* the list view of this activity and size info retrieval is initiated for the next package as
- * indicated by mComputeIndex
+ * indicated by mComputeIndex.
+ *
* When a package gets added while the activity has focus, the PkgSizeObserver posts
* ADD_PKG_START message to the handler. If the computation is not in progress, the size
* is retrieved for the newly added package through the observer object and the newly
- * installed app info is updated on the screen. If the computation is still in progress
+ * installed app info is updated on the screen. If the computation is still in progress
* the package is added to an internal structure and action deferred till the computation
- * is done for all the packages.
+ * is done for all the packages.
+ *
* When a package gets deleted, REMOVE_PKG is posted to the handler
- * if computation is not in progress(as indicated by
- * mDoneIniting), the package is deleted from the displayed list of apps. If computation is
+ * if computation is not in progress (as indicated by
+ * mDoneIniting), the package is deleted from the displayed list of apps. If computation is
* still in progress the package is added to an internal structure and action deferred till
* the computation is done for all packages.
+ *
* When the sizes of all packages is computed, the newly
* added or removed packages are processed in order.
- * If the user changes the order in which these applications are viewed by hitting the
+ * If the user changes the order in which these applications are viewed by hitting the
* menu key, REORDER_LIST message is posted to the handler. this sorts the list
* of items based on the sort order.
*/
@@ -293,8 +301,8 @@ public class ManageApplications extends ListActivity implements
}
mAppInfoAdapter.bulkUpdateSizes(pkgs, sizes, formatted);
break;
- case COMPUTE_END :
- mComputeSizes = true;
+ case COMPUTE_END:
+ mComputeSizesFinished = true;
mFirst = true;
mHandler.sendEmptyMessage(NEXT_LOAD_STEP);
break;
@@ -304,7 +312,7 @@ public class ManageApplications extends ListActivity implements
Log.w(TAG, "Ignoring message:REMOVE_PKG for null pkgName");
break;
}
- if (!mComputeSizes) {
+ if (!mComputeSizesFinished) {
Boolean currB = mAddRemoveMap.get(pkgName);
if (currB == null || (currB.equals(Boolean.TRUE))) {
mAddRemoveMap.put(pkgName, Boolean.FALSE);
@@ -344,7 +352,7 @@ public class ManageApplications extends ListActivity implements
Log.w(TAG, "Ignoring message:ADD_PKG_START for null pkgName");
break;
}
- if (!mComputeSizes || !mLoadLabels) {
+ if (!mComputeSizesFinished || !mLoadLabelsFinished) {
Boolean currB = mAddRemoveMap.get(pkgName);
if (currB == null || (currB.equals(Boolean.FALSE))) {
mAddRemoveMap.put(pkgName, Boolean.TRUE);
@@ -389,7 +397,7 @@ public class ManageApplications extends ListActivity implements
}
break;
case REFRESH_DONE:
- mLoadLabels = true;
+ mLoadLabelsFinished = true;
mHandler.sendEmptyMessage(NEXT_LOAD_STEP);
break;
case NEXT_LOAD_STEP:
@@ -399,7 +407,7 @@ public class ManageApplications extends ListActivity implements
mSetListViewLater = false;
mFirst = true;
}
- if (mComputeSizes && mLoadLabels) {
+ if (mComputeSizesFinished && mLoadLabelsFinished) {
doneLoadingData();
// Check for added/removed packages
Set<String> keys = mAddRemoveMap.keySet();
@@ -413,7 +421,7 @@ public class ManageApplications extends ListActivity implements
}
}
mAddRemoveMap.clear();
- } else if (!mComputeSizes && !mLoadLabels) {
+ } else if (!mComputeSizesFinished && !mLoadLabelsFinished) {
// Either load the package labels or initiate get size info
if (mSizesFirst) {
initComputeSizes();
@@ -426,9 +434,9 @@ public class ManageApplications extends ListActivity implements
initListView();
mSetListViewLater = false;
}
- if (!mComputeSizes) {
+ if (!mComputeSizesFinished) {
initComputeSizes();
- } else if (!mLoadLabels) {
+ } else if (!mLoadLabelsFinished) {
initResourceThread();
}
}
@@ -612,7 +620,16 @@ public class ManageApplications extends ListActivity implements
if (installedAppList == null) {
return new ArrayList<ApplicationInfo> ();
}
- if (filterOption == FILTER_APPS_THIRD_PARTY) {
+ if (filterOption == FILTER_APPS_SDCARD) {
+ List<ApplicationInfo> appList =new ArrayList<ApplicationInfo> ();
+ for (ApplicationInfo appInfo : installedAppList) {
+ if ((appInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+ // App on sdcard
+ appList.add(appInfo);
+ }
+ }
+ return appList;
+ } else if (filterOption == FILTER_APPS_THIRD_PARTY) {
List<ApplicationInfo> appList =new ArrayList<ApplicationInfo> ();
for (ApplicationInfo appInfo : installedAppList) {
boolean flag = false;
@@ -680,7 +697,21 @@ public class ManageApplications extends ListActivity implements
if(pAppList == null) {
return retList;
}
- if (filterOption == FILTER_APPS_THIRD_PARTY) {
+ if (filterOption == FILTER_APPS_SDCARD) {
+ for (ApplicationInfo appInfo : pAppList) {
+ boolean flag = false;
+ if ((appInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+ // App on sdcard
+ flag = true;
+ }
+ if (flag) {
+ if (matchFilter(filter, filterMap, appInfo.packageName)) {
+ retList.add(appInfo);
+ }
+ }
+ }
+ return retList;
+ } else if (filterOption == FILTER_APPS_THIRD_PARTY) {
for (ApplicationInfo appInfo : pAppList) {
boolean flag = false;
if ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
@@ -740,8 +771,8 @@ public class ManageApplications extends ListActivity implements
// Some initialization code used when kicking off the size computation
private void initAppList(List<ApplicationInfo> appList, int filterOption) {
setProgressBarIndeterminateVisibility(true);
- mComputeSizes = false;
- mLoadLabels = false;
+ mComputeSizesFinished = false;
+ mLoadLabelsFinished = false;
// Initialize lists
mAddRemoveMap = new TreeMap<String, Boolean>();
mAppInfoAdapter.initMapFromList(appList, filterOption);
@@ -769,7 +800,7 @@ public class ManageApplications extends ListActivity implements
if ((appList != null) && (appList.size()) > 0) {
mSizeComputor = new TaskRunner(appList);
} else {
- mComputeSizes = true;
+ mComputeSizesFinished = true;
}
}
@@ -862,8 +893,8 @@ public class ManageApplications extends ListActivity implements
static private class AppInfo {
public String pkgName;
int index;
- public CharSequence appName;
- public Drawable appIcon;
+ public CharSequence appName;
+ public Drawable appIcon;
public CharSequence appSize;
long size;
@@ -1085,7 +1116,7 @@ public class ManageApplications extends ListActivity implements
Log.w(TAG, "Invalid view position:"+position+", actual size is:"+mAppLocalList.size());
return null;
}
- // A ViewHolder keeps references to children views to avoid unneccessary calls
+ // A ViewHolder keeps references to children views to avoid unnecessary calls
// to findViewById() on each row.
AppViewHolder holder;
@@ -1243,6 +1274,10 @@ public class ManageApplications extends ListActivity implements
} else if ((info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
return true;
}
+ } else if (filterOption == FILTER_APPS_SDCARD) {
+ if ((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+ return true;
+ }
} else {
return true;
}
@@ -1529,20 +1564,42 @@ public class ManageApplications extends ListActivity implements
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
ManageApplications.this.registerReceiver(this, filter);
+ // Register for events related to sdcard installation.
+ IntentFilter sdFilter = new IntentFilter();
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ ManageApplications.this.registerReceiver(this, sdFilter);
+ }
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String actionStr = intent.getAction();
+ if (Intent.ACTION_PACKAGE_ADDED.equals(actionStr) ||
+ Intent.ACTION_PACKAGE_REMOVED.equals(actionStr)) {
+ Uri data = intent.getData();
+ String pkgName = data.getEncodedSchemeSpecificPart();
+ updatePackageList(actionStr, pkgName);
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(actionStr) ||
+ Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(actionStr)) {
+ // When applications become available or unavailable (perhaps because
+ // the SD card was inserted or ejected) we need to refresh the
+ // AppInfo with new label, icon and size information as appropriate
+ // given the newfound (un)availability of the application.
+ // A simple way to do that is to treat the refresh as a package
+ // removal followed by a package addition.
+ String pkgList[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ if (pkgList == null || pkgList.length == 0) {
+ // Ignore
+ return;
+ }
+ for (String pkgName : pkgList) {
+ updatePackageList(Intent.ACTION_PACKAGE_REMOVED, pkgName);
+ updatePackageList(Intent.ACTION_PACKAGE_ADDED, pkgName);
+ }
+ }
}
- @Override
- public void onReceive(Context context, Intent intent) {
- String actionStr = intent.getAction();
- Uri data = intent.getData();
- String pkgName = data.getEncodedSchemeSpecificPart();
- if (localLOGV) Log.i(TAG, "action:"+actionStr+", for package:"+pkgName);
- updatePackageList(actionStr, pkgName);
- }
}
-
+
private void updatePackageList(String actionStr, String pkgName) {
- // technically we dont have to invoke handler since onReceive is invoked on
- // the main thread but doing it here for better clarity
if (Intent.ACTION_PACKAGE_ADDED.equalsIgnoreCase(actionStr)) {
Bundle data = new Bundle();
data.putString(ATTR_PKG_NAME, pkgName);
@@ -1554,6 +1611,11 @@ public class ManageApplications extends ListActivity implements
}
}
+ static final String TAB_DOWNLOADED = "Downloaded";
+ static final String TAB_RUNNING = "Running";
+ static final String TAB_ALL = "All";
+ static final String TAB_SDCARD = "OnSdCard";
+ private View mRootView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -1564,9 +1626,11 @@ public class ManageApplications extends ListActivity implements
}
Intent intent = getIntent();
String action = intent.getAction();
+ String defaultTabTag = TAB_DOWNLOADED;
if (action.equals(Intent.ACTION_MANAGE_PACKAGE_STORAGE)) {
mSortOrder = SORT_ORDER_SIZE;
mFilterApps = FILTER_APPS_ALL;
+ defaultTabTag = TAB_ALL;
mSizesFirst = true;
}
mPm = getPackageManager();
@@ -1574,20 +1638,20 @@ public class ManageApplications extends ListActivity implements
requestWindowFeature(Window.FEATURE_RIGHT_ICON);
requestWindowFeature(Window.FEATURE_PROGRESS);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setContentView(R.layout.compute_sizes);
showLoadingMsg();
- mDefaultAppIcon =Resources.getSystem().getDrawable(
+ mDefaultAppIcon = Resources.getSystem().getDrawable(
com.android.internal.R.drawable.sym_def_app_icon);
mInvalidSizeStr = getText(R.string.invalid_size_value);
mComputingSizeStr = getText(R.string.computing_size);
// initialize the inflater
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mRootView = mInflater.inflate(R.layout.compute_sizes, null);
mReceiver = new PackageIntentReceiver();
mObserver = new PkgSizeObserver();
// Create adapter and list view here
- List<ApplicationInfo> appList = getInstalledApps(mSortOrder);
+ List<ApplicationInfo> appList = getInstalledApps(FILTER_APPS_ALL);
mAppInfoAdapter = new AppInfoAdapter(this, appList);
- ListView lv= (ListView) findViewById(android.R.id.list);
+ ListView lv = (ListView) mRootView.findViewById(android.R.id.list);
lv.setOnItemClickListener(this);
lv.setSaveEnabled(true);
lv.setItemsCanFocus(true);
@@ -1607,8 +1671,29 @@ public class ManageApplications extends ListActivity implements
if (DEBUG_TIME) {
Log.i(TAG, "Took " + (SystemClock.elapsedRealtime()-sStart) + " ms to init cache");
}
+
+ final TabHost tabHost = getTabHost();
+ tabHost.addTab(tabHost.newTabSpec(TAB_DOWNLOADED)
+ .setIndicator(getString(R.string.filter_apps_third_party),
+ getResources().getDrawable(R.drawable.ic_tab_download))
+ .setContent(this));
+ tabHost.addTab(tabHost.newTabSpec(TAB_RUNNING)
+ .setIndicator(getString(R.string.filter_apps_running),
+ getResources().getDrawable(R.drawable.ic_tab_running))
+ .setContent(this));
+ tabHost.addTab(tabHost.newTabSpec(TAB_ALL)
+ .setIndicator(getString(R.string.filter_apps_all),
+ getResources().getDrawable(R.drawable.ic_tab_all))
+ .setContent(this));
+ tabHost.addTab(tabHost.newTabSpec(TAB_SDCARD)
+ .setIndicator(getString(R.string.filter_apps_onsdcard),
+ getResources().getDrawable(R.drawable.ic_tab_sdcard))
+ .setContent(this));
+ tabHost.setCurrentTabByTag(defaultTabTag);
+ tabHost.setOnTabChangedListener(this);
}
+ @Override
protected void onDestroy() {
// Persist values in cache
mCache.updateCache();
@@ -1616,7 +1701,7 @@ public class ManageApplications extends ListActivity implements
}
@Override
- public Dialog onCreateDialog(int id) {
+ public Dialog onCreateDialog(int id, Bundle args) {
if (id == DLG_LOADING) {
ProgressDialog dlg = new ProgressDialog(this);
dlg.setProgressStyle(ProgressDialog.STYLE_SPINNER);
@@ -1700,7 +1785,7 @@ public class ManageApplications extends ListActivity implements
err = true;
break;
}
- // Buffer length cannot be great then max.
+ // Buffer length cannot be greater than max.
fis.read(byteBuff, 0, buffLen);
String buffStr = new String(byteBuff);
if (DEBUG_CACHE) {
@@ -1922,8 +2007,6 @@ public class ManageApplications extends ListActivity implements
.setIcon(android.R.drawable.ic_menu_sort_alphabetically);
menu.add(0, SORT_ORDER_SIZE, 2, R.string.sort_order_size)
.setIcon(android.R.drawable.ic_menu_sort_by_size);
- menu.add(0, FILTER_OPTIONS, 3, R.string.filter)
- .setIcon(R.drawable.ic_menu_filter_settings);
return true;
}
@@ -1932,7 +2015,6 @@ public class ManageApplications extends ListActivity implements
if (mFirst) {
menu.findItem(SORT_ORDER_ALPHA).setVisible(mSortOrder != SORT_ORDER_ALPHA);
menu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder != SORT_ORDER_SIZE);
- menu.findItem(FILTER_OPTIONS).setVisible(true);
return true;
}
return false;
@@ -1943,20 +2025,6 @@ public class ManageApplications extends ListActivity implements
int menuId = item.getItemId();
if ((menuId == SORT_ORDER_ALPHA) || (menuId == SORT_ORDER_SIZE)) {
sendMessageToHandler(REORDER_LIST, menuId);
- } else if (menuId == FILTER_OPTIONS) {
- // Pick up the selection value from the list of added choice items.
- int selection = mFilterApps - MENU_OPTIONS_BASE;
- if (mAlertDlg == null) {
- mAlertDlg = new AlertDialog.Builder(this).
- setTitle(R.string.filter_dlg_title).
- setNeutralButton(R.string.cancel, this).
- setSingleChoiceItems(new CharSequence[] {getText(R.string.filter_apps_all),
- getText(R.string.filter_apps_running),
- getText(R.string.filter_apps_third_party)},
- selection, this).
- create();
- }
- mAlertDlg.show();
}
return true;
}
@@ -1973,22 +2041,41 @@ public class ManageApplications extends ListActivity implements
finish();
}
- public void onClick(DialogInterface dialog, int which) {
+ public View createTabContent(String tag) {
+ return mRootView;
+ }
+
+ public void onTabChanged(String tabId) {
int newOption;
- switch (which) {
- // Make sure that values of 0, 1, 2 match options all, running, third_party when
- // created via the AlertDialog.Builder
- case FILTER_APPS_ALL:
- break;
- case FILTER_APPS_RUNNING:
- break;
- case FILTER_APPS_THIRD_PARTY:
- break;
- default:
+ if (TAB_DOWNLOADED.equalsIgnoreCase(tabId)) {
+ newOption = FILTER_APPS_THIRD_PARTY;
+ } else if (TAB_RUNNING.equalsIgnoreCase(tabId)) {
+ newOption = FILTER_APPS_RUNNING;
+ } else if (TAB_ALL.equalsIgnoreCase(tabId)) {
+ newOption = FILTER_APPS_ALL;
+ } else if (TAB_SDCARD.equalsIgnoreCase(tabId)) {
+ newOption = FILTER_APPS_SDCARD;
+ } else {
+ // Invalid option. Do nothing
return;
}
- newOption = which;
- mAlertDlg.dismiss();
sendMessageToHandler(REORDER_LIST, newOption);
}
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+ if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) {
+ // Refresh package attributes
+ try {
+ ApplicationInfo info = mPm.getApplicationInfo(mCurrentPkgName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ } catch (NameNotFoundException e) {
+ Bundle rData = new Bundle();
+ rData.putString(ATTR_PKG_NAME, mCurrentPkgName);
+ sendMessageToHandler(REMOVE_PKG, rData);
+ mCurrentPkgName = null;
+ }
+ }
+ }
}
diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java
index fd4a411..4de0e44 100644
--- a/src/com/android/settings/MasterClear.java
+++ b/src/com/android/settings/MasterClear.java
@@ -23,7 +23,6 @@ import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-import android.os.ICheckinService;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.text.TextUtils;
@@ -53,59 +52,33 @@ public class MasterClear extends Activity {
private View mFinalView;
private Button mFinalButton;
- /**
+ /**
* The user has gone through the multiple confirmation, so now we go ahead
* and invoke the Checkin Service to reset the device to its factory-default
* state (rebooting in the process).
*/
private Button.OnClickListener mFinalClickListener = new Button.OnClickListener() {
public void onClick(View v) {
-
if (Utils.isMonkeyRunning()) {
return;
}
- ICheckinService service =
- ICheckinService.Stub.asInterface(ServiceManager.getService("checkin"));
- if (service != null) {
- try {
- // This RPC should never return
- service.masterClear();
- } catch (android.os.RemoteException e) {
- // Intentionally blank - there's nothing we can do here
- Log.w("MasterClear", "Unable to invoke ICheckinService.masterClear()");
- }
- } else {
- Log.w("MasterClear", "Unable to locate ICheckinService");
- }
-
- /* If we reach this point, the master clear didn't happen -- the
- * service might have been unregistered with the ServiceManager,
- * the RPC might have thrown an exception, or for some reason
- * the implementation of masterClear() may have returned instead
- * of resetting the device.
- */
- new AlertDialog.Builder(MasterClear.this)
- .setMessage(getText(R.string.master_clear_failed))
- .setPositiveButton(getText(android.R.string.ok), null)
- .show();
+ sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
+ // Intent handling is asynchronous -- assume it will happen soon.
}
};
/**
- * Keyguard validation is run using the standard {@link ConfirmLockPattern}
+ * Keyguard validation is run using the standard {@link ConfirmLockPattern}
* component as a subactivity
+ * @param request the request code to be returned once confirmation finishes
+ * @return true if confirmation launched
*/
- private void runKeyguardConfirmation() {
- final Intent intent = new Intent();
- intent.setClassName("com.android.settings",
- "com.android.settings.ConfirmLockPattern");
- // supply header and footer text in the intent
- intent.putExtra(ConfirmLockPattern.HEADER_TEXT,
- getText(R.string.master_clear_gesture_prompt));
- intent.putExtra(ConfirmLockPattern.FOOTER_TEXT,
- getText(R.string.master_clear_gesture_explanation));
- startActivityForResult(intent, KEYGUARD_REQUEST);
+ private boolean runKeyguardConfirmation(int request) {
+ return new ChooseLockSettingsHelper(this)
+ .launchConfirmationActivity(request,
+ getText(R.string.master_clear_gesture_prompt),
+ getText(R.string.master_clear_gesture_explanation));
}
@Override
@@ -120,6 +93,8 @@ public class MasterClear extends Activity {
// confirmation prompt; otherwise, go back to the initial state.
if (resultCode == Activity.RESULT_OK) {
establishFinalConfirmationState();
+ } else if (resultCode == Activity.RESULT_CANCELED) {
+ finish();
} else {
establishInitialState();
}
@@ -132,9 +107,7 @@ public class MasterClear extends Activity {
*/
private Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
public void onClick(View v) {
- if (mLockUtils.isLockPatternEnabled()) {
- runKeyguardConfirmation();
- } else {
+ if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
establishFinalConfirmationState();
}
}
@@ -159,7 +132,7 @@ public class MasterClear extends Activity {
* click in order to initiate a confirmation sequence. This method is
* called from various other points in the code to reset the activity to
* this base state.
- *
+ *
* <p>Reinflating views from resources is expensive and prevents us from
* caching widget pointers, so we use a single-inflate pattern: we lazy-
* inflate each view, caching all of the widget pointers we'll need at the
@@ -184,7 +157,7 @@ public class MasterClear extends Activity {
mInitialView = null;
mFinalView = null;
mInflater = LayoutInflater.from(this);
- mLockUtils = new LockPatternUtils(getContentResolver());
+ mLockUtils = new LockPatternUtils(this);
establishInitialState();
}
diff --git a/src/com/android/settings/MediaFormat.java b/src/com/android/settings/MediaFormat.java
index e0d9af6..b78ff62 100644
--- a/src/com/android/settings/MediaFormat.java
+++ b/src/com/android/settings/MediaFormat.java
@@ -23,7 +23,7 @@ import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-import android.os.IMountService;
+import android.os.storage.IMountService;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.Environment;
@@ -64,15 +64,19 @@ public class MediaFormat extends Activity {
if (Utils.isMonkeyRunning()) {
return;
}
- IMountService service =
+ final IMountService service =
IMountService.Stub.asInterface(ServiceManager.getService("mount"));
if (service != null) {
- try {
- service.formatMedia(Environment.getExternalStorageDirectory().toString());
- } catch (android.os.RemoteException e) {
- // Intentionally blank - there's nothing we can do here
- Log.w("MediaFormat", "Unable to invoke IMountService.formatMedia()");
- }
+ new Thread() {
+ public void run() {
+ try {
+ service.formatVolume(Environment.getExternalStorageDirectory().toString());
+ } catch (Exception e) {
+ // Intentionally blank - there's nothing we can do here
+ Log.w("MediaFormat", "Unable to invoke IMountService.formatMedia()");
+ }
+ }
+ }.start();
} else {
Log.w("MediaFormat", "Unable to locate IMountService");
}
@@ -84,16 +88,11 @@ public class MediaFormat extends Activity {
* Keyguard validation is run using the standard {@link ConfirmLockPattern}
* component as a subactivity
*/
- private void runKeyguardConfirmation() {
- final Intent intent = new Intent();
- intent.setClassName("com.android.settings",
- "com.android.settings.ConfirmLockPattern");
- // supply header and footer text in the intent
- intent.putExtra(ConfirmLockPattern.HEADER_TEXT,
- getText(R.string.media_format_gesture_prompt));
- intent.putExtra(ConfirmLockPattern.FOOTER_TEXT,
- getText(R.string.media_format_gesture_explanation));
- startActivityForResult(intent, KEYGUARD_REQUEST);
+ private boolean runKeyguardConfirmation(int request) {
+ return new ChooseLockSettingsHelper(this)
+ .launchConfirmationActivity(request,
+ getText(R.string.media_format_gesture_prompt),
+ getText(R.string.media_format_gesture_explanation));
}
@Override
@@ -108,6 +107,8 @@ public class MediaFormat extends Activity {
// confirmation prompt; otherwise, go back to the initial state.
if (resultCode == Activity.RESULT_OK) {
establishFinalConfirmationState();
+ } else if (resultCode == Activity.RESULT_CANCELED) {
+ finish();
} else {
establishInitialState();
}
@@ -120,9 +121,7 @@ public class MediaFormat extends Activity {
*/
private Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
public void onClick(View v) {
- if (mLockUtils.isLockPatternEnabled()) {
- runKeyguardConfirmation();
- } else {
+ if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
establishFinalConfirmationState();
}
}
@@ -147,7 +146,7 @@ public class MediaFormat extends Activity {
* click in order to initiate a confirmation sequence. This method is
* called from various other points in the code to reset the activity to
* this base state.
- *
+ *
* <p>Reinflating views from resources is expensive and prevents us from
* caching widget pointers, so we use a single-inflate pattern: we lazy-
* inflate each view, caching all of the widget pointers we'll need at the
@@ -172,7 +171,7 @@ public class MediaFormat extends Activity {
mInitialView = null;
mFinalView = null;
mInflater = LayoutInflater.from(this);
- mLockUtils = new LockPatternUtils(getContentResolver());
+ mLockUtils = new LockPatternUtils(this);
establishInitialState();
}
diff --git a/src/com/android/settings/PrivacySettings.java b/src/com/android/settings/PrivacySettings.java
index 2edb328..29deacf 100644
--- a/src/com/android/settings/PrivacySettings.java
+++ b/src/com/android/settings/PrivacySettings.java
@@ -18,7 +18,7 @@ package com.android.settings;
import android.app.AlertDialog;
import android.app.Dialog;
-import android.backup.IBackupManager;
+import android.app.backup.IBackupManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
@@ -39,24 +39,17 @@ import android.widget.TextView;
* Gesture lock pattern settings.
*/
public class PrivacySettings extends PreferenceActivity implements
- DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
-
- private static final String PREFS_NAME = "location_prefs";
- private static final String PREFS_USE_LOCATION = "use_location";
+ DialogInterface.OnClickListener {
// Vendor specific
- private static final String GSETTINGS_PROVIDER = "com.google.android.providers.settings";
- private static final String LOCATION_CATEGORY = "location_category";
- private static final String SETTINGS_CATEGORY = "settings_category";
- private static final String USE_LOCATION = "use_location";
- private static final String BACKUP_SETTINGS = "backup_settings";
- private static final String KEY_DONE_USE_LOCATION = "doneLocation";
- private CheckBoxPreference mUseLocation;
+ private static final String GSETTINGS_PROVIDER = "com.google.settings";
+ private static final String BACKUP_CATEGORY = "backup_category";
+ private static final String BACKUP_DATA = "backup_data";
+ private static final String AUTO_RESTORE = "auto_restore";
private CheckBoxPreference mBackup;
- private boolean mOkClicked;
+ private CheckBoxPreference mAutoRestore;
private Dialog mConfirmDialog;
- private static final int DIALOG_USE_LOCATION = 1;
private static final int DIALOG_ERASE_BACKUP = 2;
private int mDialogType;
@@ -64,27 +57,16 @@ public class PrivacySettings extends PreferenceActivity implements
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.privacy_settings);
+ final PreferenceScreen screen = getPreferenceScreen();
- mUseLocation = (CheckBoxPreference) getPreferenceScreen().findPreference(USE_LOCATION);
- mBackup = (CheckBoxPreference) getPreferenceScreen().findPreference(BACKUP_SETTINGS);
+ mBackup = (CheckBoxPreference) screen.findPreference(BACKUP_DATA);
+ mAutoRestore = (CheckBoxPreference) screen.findPreference(AUTO_RESTORE);
// Vendor specific
- try {
- if (mUseLocation != null) {
- getPackageManager().getPackageInfo(GSETTINGS_PROVIDER, 0);
- }
- } catch (NameNotFoundException nnfe) {
- getPreferenceScreen().removePreference(findPreference(LOCATION_CATEGORY));
- getPreferenceScreen().removePreference(findPreference(SETTINGS_CATEGORY));
+ if (getPackageManager().resolveContentProvider(GSETTINGS_PROVIDER, 0) == null) {
+ screen.removePreference(findPreference(BACKUP_CATEGORY));
}
updateToggles();
-
- boolean doneUseLocation = savedInstanceState == null
- ? false : savedInstanceState.getBoolean(KEY_DONE_USE_LOCATION, true);
- if (!doneUseLocation && (getIntent().getBooleanExtra("SHOW_USE_LOCATION", false)
- || savedInstanceState != null)) {
- showUseLocationDialog(true);
- }
}
@Override
@@ -98,63 +80,32 @@ public class PrivacySettings extends PreferenceActivity implements
}
@Override
- public void onSaveInstanceState(Bundle icicle) {
- if (mConfirmDialog != null && mConfirmDialog.isShowing()
- && mDialogType == DIALOG_USE_LOCATION) {
- icicle.putBoolean(KEY_DONE_USE_LOCATION, false);
- }
- super.onSaveInstanceState(icicle);
- }
-
- @Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
- if (preference == mUseLocation) {
- //normally called on the toggle click
- if (mUseLocation.isChecked()) {
- showUseLocationDialog(false);
- } else {
- updateUseLocation();
- }
- } else if (preference == mBackup) {
+ if (preference == mBackup) {
if (!mBackup.isChecked()) {
showEraseBackupDialog();
} else {
setBackupEnabled(true);
}
+ } else if (preference == mAutoRestore) {
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ if (bm != null) {
+ // TODO: disable via the backup manager interface
+ boolean curState = mAutoRestore.isChecked();
+ try {
+ bm.setAutoRestore(curState);
+ } catch (RemoteException e) {
+ mAutoRestore.setChecked(!curState);
+ }
+ }
}
return false;
}
- private void showUseLocationDialog(boolean force) {
- // Show a warning to the user that location data will be shared
- mOkClicked = false;
- if (force) {
- mUseLocation.setChecked(true);
- }
-
- if (hasAgreedToUseLocation()) {
- updateUseLocation();
- return;
- }
-
- mDialogType = DIALOG_USE_LOCATION;
- CharSequence msg = getResources().getText(R.string.use_location_warning_message);
- mConfirmDialog = new AlertDialog.Builder(this).setMessage(msg)
- .setTitle(R.string.use_location_title)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setPositiveButton(R.string.agree, this)
- .setNegativeButton(R.string.disagree, this)
- .show();
- ((TextView)mConfirmDialog.findViewById(android.R.id.message))
- .setMovementMethod(LinkMovementMethod.getInstance());
- mConfirmDialog.setOnDismissListener(this);
- }
-
private void showEraseBackupDialog() {
- // Show a warning to the user that location data will be shared
- mOkClicked = false;
mBackup.setChecked(true);
mDialogType = DIALOG_ERASE_BACKUP;
@@ -165,7 +116,6 @@ public class PrivacySettings extends PreferenceActivity implements
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, this)
.show();
- mConfirmDialog.setOnDismissListener(this);
}
/*
@@ -173,72 +123,31 @@ public class PrivacySettings extends PreferenceActivity implements
*/
private void updateToggles() {
ContentResolver res = getContentResolver();
- mUseLocation.setChecked(Settings.Secure.getInt(res,
- Settings.Secure.USE_LOCATION_FOR_SERVICES, 2) == 1);
- mBackup.setChecked(Settings.Secure.getInt(res,
- Settings.Secure.BACKUP_ENABLED, 0) == 1);
- }
- private void updateUseLocation() {
- boolean use = mUseLocation.isChecked();
- Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.USE_LOCATION_FOR_SERVICES, use ? 1 : 0);
+ final boolean backupEnabled = Settings.Secure.getInt(res,
+ Settings.Secure.BACKUP_ENABLED, 0) == 1;
+ mBackup.setChecked(backupEnabled);
+
+ mAutoRestore.setChecked(Settings.Secure.getInt(res,
+ Settings.Secure.BACKUP_AUTO_RESTORE, 1) == 1);
+ mAutoRestore.setEnabled(backupEnabled);
}
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
//updateProviders();
- mOkClicked = true;
- if (mDialogType == DIALOG_USE_LOCATION) {
- setAgreedToUseLocation(true);
- } else if (mDialogType == DIALOG_ERASE_BACKUP) {
+ if (mDialogType == DIALOG_ERASE_BACKUP) {
setBackupEnabled(false);
}
} else {
- if (mDialogType == DIALOG_USE_LOCATION) {
- // Reset the toggle
- mUseLocation.setChecked(false);
- } else if (mDialogType == DIALOG_ERASE_BACKUP) {
+ if (mDialogType == DIALOG_ERASE_BACKUP) {
mBackup.setChecked(true);
+ mAutoRestore.setEnabled(true);
}
}
- updateUseLocation();
mDialogType = 0;
}
- public void onDismiss(DialogInterface dialog) {
- // Assuming that onClick gets called first
- if (!mOkClicked) {
- if (mDialogType == DIALOG_USE_LOCATION) {
- mUseLocation.setChecked(false);
- }
- }
- }
-
- /**
- * Checks if the user has agreed to the dialog in the past.
- */
- private boolean hasAgreedToUseLocation() {
- SharedPreferences sp = getSharedPreferences(PREFS_NAME, 0);
- if (sp == null) {
- return false;
- }
- return sp.getBoolean(PREFS_USE_LOCATION, false);
- }
-
- /**
- * Notes that the user has agreed to the dialog and won't need to be prompted in the
- * future.
- */
- private void setAgreedToUseLocation(boolean agreed) {
- if (agreed) {
- SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
- SharedPreferences.Editor editor = settings.edit();
- editor.putBoolean(PREFS_USE_LOCATION, true);
- editor.commit();
- }
- }
-
/**
* Informs the BackupManager of a change in backup state - if backup is disabled,
* the data on the server will be erased.
@@ -252,9 +161,11 @@ public class PrivacySettings extends PreferenceActivity implements
bm.setBackupEnabled(enable);
} catch (RemoteException e) {
mBackup.setChecked(!enable);
+ mAutoRestore.setEnabled(!enable);
return;
}
}
mBackup.setChecked(enable);
+ mAutoRestore.setEnabled(enable);
}
}
diff --git a/src/com/android/settings/RadioInfo.java b/src/com/android/settings/RadioInfo.java
index ce236fd..f0fcdd7 100644
--- a/src/com/android/settings/RadioInfo.java
+++ b/src/com/android/settings/RadioInfo.java
@@ -20,6 +20,8 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.net.Uri;
@@ -57,8 +59,7 @@ import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.PhoneStateIntentReceiver;
import com.android.internal.telephony.TelephonyProperties;
-import com.android.internal.telephony.gsm.GSMPhone;
-import com.android.internal.telephony.gsm.PdpConnection;
+import com.android.internal.telephony.gsm.GsmDataConnection;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
@@ -72,6 +73,8 @@ import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
+import android.util.Log;
+
public class RadioInfo extends Activity {
private final String TAG = "phone";
@@ -83,8 +86,6 @@ public class RadioInfo extends Activity {
private static final int EVENT_QUERY_PREFERRED_TYPE_DONE = 1000;
private static final int EVENT_SET_PREFERRED_TYPE_DONE = 1001;
private static final int EVENT_QUERY_NEIGHBORING_CIDS_DONE = 1002;
- private static final int EVENT_SET_QXDMLOG_DONE = 1003;
- private static final int EVENT_SET_CIPHER_DONE = 1004;
private static final int EVENT_QUERY_SMSC_DONE = 1005;
private static final int EVENT_UPDATE_SMSC_DONE = 1006;
@@ -94,7 +95,9 @@ public class RadioInfo extends Activity {
private static final int MENU_ITEM_VIEW_SDN = 3;
private static final int MENU_ITEM_GET_PDP_LIST = 4;
private static final int MENU_ITEM_TOGGLE_DATA = 5;
- private static final int MENU_ITEM_TOGGLE_DATA_ON_BOOT = 6;
+
+ static final String ENABLE_DATA_STR = "Enable data connection";
+ static final String DISABLE_DATA_STR = "Disable data connection";
private TextView mDeviceId; //DeviceId is the IMEI in GSM and the MEID in CDMA
private TextView number;
@@ -119,16 +122,14 @@ public class RadioInfo extends Activity {
private TextView mPingIpAddr;
private TextView mPingHostname;
private TextView mHttpClientTest;
- private TextView cipherState;
private TextView dnsCheckState;
private EditText smsc;
private Button radioPowerButton;
- private Button qxdmLogButton;
- private Button cipherToggleButton;
private Button dnsCheckToggleButton;
private Button pingTestButton;
private Button updateSmscButton;
private Button refreshSmscButton;
+ private Button oemInfoButton;
private Spinner preferredNetworkType;
private TelephonyManager mTelephonyManager;
@@ -136,11 +137,6 @@ public class RadioInfo extends Activity {
private PhoneStateIntentReceiver mPhoneStateReceiver;
private INetStatService netstat;
- private OemCommands mOem = null;
- private boolean mQxdmLogEnabled;
- // The requested cipher state
- private boolean mCipherOn;
-
private String mPingIpAddrResult;
private String mPingHostnameResult;
private String mHttpClientTestResult;
@@ -220,22 +216,6 @@ public class RadioInfo extends Activity {
mNeighboringCids.setText("unknown");
}
break;
- case EVENT_SET_QXDMLOG_DONE:
- ar= (AsyncResult) msg.obj;
- if (ar.exception == null) {
- mQxdmLogEnabled = !mQxdmLogEnabled;
-
- updateQxdmState(mQxdmLogEnabled);
- displayQxdmEnableResult();
- }
- break;
- case EVENT_SET_CIPHER_DONE:
- ar= (AsyncResult) msg.obj;
- if (ar.exception == null) {
- setCiphPref(mCipherOn);
- }
- updateCiphState();
- break;
case EVENT_QUERY_SMSC_DONE:
ar= (AsyncResult) msg.obj;
if (ar.exception != null) {
@@ -258,116 +238,6 @@ public class RadioInfo extends Activity {
}
};
- static private class OemCommands {
-
- public static final int OEM_QXDM_SDLOG_DEFAULT_FILE_SIZE = 32;
- public static final int OEM_QXDM_SDLOG_DEFAULT_MASK = 0;
- public static final int OEM_QXDM_SDLOG_DEFAULT_MAX_INDEX = 8;
-
- static final int SIZE_OF_INT = 4;
- static final int OEM_FEATURE_ENABLE = 1;
- static final int OEM_FEATURE_DISABLE = 0;
- static final int OEM_SIMPE_FEAUTURE_LEN = 1;
-
- static final int OEM_QXDM_SDLOG_FUNCTAG = 0x00010000;
- static final int OEM_QXDM_SDLOG_LEN = 4;
- static final int OEM_PS_AUTO_ATTACH_FUNCTAG = 0x00020000;
- static final int OEM_CIPHERING_FUNCTAG = 0x00020001;
-
- /**
- * The OEM interface to store QXDM to SD.
- *
- * To start/stop logging QXDM logs to SD card, use tag
- * OEM_RIL_HOOK_QXDM_SD_LOG_SETUP 0x00010000
- *
- * "data" is a const oem_ril_hook_qxdm_sdlog_setup_data_st *
- * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->head.func_tag
- * should be OEM_RIL_HOOK_QXDM_SD_LOG_SETUP
- * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->head.len
- * should be "sizeof(unsigned int) * 4"
- * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->mode
- * could be 0 for 'stop logging', or 1 for 'start logging'
- * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->log_file_size
- * will assign the size of each log file, and it could be a value between
- * 1 and 512 (in megabytes, default value is recommended to set as 32).
- * This value will be ignored when mode == 0.
- * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->log_mask will
- * assign the rule to filter logs, and it is a bitmask (bit0 is for MsgAll,
- * bit1 is for LogAll, and bit2 is for EventAll) recommended to be set as 0
- * by default. This value will be ignored when mode == 0.
- * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->log_max_fileindex
- * set the how many logfiles will storted before roll over. This value will
- * be ignored when mode == 0.
- *
- * "response" is NULL
- *
- * typedef struct _oem_ril_hook_raw_head_st {
- * unsigned int func_tag;
- * unsigned int len;
- * } oem_ril_hook_raw_head_st;
- *
- * typedef struct _oem_ril_hook_qxdm_sdlog_setup_data_st {
- * oem_ril_hook_raw_head_st head;
- * unsigned int mode;
- * unsigned int log_file_size;
- * unsigned int log_mask;
- * unsigned int log_max_fileindex;
- * } oem_ril_hook_qxdm_sdlog_setup_data_st;
- *
- * @param enable set true to start logging QXDM in SD card
- * @param fileSize is the log file size in MB
- * @param mask is the log mask to filter
- * @param maxIndex is the maximum roll-over file number
- * @return byteArray to use in RIL RAW command
- */
- byte[] getQxdmSdlogData(boolean enable, int fileSize, int mask, int maxIndex) {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(bos);
- try {
- writeIntLittleEndian(dos, OEM_QXDM_SDLOG_FUNCTAG);
- writeIntLittleEndian(dos, OEM_QXDM_SDLOG_LEN * SIZE_OF_INT);
- writeIntLittleEndian(dos, enable ?
- OEM_FEATURE_ENABLE : OEM_FEATURE_DISABLE);
- writeIntLittleEndian(dos, fileSize);
- writeIntLittleEndian(dos, mask);
- writeIntLittleEndian(dos, maxIndex);
- } catch (IOException e) {
- return null;
- }
- return bos.toByteArray();
- }
-
- byte[] getPsAutoAttachData(boolean enable) {
- return getSimpleFeatureData(OEM_PS_AUTO_ATTACH_FUNCTAG, enable);
- }
-
- byte[] getCipheringData(boolean enable) {
- return getSimpleFeatureData(OEM_CIPHERING_FUNCTAG, enable);
- }
-
- private byte[] getSimpleFeatureData(int tag, boolean enable) {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(bos);
- try {
- writeIntLittleEndian(dos, tag);
- writeIntLittleEndian(dos, OEM_SIMPE_FEAUTURE_LEN * SIZE_OF_INT);
- writeIntLittleEndian(dos, enable ?
- OEM_FEATURE_ENABLE : OEM_FEATURE_DISABLE);
- } catch (IOException e) {
- return null;
- }
- return bos.toByteArray();
- }
-
- private void writeIntLittleEndian(DataOutputStream dos, int val)
- throws IOException {
- dos.writeByte(val);
- dos.writeByte(val >> 8);
- dos.writeByte(val >> 16);
- dos.writeByte(val >> 24);
- }
- }
-
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -398,7 +268,6 @@ public class RadioInfo extends Activity {
sentSinceReceived = (TextView) findViewById(R.id.sentSinceReceived);
sent = (TextView) findViewById(R.id.sent);
received = (TextView) findViewById(R.id.received);
- cipherState = (TextView) findViewById(R.id.ciphState);
smsc = (EditText) findViewById(R.id.smsc);
dnsCheckState = (TextView) findViewById(R.id.dnsCheckState);
@@ -416,11 +285,6 @@ public class RadioInfo extends Activity {
radioPowerButton = (Button) findViewById(R.id.radio_power);
radioPowerButton.setOnClickListener(mPowerButtonHandler);
- qxdmLogButton = (Button) findViewById(R.id.qxdm_log);
- qxdmLogButton.setOnClickListener(mQxdmButtonHandler);
-
- cipherToggleButton = (Button) findViewById(R.id.ciph_toggle);
- cipherToggleButton.setOnClickListener(mCipherButtonHandler);
pingTestButton = (Button) findViewById(R.id.ping_test);
pingTestButton.setOnClickListener(mPingButtonHandler);
updateSmscButton = (Button) findViewById(R.id.update_smsc);
@@ -430,14 +294,20 @@ public class RadioInfo extends Activity {
dnsCheckToggleButton = (Button) findViewById(R.id.dns_check_toggle);
dnsCheckToggleButton.setOnClickListener(mDnsCheckButtonHandler);
+ oemInfoButton = (Button) findViewById(R.id.oem_info);
+ oemInfoButton.setOnClickListener(mOemInfoButtonHandler);
+ PackageManager pm = getPackageManager();
+ Intent oemInfoIntent = new Intent("com.android.settings.OEM_RADIO_INFO");
+ List<ResolveInfo> oemInfoIntentList = pm.queryIntentActivities(oemInfoIntent, 0);
+ if (oemInfoIntentList.size() == 0) {
+ oemInfoButton.setEnabled(false);
+ }
+
mPhoneStateReceiver = new PhoneStateIntentReceiver(this, mHandler);
mPhoneStateReceiver.notifySignalStrength(EVENT_SIGNAL_STRENGTH_CHANGED);
mPhoneStateReceiver.notifyServiceState(EVENT_SERVICE_STATE_CHANGED);
mPhoneStateReceiver.notifyPhoneCallState(EVENT_PHONE_STATE_CHANGED);
- updateQxdmState(null);
- mOem = new OemCommands();
-
phone.getPreferredNetworkType(
mHandler.obtainMessage(EVENT_QUERY_PREFERRED_TYPE_DONE));
phone.getNeighboringCids(
@@ -462,9 +332,7 @@ public class RadioInfo extends Activity {
updateDataStats();
updateDataStats2();
updatePowerState();
- updateQxdmState(null);
updateProperties();
- updateCiphState();
updateDnsCheckState();
Log.i(TAG, "[RadioInfo] onResume: register phone & data intents");
@@ -502,14 +370,10 @@ public class RadioInfo extends Activity {
menu.add(1, MENU_ITEM_GET_PDP_LIST,
0, R.string.radioInfo_menu_getPDP).setOnMenuItemClickListener(mGetPdpList);
menu.add(1, MENU_ITEM_TOGGLE_DATA,
- 0, R.string.radioInfo_menu_disableData).setOnMenuItemClickListener(mToggleData);
- menu.add(1, MENU_ITEM_TOGGLE_DATA_ON_BOOT,
- 0, R.string.radioInfo_menu_disableDataOnBoot).setOnMenuItemClickListener(
- mToggleDataOnBoot);
+ 0, DISABLE_DATA_STR).setOnMenuItemClickListener(mToggleData);
return true;
}
-
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Get the TOGGLE DATA menu item in the right state.
@@ -520,26 +384,16 @@ public class RadioInfo extends Activity {
switch (state) {
case TelephonyManager.DATA_CONNECTED:
case TelephonyManager.DATA_SUSPENDED:
- item.setTitle(R.string.radioInfo_menu_disableData);
+ item.setTitle(DISABLE_DATA_STR);
break;
case TelephonyManager.DATA_DISCONNECTED:
- item.setTitle(R.string.radioInfo_menu_enableData);
+ item.setTitle(ENABLE_DATA_STR);
break;
default:
visible = false;
break;
}
item.setVisible(visible);
-
- // Get the toggle-data-on-boot menu item in the right state.
- item = menu.findItem(MENU_ITEM_TOGGLE_DATA_ON_BOOT);
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- boolean value = sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false);
- if (value) {
- item.setTitle(R.string.radioInfo_menu_enableDataOnBoot);
- } else {
- item.setTitle(R.string.radioInfo_menu_disableDataOnBoot);
- }
return true;
}
@@ -554,42 +408,6 @@ public class RadioInfo extends Activity {
radioPowerButton.setText(buttonText);
}
- private void updateQxdmState(Boolean newQxdmStatus) {
- SharedPreferences sp =
- PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- mQxdmLogEnabled = sp.getBoolean("qxdmstatus", false);
- // This is called from onCreate, onResume, and the handler when the status
- // is updated.
- if (newQxdmStatus != null) {
- SharedPreferences.Editor editor = sp.edit();
- editor.putBoolean("qxdmstatus", newQxdmStatus);
- editor.commit();
- mQxdmLogEnabled = newQxdmStatus;
- }
-
- String buttonText = mQxdmLogEnabled ?
- getString(R.string.turn_off_qxdm) :
- getString(R.string.turn_on_qxdm);
- qxdmLogButton.setText(buttonText);
- }
-
- private void setCiphPref(boolean value) {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- SharedPreferences.Editor editor = sp.edit();
- editor.putBoolean(GSMPhone.CIPHERING_KEY, value);
- editor.commit();
- }
-
- private boolean getCiphPref() {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- boolean ret = sp.getBoolean(GSMPhone.CIPHERING_KEY, true);
- return ret;
- }
-
- private void updateCiphState() {
- cipherState.setText(getCiphPref() ? "Ciphering ON" : "Ciphering OFF");
- }
-
private void updateDnsCheckState() {
dnsCheckState.setText(phone.isDnsCheckDisabled() ?
"0.0.0.0 allowed" :"0.0.0.0 not allowed");
@@ -942,8 +760,8 @@ public class RadioInfo extends Activity {
List<DataConnection> dcs = phone.getCurrentDataConnectionList();
for (DataConnection dc : dcs) {
- sb.append(" State: ").append(dc.getState().toString()).append("\n");
- if (dc.getState().isActive()) {
+ sb.append(" State: ").append(dc.getStateAsString()).append("\n");
+ if (dc.isActive()) {
long timeElapsed =
(System.currentTimeMillis() - dc.getConnectionTime())/1000;
sb.append(" connected at ")
@@ -951,8 +769,8 @@ public class RadioInfo extends Activity {
.append(" and elapsed ")
.append(DateUtils.formatElapsedTime(timeElapsed));
- if (dc instanceof PdpConnection) {
- PdpConnection pdp = (PdpConnection)dc;
+ if (dc instanceof GsmDataConnection) {
+ GsmDataConnection pdp = (GsmDataConnection)dc;
sb.append("\n to ")
.append(pdp.getApn().toString());
}
@@ -966,14 +784,14 @@ public class RadioInfo extends Activity {
if (dns != null) {
sb.append("\ndns: ").append(dns[0]).append(", ").append(dns[1]);
}
- } else if (dc.getState().isInactive()) {
+ } else if (dc.isInactive()) {
sb.append(" disconnected with last try at ")
.append(DateUtils.timeString(dc.getLastFailTime()))
.append("\n fail because ")
.append(dc.getLastFailCause().toString());
} else {
- if (dc instanceof PdpConnection) {
- PdpConnection pdp = (PdpConnection)dc;
+ if (dc instanceof GsmDataConnection) {
+ GsmDataConnection pdp = (GsmDataConnection)dc;
sb.append(" is connecting to ")
.append(pdp.getApn().toString());
} else {
@@ -987,19 +805,6 @@ public class RadioInfo extends Activity {
disconnects.setText(sb.toString());
}
- private void displayQxdmEnableResult() {
- String status = mQxdmLogEnabled ? "Start QXDM Log" : "Stop QXDM Log";
-
- new AlertDialog.Builder(this).setMessage(status).show();
-
- mHandler.postDelayed(
- new Runnable() {
- public void run() {
- finish();
- }
- }, 2000);
- }
-
private MenuItem.OnMenuItemClickListener mViewADNCallback = new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
Intent intent = new Intent(Intent.ACTION_VIEW);
@@ -1046,24 +851,18 @@ public class RadioInfo extends Activity {
}
};
- private void toggleDataDisabledOnBoot() {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- SharedPreferences.Editor editor = sp.edit();
- boolean value = sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false);
- editor.putBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, !value);
- byte[] data = mOem.getPsAutoAttachData(value);
- if (data == null) {
- // don't commit
- return;
+ private MenuItem.OnMenuItemClickListener mGetPdpList = new MenuItem.OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ phone.getDataCallList(null);
+ return true;
}
+ };
- editor.commit();
- phone.invokeOemRilRequestRaw(data, null);
- }
-
- private MenuItem.OnMenuItemClickListener mToggleDataOnBoot = new MenuItem.OnMenuItemClickListener() {
+ private MenuItem.OnMenuItemClickListener mSelectBandCallback = new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
- toggleDataDisabledOnBoot();
+ Intent intent = new Intent();
+ intent.setClass(RadioInfo.this, BandMode.class);
+ startActivity(intent);
return true;
}
};
@@ -1086,22 +885,6 @@ public class RadioInfo extends Activity {
}
};
- private MenuItem.OnMenuItemClickListener mGetPdpList = new MenuItem.OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- phone.getDataCallList(null);
- return true;
- }
- };
-
- private MenuItem.OnMenuItemClickListener mSelectBandCallback = new MenuItem.OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- Intent intent = new Intent();
- intent.setClass(RadioInfo.this, BandMode.class);
- startActivity(intent);
- return true;
- }
- };
-
OnClickListener mPowerButtonHandler = new OnClickListener() {
public void onClick(View v) {
//log("toggle radio power: currently " + (isRadioOn()?"on":"off"));
@@ -1109,24 +892,23 @@ public class RadioInfo extends Activity {
}
};
- OnClickListener mCipherButtonHandler = new OnClickListener() {
+ OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
public void onClick(View v) {
- mCipherOn = !getCiphPref();
- byte[] data = mOem.getCipheringData(mCipherOn);
-
- if (data == null)
- return;
-
- cipherState.setText("Setting...");
- phone.invokeOemRilRequestRaw(data,
- mHandler.obtainMessage(EVENT_SET_CIPHER_DONE));
+ phone.disableDnsCheck(!phone.isDnsCheckDisabled());
+ updateDnsCheckState();
}
};
- OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
+ OnClickListener mOemInfoButtonHandler = new OnClickListener() {
public void onClick(View v) {
- phone.disableDnsCheck(!phone.isDnsCheckDisabled());
- updateDnsCheckState();
+ Intent intent = new Intent("com.android.settings.OEM_RADIO_INFO");
+ try {
+ startActivity(intent);
+ } catch (android.content.ActivityNotFoundException ex) {
+ Log.d(TAG, "OEM-specific Info/Settings Activity Not Found : " + ex);
+ // If the activity does not exist, there are no OEM
+ // settings, and so we can just do nothing...
+ }
}
};
@@ -1150,22 +932,6 @@ public class RadioInfo extends Activity {
}
};
- OnClickListener mQxdmButtonHandler = new OnClickListener() {
- public void onClick(View v) {
- byte[] data = mOem.getQxdmSdlogData(
- !mQxdmLogEnabled,
- mOem.OEM_QXDM_SDLOG_DEFAULT_FILE_SIZE,
- mOem.OEM_QXDM_SDLOG_DEFAULT_MASK,
- mOem.OEM_QXDM_SDLOG_DEFAULT_MAX_INDEX);
-
- if (data == null)
- return;
-
- phone.invokeOemRilRequestRaw(data,
- mHandler.obtainMessage(EVENT_SET_QXDMLOG_DONE));
- }
- };
-
AdapterView.OnItemSelectedListener
mPreferredNetworkHandler = new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView parent, View v, int pos, long id) {
diff --git a/src/com/android/settings/RingerVolumePreference.java b/src/com/android/settings/RingerVolumePreference.java
index 0d01965..3ecd819 100644
--- a/src/com/android/settings/RingerVolumePreference.java
+++ b/src/com/android/settings/RingerVolumePreference.java
@@ -39,35 +39,49 @@ public class RingerVolumePreference extends VolumePreference implements
private static final String TAG = "RingerVolumePreference";
private CheckBox mNotificationsUseRingVolumeCheckbox;
- private SeekBarVolumizer mNotificationSeekBarVolumizer;
+ private SeekBarVolumizer [] mSeekBarVolumizer;
+ private static final int[] SEEKBAR_ID = new int[] {
+ R.id.notification_volume_seekbar,
+ R.id.media_volume_seekbar,
+ R.id.alarm_volume_seekbar
+ };
+ private static final int[] SEEKBAR_TYPE = new int[] {
+ AudioManager.STREAM_NOTIFICATION,
+ AudioManager.STREAM_MUSIC,
+ AudioManager.STREAM_ALARM
+ };
+ //private SeekBarVolumizer mNotificationSeekBarVolumizer;
private TextView mNotificationVolumeTitle;
-
+
public RingerVolumePreference(Context context, AttributeSet attrs) {
super(context, attrs);
// The always visible seekbar is for ring volume
setStreamType(AudioManager.STREAM_RING);
-
+
setDialogLayoutResource(R.layout.preference_dialog_ringervolume);
+ setDialogIcon(R.drawable.ic_settings_sound);
+
+ mSeekBarVolumizer = new SeekBarVolumizer[SEEKBAR_ID.length];
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
-
+
+ for (int i = 0; i < SEEKBAR_ID.length; i++) {
+ SeekBar seekBar = (SeekBar) view.findViewById(SEEKBAR_ID[i]);
+ mSeekBarVolumizer[i] = new SeekBarVolumizer(getContext(), seekBar,
+ SEEKBAR_TYPE[i]);
+ }
+
+ mNotificationVolumeTitle = (TextView) view.findViewById(R.id.notification_volume_title);
mNotificationsUseRingVolumeCheckbox =
(CheckBox) view.findViewById(R.id.same_notification_volume);
mNotificationsUseRingVolumeCheckbox.setOnCheckedChangeListener(this);
mNotificationsUseRingVolumeCheckbox.setChecked(Settings.System.getInt(
getContext().getContentResolver(),
Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1);
-
- final SeekBar seekBar = (SeekBar) view.findViewById(R.id.notification_volume_seekbar);
- mNotificationSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar,
- AudioManager.STREAM_NOTIFICATION);
-
- mNotificationVolumeTitle = (TextView) view.findViewById(R.id.notification_volume_title);
-
setNotificationVolumeVisibility(!mNotificationsUseRingVolumeCheckbox.isChecked());
}
@@ -75,10 +89,11 @@ public class RingerVolumePreference extends VolumePreference implements
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
- if (!positiveResult && mNotificationSeekBarVolumizer != null) {
- mNotificationSeekBarVolumizer.revertVolume();
- }
-
+ if (!positiveResult) {
+ for (SeekBarVolumizer vol : mSeekBarVolumizer) {
+ if (vol != null) vol.revertVolume();
+ }
+ }
cleanup();
}
@@ -107,29 +122,30 @@ public class RingerVolumePreference extends VolumePreference implements
@Override
protected void onSampleStarting(SeekBarVolumizer volumizer) {
super.onSampleStarting(volumizer);
-
- if (mNotificationSeekBarVolumizer != null && volumizer != mNotificationSeekBarVolumizer) {
- mNotificationSeekBarVolumizer.stopSample();
+ for (SeekBarVolumizer vol : mSeekBarVolumizer) {
+ if (vol != null && vol != volumizer) vol.stopSample();
}
}
private void setNotificationVolumeVisibility(boolean visible) {
- if (mNotificationSeekBarVolumizer != null) {
- mNotificationSeekBarVolumizer.getSeekBar().setVisibility(
+ if (mSeekBarVolumizer[0] != null) {
+ mSeekBarVolumizer[0].getSeekBar().setVisibility(
visible ? View.VISIBLE : View.GONE);
- mNotificationVolumeTitle.setVisibility(visible ? View.VISIBLE : View.GONE);
}
+ mNotificationVolumeTitle.setVisibility(visible ? View.VISIBLE : View.GONE);
}
-
+
private void cleanup() {
- if (mNotificationSeekBarVolumizer != null) {
- Dialog dialog = getDialog();
- if (dialog != null && dialog.isShowing()) {
- // Stopped while dialog was showing, revert changes
- mNotificationSeekBarVolumizer.revertVolume();
+ for (int i = 0; i < SEEKBAR_ID.length; i++) {
+ if (mSeekBarVolumizer[i] != null) {
+ Dialog dialog = getDialog();
+ if (dialog != null && dialog.isShowing()) {
+ // Stopped while dialog was showing, revert changes
+ mSeekBarVolumizer[i].revertVolume();
+ }
+ mSeekBarVolumizer[i].stop();
+ mSeekBarVolumizer[i] = null;
}
- mNotificationSeekBarVolumizer.stop();
- mNotificationSeekBarVolumizer = null;
}
}
@@ -142,8 +158,12 @@ public class RingerVolumePreference extends VolumePreference implements
}
final SavedState myState = new SavedState(superState);
- if (mNotificationSeekBarVolumizer != null) {
- mNotificationSeekBarVolumizer.onSaveInstanceState(myState.getVolumeStore());
+ VolumeStore[] volumeStore = myState.getVolumeStore(SEEKBAR_ID.length);
+ for (int i = 0; i < SEEKBAR_ID.length; i++) {
+ SeekBarVolumizer vol = mSeekBarVolumizer[i];
+ if (vol != null) {
+ vol.onSaveInstanceState(volumeStore[i]);
+ }
}
return myState;
}
@@ -158,28 +178,44 @@ public class RingerVolumePreference extends VolumePreference implements
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
- if (mNotificationSeekBarVolumizer != null) {
- mNotificationSeekBarVolumizer.onRestoreInstanceState(myState.getVolumeStore());
+ VolumeStore[] volumeStore = myState.getVolumeStore(SEEKBAR_ID.length);
+ for (int i = 0; i < SEEKBAR_ID.length; i++) {
+ SeekBarVolumizer vol = mSeekBarVolumizer[i];
+ if (vol != null) {
+ vol.onRestoreInstanceState(volumeStore[i]);
+ }
}
}
private static class SavedState extends BaseSavedState {
- VolumeStore mVolumeStore = new VolumeStore();
+ VolumeStore [] mVolumeStore;
public SavedState(Parcel source) {
super(source);
- mVolumeStore.volume = source.readInt();
- mVolumeStore.originalVolume = source.readInt();
+ mVolumeStore = new VolumeStore[SEEKBAR_ID.length];
+ for (int i = 0; i < SEEKBAR_ID.length; i++) {
+ mVolumeStore[i] = new VolumeStore();
+ mVolumeStore[i].volume = source.readInt();
+ mVolumeStore[i].originalVolume = source.readInt();
+ }
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
- dest.writeInt(mVolumeStore.volume);
- dest.writeInt(mVolumeStore.originalVolume);
+ for (int i = 0; i < SEEKBAR_ID.length; i++) {
+ dest.writeInt(mVolumeStore[i].volume);
+ dest.writeInt(mVolumeStore[i].originalVolume);
+ }
}
- VolumeStore getVolumeStore() {
+ VolumeStore[] getVolumeStore(int count) {
+ if (mVolumeStore == null || mVolumeStore.length != count) {
+ mVolumeStore = new VolumeStore[count];
+ for (int i = 0; i < count; i++) {
+ mVolumeStore[i] = new VolumeStore();
+ }
+ }
return mVolumeStore;
}
diff --git a/src/com/android/settings/RunningServices.java b/src/com/android/settings/RunningServices.java
index 6c11ea0..e67adf0 100644
--- a/src/com/android/settings/RunningServices.java
+++ b/src/com/android/settings/RunningServices.java
@@ -35,9 +35,14 @@ import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -53,11 +58,14 @@ import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import java.io.FileInputStream;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -72,6 +80,7 @@ public class RunningServices extends ListActivity
static final int MSG_UPDATE_TIMES = 1;
static final int MSG_UPDATE_CONTENTS = 2;
+ static final int MSG_REFRESH_UI = 3;
static final long TIME_UPDATE_DELAY = 1000;
static final long CONTENTS_UPDATE_DELAY = 2000;
@@ -93,13 +102,16 @@ public class RunningServices extends ListActivity
int mProcessBgColor;
+ LinearColorBar mColorBar;
TextView mBackgroundProcessText;
TextView mForegroundProcessText;
int mLastNumBackgroundProcesses = -1;
int mLastNumForegroundProcesses = -1;
+ int mLastNumServiceProcesses = -1;
long mLastBackgroundProcessMemory = -1;
long mLastForegroundProcessMemory = -1;
+ long mLastServiceProcessMemory = -1;
long mLastAvailMemory = -1;
Dialog mCurDialog;
@@ -179,6 +191,11 @@ public class RunningServices extends ListActivity
int mRunningSeq;
ActivityManager.RunningAppProcessInfo mRunningProcessInfo;
+ // Purely for sorting.
+ boolean mIsSystem;
+ boolean mIsStarted;
+ long mActiveSince;
+
public ProcessItem(Context context, int uid, String processName) {
super(true);
mDescription = context.getResources().getString(
@@ -372,26 +389,56 @@ public class RunningServices extends ListActivity
}
}
+ static class ServiceProcessComparator implements Comparator<ProcessItem> {
+ public int compare(ProcessItem object1, ProcessItem object2) {
+ if (object1.mIsStarted != object2.mIsStarted) {
+ // Non-started processes go last.
+ return object1.mIsStarted ? -1 : 1;
+ }
+ if (object1.mIsSystem != object2.mIsSystem) {
+ // System processes go below non-system.
+ return object1.mIsSystem ? 1 : -1;
+ }
+ if (object1.mActiveSince != object2.mActiveSince) {
+ // Remaining ones are sorted with the longest running
+ // services last.
+ return (object1.mActiveSince > object2.mActiveSince) ? -1 : 1;
+ }
+ return 0;
+ }
+ }
+
static class State {
final SparseArray<HashMap<String, ProcessItem>> mProcesses
= new SparseArray<HashMap<String, ProcessItem>>();
final SparseArray<ProcessItem> mActiveProcesses
= new SparseArray<ProcessItem>();
+ final ServiceProcessComparator mServiceProcessComparator
+ = new ServiceProcessComparator();
// Temporary for finding process dependencies.
final SparseArray<ProcessItem> mRunningProcesses
= new SparseArray<ProcessItem>();
- final ArrayList<BaseItem> mItems = new ArrayList<BaseItem>();
final ArrayList<ProcessItem> mProcessItems = new ArrayList<ProcessItem>();
final ArrayList<ProcessItem> mAllProcessItems = new ArrayList<ProcessItem>();
int mSequence = 0;
+ // ----- following protected by mLock -----
+
+ // Lock for protecting the state that will be shared between the
+ // background update thread and the UI thread.
+ final Object mLock = new Object();
+
+ ArrayList<BaseItem> mItems = new ArrayList<BaseItem>();
+
int mNumBackgroundProcesses;
long mBackgroundProcessMemory;
int mNumForegroundProcesses;
long mForegroundProcessMemory;
+ int mNumServiceProcesses;
+ long mServiceProcessMemory;
boolean update(Context context, ActivityManager am) {
final PackageManager pm = context.getPackageManager();
@@ -547,35 +594,65 @@ public class RunningServices extends ListActivity
}
if (changed) {
- mItems.clear();
- mProcessItems.clear();
+ // First determine an order for the services.
+ ArrayList<ProcessItem> sortedProcesses = new ArrayList<ProcessItem>();
for (int i=0; i<mProcesses.size(); i++) {
for (ProcessItem pi : mProcesses.valueAt(i).values()) {
- pi.mNeedDivider = false;
- // First add processes we are dependent on.
- pi.addDependentProcesses(mItems, mProcessItems);
- // And add the process itself.
- mItems.add(pi);
- if (pi.mPid > 0) {
- mProcessItems.add(pi);
- }
- // And finally the services running in it.
- boolean needDivider = false;
+ pi.mIsSystem = false;
+ pi.mIsStarted = true;
+ pi.mActiveSince = Long.MAX_VALUE;
for (ServiceItem si : pi.mServices.values()) {
- si.mNeedDivider = needDivider;
- needDivider = true;
- mItems.add(si);
+ if (si.mServiceInfo != null
+ && (si.mServiceInfo.applicationInfo.flags
+ & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ pi.mIsSystem = true;
+ }
+ if (si.mRunningService != null
+ && si.mRunningService.clientLabel != 0) {
+ pi.mIsStarted = false;
+ if (pi.mActiveSince > si.mRunningService.activeSince) {
+ pi.mActiveSince = si.mRunningService.activeSince;
+ }
+ }
}
+ sortedProcesses.add(pi);
}
}
+
+ Collections.sort(sortedProcesses, mServiceProcessComparator);
+
+ ArrayList<BaseItem> newItems = new ArrayList<BaseItem>();
+ mProcessItems.clear();
+ for (int i=0; i<sortedProcesses.size(); i++) {
+ ProcessItem pi = sortedProcesses.get(i);
+ pi.mNeedDivider = false;
+ // First add processes we are dependent on.
+ pi.addDependentProcesses(newItems, mProcessItems);
+ // And add the process itself.
+ newItems.add(pi);
+ if (pi.mPid > 0) {
+ mProcessItems.add(pi);
+ }
+ // And finally the services running in it.
+ boolean needDivider = false;
+ for (ServiceItem si : pi.mServices.values()) {
+ si.mNeedDivider = needDivider;
+ needDivider = true;
+ newItems.add(si);
+ }
+ }
+ synchronized (mLock) {
+ mItems = newItems;
+ }
}
// Count number of interesting other (non-active) processes, and
// build a list of all processes we will retrieve memory for.
mAllProcessItems.clear();
mAllProcessItems.addAll(mProcessItems);
- mNumBackgroundProcesses = 0;
- mNumForegroundProcesses = 0;
+ int numBackgroundProcesses = 0;
+ int numForegroundProcesses = 0;
+ int numServiceProcesses = 0;
NRP = mRunningProcesses.size();
for (int i=0; i<NRP; i++) {
ProcessItem proc = mRunningProcesses.valueAt(i);
@@ -584,19 +661,25 @@ public class RunningServices extends ListActivity
// of our active ones, so add it up if needed.
if (proc.mRunningProcessInfo.importance >=
ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
- mNumBackgroundProcesses++;
+ numBackgroundProcesses++;
mAllProcessItems.add(proc);
} else if (proc.mRunningProcessInfo.importance <=
ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
- mNumForegroundProcesses++;
+ numForegroundProcesses++;
mAllProcessItems.add(proc);
+ } else {
+ Log.i(TAG, "Unknown non-service process: "
+ + proc.mProcessName + " #" + proc.mPid);
}
+ } else {
+ numServiceProcesses++;
}
}
+ long backgroundProcessMemory = 0;
+ long foregroundProcessMemory = 0;
+ long serviceProcessMemory = 0;
try {
- mBackgroundProcessMemory = 0;
- mForegroundProcessMemory = 0;
final int numProc = mAllProcessItems.size();
int[] pids = new int[numProc];
for (int i=0; i<numProc; i++) {
@@ -608,21 +691,35 @@ public class RunningServices extends ListActivity
ProcessItem proc = mAllProcessItems.get(i);
changed |= proc.updateSize(context, mem[i], mSequence);
if (proc.mCurSeq == mSequence) {
- continue;
- }
- if (proc.mRunningProcessInfo.importance >=
+ serviceProcessMemory += proc.mSize;
+ } else if (proc.mRunningProcessInfo.importance >=
ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
- mBackgroundProcessMemory += proc.mSize;
+ backgroundProcessMemory += proc.mSize;
} else if (proc.mRunningProcessInfo.importance <=
ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
- mForegroundProcessMemory += proc.mSize;
+ foregroundProcessMemory += proc.mSize;
}
}
} catch (RemoteException e) {
}
+ synchronized (mLock) {
+ mNumBackgroundProcesses = numBackgroundProcesses;
+ mNumForegroundProcesses = numForegroundProcesses;
+ mNumServiceProcesses = numServiceProcesses;
+ mBackgroundProcessMemory = backgroundProcessMemory;
+ mForegroundProcessMemory = foregroundProcessMemory;
+ mServiceProcessMemory = serviceProcessMemory;
+ }
+
return changed;
}
+
+ ArrayList<BaseItem> getCurrentItems() {
+ synchronized (mLock) {
+ return mItems;
+ }
+ }
}
static class TimeTicker extends TextView {
@@ -642,26 +739,38 @@ public class RunningServices extends ListActivity
class ServiceListAdapter extends BaseAdapter {
final State mState;
final LayoutInflater mInflater;
+ ArrayList<BaseItem> mItems;
ServiceListAdapter(State state) {
mState = state;
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ refreshItems();
}
+ void refreshItems() {
+ ArrayList<BaseItem> newItems = mState.getCurrentItems();
+ if (mItems != newItems) {
+ mItems = newItems;
+ }
+ if (mItems == null) {
+ mItems = new ArrayList<BaseItem>();
+ }
+ }
+
public boolean hasStableIds() {
return true;
}
public int getCount() {
- return mState.mItems.size();
+ return mItems.size();
}
public Object getItem(int position) {
- return mState.mItems.get(position);
+ return mItems.get(position);
}
public long getItemId(int position) {
- return position;
+ return mItems.get(position).hashCode();
}
public boolean areAllItemsEnabled() {
@@ -669,7 +778,7 @@ public class RunningServices extends ListActivity
}
public boolean isEnabled(int position) {
- return !mState.mItems.get(position).mIsProcess;
+ return !mItems.get(position).mIsProcess;
}
public View getView(int position, View convertView, ViewGroup parent) {
@@ -696,35 +805,126 @@ public class RunningServices extends ListActivity
}
public void bindView(View view, int position) {
- ViewHolder vh = (ViewHolder) view.getTag();
- BaseItem item = mState.mItems.get(position);
- vh.name.setText(item.mDisplayLabel);
- vh.separator.setVisibility(item.mNeedDivider
- ? View.VISIBLE : View.INVISIBLE);
- ActiveItem ai = new ActiveItem();
- ai.mRootView = view;
- ai.mItem = item;
- ai.mHolder = vh;
- ai.mFirstRunTime = item.mActiveSince;
- vh.description.setText(item.mDescription);
- if (item.mIsProcess) {
- view.setBackgroundColor(mProcessBgColor);
- vh.icon.setImageDrawable(null);
- vh.icon.setVisibility(View.GONE);
- vh.description.setText(item.mDescription);
- item.mCurSizeStr = null;
- } else {
- view.setBackgroundDrawable(null);
- vh.icon.setImageDrawable(item.mPackageInfo.loadIcon(getPackageManager()));
- vh.icon.setVisibility(View.VISIBLE);
- vh.description.setText(item.mDescription);
+ synchronized (mState.mLock) {
+ ViewHolder vh = (ViewHolder) view.getTag();
+ if (position >= mItems.size()) {
+ // List must have changed since we last reported its
+ // size... ignore here, we will be doing a data changed
+ // to refresh the entire list.
+ return;
+ }
+ BaseItem item = mItems.get(position);
+ vh.name.setText(item.mDisplayLabel);
+ vh.separator.setVisibility(item.mNeedDivider
+ ? View.VISIBLE : View.INVISIBLE);
+ ActiveItem ai = new ActiveItem();
+ ai.mRootView = view;
+ ai.mItem = item;
+ ai.mHolder = vh;
ai.mFirstRunTime = item.mActiveSince;
+ vh.description.setText(item.mDescription);
+ if (item.mIsProcess) {
+ view.setBackgroundColor(mProcessBgColor);
+ vh.icon.setImageDrawable(null);
+ vh.icon.setVisibility(View.GONE);
+ vh.description.setText(item.mDescription);
+ item.mCurSizeStr = null;
+ } else {
+ view.setBackgroundDrawable(null);
+ vh.icon.setImageDrawable(item.mPackageInfo.loadIcon(getPackageManager()));
+ vh.icon.setVisibility(View.VISIBLE);
+ vh.description.setText(item.mDescription);
+ ai.mFirstRunTime = item.mActiveSince;
+ }
+ ai.updateTime(RunningServices.this);
+ mActiveItems.put(view, ai);
+ }
+ }
+ }
+
+ public static class LinearColorBar extends LinearLayout {
+ private float mRedRatio;
+ private float mYellowRatio;
+ private float mGreenRatio;
+
+ final Rect mRect = new Rect();
+ final Paint mPaint = new Paint();
+
+ public LinearColorBar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setWillNotDraw(false);
+ mPaint.setStyle(Paint.Style.FILL);
+ }
+
+ public void setRatios(float red, float yellow, float green) {
+ mRedRatio = red;
+ mYellowRatio = yellow;
+ mGreenRatio = green;
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ int width = getWidth();
+ mRect.top = 0;
+ mRect.bottom = getHeight();
+
+ int left = 0;
+
+ int right = left + (int)(width*mRedRatio);
+ if (left < right) {
+ mRect.left = left;
+ mRect.right = right;
+ mPaint.setColor(0xffff8080);
+ canvas.drawRect(mRect, mPaint);
+ width -= (right-left);
+ left = right;
+ }
+
+ right = left + (int)(width*mYellowRatio);
+ if (left < right) {
+ mRect.left = left;
+ mRect.right = right;
+ mPaint.setColor(0xffffff00);
+ canvas.drawRect(mRect, mPaint);
+ width -= (right-left);
+ left = right;
+ }
+
+ right = left + width;
+ if (left < right) {
+ mRect.left = left;
+ mRect.right = right;
+ mPaint.setColor(0xff80ff80);
+ canvas.drawRect(mRect, mPaint);
}
- ai.updateTime(RunningServices.this);
- mActiveItems.put(view, ai);
}
}
+ HandlerThread mBackgroundThread;
+ final class BackgroundHandler extends Handler {
+ public BackgroundHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UPDATE_CONTENTS:
+ Message cmd = mHandler.obtainMessage(MSG_REFRESH_UI);
+ cmd.arg1 = mState.update(RunningServices.this, mAm) ? 1 : 0;
+ mHandler.sendMessage(cmd);
+ removeMessages(MSG_UPDATE_CONTENTS);
+ msg = obtainMessage(MSG_UPDATE_CONTENTS);
+ sendMessageDelayed(msg, CONTENTS_UPDATE_DELAY);
+ break;
+ }
+ }
+ };
+ BackgroundHandler mBackgroundHandler;
+
final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -744,11 +944,8 @@ public class RunningServices extends ListActivity
msg = obtainMessage(MSG_UPDATE_TIMES);
sendMessageDelayed(msg, TIME_UPDATE_DELAY);
break;
- case MSG_UPDATE_CONTENTS:
- updateList();
- removeMessages(MSG_UPDATE_CONTENTS);
- msg = obtainMessage(MSG_UPDATE_CONTENTS);
- sendMessageDelayed(msg, CONTENTS_UPDATE_DELAY);
+ case MSG_REFRESH_UI:
+ refreshUi(msg.arg1 != 0);
break;
}
}
@@ -823,6 +1020,7 @@ public class RunningServices extends ListActivity
setContentView(R.layout.running_services);
getListView().setDivider(null);
getListView().setAdapter(new ServiceListAdapter(mState));
+ mColorBar = (LinearColorBar)findViewById(R.id.color_bar);
mBackgroundProcessText = (TextView)findViewById(R.id.backgroundText);
mForegroundProcessText = (TextView)findViewById(R.id.foregroundText);
@@ -831,9 +1029,11 @@ public class RunningServices extends ListActivity
Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
}
- void updateList() {
- if (mState.update(this, mAm)) {
- ((ServiceListAdapter)(getListView().getAdapter())).notifyDataSetChanged();
+ void refreshUi(boolean dataChanged) {
+ if (dataChanged) {
+ ServiceListAdapter adapter = (ServiceListAdapter)(getListView().getAdapter());
+ adapter.refreshItems();
+ adapter.notifyDataSetChanged();
}
// This is the amount of available memory until we start killing
@@ -843,26 +1043,36 @@ public class RunningServices extends ListActivity
availMem = 0;
}
- if (mLastNumBackgroundProcesses != mState.mNumBackgroundProcesses
- || mLastBackgroundProcessMemory != mState.mBackgroundProcessMemory
- || mLastAvailMemory != availMem) {
- mLastNumBackgroundProcesses = mState.mNumBackgroundProcesses;
- mLastBackgroundProcessMemory = mState.mBackgroundProcessMemory;
- mLastAvailMemory = availMem;
- String availStr = availMem != 0
- ? Formatter.formatShortFileSize(this, availMem) : "0";
- String sizeStr = Formatter.formatShortFileSize(this, mLastBackgroundProcessMemory);
- mBackgroundProcessText.setText(getResources().getString(
- R.string.service_background_processes,
- mLastNumBackgroundProcesses, availStr, sizeStr));
- }
- if (mLastNumForegroundProcesses != mState.mNumForegroundProcesses
- || mLastForegroundProcessMemory != mState.mForegroundProcessMemory) {
- mLastNumForegroundProcesses = mState.mNumForegroundProcesses;
- mLastForegroundProcessMemory = mState.mForegroundProcessMemory;
- String sizeStr = Formatter.formatShortFileSize(this, mLastForegroundProcessMemory);
- mForegroundProcessText.setText(getResources().getString(
- R.string.service_foreground_processes, mLastNumForegroundProcesses, sizeStr));
+ synchronized (mState.mLock) {
+ if (mLastNumBackgroundProcesses != mState.mNumBackgroundProcesses
+ || mLastBackgroundProcessMemory != mState.mBackgroundProcessMemory
+ || mLastAvailMemory != availMem) {
+ mLastNumBackgroundProcesses = mState.mNumBackgroundProcesses;
+ mLastBackgroundProcessMemory = mState.mBackgroundProcessMemory;
+ mLastAvailMemory = availMem;
+ String availStr = availMem != 0
+ ? Formatter.formatShortFileSize(this, availMem) : "0";
+ String sizeStr = Formatter.formatShortFileSize(this, mLastBackgroundProcessMemory);
+ mBackgroundProcessText.setText(getResources().getString(
+ R.string.service_background_processes,
+ mLastNumBackgroundProcesses, availStr, sizeStr));
+ }
+ if (mLastNumForegroundProcesses != mState.mNumForegroundProcesses
+ || mLastForegroundProcessMemory != mState.mForegroundProcessMemory) {
+ mLastNumForegroundProcesses = mState.mNumForegroundProcesses;
+ mLastForegroundProcessMemory = mState.mForegroundProcessMemory;
+ String sizeStr = Formatter.formatShortFileSize(this, mLastForegroundProcessMemory);
+ mForegroundProcessText.setText(getResources().getString(
+ R.string.service_foreground_processes, mLastNumForegroundProcesses, sizeStr));
+ }
+ mLastNumServiceProcesses = mState.mNumServiceProcesses;
+ mLastServiceProcessMemory = mState.mServiceProcessMemory;
+
+ float totalMem = availMem + mLastBackgroundProcessMemory
+ + mLastForegroundProcessMemory + mLastServiceProcessMemory;
+ mColorBar.setRatios(mLastForegroundProcessMemory/totalMem,
+ mLastServiceProcessMemory/totalMem,
+ (availMem+mLastBackgroundProcessMemory)/totalMem);
}
}
@@ -911,7 +1121,9 @@ public class RunningServices extends ListActivity
if (mCurSelected != null) {
stopService(new Intent().setComponent(
((ServiceItem)mCurSelected).mRunningService.service));
- updateList();
+ if (mBackgroundHandler != null) {
+ mBackgroundHandler.sendEmptyMessage(MSG_UPDATE_CONTENTS);
+ }
}
}
@@ -919,19 +1131,26 @@ public class RunningServices extends ListActivity
protected void onPause() {
super.onPause();
mHandler.removeMessages(MSG_UPDATE_TIMES);
- mHandler.removeMessages(MSG_UPDATE_CONTENTS);
+ if (mBackgroundThread != null) {
+ mBackgroundThread.quit();
+ mBackgroundThread = null;
+ mBackgroundHandler = null;
+ }
}
@Override
protected void onResume() {
super.onResume();
- updateList();
+ refreshUi(mState.update(this, mAm));
+ mBackgroundThread = new HandlerThread("RunningServices");
+ mBackgroundThread.start();
+ mBackgroundHandler = new BackgroundHandler(mBackgroundThread.getLooper());
mHandler.removeMessages(MSG_UPDATE_TIMES);
Message msg = mHandler.obtainMessage(MSG_UPDATE_TIMES);
mHandler.sendMessageDelayed(msg, TIME_UPDATE_DELAY);
- mHandler.removeMessages(MSG_UPDATE_CONTENTS);
- msg = mHandler.obtainMessage(MSG_UPDATE_CONTENTS);
- mHandler.sendMessageDelayed(msg, CONTENTS_UPDATE_DELAY);
+ mBackgroundHandler.removeMessages(MSG_UPDATE_CONTENTS);
+ msg = mBackgroundHandler.obtainMessage(MSG_UPDATE_CONTENTS);
+ mBackgroundHandler.sendMessageDelayed(msg, CONTENTS_UPDATE_DELAY);
}
@Override
diff --git a/src/com/android/settings/SdCardIntentReceiver.java b/src/com/android/settings/SdCardIntentReceiver.java
deleted file mode 100644
index 9648ec1..0000000
--- a/src/com/android/settings/SdCardIntentReceiver.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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 com.android.settings;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.BroadcastReceiver;
-import android.util.Config;
-import android.util.Log;
-
-/**
- *
- */
-public class SdCardIntentReceiver extends BroadcastReceiver {
-
- private static final int SDCARD_STATUS = 1;
- private static final String TAG = "SdCardIntentReceiver";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- NotificationManager nm = (NotificationManager) context
- .getSystemService(Context.NOTIFICATION_SERVICE);
- String action = intent.getAction();
- if (Config.LOGD) Log.d(TAG, "onReceiveIntent " + action);
-
- if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
- nm.cancel(SDCARD_STATUS);
-
- Intent statusIntent = new Intent(Intent.ACTION_MAIN, null);
- statusIntent.setClass(context, SdCardSettings.class);
- nm.notify(SDCARD_STATUS, new Notification(context,
- android.R.drawable.stat_notify_sdcard,
- null,
- System.currentTimeMillis(),
- context.getText(R.string.sdcard_setting),
- null,
- statusIntent));
- } else if (action.equals(Intent.ACTION_MEDIA_REMOVED)) {
- nm.cancel(SDCARD_STATUS);
- } else if (action.equals(Intent.ACTION_MEDIA_SHARED)) {
- nm.cancel(SDCARD_STATUS);
-
- Intent statusIntent = new Intent(Intent.ACTION_MAIN, null);
- statusIntent.setClass(context, SdCardSettings.class);
- nm.notify(SDCARD_STATUS, new Notification(context,
- android.R.drawable.stat_notify_sdcard_usb,
- null,
- System.currentTimeMillis(),
- "SD Card",
- null,
- statusIntent));
- }
- }
-}
diff --git a/src/com/android/settings/SdCardSettings.java b/src/com/android/settings/SdCardSettings.java
deleted file mode 100644
index 67f3550..0000000
--- a/src/com/android/settings/SdCardSettings.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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 com.android.settings;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.Environment;
-import android.os.IMountService;
-import android.os.ServiceManager;
-import android.os.StatFs;
-import android.text.format.Formatter;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.TextView;
-
-import java.io.File;
-
-
-public class SdCardSettings extends Activity
-{
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- setContentView(R.layout.sdcard_settings_screen);
-
- mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
-
- mRemovedLayout = findViewById(R.id.removed);
- mMountedLayout = findViewById(R.id.mounted);
- mUnmountedLayout = findViewById(R.id.unmounted);
- mScanningLayout = findViewById(R.id.scanning);
- mSharedLayout = findViewById(R.id.shared);
- mBadRemovalLayout = findViewById(R.id.bad_removal);
- mReadOnlyStatus = findViewById(R.id.read_only);
-
- mMassStorage = (CheckBox)findViewById(R.id.mass_storage);
- mMassStorage.setOnClickListener(mMassStorageListener);
-
- Button unmountButton = (Button)findViewById(R.id.sdcard_unmount);
- unmountButton.setOnClickListener(mUnmountButtonHandler);
-
- Button formatButton = (Button)findViewById(R.id.sdcard_format);
- formatButton.setOnClickListener(mFormatButtonHandler);
-
- mTotalSize = (TextView)findViewById(R.id.total);
- mUsedSize = (TextView)findViewById(R.id.used);
- mAvailableSize = (TextView)findViewById(R.id.available);
-
- // install an intent filter to receive SD card related events.
- IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_REMOVED);
- intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
- intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
- intentFilter.addAction(Intent.ACTION_MEDIA_SHARED);
- intentFilter.addAction(Intent.ACTION_MEDIA_CHECKING);
- intentFilter.addAction(Intent.ACTION_MEDIA_NOFS);
- intentFilter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
- intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
- intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
- intentFilter.addDataScheme("file");
- registerReceiver(mReceiver, intentFilter);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- update();
- }
-
- private void setLayout(View layout) {
- mRemovedLayout.setVisibility(layout == mRemovedLayout ? View.VISIBLE : View.GONE);
- mMountedLayout.setVisibility(layout == mMountedLayout ? View.VISIBLE : View.GONE);
- mUnmountedLayout.setVisibility(layout == mUnmountedLayout ? View.VISIBLE : View.GONE);
- mScanningLayout.setVisibility(layout == mScanningLayout ? View.VISIBLE : View.GONE);
- mSharedLayout.setVisibility(layout == mSharedLayout ? View.VISIBLE : View.GONE);
- mBadRemovalLayout.setVisibility(layout == mBadRemovalLayout ? View.VISIBLE : View.GONE);
- }
-
- private void update() {
- try {
- mMassStorage.setChecked(mMountService.getMassStorageEnabled());
- } catch (RemoteException ex) {
- }
-
- String status = Environment.getExternalStorageState();
- boolean readOnly = false;
-
- if (status.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
- status = Environment.MEDIA_MOUNTED;
- readOnly = true;
- }
-
- if (status.equals(Environment.MEDIA_MOUNTED)) {
- try {
- File path = Environment.getExternalStorageDirectory();
- StatFs stat = new StatFs(path.getPath());
- long blockSize = stat.getBlockSize();
- long totalBlocks = stat.getBlockCount();
- long availableBlocks = stat.getAvailableBlocks();
-
- mTotalSize.setText(formatSize(totalBlocks * blockSize));
- mUsedSize.setText(formatSize((totalBlocks - availableBlocks) * blockSize));
- mAvailableSize.setText(formatSize(availableBlocks * blockSize));
- } catch (IllegalArgumentException e) {
- // this can occur if the SD card is removed, but we haven't received the
- // ACTION_MEDIA_REMOVED Intent yet.
- status = Environment.MEDIA_REMOVED;
- }
-
- mReadOnlyStatus.setVisibility(readOnly ? View.VISIBLE : View.GONE);
- setLayout(mMountedLayout);
- } else if (status.equals(Environment.MEDIA_UNMOUNTED)) {
- setLayout(mUnmountedLayout);
- } else if (status.equals(Environment.MEDIA_REMOVED)) {
- setLayout(mRemovedLayout);
- } else if (status.equals(Environment.MEDIA_SHARED)) {
- setLayout(mSharedLayout);
- } else if (status.equals(Environment.MEDIA_BAD_REMOVAL)) {
- setLayout(mBadRemovalLayout);
- }
- }
-
- private String formatSize(long size) {
- return Formatter.formatFileSize(this, size);
- }
-
- OnClickListener mMassStorageListener = new OnClickListener() {
- public void onClick(View v) {
- try {
- mMountService.setMassStorageEnabled(mMassStorage.isChecked());
- } catch (RemoteException ex) {
- }
- }
- };
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- update();
- }
- };
-
- OnClickListener mUnmountButtonHandler = new OnClickListener() {
- public void onClick(View v) {
- try {
- mMountService.unmountMedia(Environment.getExternalStorageDirectory().toString());
- } catch (RemoteException ex) {
- }
- }
- };
-
- OnClickListener mFormatButtonHandler = new OnClickListener() {
- public void onClick(View v) {
- try {
- mMountService.formatMedia(Environment.getExternalStorageDirectory().toString());
- } catch (RemoteException ex) {
- }
- }
- };
-
- private IMountService mMountService;
-
- private CheckBox mMassStorage;
-
- private TextView mTotalSize;
- private TextView mUsedSize;
- private TextView mAvailableSize;
-
- private View mRemovedLayout;
- private View mMountedLayout;
- private View mUnmountedLayout;
- private View mScanningLayout;
- private View mSharedLayout;
- private View mBadRemovalLayout;
- private View mReadOnlyStatus;
-}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index fcacccc..1348d48 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -17,92 +17,81 @@
package com.android.settings;
+import java.util.Observable;
+import java.util.Observer;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.app.admin.DevicePolicyManager;
import android.content.ContentQueryMap;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.location.LocationManager;
import android.os.Bundle;
+import android.os.SystemProperties;
import android.preference.CheckBoxPreference;
-import android.preference.EditTextPreference;
+import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
-import android.preference.PreferenceGroup;
+import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
+import android.preference.Preference.OnPreferenceChangeListener;
import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyStore;
-import android.text.Html;
-import android.text.TextUtils;
-import android.text.method.LinkMovementMethod;
+import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.android.internal.widget.LockPatternUtils;
-import android.telephony.TelephonyManager;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Observable;
-import java.util.Observer;
/**
* Gesture lock pattern settings.
*/
public class SecuritySettings extends PreferenceActivity {
+ private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change";
// Lock Settings
+ private static final String PACKAGE = "com.android.settings";
+ private static final String ICC_LOCK_SETTINGS = PACKAGE + ".IccLockSettings";
private static final String KEY_LOCK_ENABLED = "lockenabled";
private static final String KEY_VISIBLE_PATTERN = "visiblepattern";
- private static final String KEY_TACTILE_FEEDBACK_ENABLED = "tactilefeedback";
- private static final int CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE = 55;
-
- private static final String PREFS_NAME = "location_prefs";
- private static final String PREFS_USE_LOCATION = "use_location";
+ private static final String KEY_TACTILE_FEEDBACK_ENABLED = "unlock_tactile_feedback";
- private LockPatternUtils mLockPatternUtils;
- private CheckBoxPreference mLockEnabled;
private CheckBoxPreference mVisiblePattern;
private CheckBoxPreference mTactileFeedback;
- private Preference mChoosePattern;
private CheckBoxPreference mShowPassword;
// Location Settings
- private static final String LOCATION_CATEGORY = "location_category";
private static final String LOCATION_NETWORK = "location_network";
private static final String LOCATION_GPS = "location_gps";
private static final String ASSISTED_GPS = "assisted_gps";
+ private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123;
// Credential storage
- private static final int CSTOR_MIN_PASSWORD_LENGTH = 8;
-
- private static final int CSTOR_INIT_DIALOG = 1;
- private static final int CSTOR_CHANGE_PASSWORD_DIALOG = 2;
- private static final int CSTOR_UNLOCK_DIALOG = 3;
- private static final int CSTOR_RESET_DIALOG = 4;
-
private CredentialStorage mCredentialStorage = new CredentialStorage();
private CheckBoxPreference mNetwork;
private CheckBoxPreference mGps;
private CheckBoxPreference mAssistedGps;
+ DevicePolicyManager mDPM;
+
// These provide support for receiving notification when Location Manager settings change.
// This is necessary because the Network Location Provider can change settings
// if the user does not confirm enabling the provider.
private ContentQueryMap mContentQueryMap;
+ private ChooseLockSettingsHelper mChooseLockSettingsHelper;
+ private LockPatternUtils mLockPatternUtils;
private final class SettingsObserver implements Observer {
public void update(Observable o, Object arg) {
updateToggles();
@@ -112,15 +101,14 @@ public class SecuritySettings extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.security_settings);
- mLockPatternUtils = new LockPatternUtils(getContentResolver());
+ mLockPatternUtils = new LockPatternUtils(this);
- createPreferenceHierarchy();
+ mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
- mNetwork = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_NETWORK);
- mGps = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_GPS);
- mAssistedGps = (CheckBoxPreference) getPreferenceScreen().findPreference(ASSISTED_GPS);
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
+
+ createPreferenceHierarchy();
updateToggles();
@@ -131,45 +119,48 @@ public class SecuritySettings extends PreferenceActivity {
null);
mContentQueryMap = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, null);
mContentQueryMap.addObserver(new SettingsObserver());
-
- mCredentialStorage.handleIntent(getIntent());
}
private PreferenceScreen createPreferenceHierarchy() {
- // Root
PreferenceScreen root = this.getPreferenceScreen();
+ if (root != null) {
+ root.removeAll();
+ }
+ addPreferencesFromResource(R.xml.security_settings);
+ root = this.getPreferenceScreen();
+
+ mNetwork = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_NETWORK);
+ mGps = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_GPS);
+ mAssistedGps = (CheckBoxPreference) getPreferenceScreen().findPreference(ASSISTED_GPS);
+
+ PreferenceManager pm = getPreferenceManager();
+
+ // Lock screen
+ if (!mLockPatternUtils.isSecure()) {
+ addPreferencesFromResource(R.xml.security_settings_chooser);
+ } else {
+ switch (mLockPatternUtils.getKeyguardStoredPasswordQuality()) {
+ case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
+ addPreferencesFromResource(R.xml.security_settings_pattern);
+ break;
+ case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
+ addPreferencesFromResource(R.xml.security_settings_pin);
+ break;
+ case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
+ case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
+ addPreferencesFromResource(R.xml.security_settings_password);
+ break;
+ }
+ }
- // Inline preferences
- PreferenceCategory inlinePrefCat = new PreferenceCategory(this);
- inlinePrefCat.setTitle(R.string.lock_settings_title);
- root.addPreference(inlinePrefCat);
-
- // change pattern lock
- Intent intent = new Intent();
- intent.setClassName("com.android.settings",
- "com.android.settings.ChooseLockPatternTutorial");
- mChoosePattern = getPreferenceManager().createPreferenceScreen(this);
- mChoosePattern.setIntent(intent);
- inlinePrefCat.addPreference(mChoosePattern);
-
- // autolock toggle
- mLockEnabled = new LockEnabledPref(this);
- mLockEnabled.setTitle(R.string.lockpattern_settings_enable_title);
- mLockEnabled.setSummary(R.string.lockpattern_settings_enable_summary);
- mLockEnabled.setKey(KEY_LOCK_ENABLED);
- inlinePrefCat.addPreference(mLockEnabled);
+ // set or change current. Should be common to all unlock preference screens
+ // mSetOrChange = (PreferenceScreen) pm.findPreference(KEY_UNLOCK_SET_OR_CHANGE);
// visible pattern
- mVisiblePattern = new CheckBoxPreference(this);
- mVisiblePattern.setKey(KEY_VISIBLE_PATTERN);
- mVisiblePattern.setTitle(R.string.lockpattern_settings_enable_visible_pattern_title);
- inlinePrefCat.addPreference(mVisiblePattern);
+ mVisiblePattern = (CheckBoxPreference) pm.findPreference(KEY_VISIBLE_PATTERN);
- // tactile feedback
- mTactileFeedback = new CheckBoxPreference(this);
- mTactileFeedback.setKey(KEY_TACTILE_FEEDBACK_ENABLED);
- mTactileFeedback.setTitle(R.string.lockpattern_settings_enable_tactile_feedback_title);
- inlinePrefCat.addPreference(mTactileFeedback);
+ // tactile feedback. Should be common to all unlock preference screens.
+ mTactileFeedback = (CheckBoxPreference) pm.findPreference(KEY_TACTILE_FEEDBACK_ENABLED);
int activePhoneType = TelephonyManager.getDefault().getPhoneType();
@@ -180,10 +171,7 @@ public class SecuritySettings extends PreferenceActivity {
.createPreferenceScreen(this);
simLockPreferences.setTitle(R.string.sim_lock_settings_category);
// Intent to launch SIM lock settings
- intent = new Intent();
- intent.setClassName("com.android.settings", "com.android.settings.IccLockSettings");
- simLockPreferences.setIntent(intent);
-
+ simLockPreferences.setIntent(new Intent().setClassName(PACKAGE, ICC_LOCK_SETTINGS));
PreferenceCategory simLockCat = new PreferenceCategory(this);
simLockCat.setTitle(R.string.sim_lock_settings_title);
root.addPreference(simLockCat);
@@ -202,11 +190,24 @@ public class SecuritySettings extends PreferenceActivity {
showPassword.setPersistent(false);
passwordsCat.addPreference(showPassword);
+ // Device policies
+ PreferenceCategory devicePoliciesCat = new PreferenceCategory(this);
+ devicePoliciesCat.setTitle(R.string.device_admin_title);
+ root.addPreference(devicePoliciesCat);
+
+ Preference deviceAdminButton = new Preference(this);
+ deviceAdminButton.setTitle(R.string.manage_device_admin);
+ deviceAdminButton.setSummary(R.string.manage_device_admin_summary);
+ Intent deviceAdminIntent = new Intent();
+ deviceAdminIntent.setClass(this, DeviceAdminSettings.class);
+ deviceAdminButton.setIntent(deviceAdminIntent);
+ devicePoliciesCat.addPreference(deviceAdminButton);
+
// Credential storage
PreferenceCategory credentialsCat = new PreferenceCategory(this);
credentialsCat.setTitle(R.string.credentials_category);
root.addPreference(credentialsCat);
- mCredentialStorage.createPreferences(credentialsCat);
+ mCredentialStorage.createPreferences(credentialsCat, CredentialStorage.TYPE_KEYSTORE);
return root;
}
@@ -215,19 +216,13 @@ public class SecuritySettings extends PreferenceActivity {
protected void onResume() {
super.onResume();
- boolean patternExists = mLockPatternUtils.savedPatternExists();
- mLockEnabled.setEnabled(patternExists);
- mVisiblePattern.setEnabled(patternExists);
- mTactileFeedback.setEnabled(patternExists);
-
- mLockEnabled.setChecked(mLockPatternUtils.isLockPatternEnabled());
- mVisiblePattern.setChecked(mLockPatternUtils.isVisiblePatternEnabled());
- mTactileFeedback.setChecked(mLockPatternUtils.isTactileFeedbackEnabled());
-
- int chooseStringRes = mLockPatternUtils.savedPatternExists() ?
- R.string.lockpattern_settings_change_lock_pattern :
- R.string.lockpattern_settings_choose_lock_pattern;
- mChoosePattern.setTitle(chooseStringRes);
+ final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
+ if (mVisiblePattern != null) {
+ mVisiblePattern.setChecked(lockPatternUtils.isVisiblePatternEnabled());
+ }
+ if (mTactileFeedback != null) {
+ mTactileFeedback.setChecked(lockPatternUtils.isTactileFeedbackEnabled());
+ }
mShowPassword.setChecked(Settings.System.getInt(getContentResolver(),
Settings.System.TEXT_SHOW_PASSWORD, 1) != 0);
@@ -240,12 +235,16 @@ public class SecuritySettings extends PreferenceActivity {
Preference preference) {
final String key = preference.getKey();
- if (KEY_LOCK_ENABLED.equals(key)) {
- mLockPatternUtils.setLockPatternEnabled(isToggled(preference));
+ final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
+ if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) {
+ Intent intent = new Intent(this, ChooseLockGeneric.class);
+ startActivityForResult(intent, SET_OR_CHANGE_LOCK_METHOD_REQUEST);
+ } else if (KEY_LOCK_ENABLED.equals(key)) {
+ lockPatternUtils.setLockPatternEnabled(isToggled(preference));
} else if (KEY_VISIBLE_PATTERN.equals(key)) {
- mLockPatternUtils.setVisiblePatternEnabled(isToggled(preference));
+ lockPatternUtils.setVisiblePatternEnabled(isToggled(preference));
} else if (KEY_TACTILE_FEEDBACK_ENABLED.equals(key)) {
- mLockPatternUtils.setTactileFeedbackEnabled(isToggled(preference));
+ lockPatternUtils.setTactileFeedbackEnabled(isToggled(preference));
} else if (preference == mShowPassword) {
Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD,
mShowPassword.isChecked() ? 1 : 0);
@@ -267,11 +266,6 @@ public class SecuritySettings extends PreferenceActivity {
return false;
}
- private void showPrivacyPolicy() {
- Intent intent = new Intent("android.settings.TERMS");
- startActivity(intent);
- }
-
/*
* Creates toggles for each available location provider
*/
@@ -294,102 +288,56 @@ public class SecuritySettings extends PreferenceActivity {
}
/**
- * For the user to disable keyguard, we first make them verify their
- * existing pattern.
- */
- private class LockEnabledPref extends CheckBoxPreference {
-
- public LockEnabledPref(Context context) {
- super(context);
- }
-
- @Override
- protected void onClick() {
- if (mLockPatternUtils.savedPatternExists() && isChecked()) {
- confirmPatternThenDisableAndClear();
- } else {
- super.onClick();
- }
- }
- }
-
- /**
- * Launch screen to confirm the existing lock pattern.
- * @see #onActivityResult(int, int, android.content.Intent)
- */
- private void confirmPatternThenDisableAndClear() {
- final Intent intent = new Intent();
- intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPattern");
- startActivityForResult(intent, CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE);
- }
-
- /**
* @see #confirmPatternThenDisableAndClear
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
-
- final boolean resultOk = resultCode == Activity.RESULT_OK;
-
- if ((requestCode == CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE)
- && resultOk) {
- mLockPatternUtils.setLockPatternEnabled(false);
- mLockPatternUtils.saveLockPattern(null);
- }
- }
-
- @Override
- protected Dialog onCreateDialog(int id) {
- return mCredentialStorage.createDialog(id);
+ createPreferenceHierarchy();
}
private class CredentialStorage implements DialogInterface.OnClickListener,
DialogInterface.OnDismissListener, Preference.OnPreferenceChangeListener,
Preference.OnPreferenceClickListener {
private static final int MINIMUM_PASSWORD_LENGTH = 8;
- private static final int UNLOCK_DIALOG = 1;
- private static final int PASSWORD_DIALOG = 2;
- private static final int RESET_DIALOG = 3;
+
+ private static final int TYPE_KEYSTORE = 0;
+
+ // Dialog identifiers
+ private static final int DLG_BASE = 0;
+ private static final int DLG_UNLOCK = DLG_BASE + 1;
+ private static final int DLG_PASSWORD = DLG_UNLOCK + 1;
+ private static final int DLG_RESET = DLG_PASSWORD + 1;
private KeyStore mKeyStore = KeyStore.getInstance();
- private int mState = mKeyStore.test();
- private int mDialogId;
- private boolean mSubmit;
+ private int mState;
+ private boolean mSubmit = false;
+ private boolean mExternal = false;
+
+ private int mShowingDialog = 0;
+ // Key Store controls
private CheckBoxPreference mAccessCheckBox;
private Preference mInstallButton;
private Preference mPasswordButton;
private Preference mResetButton;
- private Intent mExternalIntent;
-
- void handleIntent(Intent intent) {
- if (intent != null) {
- if (Credentials.UNLOCK_ACTION.equals(intent.getAction())) {
- mExternalIntent = intent;
- showDialog((mState == KeyStore.UNINITIALIZED) ?
- PASSWORD_DIALOG : UNLOCK_DIALOG);
- }
- }
- }
-
void resume() {
mState = mKeyStore.test();
updatePreferences(mState);
- }
- Dialog createDialog(int id) {
- mDialogId = id;
- switch (id) {
- case UNLOCK_DIALOG:
- return createUnlockDialog();
- case PASSWORD_DIALOG:
- return createPasswordDialog();
- case RESET_DIALOG:
- return createResetDialog();
+ Intent intent = getIntent();
+ if (!mExternal && intent != null &&
+ Credentials.UNLOCK_ACTION.equals(intent.getAction())) {
+ mExternal = true;
+ if (mState == KeyStore.UNINITIALIZED) {
+ showPasswordDialog();
+ } else if (mState == KeyStore.LOCKED) {
+ showUnlockDialog();
+ } else {
+ finish();
+ }
}
- return null;
}
private void initialize(String password) {
@@ -420,23 +368,22 @@ public class SecuritySettings extends PreferenceActivity {
public boolean onPreferenceChange(Preference preference, Object value) {
if (preference == mAccessCheckBox) {
if ((Boolean) value) {
- showDialog((mState == KeyStore.UNINITIALIZED) ?
- PASSWORD_DIALOG : UNLOCK_DIALOG);
+ showUnlockDialog();
} else {
lock();
}
return true;
}
- return false;
+ return true;
}
public boolean onPreferenceClick(Preference preference) {
if (preference == mInstallButton) {
Credentials.getInstance().installFromSdCard(SecuritySettings.this);
} else if (preference == mPasswordButton) {
- showDialog(PASSWORD_DIALOG);
+ showPasswordDialog();
} else if (preference == mResetButton) {
- showDialog(RESET_DIALOG);
+ showResetDialog();
} else {
return false;
}
@@ -454,14 +401,12 @@ public class SecuritySettings extends PreferenceActivity {
if (mSubmit && !isFinishing()) {
mSubmit = false;
if (!checkPassword((Dialog) dialog)) {
- showDialog(mDialogId);
+ ((Dialog) dialog).show();
return;
}
}
- removeDialog(mDialogId);
updatePreferences(mState);
- if (mExternalIntent != null) {
- mExternalIntent = null;
+ if (mExternal) {
finish();
}
}
@@ -534,36 +479,44 @@ public class SecuritySettings extends PreferenceActivity {
}
}
- private void createPreferences(PreferenceCategory category) {
- mAccessCheckBox = new CheckBoxPreference(SecuritySettings.this);
- mAccessCheckBox.setTitle(R.string.credentials_access);
- mAccessCheckBox.setSummary(R.string.credentials_access_summary);
- mAccessCheckBox.setOnPreferenceChangeListener(this);
- category.addPreference(mAccessCheckBox);
-
- mInstallButton = new Preference(SecuritySettings.this);
- mInstallButton.setTitle(R.string.credentials_install_certificates);
- mInstallButton.setSummary(R.string.credentials_install_certificates_summary);
- mInstallButton.setOnPreferenceClickListener(this);
- category.addPreference(mInstallButton);
-
- mPasswordButton = new Preference(SecuritySettings.this);
- mPasswordButton.setTitle(R.string.credentials_set_password);
- mPasswordButton.setSummary(R.string.credentials_set_password_summary);
- mPasswordButton.setOnPreferenceClickListener(this);
- category.addPreference(mPasswordButton);
-
- mResetButton = new Preference(SecuritySettings.this);
- mResetButton.setTitle(R.string.credentials_reset);
- mResetButton.setSummary(R.string.credentials_reset_summary);
- mResetButton.setOnPreferenceClickListener(this);
- category.addPreference(mResetButton);
+ private void createPreferences(PreferenceCategory category, int type) {
+ switch(type) {
+ case TYPE_KEYSTORE:
+ mAccessCheckBox = new CheckBoxPreference(SecuritySettings.this);
+ mAccessCheckBox.setTitle(R.string.credentials_access);
+ mAccessCheckBox.setSummary(R.string.credentials_access_summary);
+ mAccessCheckBox.setOnPreferenceChangeListener(this);
+ category.addPreference(mAccessCheckBox);
+
+ mInstallButton = new Preference(SecuritySettings.this);
+ mInstallButton.setTitle(R.string.credentials_install_certificates);
+ mInstallButton.setSummary(R.string.credentials_install_certificates_summary);
+ mInstallButton.setOnPreferenceClickListener(this);
+ category.addPreference(mInstallButton);
+
+ mPasswordButton = new Preference(SecuritySettings.this);
+ mPasswordButton.setTitle(R.string.credentials_set_password);
+ mPasswordButton.setSummary(R.string.credentials_set_password_summary);
+ mPasswordButton.setOnPreferenceClickListener(this);
+ category.addPreference(mPasswordButton);
+
+ mResetButton = new Preference(SecuritySettings.this);
+ mResetButton.setTitle(R.string.credentials_reset);
+ mResetButton.setSummary(R.string.credentials_reset_summary);
+ mResetButton.setOnPreferenceClickListener(this);
+ category.addPreference(mResetButton);
+ break;
+
+ }
}
private void updatePreferences(int state) {
- mAccessCheckBox.setEnabled(state != KeyStore.UNINITIALIZED);
mAccessCheckBox.setChecked(state == KeyStore.NO_ERROR);
+
mResetButton.setEnabled(state != KeyStore.UNINITIALIZED);
+ mAccessCheckBox.setEnabled(state != KeyStore.UNINITIALIZED);
+
+ // Encrypted File system preferences
// Show a toast message if the state is changed.
if (mState == state) {
@@ -581,12 +534,12 @@ public class SecuritySettings extends PreferenceActivity {
mState = state;
}
- private Dialog createUnlockDialog() {
+ private void showUnlockDialog() {
View view = View.inflate(SecuritySettings.this,
R.layout.credentials_unlock_dialog, null);
- // show extra hint only when the action comes from outside
- if (mExternalIntent != null) {
+ // Show extra hint only when the action comes from outside.
+ if (mExternal) {
view.findViewById(R.id.hint).setVisibility(View.VISIBLE);
}
@@ -597,10 +550,11 @@ public class SecuritySettings extends PreferenceActivity {
.setNegativeButton(android.R.string.cancel, this)
.create();
dialog.setOnDismissListener(this);
- return dialog;
+ mShowingDialog = DLG_UNLOCK;
+ dialog.show();
}
- private Dialog createPasswordDialog() {
+ private void showPasswordDialog() {
View view = View.inflate(SecuritySettings.this,
R.layout.credentials_password_dialog, null);
@@ -618,17 +572,19 @@ public class SecuritySettings extends PreferenceActivity {
.setNegativeButton(android.R.string.cancel, this)
.create();
dialog.setOnDismissListener(this);
- return dialog;
+ mShowingDialog = DLG_PASSWORD;
+ dialog.show();
}
- private Dialog createResetDialog() {
- return new AlertDialog.Builder(SecuritySettings.this)
+ private void showResetDialog() {
+ mShowingDialog = DLG_RESET;
+ new AlertDialog.Builder(SecuritySettings.this)
.setTitle(android.R.string.dialog_alert_title)
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(R.string.credentials_reset_hint)
.setNeutralButton(getString(android.R.string.ok), this)
.setNegativeButton(getString(android.R.string.cancel), this)
- .create();
+ .create().show();
}
}
}
diff --git a/src/com/android/settings/SettingsSafetyLegalActivity.java b/src/com/android/settings/SettingsSafetyLegalActivity.java
index 619dc94..0c51928 100644
--- a/src/com/android/settings/SettingsSafetyLegalActivity.java
+++ b/src/com/android/settings/SettingsSafetyLegalActivity.java
@@ -58,7 +58,11 @@ public class SettingsSafetyLegalActivity extends AlertActivity
// Begin accessing
mWebView.getSettings().setJavaScriptEnabled(true);
- mWebView.loadUrl(userSafetylegalUrl);
+ if (savedInstanceState == null) {
+ mWebView.loadUrl(userSafetylegalUrl);
+ } else {
+ mWebView.restoreState(savedInstanceState);
+ }
mWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
@@ -110,4 +114,10 @@ public class SettingsSafetyLegalActivity extends AlertActivity
public void onCancel(DialogInterface dialog) {
finish();
}
+
+ @Override
+ public void onSaveInstanceState(Bundle icicle) {
+ mWebView.saveState(icicle);
+ super.onSaveInstanceState(icicle);
+ }
}
diff --git a/src/com/android/settings/SoundAndDisplaySettings.java b/src/com/android/settings/SoundSettings.java
index 29eb878..bfb5566 100644
--- a/src/com/android/settings/SoundAndDisplaySettings.java
+++ b/src/com/android/settings/SoundSettings.java
@@ -25,7 +25,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Bundle;
-import android.os.IMountService;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.preference.CheckBoxPreference;
@@ -40,7 +39,7 @@ import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.IWindowManager;
-public class SoundAndDisplaySettings extends PreferenceActivity implements
+public class SoundSettings extends PreferenceActivity implements
Preference.OnPreferenceChangeListener {
private static final String TAG = "SoundAndDisplaysSettings";
@@ -50,23 +49,20 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
private static final String KEY_SILENT = "silent";
private static final String KEY_VIBRATE = "vibrate";
- private static final String KEY_SCREEN_TIMEOUT = "screen_timeout";
private static final String KEY_DTMF_TONE = "dtmf_tone";
private static final String KEY_SOUND_EFFECTS = "sound_effects";
private static final String KEY_HAPTIC_FEEDBACK = "haptic_feedback";
- private static final String KEY_ANIMATIONS = "animations";
- private static final String KEY_ACCELEROMETER = "accelerometer";
- private static final String KEY_PLAY_MEDIA_NOTIFICATION_SOUNDS =
- "play_media_notification_sounds";
private static final String KEY_EMERGENCY_TONE = "emergency_tone";
private static final String KEY_SOUND_SETTINGS = "sound_settings";
private static final String KEY_NOTIFICATION_PULSE = "notification_pulse";
+ private static final String KEY_LOCK_SOUNDS = "lock_sounds";
- private CheckBoxPreference mSilent;
-
- private CheckBoxPreference mPlayMediaNotificationSounds;
+ private static final String VALUE_VIBRATE_NEVER = "never";
+ private static final String VALUE_VIBRATE_ALWAYS = "always";
+ private static final String VALUE_VIBRATE_ONLY_SILENT = "silent";
+ private static final String VALUE_VIBRATE_UNLESS_SILENT = "notsilent";
- private IMountService mMountService = null;
+ private CheckBoxPreference mSilent;
/*
* If we are currently in one of the silent modes (the ringer mode is set to either
@@ -75,19 +71,15 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
* Otherwise, it will adjust the normal ringer mode's ring or ring+vibrate
* setting.
*/
- private CheckBoxPreference mVibrate;
+ private ListPreference mVibrate;
private CheckBoxPreference mDtmfTone;
private CheckBoxPreference mSoundEffects;
private CheckBoxPreference mHapticFeedback;
- private ListPreference mAnimations;
- private CheckBoxPreference mAccelerometer;
private CheckBoxPreference mNotificationPulse;
- private float[] mAnimationScales;
+ private CheckBoxPreference mLockSounds;
private AudioManager mAudioManager;
- private IWindowManager mWindowManager;
-
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -106,11 +98,8 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
int activePhoneType = TelephonyManager.getDefault().getPhoneType();
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
- mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
- mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
-
- addPreferencesFromResource(R.xml.sound_and_display_settings);
+ addPreferencesFromResource(R.xml.sound_settings);
if (TelephonyManager.PHONE_TYPE_CDMA != activePhoneType) {
// device is not CDMA, do not display CDMA emergency_tone
@@ -118,9 +107,10 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
}
mSilent = (CheckBoxPreference) findPreference(KEY_SILENT);
- mPlayMediaNotificationSounds = (CheckBoxPreference) findPreference(KEY_PLAY_MEDIA_NOTIFICATION_SOUNDS);
- mVibrate = (CheckBoxPreference) findPreference(KEY_VIBRATE);
+ mVibrate = (ListPreference) findPreference(KEY_VIBRATE);
+ mVibrate.setOnPreferenceChangeListener(this);
+
mDtmfTone = (CheckBoxPreference) findPreference(KEY_DTMF_TONE);
mDtmfTone.setPersistent(false);
mDtmfTone.setChecked(Settings.System.getInt(resolver,
@@ -133,16 +123,10 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
mHapticFeedback.setPersistent(false);
mHapticFeedback.setChecked(Settings.System.getInt(resolver,
Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) != 0);
- mAnimations = (ListPreference) findPreference(KEY_ANIMATIONS);
- mAnimations.setOnPreferenceChangeListener(this);
- mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);
- mAccelerometer.setPersistent(false);
-
- ListPreference screenTimeoutPreference =
- (ListPreference) findPreference(KEY_SCREEN_TIMEOUT);
- screenTimeoutPreference.setValue(String.valueOf(Settings.System.getInt(
- resolver, SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE)));
- screenTimeoutPreference.setOnPreferenceChangeListener(this);
+ mLockSounds = (CheckBoxPreference) findPreference(KEY_LOCK_SOUNDS);
+ mLockSounds.setPersistent(false);
+ mLockSounds.setChecked(Settings.System.getInt(resolver,
+ Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) != 0);
if (TelephonyManager.PHONE_TYPE_CDMA == activePhoneType) {
ListPreference emergencyTonePreference =
@@ -187,8 +171,85 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
unregisterReceiver(mReceiver);
}
+ private String getPhoneVibrateSettingValue() {
+ boolean vibeInSilent = (Settings.System.getInt(
+ getContentResolver(),
+ Settings.System.VIBRATE_IN_SILENT,
+ 1) == 1);
+
+ // Control phone vibe independent of silent mode
+ int callsVibrateSetting =
+ mAudioManager.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
+
+ if (vibeInSilent) {
+ if (callsVibrateSetting == AudioManager.VIBRATE_SETTING_OFF) {
+ // this state does not make sense; fix it up for the user
+ mAudioManager.setVibrateSetting(
+ AudioManager.VIBRATE_TYPE_RINGER,
+ AudioManager.VIBRATE_SETTING_ONLY_SILENT);
+ }
+ if (callsVibrateSetting == AudioManager.VIBRATE_SETTING_ON) {
+ return VALUE_VIBRATE_ALWAYS;
+ } else {
+ return VALUE_VIBRATE_ONLY_SILENT;
+ }
+ } else {
+ if (callsVibrateSetting == AudioManager.VIBRATE_SETTING_ONLY_SILENT) {
+ // this state does not make sense; fix it up
+ mAudioManager.setVibrateSetting(
+ AudioManager.VIBRATE_TYPE_RINGER,
+ AudioManager.VIBRATE_SETTING_OFF);
+ }
+ if (callsVibrateSetting == AudioManager.VIBRATE_SETTING_ON) {
+ return VALUE_VIBRATE_UNLESS_SILENT;
+ } else {
+ return VALUE_VIBRATE_NEVER;
+ }
+ }
+ }
+
+ private void setPhoneVibrateSettingValue(String value) {
+ boolean vibeInSilent;
+ int callsVibrateSetting;
+
+ if (value.equals(VALUE_VIBRATE_UNLESS_SILENT)) {
+ callsVibrateSetting = AudioManager.VIBRATE_SETTING_ON;
+ vibeInSilent = false;
+ } else if (value.equals(VALUE_VIBRATE_NEVER)) {
+ callsVibrateSetting = AudioManager.VIBRATE_SETTING_OFF;
+ vibeInSilent = false;
+ } else if (value.equals(VALUE_VIBRATE_ONLY_SILENT)) {
+ callsVibrateSetting = AudioManager.VIBRATE_SETTING_ONLY_SILENT;
+ vibeInSilent = true;
+ } else { //VALUE_VIBRATE_ALWAYS
+ callsVibrateSetting = AudioManager.VIBRATE_SETTING_ON;
+ vibeInSilent = true;
+ }
+
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.VIBRATE_IN_SILENT,
+ vibeInSilent ? 1 : 0);
+
+ // might need to switch the ringer mode from one kind of "silent" to
+ // another
+ if (mSilent.isChecked()) {
+ mAudioManager.setRingerMode(
+ vibeInSilent ? AudioManager.RINGER_MODE_VIBRATE
+ : AudioManager.RINGER_MODE_SILENT);
+ }
+
+ mAudioManager.setVibrateSetting(
+ AudioManager.VIBRATE_TYPE_RINGER,
+ callsVibrateSetting);
+ }
+
+ // updateState in fact updates the UI to reflect the system state
private void updateState(boolean force) {
final int ringerMode = mAudioManager.getRingerMode();
+
+ // NB: in the UI we now simply call this "silent mode". A separate
+ // setting controls whether we're in RINGER_MODE_SILENT or
+ // RINGER_MODE_VIBRATE.
final boolean silentOrVibrateMode =
ringerMode != AudioManager.RINGER_MODE_NORMAL;
@@ -196,21 +257,12 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
mSilent.setChecked(silentOrVibrateMode);
}
- try {
- mPlayMediaNotificationSounds.setChecked(mMountService.getPlayNotificationSounds());
- } catch (RemoteException e) {
- }
+ String phoneVibrateSetting = getPhoneVibrateSettingValue();
- boolean vibrateSetting;
- if (silentOrVibrateMode) {
- vibrateSetting = ringerMode == AudioManager.RINGER_MODE_VIBRATE;
- } else {
- vibrateSetting = mAudioManager.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER)
- == AudioManager.VIBRATE_SETTING_ON;
- }
- if (vibrateSetting != mVibrate.isChecked() || force) {
- mVibrate.setChecked(vibrateSetting);
+ if (! phoneVibrateSetting.equals(mVibrate.getValue()) || force) {
+ mVibrate.setValue(phoneVibrateSetting);
}
+ mVibrate.setSummary(mVibrate.getEntry());
int silentModeStreams = Settings.System.getInt(getContentResolver(),
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
@@ -218,72 +270,23 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
mSilent.setSummary(isAlarmInclSilentMode ?
R.string.silent_mode_incl_alarm_summary :
R.string.silent_mode_summary);
-
- int animations = 0;
- try {
- mAnimationScales = mWindowManager.getAnimationScales();
- } catch (RemoteException e) {
- }
- if (mAnimationScales != null) {
- if (mAnimationScales.length >= 1) {
- animations = ((int)(mAnimationScales[0]+.5f)) % 10;
- }
- if (mAnimationScales.length >= 2) {
- animations += (((int)(mAnimationScales[1]+.5f)) & 0x7) * 10;
- }
- }
- int idx = 0;
- int best = 0;
- CharSequence[] aents = mAnimations.getEntryValues();
- for (int i=0; i<aents.length; i++) {
- int val = Integer.parseInt(aents[i].toString());
- if (val <= animations && val > best) {
- best = val;
- idx = i;
- }
- }
- mAnimations.setValueIndex(idx);
- updateAnimationsSummary(mAnimations.getValue());
- mAccelerometer.setChecked(Settings.System.getInt(
- getContentResolver(),
- Settings.System.ACCELEROMETER_ROTATION, 0) != 0);
- }
-
- private void updateAnimationsSummary(Object value) {
- CharSequence[] summaries = getResources().getTextArray(R.array.animations_summaries);
- CharSequence[] values = mAnimations.getEntryValues();
- for (int i=0; i<values.length; i++) {
- //Log.i("foo", "Comparing entry "+ values[i] + " to current "
- // + mAnimations.getValue());
- if (values[i].equals(value)) {
- mAnimations.setSummary(summaries[i]);
- break;
- }
- }
- }
-
- private void setRingerMode(boolean silent, boolean vibrate) {
- if (silent) {
- mAudioManager.setRingerMode(vibrate ? AudioManager.RINGER_MODE_VIBRATE :
- AudioManager.RINGER_MODE_SILENT);
- } else {
- mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
- mAudioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,
- vibrate ? AudioManager.VIBRATE_SETTING_ON
- : AudioManager.VIBRATE_SETTING_OFF);
- }
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
- if (preference == mSilent || preference == mVibrate) {
- setRingerMode(mSilent.isChecked(), mVibrate.isChecked());
- if (preference == mSilent) updateState(false);
- } else if (preference == mPlayMediaNotificationSounds) {
- try {
- mMountService.setPlayNotificationSounds(mPlayMediaNotificationSounds.isChecked());
- } catch (RemoteException e) {
+ if (preference == mSilent) {
+ if (mSilent.isChecked()) {
+ boolean vibeInSilent = (1 == Settings.System.getInt(
+ getContentResolver(),
+ Settings.System.VIBRATE_IN_SILENT,
+ 1));
+ mAudioManager.setRingerMode(
+ vibeInSilent ? AudioManager.RINGER_MODE_VIBRATE
+ : AudioManager.RINGER_MODE_SILENT);
+ } else {
+ mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
}
+ updateState(false);
} else if (preference == mDtmfTone) {
Settings.System.putInt(getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING,
mDtmfTone.isChecked() ? 1 : 0);
@@ -301,10 +304,10 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
Settings.System.putInt(getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED,
mHapticFeedback.isChecked() ? 1 : 0);
- } else if (preference == mAccelerometer) {
- Settings.System.putInt(getContentResolver(),
- Settings.System.ACCELEROMETER_ROTATION,
- mAccelerometer.isChecked() ? 1 : 0);
+ } else if (preference == mLockSounds) {
+ Settings.System.putInt(getContentResolver(), Settings.System.LOCKSCREEN_SOUNDS_ENABLED,
+ mLockSounds.isChecked() ? 1 : 0);
+
} else if (preference == mNotificationPulse) {
boolean value = mNotificationPulse.isChecked();
Settings.System.putInt(getContentResolver(),
@@ -316,34 +319,7 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
public boolean onPreferenceChange(Preference preference, Object objValue) {
final String key = preference.getKey();
- if (KEY_ANIMATIONS.equals(key)) {
- try {
- int value = Integer.parseInt((String) objValue);
- if (mAnimationScales.length >= 1) {
- mAnimationScales[0] = value%10;
- }
- if (mAnimationScales.length >= 2) {
- mAnimationScales[1] = (value/10)%10;
- }
- try {
- mWindowManager.setAnimationScales(mAnimationScales);
- } catch (RemoteException e) {
- }
- updateAnimationsSummary(objValue);
- } catch (NumberFormatException e) {
- Log.e(TAG, "could not persist animation setting", e);
- }
-
- }
- if (KEY_SCREEN_TIMEOUT.equals(key)) {
- int value = Integer.parseInt((String) objValue);
- try {
- Settings.System.putInt(getContentResolver(),
- SCREEN_OFF_TIMEOUT, value);
- } catch (NumberFormatException e) {
- Log.e(TAG, "could not persist screen timeout setting", e);
- }
- } else if (KEY_EMERGENCY_TONE.equals(key)) {
+ if (KEY_EMERGENCY_TONE.equals(key)) {
int value = Integer.parseInt((String) objValue);
try {
Settings.System.putInt(getContentResolver(),
@@ -351,6 +327,9 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
} catch (NumberFormatException e) {
Log.e(TAG, "could not persist emergency tone setting", e);
}
+ } else if (preference == mVibrate) {
+ setPhoneVibrateSettingValue(objValue.toString());
+ updateState(false);
}
return true;
diff --git a/src/com/android/settings/TetherSettings.java b/src/com/android/settings/TetherSettings.java
new file mode 100644
index 0000000..9eee4e0
--- /dev/null
+++ b/src/com/android/settings/TetherSettings.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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 com.android.settings;
+
+import com.android.settings.wifi.WifiApEnabler;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.os.Bundle;
+import android.os.SystemProperties;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.AssetManager;
+import android.net.ConnectivityManager;
+import android.os.Environment;
+import android.preference.CheckBoxPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.provider.Settings;
+import android.util.Log;
+import android.webkit.WebView;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Locale;
+
+/*
+ * Displays preferences for Tethering.
+ */
+public class TetherSettings extends PreferenceActivity {
+ private static final String USB_TETHER_SETTINGS = "usb_tether_settings";
+ private static final String ENABLE_WIFI_AP = "enable_wifi_ap";
+ private static final String WIFI_AP_SETTINGS = "wifi_ap_settings";
+ private static final String TETHERING_HELP = "tethering_help";
+ private static final String USB_HELP_MODIFIER = "usb_";
+ private static final String WIFI_HELP_MODIFIER = "wifi_";
+ private static final String HELP_URL = "file:///android_asset/html/%y%z/tethering_%xhelp.html";
+ private static final String HELP_PATH = "html/%y%z/tethering_help.html";
+
+ private static final int DIALOG_TETHER_HELP = 1;
+
+ private WebView mView;
+ private CheckBoxPreference mUsbTether;
+
+ private CheckBoxPreference mEnableWifiAp;
+ private PreferenceScreen mWifiApSettings;
+ private WifiApEnabler mWifiApEnabler;
+ private PreferenceScreen mTetherHelp;
+
+ private BroadcastReceiver mTetherChangeReceiver;
+
+ private String[] mUsbRegexs;
+ private ArrayList mUsbIfaces;
+
+ private String[] mWifiRegexs;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ addPreferencesFromResource(R.xml.tether_prefs);
+
+ mEnableWifiAp = (CheckBoxPreference) findPreference(ENABLE_WIFI_AP);
+ mWifiApSettings = (PreferenceScreen) findPreference(WIFI_AP_SETTINGS);
+ mUsbTether = (CheckBoxPreference) findPreference(USB_TETHER_SETTINGS);
+ mTetherHelp = (PreferenceScreen) findPreference(TETHERING_HELP);
+
+ ConnectivityManager cm =
+ (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ mUsbRegexs = cm.getTetherableUsbRegexs();
+ if (mUsbRegexs.length == 0) {
+ getPreferenceScreen().removePreference(mUsbTether);
+
+ setTitle(R.string.tether_settings_title_wifi);
+ }
+
+ mWifiRegexs = cm.getTetherableWifiRegexs();
+ if (mWifiRegexs.length == 0) {
+ getPreferenceScreen().removePreference(mEnableWifiAp);
+ getPreferenceScreen().removePreference(mWifiApSettings);
+
+ setTitle(R.string.tether_settings_title_usb);
+ } else if (mUsbRegexs.length != 0) {
+ // have both
+ setTitle(R.string.tether_settings_title_both);
+ }
+ mWifiApEnabler = new WifiApEnabler(this, mEnableWifiAp);
+ mView = new WebView(this);
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ if (id == DIALOG_TETHER_HELP) {
+ Locale locale = Locale.getDefault();
+
+ // check for the full language + country resource, if not there, try just language
+ AssetManager am = getAssets();
+ String path = HELP_PATH.replace("%y", locale.getLanguage().toLowerCase());
+ path = path.replace("%z", "_"+locale.getCountry().toLowerCase());
+ boolean useCountry = true;
+ InputStream is = null;
+ try {
+ is = am.open(path);
+ } catch (Exception e) {
+ useCountry = false;
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (Exception e) {}
+ }
+ }
+ String url = HELP_URL.replace("%y", locale.getLanguage().toLowerCase());
+ url = url.replace("%z", (useCountry ? "_"+locale.getCountry().toLowerCase() : ""));
+ if ((mUsbRegexs.length != 0) && (mWifiRegexs.length == 0)) {
+ url = url.replace("%x", USB_HELP_MODIFIER);
+ } else if ((mWifiRegexs.length != 0) && (mUsbRegexs.length == 0)) {
+ url = url.replace("%x", WIFI_HELP_MODIFIER);
+ } else {
+ // could assert that both wifi and usb have regexs, but the default
+ // is to use this anyway so no check is needed
+ url = url.replace("%x", "");
+ }
+
+ mView.loadUrl(url);
+
+ return new AlertDialog.Builder(this)
+ .setCancelable(true)
+ .setTitle(R.string.tethering_help_button_text)
+ .setView(mView)
+ .create();
+ }
+ return null;
+ }
+
+ private class TetherChangeReceiver extends BroadcastReceiver {
+ public void onReceive(Context content, Intent intent) {
+ if (intent.getAction().equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
+ // TODO - this should understand the interface types
+ ArrayList<String> available = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ ArrayList<String> active = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_ACTIVE_TETHER);
+ ArrayList<String> errored = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_ERRORED_TETHER);
+ updateState(available.toArray(), active.toArray(), errored.toArray());
+ } else if (intent.getAction().equals(Intent.ACTION_MEDIA_SHARED) ||
+ intent.getAction().equals(Intent.ACTION_MEDIA_UNSHARED)) {
+ updateState();
+ }
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ IntentFilter filter = new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+ mTetherChangeReceiver = new TetherChangeReceiver();
+ Intent intent = registerReceiver(mTetherChangeReceiver, filter);
+
+ filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_MEDIA_SHARED);
+ filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
+ filter.addDataScheme("file");
+ registerReceiver(mTetherChangeReceiver, filter);
+
+ if (intent != null) mTetherChangeReceiver.onReceive(this, intent);
+ mWifiApEnabler.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ unregisterReceiver(mTetherChangeReceiver);
+ mTetherChangeReceiver = null;
+ mWifiApEnabler.pause();
+ }
+
+ private void updateState() {
+ ConnectivityManager cm =
+ (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ String[] available = cm.getTetherableIfaces();
+ String[] tethered = cm.getTetheredIfaces();
+ String[] errored = cm.getTetheringErroredIfaces();
+ updateState(available, tethered, errored);
+ }
+
+ private void updateState(Object[] available, Object[] tethered,
+ Object[] errored) {
+ ConnectivityManager cm =
+ (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
+ boolean usbTethered = false;
+ boolean usbAvailable = false;
+ int usbError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ boolean usbErrored = false;
+ boolean massStorageActive =
+ Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState());
+ for (Object o : available) {
+ String s = (String)o;
+ for (String regex : mUsbRegexs) {
+ if (s.matches(regex)) {
+ usbAvailable = true;
+ if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ usbError = cm.getLastTetherError(s);
+ }
+ }
+ }
+ }
+ for (Object o : tethered) {
+ String s = (String)o;
+ for (String regex : mUsbRegexs) {
+ if (s.matches(regex)) usbTethered = true;
+ }
+ }
+ for (Object o: errored) {
+ String s = (String)o;
+ for (String regex : mUsbRegexs) {
+ if (s.matches(regex)) usbErrored = true;
+ }
+ }
+
+ if (usbTethered) {
+ mUsbTether.setSummary(R.string.usb_tethering_active_subtext);
+ mUsbTether.setEnabled(true);
+ mUsbTether.setChecked(true);
+ } else if (usbAvailable) {
+ if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ mUsbTether.setSummary(R.string.usb_tethering_available_subtext);
+ } else {
+ mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
+ }
+ mUsbTether.setEnabled(true);
+ mUsbTether.setChecked(false);
+ } else if (usbErrored) {
+ mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
+ mUsbTether.setEnabled(false);
+ mUsbTether.setChecked(false);
+ } else if (massStorageActive) {
+ mUsbTether.setSummary(R.string.usb_tethering_storage_active_subtext);
+ mUsbTether.setEnabled(false);
+ mUsbTether.setChecked(false);
+ } else {
+ mUsbTether.setSummary(R.string.usb_tethering_unavailable_subtext);
+ mUsbTether.setEnabled(false);
+ mUsbTether.setChecked(false);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (preference == mUsbTether) {
+ boolean newState = mUsbTether.isChecked();
+
+ ConnectivityManager cm =
+ (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ if (newState) {
+ String[] available = cm.getTetherableIfaces();
+
+ String usbIface = findIface(available, mUsbRegexs);
+ if (usbIface == null) {
+ updateState();
+ return true;
+ }
+ if (cm.tether(usbIface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ mUsbTether.setChecked(false);
+ mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
+ return true;
+ }
+ mUsbTether.setSummary("");
+ } else {
+ String [] tethered = cm.getTetheredIfaces();
+
+ String usbIface = findIface(tethered, mUsbRegexs);
+ if (usbIface == null) {
+ updateState();
+ return true;
+ }
+ if (cm.untether(usbIface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
+ return true;
+ }
+ mUsbTether.setSummary("");
+ }
+ } else if (preference == mTetherHelp) {
+
+ showDialog(DIALOG_TETHER_HELP);
+ }
+ return false;
+ }
+
+ private String findIface(String[] ifaces, String[] regexes) {
+ for (String iface : ifaces) {
+ for (String regex : regexes) {
+ if (iface.matches(regex)) {
+ return iface;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/settings/TextToSpeechSettings.java b/src/com/android/settings/TextToSpeechSettings.java
index f60d0f2..89a4641 100644
--- a/src/com/android/settings/TextToSpeechSettings.java
+++ b/src/com/android/settings/TextToSpeechSettings.java
@@ -22,8 +22,11 @@ import static android.provider.Settings.Secure.TTS_DEFAULT_LANG;
import static android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY;
import static android.provider.Settings.Secure.TTS_DEFAULT_VARIANT;
import static android.provider.Settings.Secure.TTS_DEFAULT_SYNTH;
+import static android.provider.Settings.Secure.TTS_ENABLED_PLUGINS;
+import android.app.AlertDialog;
import android.content.ContentResolver;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
@@ -31,13 +34,17 @@ import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
import android.preference.CheckBoxPreference;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.speech.tts.TextToSpeech;
import android.util.Log;
+import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;
@@ -48,6 +55,7 @@ public class TextToSpeechSettings extends PreferenceActivity implements
private static final String TAG = "TextToSpeechSettings";
+ private static final String SYSTEM_TTS = "com.svox.pico";
private static final String KEY_TTS_PLAY_EXAMPLE = "tts_play_example";
private static final String KEY_TTS_INSTALL_DATA = "tts_install_data";
private static final String KEY_TTS_USE_DEFAULT = "toggle_use_default_tts_settings";
@@ -55,6 +63,11 @@ public class TextToSpeechSettings extends PreferenceActivity implements
private static final String KEY_TTS_DEFAULT_LANG = "tts_default_lang";
private static final String KEY_TTS_DEFAULT_COUNTRY = "tts_default_country";
private static final String KEY_TTS_DEFAULT_VARIANT = "tts_default_variant";
+ private static final String KEY_TTS_DEFAULT_SYNTH = "tts_default_synth";
+
+ private static final String KEY_PLUGIN_ENABLED_PREFIX = "ENABLED_";
+ private static final String KEY_PLUGIN_SETTINGS_PREFIX = "SETTINGS_";
+
// TODO move default Locale values to TextToSpeech.Engine
private static final String DEFAULT_LANG_VAL = "eng";
private static final String DEFAULT_COUNTRY_VAL = "USA";
@@ -70,6 +83,7 @@ public class TextToSpeechSettings extends PreferenceActivity implements
private CheckBoxPreference mUseDefaultPref = null;
private ListPreference mDefaultRatePref = null;
private ListPreference mDefaultLocPref = null;
+ private ListPreference mDefaultSynthPref = null;
private String mDefaultLanguage = null;
private String mDefaultCountry = null;
private String mDefaultLocVariant = null;
@@ -82,14 +96,17 @@ public class TextToSpeechSettings extends PreferenceActivity implements
private int mDemoStringIndex = 0;
private boolean mEnableDemo = false;
+ private boolean mVoicesMissing = false;
private TextToSpeech mTts = null;
+ private boolean mTtsStarted = false;
/**
* Request code (arbitrary value) for voice data check through
* startActivityForResult.
*/
private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
+ private static final int GET_SAMPLE_TEXT = 1983;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -97,25 +114,35 @@ public class TextToSpeechSettings extends PreferenceActivity implements
addPreferencesFromResource(R.xml.tts_settings);
+ addEngineSpecificSettings();
+
mDemoStrings = getResources().getStringArray(R.array.tts_demo_strings);
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
mEnableDemo = false;
- initClickers();
- initDefaultSettings();
+ mTtsStarted = false;
+
+ Locale currentLocale = Locale.getDefault();
+ mDefaultLanguage = currentLocale.getISO3Language();
+ mDefaultCountry = currentLocale.getISO3Country();
+ mDefaultLocVariant = currentLocale.getVariant();
+
+ mTts = new TextToSpeech(this, this);
}
@Override
protected void onStart() {
super.onStart();
- // whenever we return to this screen, we don't know the state of the
- // system, so we have to recheck that we can play the demo, or it must be disabled.
- // TODO make the TTS service listen to "changes in the system", i.e. sd card un/mount
- initClickers();
- updateWidgetState();
- checkVoiceData();
+ if (mTtsStarted){
+ // whenever we return to this screen, we don't know the state of the
+ // system, so we have to recheck that we can play the demo, or it must be disabled.
+ // TODO make the TTS service listen to "changes in the system", i.e. sd card un/mount
+ initClickers();
+ updateWidgetState();
+ checkVoiceData();
+ }
}
@@ -127,6 +154,70 @@ public class TextToSpeechSettings extends PreferenceActivity implements
}
}
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if ((mDefaultRatePref != null) && (mDefaultRatePref.getDialog() != null)) {
+ mDefaultRatePref.getDialog().dismiss();
+ }
+ if ((mDefaultLocPref != null) && (mDefaultLocPref.getDialog() != null)) {
+ mDefaultLocPref.getDialog().dismiss();
+ }
+ if ((mDefaultSynthPref != null) && (mDefaultSynthPref.getDialog() != null)) {
+ mDefaultSynthPref.getDialog().dismiss();
+ }
+ }
+
+
+
+ private void addEngineSpecificSettings() {
+ PreferenceGroup enginesCategory = (PreferenceGroup) findPreference("tts_engines_section");
+ Intent intent = new Intent("android.intent.action.START_TTS_ENGINE");
+ ResolveInfo[] enginesArray = new ResolveInfo[0];
+ PackageManager pm = getPackageManager();
+ enginesArray = pm.queryIntentActivities(intent, 0).toArray(enginesArray);
+ for (int i = 0; i < enginesArray.length; i++) {
+ String prefKey = "";
+ final String pluginPackageName = enginesArray[i].activityInfo.packageName;
+ if (!enginesArray[i].activityInfo.packageName.equals(SYSTEM_TTS)) {
+ CheckBoxPreference chkbxPref = new CheckBoxPreference(this);
+ prefKey = KEY_PLUGIN_ENABLED_PREFIX + pluginPackageName;
+ chkbxPref.setKey(prefKey);
+ chkbxPref.setTitle(enginesArray[i].loadLabel(pm));
+ enginesCategory.addPreference(chkbxPref);
+ }
+ if (pluginHasSettings(pluginPackageName)) {
+ Preference pref = new Preference(this);
+ prefKey = KEY_PLUGIN_SETTINGS_PREFIX + pluginPackageName;
+ pref.setKey(prefKey);
+ pref.setTitle(enginesArray[i].loadLabel(pm));
+ CharSequence settingsLabel = getResources().getString(
+ R.string.tts_engine_name_settings, enginesArray[i].loadLabel(pm));
+ pref.setSummary(settingsLabel);
+ pref.setOnPreferenceClickListener(new OnPreferenceClickListener(){
+ public boolean onPreferenceClick(Preference preference){
+ Intent i = new Intent();
+ i.setClassName(pluginPackageName,
+ pluginPackageName + ".EngineSettings");
+ startActivity(i);
+ return true;
+ }
+ });
+ enginesCategory.addPreference(pref);
+ }
+ }
+ }
+
+ private boolean pluginHasSettings(String pluginPackageName) {
+ PackageManager pm = getPackageManager();
+ Intent i = new Intent();
+ i.setClassName(pluginPackageName, pluginPackageName + ".EngineSettings");
+ if (pm.resolveActivity(i, PackageManager.MATCH_DEFAULT_ONLY) != null){
+ return true;
+ }
+ return false;
+ }
+
private void initClickers() {
mPlayExample = findPreference(KEY_TTS_PLAY_EXAMPLE);
@@ -156,7 +247,10 @@ public class TextToSpeechSettings extends PreferenceActivity implements
mUseDefaultPref.setChecked(useDefault == 1);
mUseDefaultPref.setOnPreferenceChangeListener(this);
- // Default engine
+ // Default synthesis engine
+ mDefaultSynthPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_SYNTH);
+ loadEngines();
+ mDefaultSynthPref.setOnPreferenceChangeListener(this);
String engine = Settings.Secure.getString(resolver, TTS_DEFAULT_SYNTH);
if (engine == null) {
// TODO move FALLBACK_TTS_DEFAULT_SYNTH to TextToSpeech
@@ -225,16 +319,54 @@ public class TextToSpeechSettings extends PreferenceActivity implements
}
}
+ /**
+ * Ask the current default engine to return a string of sample text to be
+ * spoken to the user.
+ */
+ private void getSampleText() {
+ PackageManager pm = getPackageManager();
+ Intent intent = new Intent();
+ // TODO (clchen): Replace Intent string with the actual
+ // Intent defined in the list of platform Intents.
+ intent.setAction("android.speech.tts.engine.GET_SAMPLE_TEXT");
+ intent.putExtra("language", mDefaultLanguage);
+ intent.putExtra("country", mDefaultCountry);
+ intent.putExtra("variant", mDefaultLocVariant);
+ List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
+ // query only the package that matches that of the default engine
+ for (int i = 0; i < resolveInfos.size(); i++) {
+ ActivityInfo currentActivityInfo = resolveInfos.get(i).activityInfo;
+ if (mDefaultEng.equals(currentActivityInfo.packageName)) {
+ intent.setClassName(mDefaultEng, currentActivityInfo.name);
+ this.startActivityForResult(intent, GET_SAMPLE_TEXT);
+ }
+ }
+ }
+
/**
* Called when the TTS engine is initialized.
*/
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
- Log.v(TAG, "TTS engine for settings screen initialized.");
mEnableDemo = true;
- mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry));
+ if (mDefaultLanguage == null) {
+ mDefaultLanguage = Locale.getDefault().getISO3Language();
+ }
+ if (mDefaultCountry == null) {
+ mDefaultCountry = Locale.getDefault().getISO3Country();
+ }
+ if (mDefaultLocVariant == null) {
+ mDefaultLocVariant = new String();
+ }
+ mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
mTts.setSpeechRate((float)(mDefaultRate/100.0f));
+ initDefaultSettings();
+ initClickers();
+ updateWidgetState();
+ checkVoiceData();
+ mTtsStarted = true;
+ Log.v(TAG, "TTS engine for settings screen initialized.");
} else {
Log.v(TAG, "TTS engine for settings screen failed to initialize successfully.");
mEnableDemo = false;
@@ -248,15 +380,114 @@ public class TextToSpeechSettings extends PreferenceActivity implements
*/
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == VOICE_DATA_INTEGRITY_CHECK) {
- if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
- Log.v(TAG, "Voice data check passed");
+ if (data == null){
+ // The CHECK_TTS_DATA activity for the plugin did not run properly;
+ // disable the preview and install controls and return.
+ mEnableDemo = false;
+ mVoicesMissing = false;
+ updateWidgetState();
+ return;
+ }
+ ArrayList<String> available =
+ data.getStringArrayListExtra(TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES);
+ ArrayList<String> unavailable =
+ data.getStringArrayListExtra(TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES);
+ if ((available == null) || (unavailable == null)){
+ // The CHECK_TTS_DATA activity for the plugin did not run properly;
+ // disable the preview and install controls and return.
+ mEnableDemo = false;
+ mVoicesMissing = false;
+ updateWidgetState();
+ return;
+ }
+ if (available.size() > 0){
if (mTts == null) {
mTts = new TextToSpeech(this, this);
}
+ ListPreference ttsLanguagePref =
+ (ListPreference) findPreference("tts_default_lang");
+ CharSequence[] entries = new CharSequence[available.size()];
+ CharSequence[] entryValues = new CharSequence[available.size()];
+ int selectedLanguageIndex = -1;
+ String selectedLanguagePref = mDefaultLanguage;
+ if (mDefaultCountry.length() > 0) {
+ selectedLanguagePref = selectedLanguagePref + LOCALE_DELIMITER +
+ mDefaultCountry;
+ }
+ if (mDefaultLocVariant.length() > 0) {
+ selectedLanguagePref = selectedLanguagePref + LOCALE_DELIMITER +
+ mDefaultLocVariant;
+ }
+ for (int i = 0; i < available.size(); i++) {
+ String[] langCountryVariant = available.get(i).split("-");
+ Locale loc = null;
+ if (langCountryVariant.length == 1){
+ loc = new Locale(langCountryVariant[0]);
+ } else if (langCountryVariant.length == 2){
+ loc = new Locale(langCountryVariant[0], langCountryVariant[1]);
+ } else if (langCountryVariant.length == 3){
+ loc = new Locale(langCountryVariant[0], langCountryVariant[1],
+ langCountryVariant[2]);
+ }
+ if (loc != null){
+ entries[i] = loc.getDisplayName();
+ entryValues[i] = available.get(i);
+ if (entryValues[i].equals(selectedLanguagePref)) {
+ selectedLanguageIndex = i;
+ }
+ }
+ }
+ ttsLanguagePref.setEntries(entries);
+ ttsLanguagePref.setEntryValues(entryValues);
+ if (selectedLanguageIndex > -1) {
+ ttsLanguagePref.setValueIndex(selectedLanguageIndex);
+ }
+ mEnableDemo = true;
+ // Make sure that the default language can be used.
+ int languageResult = mTts.setLanguage(
+ new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
+ if (languageResult < TextToSpeech.LANG_AVAILABLE){
+ Locale currentLocale = Locale.getDefault();
+ mDefaultLanguage = currentLocale.getISO3Language();
+ mDefaultCountry = currentLocale.getISO3Country();
+ mDefaultLocVariant = currentLocale.getVariant();
+ languageResult = mTts.setLanguage(
+ new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
+ // If the default Locale isn't supported, just choose the first available
+ // language so that there is at least something.
+ if (languageResult < TextToSpeech.LANG_AVAILABLE){
+ parseLocaleInfo(ttsLanguagePref.getEntryValues()[0].toString());
+ mTts.setLanguage(
+ new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
+ }
+ ContentResolver resolver = getContentResolver();
+ Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, mDefaultLanguage);
+ Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, mDefaultCountry);
+ Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, mDefaultLocVariant);
+ }
} else {
- Log.v(TAG, "Voice data check failed");
mEnableDemo = false;
- updateWidgetState();
+ }
+
+ if (unavailable.size() > 0){
+ mVoicesMissing = true;
+ } else {
+ mVoicesMissing = false;
+ }
+
+ updateWidgetState();
+ } else if (requestCode == GET_SAMPLE_TEXT) {
+ if (resultCode == TextToSpeech.LANG_AVAILABLE) {
+ String sample = getString(R.string.tts_demo);
+ if ((data != null) && (data.getStringExtra("sampleText") != null)) {
+ sample = data.getStringExtra("sampleText");
+ }
+ if (mTts != null) {
+ mTts.speak(sample, TextToSpeech.QUEUE_FLUSH, null);
+ }
+ } else {
+ // TODO: Display an error here to the user.
+ Log.e(TAG, "Did not have a sample string for the requested language");
}
}
}
@@ -292,11 +523,22 @@ public class TextToSpeechSettings extends PreferenceActivity implements
Log.v(TAG, "TTS default lang/country/variant set to "
+ mDefaultLanguage + "/" + mDefaultCountry + "/" + mDefaultLocVariant);
if (mTts != null) {
- mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry));
+ mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
}
int newIndex = mDefaultLocPref.findIndexOfValue((String)objValue);
Log.v("Settings", " selected is " + newIndex);
mDemoStringIndex = newIndex > -1 ? newIndex : 0;
+ } else if (KEY_TTS_DEFAULT_SYNTH.equals(preference.getKey())) {
+ mDefaultEng = objValue.toString();
+ Settings.Secure.putString(getContentResolver(), TTS_DEFAULT_SYNTH, mDefaultEng);
+ if (mTts != null) {
+ mTts.setEngineByPackageName(mDefaultEng);
+ mEnableDemo = false;
+ mVoicesMissing = false;
+ updateWidgetState();
+ checkVoiceData();
+ }
+ Log.v("Settings", "The default synth is: " + objValue.toString());
}
return true;
@@ -308,10 +550,9 @@ public class TextToSpeechSettings extends PreferenceActivity implements
*/
public boolean onPreferenceClick(Preference preference) {
if (preference == mPlayExample) {
- // Play example
- if (mTts != null) {
- mTts.speak(mDemoStrings[mDemoStringIndex], TextToSpeech.QUEUE_FLUSH, null);
- }
+ // Get the sample text from the TTS engine; onActivityResult will do
+ // the actual speaking
+ getSampleText();
return true;
}
if (preference == mInstallData) {
@@ -323,6 +564,46 @@ public class TextToSpeechSettings extends PreferenceActivity implements
return false;
}
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (Utils.isMonkeyRunning()) {
+ return false;
+ }
+
+ if (preference instanceof CheckBoxPreference) {
+ final CheckBoxPreference chkPref = (CheckBoxPreference) preference;
+ if (!chkPref.getKey().equals(KEY_TTS_USE_DEFAULT)){
+ if (chkPref.isChecked()) {
+ chkPref.setChecked(false);
+ AlertDialog d = (new AlertDialog.Builder(this))
+ .setTitle(android.R.string.dialog_alert_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(getString(R.string.tts_engine_security_warning,
+ chkPref.getTitle()))
+ .setCancelable(true)
+ .setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ chkPref.setChecked(true);
+ loadEngines();
+ }
+ })
+ .setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ }
+ })
+ .create();
+ d.show();
+ } else {
+ loadEngines();
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
private void updateWidgetState() {
mPlayExample.setEnabled(mEnableDemo);
@@ -330,7 +611,7 @@ public class TextToSpeechSettings extends PreferenceActivity implements
mDefaultRatePref.setEnabled(mEnableDemo);
mDefaultLocPref.setEnabled(mEnableDemo);
- mInstallData.setEnabled(!mEnableDemo);
+ mInstallData.setEnabled(mVoicesMissing);
}
@@ -372,13 +653,15 @@ public class TextToSpeechSettings extends PreferenceActivity implements
// demo string (at this stage there is a default language pref)
ContentResolver resolver = getContentResolver();
mDefaultLanguage = Settings.Secure.getString(resolver, TTS_DEFAULT_LANG);
- mDefaultCountry = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_COUNTRY);
- mDefaultLocVariant = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_VARIANT);
+ mDefaultCountry = Settings.Secure.getString(resolver, TTS_DEFAULT_COUNTRY);
+ mDefaultLocVariant = Settings.Secure.getString(resolver, TTS_DEFAULT_VARIANT);
// update the demo string
mDemoStringIndex = mDefaultLocPref.findIndexOfValue(mDefaultLanguage + LOCALE_DELIMITER
+ mDefaultCountry);
- mDefaultLocPref.setValueIndex(mDemoStringIndex);
+ if (mDemoStringIndex > -1){
+ mDefaultLocPref.setValueIndex(mDemoStringIndex);
+ }
}
/**
@@ -386,8 +669,20 @@ public class TextToSpeechSettings extends PreferenceActivity implements
* Returns whether there is a default language in the TTS settings.
*/
private boolean hasLangPref() {
- String language = Settings.Secure.getString(getContentResolver(), TTS_DEFAULT_LANG);
- return (language != null);
+ ContentResolver resolver = getContentResolver();
+ String language = Settings.Secure.getString(resolver, TTS_DEFAULT_LANG);
+ if ((language == null) || (language.length() < 1)) {
+ return false;
+ }
+ String country = Settings.Secure.getString(resolver, TTS_DEFAULT_COUNTRY);
+ if (country == null) {
+ return false;
+ }
+ String variant = Settings.Secure.getString(resolver, TTS_DEFAULT_VARIANT);
+ if (variant == null) {
+ return false;
+ }
+ return true;
}
/**
@@ -424,4 +719,50 @@ public class TextToSpeechSettings extends PreferenceActivity implements
Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, DEFAULT_VARIANT_VAL);
}
+
+ private void loadEngines() {
+ mDefaultSynthPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_SYNTH);
+
+ // TODO (clchen): Try to see if it is possible to be more efficient here
+ // and not search for plugins again.
+ Intent intent = new Intent("android.intent.action.START_TTS_ENGINE");
+ ResolveInfo[] enginesArray = new ResolveInfo[0];
+ PackageManager pm = getPackageManager();
+ enginesArray = pm.queryIntentActivities(intent, 0).toArray(enginesArray);
+ ArrayList<CharSequence> entries = new ArrayList<CharSequence>();
+ ArrayList<CharSequence> values = new ArrayList<CharSequence>();
+ String enabledEngines = "";
+ for (int i = 0; i < enginesArray.length; i++) {
+ String pluginPackageName = enginesArray[i].activityInfo.packageName;
+ if (pluginPackageName.equals(SYSTEM_TTS)) {
+ entries.add(enginesArray[i].loadLabel(pm));
+ values.add(pluginPackageName);
+ } else {
+ CheckBoxPreference pref = (CheckBoxPreference) findPreference(
+ KEY_PLUGIN_ENABLED_PREFIX + pluginPackageName);
+ if ((pref != null) && pref.isChecked()){
+ entries.add(enginesArray[i].loadLabel(pm));
+ values.add(pluginPackageName);
+ enabledEngines = enabledEngines + pluginPackageName + " ";
+ }
+ }
+ }
+ ContentResolver resolver = getContentResolver();
+ Settings.Secure.putString(resolver, TTS_ENABLED_PLUGINS, enabledEngines);
+
+ CharSequence entriesArray[] = new CharSequence[entries.size()];
+ CharSequence valuesArray[] = new CharSequence[values.size()];
+
+ mDefaultSynthPref.setEntries(entries.toArray(entriesArray));
+ mDefaultSynthPref.setEntryValues(values.toArray(valuesArray));
+
+ // Set the selected engine based on the saved preference
+ String selectedEngine = Settings.Secure.getString(getContentResolver(), TTS_DEFAULT_SYNTH);
+ int selectedEngineIndex = mDefaultSynthPref.findIndexOfValue(selectedEngine);
+ if (selectedEngineIndex == -1){
+ selectedEngineIndex = mDefaultSynthPref.findIndexOfValue(SYSTEM_TTS);
+ }
+ mDefaultSynthPref.setValueIndex(selectedEngineIndex);
+ }
+
}
diff --git a/src/com/android/settings/UserDictionarySettings.java b/src/com/android/settings/UserDictionarySettings.java
index 4b30b53..6ffcb3d 100644
--- a/src/com/android/settings/UserDictionarySettings.java
+++ b/src/com/android/settings/UserDictionarySettings.java
@@ -159,7 +159,8 @@ public class UserDictionarySettings extends ListActivity {
AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo;
String word = getWord(adapterMenuInfo.position);
-
+ if (word == null) return true;
+
switch (item.getItemId()) {
case CONTEXT_MENU_DELETE:
deleteWord(word);
@@ -193,6 +194,9 @@ public class UserDictionarySettings extends ListActivity {
private String getWord(int position) {
mCursor.moveToPosition(position);
+ // Handle a possible race-condition
+ if (mCursor.isAfterLast()) return null;
+
return mCursor.getString(
mCursor.getColumnIndexOrThrow(UserDictionary.Words.WORD));
}
diff --git a/src/com/android/settings/VoiceInputOutputSettings.java b/src/com/android/settings/VoiceInputOutputSettings.java
new file mode 100644
index 0000000..30bedda
--- /dev/null
+++ b/src/com/android/settings/VoiceInputOutputSettings.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Bundle;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.provider.Settings;
+import android.speech.RecognitionService;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Settings screen for voice input/output.
+ */
+public class VoiceInputOutputSettings extends PreferenceActivity
+ implements OnPreferenceChangeListener {
+
+ private static final String TAG = "VoiceInputOutputSettings";
+
+ private static final String KEY_PARENT = "parent";
+ private static final String KEY_VOICE_INPUT_CATEGORY = "voice_input_category";
+ private static final String KEY_RECOGNIZER = "recognizer";
+ private static final String KEY_RECOGNIZER_SETTINGS = "recognizer_settings";
+
+ private PreferenceGroup mParent;
+ private PreferenceCategory mVoiceInputCategory;
+ private ListPreference mRecognizerPref;
+ private PreferenceScreen mSettingsPref;
+
+ private HashMap<String, ResolveInfo> mAvailableRecognizersMap;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ addPreferencesFromResource(R.xml.voice_input_output_settings);
+
+ mParent = (PreferenceGroup) findPreference(KEY_PARENT);
+ mVoiceInputCategory = (PreferenceCategory) mParent.findPreference(KEY_VOICE_INPUT_CATEGORY);
+ mRecognizerPref = (ListPreference) mParent.findPreference(KEY_RECOGNIZER);
+ mRecognizerPref.setOnPreferenceChangeListener(this);
+ mSettingsPref = (PreferenceScreen) mParent.findPreference(KEY_RECOGNIZER_SETTINGS);
+
+ mAvailableRecognizersMap = new HashMap<String, ResolveInfo>();
+
+ populateOrRemoveRecognizerPreference();
+ }
+
+ private void populateOrRemoveRecognizerPreference() {
+ List<ResolveInfo> availableRecognitionServices = getPackageManager().queryIntentServices(
+ new Intent(RecognitionService.SERVICE_INTERFACE), PackageManager.GET_META_DATA);
+ int numAvailable = availableRecognitionServices.size();
+
+ if (numAvailable == 0) {
+ // No recognizer available - remove all related preferences.
+ removePreference(mVoiceInputCategory);
+ removePreference(mRecognizerPref);
+ removePreference(mSettingsPref);
+ } else if (numAvailable == 1) {
+ // Only one recognizer available, so don't show the list of choices, but do
+ // set up the link to settings for the available recognizer.
+ removePreference(mRecognizerPref);
+
+ // But first set up the available recognizers map with just the one recognizer.
+ ResolveInfo resolveInfo = availableRecognitionServices.get(0);
+ String recognizerComponent =
+ new ComponentName(resolveInfo.serviceInfo.packageName,
+ resolveInfo.serviceInfo.name).flattenToShortString();
+
+ mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
+
+ String currentSetting = Settings.Secure.getString(
+ getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
+ updateSettingsLink(currentSetting);
+ } else {
+ // Multiple recognizers available, so show the full list of choices.
+ populateRecognizerPreference(availableRecognitionServices);
+ }
+ }
+
+ private void removePreference(Preference pref) {
+ if (pref != null) {
+ mParent.removePreference(pref);
+ }
+ }
+
+ private void populateRecognizerPreference(List<ResolveInfo> recognizers) {
+ int size = recognizers.size();
+ CharSequence[] entries = new CharSequence[size];
+ CharSequence[] values = new CharSequence[size];
+
+ // Get the current value from the secure setting.
+ String currentSetting = Settings.Secure.getString(
+ getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
+
+ // Iterate through all the available recognizers and load up their info to show
+ // in the preference. Also build up a map of recognizer component names to their
+ // ResolveInfos - we'll need that a little later.
+ for (int i = 0; i < size; i++) {
+ ResolveInfo resolveInfo = recognizers.get(i);
+ String recognizerComponent =
+ new ComponentName(resolveInfo.serviceInfo.packageName,
+ resolveInfo.serviceInfo.name).flattenToShortString();
+
+ mAvailableRecognizersMap.put(recognizerComponent, resolveInfo);
+
+ entries[i] = resolveInfo.loadLabel(getPackageManager());
+ values[i] = recognizerComponent;
+ }
+
+ mRecognizerPref.setEntries(entries);
+ mRecognizerPref.setEntryValues(values);
+
+ mRecognizerPref.setDefaultValue(currentSetting);
+ mRecognizerPref.setValue(currentSetting);
+
+ updateSettingsLink(currentSetting);
+ }
+
+ private void updateSettingsLink(String currentSetting) {
+ ResolveInfo currentRecognizer = mAvailableRecognizersMap.get(currentSetting);
+ ServiceInfo si = currentRecognizer.serviceInfo;
+ XmlResourceParser parser = null;
+ String settingsActivity = null;
+ try {
+ parser = si.loadXmlMetaData(getPackageManager(), RecognitionService.SERVICE_META_DATA);
+ if (parser == null) {
+ throw new XmlPullParserException("No " + RecognitionService.SERVICE_META_DATA +
+ " meta-data for " + si.packageName);
+ }
+
+ Resources res = getPackageManager().getResourcesForApplication(
+ si.applicationInfo);
+
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ }
+
+ String nodeName = parser.getName();
+ if (!"recognition-service".equals(nodeName)) {
+ throw new XmlPullParserException(
+ "Meta-data does not start with recognition-service tag");
+ }
+
+ TypedArray array = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.RecognitionService);
+ settingsActivity = array.getString(
+ com.android.internal.R.styleable.RecognitionService_settingsActivity);
+ array.recycle();
+ } catch (XmlPullParserException e) {
+ Log.e(TAG, "error parsing recognition service meta-data", e);
+ } catch (IOException e) {
+ Log.e(TAG, "error parsing recognition service meta-data", e);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "error parsing recognition service meta-data", e);
+ } finally {
+ if (parser != null) parser.close();
+ }
+
+ if (settingsActivity == null) {
+ // No settings preference available - hide the preference.
+ Log.w(TAG, "no recognizer settings available for " + si.packageName);
+ mSettingsPref.setIntent(null);
+ mParent.removePreference(mSettingsPref);
+ } else {
+ Intent i = new Intent(Intent.ACTION_MAIN);
+ i.setComponent(new ComponentName(si.packageName, settingsActivity));
+ mSettingsPref.setIntent(i);
+ mRecognizerPref.setSummary(currentRecognizer.loadLabel(getPackageManager()));
+ }
+ }
+
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference == mRecognizerPref) {
+ String setting = (String) newValue;
+
+ // Put the new value back into secure settings.
+ Settings.Secure.putString(
+ getContentResolver(),
+ Settings.Secure.VOICE_RECOGNITION_SERVICE,
+ setting);
+
+ // Update the settings item so it points to the right settings.
+ updateSettingsLink(setting);
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/settings/WirelessSettings.java b/src/com/android/settings/WirelessSettings.java
index 22417bb..78cf8cf 100644
--- a/src/com/android/settings/WirelessSettings.java
+++ b/src/com/android/settings/WirelessSettings.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,10 +17,11 @@
package com.android.settings;
import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
import android.content.Intent;
+import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.preference.CheckBoxPreference;
@@ -28,6 +29,7 @@ import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.provider.Settings;
+import android.util.Log;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
@@ -42,13 +44,14 @@ public class WirelessSettings extends PreferenceActivity {
private static final String KEY_WIFI_SETTINGS = "wifi_settings";
private static final String KEY_BT_SETTINGS = "bt_settings";
private static final String KEY_VPN_SETTINGS = "vpn_settings";
+ private static final String KEY_TETHER_SETTINGS = "tether_settings";
public static final String EXIT_ECM_RESULT = "exit_ecm_result";
public static final int REQUEST_CODE_EXIT_ECM = 1;
- private WifiEnabler mWifiEnabler;
private AirplaneModeEnabler mAirplaneModeEnabler;
- private BluetoothEnabler mBtEnabler;
private CheckBoxPreference mAirplaneModePreference;
+ private WifiEnabler mWifiEnabler;
+ private BluetoothEnabler mBtEnabler;
/**
* Invoked on each preference click in this hierarchy, overrides
@@ -57,96 +60,113 @@ public class WirelessSettings extends PreferenceActivity {
*/
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
- if ( (preference == mAirplaneModePreference) &&
- (Boolean.parseBoolean(
- SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) ) {
+ if (preference == mAirplaneModePreference && Boolean.parseBoolean(
+ SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
// In ECM mode launch ECM app dialog
startActivityForResult(
new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null),
REQUEST_CODE_EXIT_ECM);
-
return true;
}
- else {
- // Let the intents be launched by the Preference manager
- return false;
+ // Let the intents be launched by the Preference manager
+ return false;
+ }
+
+ public static boolean isRadioAllowed(Context context, String type) {
+ if (!AirplaneModeEnabler.isAirplaneModeOn(context)) {
+ return true;
}
+ // Here we use the same logic in onCreate().
+ String toggleable = Settings.System.getString(context.getContentResolver(),
+ Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+ return toggleable != null && toggleable.contains(type);
}
-
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.wireless_settings);
- initToggles();
+ CheckBoxPreference airplane = (CheckBoxPreference) findPreference(KEY_TOGGLE_AIRPLANE);
+ CheckBoxPreference wifi = (CheckBoxPreference) findPreference(KEY_TOGGLE_WIFI);
+ CheckBoxPreference bt = (CheckBoxPreference) findPreference(KEY_TOGGLE_BLUETOOTH);
+
+ mAirplaneModeEnabler = new AirplaneModeEnabler(this, airplane);
mAirplaneModePreference = (CheckBoxPreference) findPreference(KEY_TOGGLE_AIRPLANE);
+ mWifiEnabler = new WifiEnabler(this, wifi);
+ mBtEnabler = new BluetoothEnabler(this, bt);
+
+ String toggleable = Settings.System.getString(getContentResolver(),
+ Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+
+ // Manually set dependencies for Wifi when not toggleable.
+ if (toggleable == null || !toggleable.contains(Settings.System.RADIO_WIFI)) {
+ wifi.setDependency(KEY_TOGGLE_AIRPLANE);
+ findPreference(KEY_WIFI_SETTINGS).setDependency(KEY_TOGGLE_AIRPLANE);
+ findPreference(KEY_VPN_SETTINGS).setDependency(KEY_TOGGLE_AIRPLANE);
+ }
+
+ // Manually set dependencies for Bluetooth when not toggleable.
+ if (toggleable == null || !toggleable.contains(Settings.System.RADIO_BLUETOOTH)) {
+ bt.setDependency(KEY_TOGGLE_AIRPLANE);
+ findPreference(KEY_BT_SETTINGS).setDependency(KEY_TOGGLE_AIRPLANE);
+ }
+
+ // Disable Bluetooth Settings if Bluetooth service is not available.
+ if (ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE) == null) {
+ findPreference(KEY_BT_SETTINGS).setEnabled(false);
+ }
+
+ // Disable Tethering if it's not allowed
+ ConnectivityManager cm =
+ (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (!cm.isTetheringSupported()) {
+ getPreferenceScreen().removePreference(findPreference(KEY_TETHER_SETTINGS));
+ } else {
+ String[] usbRegexs = cm.getTetherableUsbRegexs();
+ String[] wifiRegexs = cm.getTetherableWifiRegexs();
+ Preference p = findPreference(KEY_TETHER_SETTINGS);
+ if (wifiRegexs.length == 0) {
+ p.setTitle(R.string.tether_settings_title_usb);
+ p.setSummary(R.string.tether_settings_summary_usb);
+ } else {
+ if (usbRegexs.length == 0) {
+ p.setTitle(R.string.tether_settings_title_wifi);
+ p.setSummary(R.string.tether_settings_summary_wifi);
+ } else {
+ p.setTitle(R.string.tether_settings_title_both);
+ p.setSummary(R.string.tether_settings_summary_both);
+ }
+ }
+ }
}
-
+
@Override
protected void onResume() {
super.onResume();
+ mAirplaneModeEnabler.resume();
mWifiEnabler.resume();
mBtEnabler.resume();
- mAirplaneModeEnabler.resume();
}
@Override
protected void onPause() {
super.onPause();
- mWifiEnabler.pause();
mAirplaneModeEnabler.pause();
+ mWifiEnabler.pause();
mBtEnabler.pause();
}
- private void initToggles() {
-
- Preference airplanePreference = findPreference(KEY_TOGGLE_AIRPLANE);
- Preference wifiPreference = findPreference(KEY_TOGGLE_WIFI);
- Preference btPreference = findPreference(KEY_TOGGLE_BLUETOOTH);
- Preference wifiSettings = findPreference(KEY_WIFI_SETTINGS);
- Preference vpnSettings = findPreference(KEY_VPN_SETTINGS);
-
- IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
- if (b == null) {
- // Disable BT Settings if BT service is not available.
- Preference btSettings = findPreference(KEY_BT_SETTINGS);
- btSettings.setEnabled(false);
- }
-
- mWifiEnabler = new WifiEnabler(
- this, (WifiManager) getSystemService(WIFI_SERVICE),
- (CheckBoxPreference) wifiPreference);
- mAirplaneModeEnabler = new AirplaneModeEnabler(
- this, (CheckBoxPreference) airplanePreference);
- mBtEnabler = new BluetoothEnabler(this, (CheckBoxPreference) btPreference);
-
- // manually set up dependencies for Wifi if its radio is not toggleable in airplane mode
- String toggleableRadios = Settings.System.getString(getContentResolver(),
- Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
- if (toggleableRadios == null || !toggleableRadios.contains(Settings.System.RADIO_WIFI)) {
- wifiPreference.setDependency(airplanePreference.getKey());
- wifiSettings.setDependency(airplanePreference.getKey());
- vpnSettings.setDependency(airplanePreference.getKey());
- }
- }
-
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch(requestCode) {
- case REQUEST_CODE_EXIT_ECM:
- Boolean isChoiceYes =
- data.getBooleanExtra(EXIT_ECM_RESULT, false);
+ if (requestCode == REQUEST_CODE_EXIT_ECM) {
+ Boolean isChoiceYes = data.getBooleanExtra(EXIT_ECM_RESULT, false);
// Set Airplane mode based on the return value and checkbox state
mAirplaneModeEnabler.setAirplaneModeInECM(isChoiceYes,
mAirplaneModePreference.isChecked());
- break;
-
- default:
- break;
}
}
-
}
diff --git a/src/com/android/settings/bluetooth/BluetoothEnabler.java b/src/com/android/settings/bluetooth/BluetoothEnabler.java
index b872916..426a4d3 100644
--- a/src/com/android/settings/bluetooth/BluetoothEnabler.java
+++ b/src/com/android/settings/bluetooth/BluetoothEnabler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
package com.android.settings.bluetooth;
import com.android.settings.R;
+import com.android.settings.WirelessSettings;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
@@ -25,8 +26,9 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.preference.Preference;
import android.preference.CheckBoxPreference;
+import android.provider.Settings;
import android.text.TextUtils;
-import android.util.Config;
+import android.widget.Toast;
/**
* BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox
@@ -34,16 +36,12 @@ import android.util.Config;
* preference reflects the current state.
*/
public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
-
- private static final boolean LOCAL_LOGD = Config.LOGD || false;
- private static final String TAG = "BluetoothEnabler";
-
private final Context mContext;
- private final CheckBoxPreference mCheckBoxPreference;
+ private final CheckBoxPreference mCheckBox;
private final CharSequence mOriginalSummary;
private final LocalBluetoothManager mLocalManager;
-
+ private final IntentFilter mIntentFilter;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -52,18 +50,18 @@ public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
}
};
- public BluetoothEnabler(Context context, CheckBoxPreference checkBoxPreference) {
+ public BluetoothEnabler(Context context, CheckBoxPreference checkBox) {
mContext = context;
- mCheckBoxPreference = checkBoxPreference;
-
- mOriginalSummary = checkBoxPreference.getSummary();
- checkBoxPreference.setPersistent(false);
+ mCheckBox = checkBox;
+ mOriginalSummary = checkBox.getSummary();
+ checkBox.setPersistent(false);
mLocalManager = LocalBluetoothManager.getInstance(context);
if (mLocalManager == null) {
- // Bluetooth not supported
- checkBoxPreference.setEnabled(false);
+ // Bluetooth is not supported
+ checkBox.setEnabled(false);
}
+ mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
}
public void resume() {
@@ -71,16 +69,11 @@ public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
return;
}
- int state = mLocalManager.getBluetoothState();
- // This is the widget enabled state, not the preference toggled state
- mCheckBoxPreference.setEnabled(state == BluetoothAdapter.STATE_ON ||
- state == BluetoothAdapter.STATE_OFF);
- // BT state is not a sticky broadcast, so set it manually
- handleStateChanged(state);
+ // Bluetooth state is not sticky, so set it manually
+ handleStateChanged(mLocalManager.getBluetoothState());
- mContext.registerReceiver(mReceiver,
- new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
- mCheckBoxPreference.setOnPreferenceChangeListener(this);
+ mContext.registerReceiver(mReceiver, mIntentFilter);
+ mCheckBox.setOnPreferenceChangeListener(this);
}
public void pause() {
@@ -89,72 +82,51 @@ public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
}
mContext.unregisterReceiver(mReceiver);
- mCheckBoxPreference.setOnPreferenceChangeListener(null);
+ mCheckBox.setOnPreferenceChangeListener(null);
}
public boolean onPreferenceChange(Preference preference, Object value) {
- // Turn on/off BT
- setEnabled((Boolean) value);
+ boolean enable = (Boolean) value;
+
+ // Show toast message if Bluetooth is not allowed in airplane mode
+ if (enable && !WirelessSettings
+ .isRadioAllowed(mContext, Settings.System.RADIO_BLUETOOTH)) {
+ Toast.makeText(mContext, R.string.wifi_in_airplane_mode,
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+
+ mLocalManager.setBluetoothEnabled(enable);
+ mCheckBox.setEnabled(false);
// Don't update UI to opposite state until we're sure
return false;
}
- private void setEnabled(final boolean enable) {
- // Disable preference
- mCheckBoxPreference.setEnabled(false);
-
- mLocalManager.setBluetoothEnabled(enable);
- }
-
private void handleStateChanged(int state) {
-
- if (state == BluetoothAdapter.STATE_OFF ||
- state == BluetoothAdapter.STATE_ON) {
- mCheckBoxPreference.setChecked(state == BluetoothAdapter.STATE_ON);
- mCheckBoxPreference.setSummary(state == BluetoothAdapter.STATE_OFF ?
- mOriginalSummary :
- null);
-
- /*
- * Don't ever disable the preference. Only enable here. Disablement
- * is taken care of by the dependency code. If this is disabled
- * here, it may not be re-enabled from the framework when dependency
- * is met. http://b/issue?id=2053751
- */
- if (isEnabledByDependency()) {
- mCheckBoxPreference.setEnabled(true);
- }
-
- } else if (state == BluetoothAdapter.STATE_TURNING_ON ||
- state == BluetoothAdapter.STATE_TURNING_OFF) {
- mCheckBoxPreference.setSummary(state == BluetoothAdapter.STATE_TURNING_ON
- ? R.string.wifi_starting
- : R.string.wifi_stopping);
-
- } else {
- mCheckBoxPreference.setChecked(false);
- mCheckBoxPreference.setSummary(R.string.wifi_error);
- mCheckBoxPreference.setEnabled(true);
- }
- }
-
- private boolean isEnabledByDependency() {
- Preference dep = getDependencyPreference();
- if (dep == null) {
- return true;
- }
-
- return !dep.shouldDisableDependents();
- }
-
- private Preference getDependencyPreference() {
- String depKey = mCheckBoxPreference.getDependency();
- if (TextUtils.isEmpty(depKey)) {
- return null;
+ switch (state) {
+ case BluetoothAdapter.STATE_TURNING_ON:
+ mCheckBox.setSummary(R.string.wifi_starting);
+ mCheckBox.setEnabled(false);
+ break;
+ case BluetoothAdapter.STATE_ON:
+ mCheckBox.setChecked(true);
+ mCheckBox.setSummary(null);
+ mCheckBox.setEnabled(true);
+ break;
+ case BluetoothAdapter.STATE_TURNING_OFF:
+ mCheckBox.setSummary(R.string.wifi_stopping);
+ mCheckBox.setEnabled(false);
+ break;
+ case BluetoothAdapter.STATE_OFF:
+ mCheckBox.setChecked(false);
+ mCheckBox.setSummary(mOriginalSummary);
+ mCheckBox.setEnabled(true);
+ break;
+ default:
+ mCheckBox.setChecked(false);
+ mCheckBox.setSummary(R.string.wifi_error);
+ mCheckBox.setEnabled(true);
}
-
- return mCheckBoxPreference.getPreferenceManager().findPreference(depKey);
}
-
}
diff --git a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
index c1a2116..dbdf6c1 100644
--- a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
+++ b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
@@ -16,6 +16,9 @@
package com.android.settings.bluetooth;
+import com.android.settings.R;
+import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
+
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
@@ -25,11 +28,9 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SharedPreferences;
import android.util.Log;
-import com.android.settings.R;
-import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
-
/**
* BluetoothEventRedirector receives broadcasts and callbacks from the Bluetooth
* API and dispatches the event on the UI thread to the right class in the
@@ -53,9 +54,11 @@ public class BluetoothEventRedirector {
BluetoothAdapter.ERROR);
mManager.setBluetoothStateInt(state);
} else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) {
+ persistDiscoveringTimestamp();
mManager.onScanningStateChanged(true);
} else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
+ persistDiscoveringTimestamp();
mManager.onScanningStateChanged(false);
} else if (action.equals(BluetoothDevice.ACTION_FOUND)) {
@@ -191,4 +194,11 @@ public class BluetoothEventRedirector {
}
return null;
}
+
+ private void persistDiscoveringTimestamp() {
+ SharedPreferences.Editor editor = mManager.getSharedPreferences().edit();
+ editor.putLong(LocalBluetoothManager.SHARED_PREFERENCES_KEY_DISCOVERING_TIMESTAMP,
+ System.currentTimeMillis());
+ editor.commit();
+ }
}
diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java
index 4364795..1e73b2d 100644
--- a/src/com/android/settings/bluetooth/BluetoothSettings.java
+++ b/src/com/android/settings/bluetooth/BluetoothSettings.java
@@ -35,7 +35,6 @@ import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.view.ContextMenu;
-import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
@@ -53,8 +52,6 @@ public class BluetoothSettings extends PreferenceActivity
private static final String TAG = "BluetoothSettings";
- private static final int MENU_SCAN = Menu.FIRST;
-
private static final String KEY_BT_CHECKBOX = "bt_checkbox";
private static final String KEY_BT_DISCOVERABLE = "bt_discoverable";
private static final String KEY_BT_DEVICE_LIST = "bt_device_list";
@@ -202,6 +199,12 @@ public class BluetoothSettings extends PreferenceActivity
}
}
+ @Override
+ protected void onUserLeaveHint() {
+ super.onUserLeaveHint();
+ mLocalManager.stopScanning();
+ }
+
private void addDevices() {
List<CachedBluetoothDevice> cachedDevices =
mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
@@ -211,33 +214,6 @@ public class BluetoothSettings extends PreferenceActivity
}
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, MENU_SCAN, 0, R.string.bluetooth_scan_for_devices)
- .setIcon(com.android.internal.R.drawable.ic_menu_refresh)
- .setAlphabeticShortcut('r');
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- menu.findItem(MENU_SCAN).setEnabled(mLocalManager.getBluetoothAdapter().isEnabled());
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
-
- case MENU_SCAN:
- mLocalManager.startScanning(true);
- return true;
-
- default:
- return false;
- }
- }
-
- @Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
@@ -254,6 +230,7 @@ public class BluetoothSettings extends PreferenceActivity
CachedBluetoothDevice device = btPreference.getCachedDevice();
mSelectedDevice = device.getDevice();
+ mLocalManager.stopScanning();
mLocalManager.persistSelectedDeviceInPicker(mSelectedDevice.getAddress());
if ((device.getBondState() == BluetoothDevice.BOND_BONDED) ||
(mNeedAuth == false)) {
diff --git a/src/com/android/settings/bluetooth/CachedBluetoothDevice.java b/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
index 57bffa9..aa4a958 100644
--- a/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
+++ b/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
@@ -95,7 +95,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
private static final long MAX_WAIT_TIME_FOR_FRAMEWORK = 25 * 1000;
private enum BluetoothCommand {
- CONNECT, DISCONNECT,
+ CONNECT, DISCONNECT, REMOVE_BOND,
}
static class BluetoothJob {
@@ -118,7 +118,9 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
StringBuilder sb = new StringBuilder();
sb.append(command.name());
sb.append(" Address:").append(cachedDevice.mDevice);
- sb.append(" Profile:").append(profile.name());
+ if (profile != null) {
+ sb.append(" Profile:").append(profile.name());
+ }
sb.append(" TimeSent:");
if (timeSent == 0) {
sb.append("not yet");
@@ -210,6 +212,12 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
case DISCONNECT:
successful = disconnectInt(job.cachedDevice, job.profile);
break;
+ case REMOVE_BOND:
+ BluetoothDevice dev = job.cachedDevice.getDevice();
+ if (dev != null) {
+ successful = dev.removeBond();
+ }
+ break;
}
if (successful) {
@@ -510,32 +518,16 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
}
public void unpair() {
- synchronized (workQueue) {
- // Remove any pending commands for this device
- boolean processNow = false;
- Iterator<BluetoothJob> it = workQueue.iterator();
- while (it.hasNext()) {
- BluetoothJob job = it.next();
- if (job.cachedDevice.mDevice.equals(this.mDevice)) {
- it.remove();
- if (job.timeSent != 0) {
- processNow = true;
- }
- }
- }
- if (processNow) {
- processCommands();
- }
- }
+ disconnect();
- switch (getBondState()) {
- case BluetoothDevice.BOND_BONDED:
- mDevice.removeBond();
- break;
+ int state = getBondState();
- case BluetoothDevice.BOND_BONDING:
+ if (state == BluetoothDevice.BOND_BONDING) {
mDevice.cancelBondProcess();
- break;
+ }
+
+ if (state != BluetoothDevice.BOND_NONE) {
+ queueCommand(new BluetoothJob(BluetoothCommand.REMOVE_BOND, this, null));
}
}
@@ -757,7 +749,32 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
public void onBondingStateChanged(int bondState) {
if (bondState == BluetoothDevice.BOND_NONE) {
mProfiles.clear();
+
+ BluetoothJob job = workQueue.peek();
+ if (job != null) {
+ // Remove the first item and process the next one
+ if (job.command == BluetoothCommand.REMOVE_BOND
+ && job.cachedDevice.mDevice.equals(mDevice)) {
+ workQueue.poll(); // dequeue
+ } else {
+ // Unexpected job
+ if (D) {
+ Log.d(TAG, "job.command = " + job.command);
+ Log.d(TAG, "mDevice:" + mDevice + " != head:" + job.toString());
+ }
+
+ // Check to see if we need to remove the stale items from the queue
+ if (!pruneQueue(null)) {
+ // nothing in the queue was modify. Just ignore the notification and return.
+ refresh();
+ return;
+ }
+ }
+
+ processCommands();
+ }
}
+
refresh();
}
diff --git a/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java b/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java
index 7906d79..4497480 100644
--- a/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java
+++ b/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java
@@ -43,7 +43,6 @@ public class CachedBluetoothDeviceManager {
public CachedBluetoothDeviceManager(LocalBluetoothManager localManager) {
mLocalManager = localManager;
mCallbacks = localManager.getCallbacks();
- readPairedDevices();
}
private synchronized boolean readPairedDevices() {
diff --git a/src/com/android/settings/bluetooth/DockEventReceiver.java b/src/com/android/settings/bluetooth/DockEventReceiver.java
index 2d634b2..6d11972 100644
--- a/src/com/android/settings/bluetooth/DockEventReceiver.java
+++ b/src/com/android/settings/bluetooth/DockEventReceiver.java
@@ -16,12 +16,17 @@
package com.android.settings.bluetooth;
+import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
+
import android.app.Service;
+import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.os.PowerManager;
import android.util.Log;
@@ -75,6 +80,54 @@ public class DockEventReceiver extends BroadcastReceiver {
if (DEBUG) Log.e(TAG, "Unknown state");
break;
}
+ } else if (BluetoothHeadset.ACTION_STATE_CHANGED.equals(intent.getAction())) {
+ /*
+ * Reconnect to the dock if:
+ * 1) it is a dock
+ * 2) it is disconnected
+ * 3) the disconnect is initiated remotely
+ * 4) the dock is still docked (check can only be done in the Service)
+ */
+ if (device == null) {
+ if (DEBUG) Log.d(TAG, "Device is missing");
+ return;
+ }
+
+ int newState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
+ BluetoothHeadset.STATE_CONNECTED);
+ if (newState != BluetoothHeadset.STATE_DISCONNECTED) return;
+
+ int source = intent.getIntExtra(BluetoothHeadset.EXTRA_DISCONNECT_INITIATOR,
+ BluetoothHeadset.LOCAL_DISCONNECT);
+ if (source != BluetoothHeadset.REMOTE_DISCONNECT) return;
+
+ // Too bad, the dock state can't be checked from a BroadcastReceiver.
+ Intent i = new Intent(intent);
+ i.setClass(context, DockService.class);
+ beginStartingService(context, i);
+
+ } else if (BluetoothA2dp.ACTION_SINK_STATE_CHANGED.equals(intent.getAction())) {
+ /*
+ * Reconnect to the dock if:
+ * 1) it is a dock
+ * 2) it is an unexpected disconnect i.e. didn't go through disconnecting state
+ * 3) the dock is still docked (check can only be done in the Service)
+ */
+ if (device == null) {
+ if (DEBUG) Log.d(TAG, "Device is missing");
+ return;
+ }
+
+ int newState = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE, 0);
+ int oldState = intent.getIntExtra(BluetoothA2dp.EXTRA_PREVIOUS_SINK_STATE, 0);
+ if (newState == BluetoothA2dp.STATE_DISCONNECTED &&
+ oldState != BluetoothA2dp.STATE_DISCONNECTING) {
+ // Too bad, the dock state can't be checked from a BroadcastReceiver.
+ Intent i = new Intent(intent);
+ i.setClass(context, DockService.class);
+ beginStartingService(context, i);
+ }
+
} else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
if (btState != BluetoothAdapter.STATE_TURNING_ON) {
diff --git a/src/com/android/settings/bluetooth/DockService.java b/src/com/android/settings/bluetooth/DockService.java
index 1425e23..f318987 100644
--- a/src/com/android/settings/bluetooth/DockService.java
+++ b/src/com/android/settings/bluetooth/DockService.java
@@ -87,6 +87,15 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
private static final String SHARED_PREFERENCES_KEY_DISABLE_BT =
"disable_bt";
+ private static final String SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT =
+ "connect_retry_count";
+
+ /*
+ * If disconnected unexpectedly, reconnect up to 6 times. Each profile counts
+ * as one time so it's only 3 times for both profiles on the car dock.
+ */
+ private static final int MAX_CONNECT_RETRY = 6;
+
private static final int INVALID_STARTID = -100;
// Created in OnCreate()
@@ -161,6 +170,32 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
return START_NOT_STICKY;
}
+ /*
+ * This assumes that the intent sender has checked that this is a dock
+ * and that the intent is for a disconnect
+ */
+ if (BluetoothHeadset.ACTION_STATE_CHANGED.equals(intent.getAction())) {
+ BluetoothDevice disconnectedDevice = intent
+ .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+
+ int retryCount = getSettingInt(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT, 0);
+ if (retryCount < MAX_CONNECT_RETRY) {
+ setSettingInt(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT, retryCount + 1);
+ handleUnexpectedDisconnect(disconnectedDevice, Profile.HEADSET, startId);
+ }
+ return START_NOT_STICKY;
+ } else if (BluetoothA2dp.ACTION_SINK_STATE_CHANGED.equals(intent.getAction())) {
+ BluetoothDevice disconnectedDevice = intent
+ .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+
+ int retryCount = getSettingInt(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT, 0);
+ if (retryCount < MAX_CONNECT_RETRY) {
+ setSettingInt(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT, retryCount + 1);
+ handleUnexpectedDisconnect(disconnectedDevice, Profile.A2DP, startId);
+ }
+ return START_NOT_STICKY;
+ }
+
Message msg = parseIntent(intent);
if (msg == null) {
// Bad intent
@@ -169,6 +204,10 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
return START_NOT_STICKY;
}
+ if (msg.what == MSG_TYPE_DOCKED) {
+ removeSetting(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT);
+ }
+
msg.arg2 = startId;
processMessage(msg);
@@ -248,10 +287,10 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
if (DEBUG) {
Log.d(TAG, "DISABLE_BT_WHEN_UNDOCKED = "
- + getSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED));
+ + getSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED));
}
- if (getSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED)) {
+ if (getSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED)) {
// BT was disabled when we first docked
if (!hasOtherConnectedDevices(device)) {
if(DEBUG) Log.d(TAG, "QUEUED BT DISABLE");
@@ -280,7 +319,7 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED);
} else {
// disable() returned an error. Persist a flag to disable BT later
- setSetting(SHARED_PREFERENCES_KEY_DISABLE_BT, true);
+ setSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT, true);
mPendingTurnOffStartId = startId;
deferFinishCall = true;
if(DEBUG) Log.d(TAG, "disable failed. try again later " + startId);
@@ -509,7 +548,7 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
} else {
if (DEBUG) {
Log.d(TAG, "A DISABLE_BT_WHEN_UNDOCKED = "
- + getSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED));
+ + getSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED));
}
// Reconnect if docked and bluetooth was enabled by user.
Intent i = registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
@@ -522,7 +561,7 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
if (device != null) {
connectIfEnabled(device);
}
- } else if (getSetting(SHARED_PREFERENCES_KEY_DISABLE_BT)
+ } else if (getSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT)
&& mBtManager.getBluetoothAdapter().disable()) {
mPendingTurnOffStartId = startId;
removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT);
@@ -565,6 +604,34 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
}
}
+ private void handleUnexpectedDisconnect(BluetoothDevice disconnectedDevice, Profile profile,
+ int startId) {
+ synchronized (this) {
+ if (DEBUG) Log.d(TAG, "handling failed connect for " + disconnectedDevice);
+
+ // Reconnect if docked.
+ if (disconnectedDevice != null) {
+ // registerReceiver can't be called from a BroadcastReceiver
+ Intent i = registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
+ if (i != null) {
+ int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE,
+ Intent.EXTRA_DOCK_STATE_UNDOCKED);
+ if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+ BluetoothDevice dockedDevice = i
+ .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (dockedDevice != null && dockedDevice.equals(disconnectedDevice)) {
+ CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(mContext,
+ mBtManager, dockedDevice);
+ cachedDevice.connect(profile);
+ }
+ }
+ }
+ }
+
+ DockEventReceiver.finishStartingService(this, startId);
+ }
+ }
+
private synchronized void connectIfEnabled(BluetoothDevice device) {
CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(mContext, mBtManager, device);
List<Profile> profiles = cachedDevice.getConnectableProfiles();
@@ -612,7 +679,8 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
mPendingDevice = device;
mPendingStartId = startId;
if (btState != BluetoothAdapter.STATE_TURNING_ON) {
- setSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED, true);
+ setSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED,
+ true);
}
return;
}
@@ -676,16 +744,29 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
return cachedBluetoothDevice;
}
- private boolean getSetting(String key) {
+ private boolean getSettingBool(String key) {
SharedPreferences sharedPref = getSharedPreferences(SHARED_PREFERENCES_NAME,
Context.MODE_PRIVATE);
return sharedPref.getBoolean(key, false);
}
- private void setSetting(String key, boolean disableBt) {
+ private int getSettingInt(String key, int defaultValue) {
+ SharedPreferences sharedPref = getSharedPreferences(SHARED_PREFERENCES_NAME,
+ Context.MODE_PRIVATE);
+ return sharedPref.getInt(key, defaultValue);
+ }
+
+ private void setSettingBool(String key, boolean bool) {
+ SharedPreferences.Editor editor = getSharedPreferences(SHARED_PREFERENCES_NAME,
+ Context.MODE_PRIVATE).edit();
+ editor.putBoolean(key, bool);
+ editor.commit();
+ }
+
+ private void setSettingInt(String key, int value) {
SharedPreferences.Editor editor = getSharedPreferences(SHARED_PREFERENCES_NAME,
Context.MODE_PRIVATE).edit();
- editor.putBoolean(key, disableBt);
+ editor.putInt(key, value);
editor.commit();
}
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothManager.java b/src/com/android/settings/bluetooth/LocalBluetoothManager.java
index ec5c6bc..2ffb139 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothManager.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothManager.java
@@ -72,6 +72,9 @@ public class LocalBluetoothManager {
// of raising notifications
private static long GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND = 60 * 1000;
+ public static final String SHARED_PREFERENCES_KEY_DISCOVERING_TIMESTAMP =
+ "last_discovering_time";
+
private static final String SHARED_PREFERENCES_KEY_LAST_SELECTED_DEVICE =
"last_selected_device";
@@ -198,6 +201,12 @@ public class LocalBluetoothManager {
}
}
+ public void stopScanning() {
+ if (mAdapter.isDiscovering()) {
+ mAdapter.cancelDiscovery();
+ }
+ }
+
public int getBluetoothState() {
if (mState == BluetoothAdapter.ERROR) {
@@ -308,7 +317,7 @@ public class LocalBluetoothManager {
long currentTimeMillis = System.currentTimeMillis();
SharedPreferences sharedPreferences = getSharedPreferences();
- // If the device was in discoverable mode recently
+ // If the device was in discoverABLE mode recently
long lastDiscoverableEndTime = sharedPreferences.getLong(
BluetoothDiscoverableEnabler.SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP, 0);
if ((lastDiscoverableEndTime + GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND)
@@ -316,6 +325,14 @@ public class LocalBluetoothManager {
return true;
}
+ // If the device was discoverING recently
+ if (mAdapter != null && mAdapter.isDiscovering()) {
+ return true;
+ } else if ((sharedPreferences.getLong(SHARED_PREFERENCES_KEY_DISCOVERING_TIMESTAMP, 0) +
+ GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND) > currentTimeMillis) {
+ return true;
+ }
+
// If the device was picked in the device picker recently
if (deviceAddress != null) {
String lastSelectedDevice = sharedPreferences.getString(
diff --git a/src/com/android/settings/bluetooth/RequestPermissionActivity.java b/src/com/android/settings/bluetooth/RequestPermissionActivity.java
index 9fdb338..eca233c 100644
--- a/src/com/android/settings/bluetooth/RequestPermissionActivity.java
+++ b/src/com/android/settings/bluetooth/RequestPermissionActivity.java
@@ -16,11 +16,10 @@
package com.android.settings.bluetooth;
-import com.android.internal.app.AlertActivity;
-import com.android.internal.app.AlertController;
import com.android.settings.R;
import android.app.Activity;
+import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
@@ -31,14 +30,12 @@ import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
-import android.view.View;
-import android.widget.TextView;
/**
* RequestPermissionActivity asks the user whether to enable discovery. This is
* usually started by an application wanted to start bluetooth and or discovery
*/
-public class RequestPermissionActivity extends AlertActivity implements
+public class RequestPermissionActivity extends Activity implements
DialogInterface.OnClickListener {
// Command line to test this
// adb shell am start -a android.bluetooth.adapter.action.REQUEST_ENABLE
@@ -73,6 +70,8 @@ public class RequestPermissionActivity extends AlertActivity implements
private boolean mUserConfirmed = false;
+ private AlertDialog mDialog = null;
+
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -84,7 +83,7 @@ public class RequestPermissionActivity extends AlertActivity implements
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothDevice.ERROR);
if (state == BluetoothAdapter.STATE_ON) {
if (mUserConfirmed) {
- proceedAndFinish(false);
+ proceedAndFinish();
}
}
}
@@ -136,7 +135,7 @@ public class RequestPermissionActivity extends AlertActivity implements
case BluetoothAdapter.STATE_ON:
if (mEnableOnly) {
// Nothing to do. Already enabled.
- proceedAndFinish(false);
+ proceedAndFinish();
return;
} else {
// Ask the user about enabling discovery mode
@@ -147,28 +146,24 @@ public class RequestPermissionActivity extends AlertActivity implements
}
private void createDialog() {
- final AlertController.AlertParams p = mAlertParams;
- p.mIconId = android.R.drawable.ic_dialog_info;
- p.mTitle = getString(R.string.bluetooth_permission_request);
-
- View view = getLayoutInflater().inflate(R.layout.bluetooth_discoverable, null);
- p.mView = view;
- TextView tv = (TextView) view.findViewById(R.id.message);
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setIcon(android.R.drawable.ic_dialog_info);
+ builder.setTitle(getString(R.string.bluetooth_permission_request));
if (mNeededToEnableBluetooth) {
// RequestPermissionHelperActivity has gotten confirmation from user
// to turn on BT
- tv.setText(getString(R.string.bluetooth_turning_on));
+ builder.setMessage(getString(R.string.bluetooth_turning_on));
+ builder.setCancelable(false);
} else {
// Ask the user whether to turn on discovery mode or not
- tv.setText(getString(R.string.bluetooth_ask_enablement_and_discovery, mTimeout));
- p.mPositiveButtonText = getString(R.string.yes);
- p.mPositiveButtonListener = this;
- p.mNegativeButtonText = getString(R.string.no);
- p.mNegativeButtonListener = this;
+ builder.setMessage(getString(R.string.bluetooth_ask_enablement_and_discovery, mTimeout));
+ builder.setPositiveButton(getString(R.string.yes), this);
+ builder.setNegativeButton(getString(R.string.no), this);
}
- setupAlert();
+ mDialog = builder.create();
+ mDialog.show();
}
@Override
@@ -182,6 +177,7 @@ public class RequestPermissionActivity extends AlertActivity implements
if (resultCode != RESULT_BT_STARTING_OR_STARTED) {
setResult(resultCode);
finish();
+ return;
}
// Back from RequestPermissionHelperActivity. User confirmed to enable
@@ -189,7 +185,7 @@ public class RequestPermissionActivity extends AlertActivity implements
mUserConfirmed = true;
if (mLocalManager.getBluetoothState() == BluetoothAdapter.STATE_ON) {
- proceedAndFinish(false);
+ proceedAndFinish();
} else {
// If BT is not up yet, show "Turning on Bluetooth..."
createDialog();
@@ -199,16 +195,17 @@ public class RequestPermissionActivity extends AlertActivity implements
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
- proceedAndFinish(true);
+ proceedAndFinish();
break;
case DialogInterface.BUTTON_NEGATIVE:
setResult(Activity.RESULT_CANCELED);
+ finish();
break;
}
}
- private void proceedAndFinish(boolean buttonPressed) {
+ private void proceedAndFinish() {
int returnCode;
if (mEnableOnly) {
@@ -227,10 +224,12 @@ public class RequestPermissionActivity extends AlertActivity implements
returnCode = Activity.RESULT_CANCELED;
}
- setResult(returnCode);
- if (!buttonPressed) {
- finish();
+ if (mDialog != null) {
+ mDialog.dismiss();
}
+
+ setResult(returnCode);
+ finish();
}
private boolean parseIntent() {
diff --git a/src/com/android/settings/deviceinfo/Memory.java b/src/com/android/settings/deviceinfo/Memory.java
index 53e2a69..b574849 100644
--- a/src/com/android/settings/deviceinfo/Memory.java
+++ b/src/com/android/settings/deviceinfo/Memory.java
@@ -16,60 +16,86 @@
package com.android.settings.deviceinfo;
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.DialogInterface.OnCancelListener;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Message;
import android.os.RemoteException;
import android.os.Environment;
-import android.os.IMountService;
+import android.os.storage.IMountService;
import android.os.ServiceManager;
import android.os.StatFs;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageEventListener;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.text.format.Formatter;
import android.util.Log;
+import android.widget.Toast;
import com.android.settings.R;
import java.io.File;
-import java.text.DecimalFormat;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
-public class Memory extends PreferenceActivity {
-
+public class Memory extends PreferenceActivity implements OnCancelListener {
private static final String TAG = "Memory";
+ private static final boolean localLOGV = false;
private static final String MEMORY_SD_SIZE = "memory_sd_size";
private static final String MEMORY_SD_AVAIL = "memory_sd_avail";
- private static final String MEMORY_SD_UNMOUNT = "memory_sd_unmount";
+ private static final String MEMORY_SD_MOUNT_TOGGLE = "memory_sd_mount_toggle";
private static final String MEMORY_SD_FORMAT = "memory_sd_format";
+
+ private static final int DLG_CONFIRM_UNMOUNT = 1;
+ private static final int DLG_ERROR_UNMOUNT = 2;
+
private Resources mRes;
private Preference mSdSize;
private Preference mSdAvail;
- private Preference mSdUnmount;
+ private Preference mSdMountToggle;
private Preference mSdFormat;
// Access using getMountService()
private IMountService mMountService = null;
+ private StorageManager mStorageManager = null;
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
-
+
+ if (mStorageManager == null) {
+ mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
+ mStorageManager.registerListener(mStorageListener);
+ }
+
addPreferencesFromResource(R.xml.device_info_memory);
mRes = getResources();
mSdSize = findPreference(MEMORY_SD_SIZE);
mSdAvail = findPreference(MEMORY_SD_AVAIL);
- mSdUnmount = findPreference(MEMORY_SD_UNMOUNT);
+ mSdMountToggle = findPreference(MEMORY_SD_MOUNT_TOGGLE);
mSdFormat = findPreference(MEMORY_SD_FORMAT);
}
@@ -77,27 +103,39 @@ public class Memory extends PreferenceActivity {
protected void onResume() {
super.onResume();
- IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_REMOVED);
- intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
- intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
- intentFilter.addAction(Intent.ACTION_MEDIA_SHARED);
- intentFilter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
- intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTABLE);
- intentFilter.addAction(Intent.ACTION_MEDIA_NOFS);
- intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
+ IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED);
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
intentFilter.addDataScheme("file");
registerReceiver(mReceiver, intentFilter);
updateMemoryStatus();
}
+
+ StorageEventListener mStorageListener = new StorageEventListener() {
+
+ @Override
+ public void onStorageStateChanged(String path, String oldState, String newState) {
+ Log.i(TAG, "Received storage state changed notification that " +
+ path + " changed state from " + oldState +
+ " to " + newState);
+ updateMemoryStatus();
+ }
+ };
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
-
+
+ @Override
+ protected void onDestroy() {
+ if (mStorageManager != null && mStorageListener != null) {
+ mStorageManager.unregisterListener(mStorageListener);
+ }
+ super.onDestroy();
+ }
+
private synchronized IMountService getMountService() {
if (mMountService == null) {
IBinder service = ServiceManager.getService("mount");
@@ -112,8 +150,13 @@ public class Memory extends PreferenceActivity {
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
- if (preference == mSdUnmount) {
- unmount();
+ if (preference == mSdMountToggle) {
+ String status = Environment.getExternalStorageState();
+ if (status.equals(Environment.MEDIA_MOUNTED)) {
+ unmount();
+ } else {
+ mount();
+ }
return true;
} else if (preference == mSdFormat) {
Intent intent = new Intent(Intent.ACTION_VIEW);
@@ -132,17 +175,95 @@ public class Memory extends PreferenceActivity {
}
};
+ @Override
+ public Dialog onCreateDialog(int id, Bundle args) {
+ switch (id) {
+ case DLG_CONFIRM_UNMOUNT:
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.dlg_confirm_unmount_title)
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ doUnmount(true);
+ }})
+ .setNegativeButton(R.string.cancel, null)
+ .setMessage(R.string.dlg_confirm_unmount_text)
+ .setOnCancelListener(this)
+ .create();
+ case DLG_ERROR_UNMOUNT:
+ return new AlertDialog.Builder(this )
+ .setTitle(R.string.dlg_error_unmount_title)
+ .setNeutralButton(R.string.dlg_ok, null)
+ .setMessage(R.string.dlg_error_unmount_text)
+ .setOnCancelListener(this)
+ .create();
+ }
+ return null;
+ }
+
+ private void doUnmount(boolean force) {
+ // Present a toast here
+ Toast.makeText(this, R.string.unmount_inform_text, Toast.LENGTH_SHORT).show();
+ IMountService mountService = getMountService();
+ String extStoragePath = Environment.getExternalStorageDirectory().toString();
+ try {
+ mSdMountToggle.setEnabled(false);
+ mSdMountToggle.setTitle(mRes.getString(R.string.sd_ejecting_title));
+ mSdMountToggle.setSummary(mRes.getString(R.string.sd_ejecting_summary));
+ mountService.unmountVolume(extStoragePath, force);
+ } catch (RemoteException e) {
+ // Informative dialog to user that
+ // unmount failed.
+ showDialogInner(DLG_ERROR_UNMOUNT);
+ }
+ }
+
+ private void showDialogInner(int id) {
+ removeDialog(id);
+ showDialog(id);
+ }
+
+ private boolean hasAppsAccessingStorage() throws RemoteException {
+ String extStoragePath = Environment.getExternalStorageDirectory().toString();
+ IMountService mountService = getMountService();
+ boolean showPidDialog = false;
+ int stUsers[] = mountService.getStorageUsers(extStoragePath);
+ if (stUsers != null && stUsers.length > 0) {
+ return true;
+ }
+ ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
+ List<ApplicationInfo> list = am.getRunningExternalApplications();
+ if (list != null && list.size() > 0) {
+ return true;
+ }
+ return false;
+ }
+
private void unmount() {
+ // Check if external media is in use.
+ try {
+ if (hasAppsAccessingStorage()) {
+ if (localLOGV) Log.i(TAG, "Do have storage users accessing media");
+ // Present dialog to user
+ showDialogInner(DLG_CONFIRM_UNMOUNT);
+ } else {
+ doUnmount(true);
+ }
+ } catch (RemoteException e) {
+ // Very unlikely. But present an error dialog anyway
+ Log.e(TAG, "Is MountService running?");
+ showDialogInner(DLG_ERROR_UNMOUNT);
+ }
+ }
+
+ private void mount() {
IMountService mountService = getMountService();
try {
if (mountService != null) {
- mountService.unmountMedia(Environment.getExternalStorageDirectory().toString());
+ mountService.mountVolume(Environment.getExternalStorageDirectory().toString());
} else {
- Log.e(TAG, "Mount service is null, can't unmount");
+ Log.e(TAG, "Mount service is null, can't mount");
}
} catch (RemoteException ex) {
- // Failed for some reason, try to update UI to actual state
- updateMemoryStatus();
}
}
@@ -166,7 +287,11 @@ public class Memory extends PreferenceActivity {
mSdSize.setSummary(formatSize(totalBlocks * blockSize));
mSdAvail.setSummary(formatSize(availableBlocks * blockSize) + readOnly);
- mSdUnmount.setEnabled(true);
+
+ mSdMountToggle.setEnabled(true);
+ mSdMountToggle.setTitle(mRes.getString(R.string.sd_eject));
+ mSdMountToggle.setSummary(mRes.getString(R.string.sd_eject_summary));
+
} catch (IllegalArgumentException e) {
// this can occur if the SD card is removed, but we haven't received the
// ACTION_MEDIA_REMOVED Intent yet.
@@ -176,15 +301,20 @@ public class Memory extends PreferenceActivity {
} else {
mSdSize.setSummary(mRes.getString(R.string.sd_unavailable));
mSdAvail.setSummary(mRes.getString(R.string.sd_unavailable));
- mSdUnmount.setEnabled(false);
+
if (status.equals(Environment.MEDIA_UNMOUNTED) ||
status.equals(Environment.MEDIA_NOFS) ||
status.equals(Environment.MEDIA_UNMOUNTABLE) ) {
mSdFormat.setEnabled(true);
+ mSdMountToggle.setEnabled(true);
+ mSdMountToggle.setTitle(mRes.getString(R.string.sd_mount));
+ mSdMountToggle.setSummary(mRes.getString(R.string.sd_mount_summary));
+ } else {
+ mSdMountToggle.setEnabled(false);
+ mSdMountToggle.setTitle(mRes.getString(R.string.sd_mount));
+ mSdMountToggle.setSummary(mRes.getString(R.string.sd_insert_summary));
}
-
-
}
File path = Environment.getDataDirectory();
@@ -197,5 +327,9 @@ public class Memory extends PreferenceActivity {
private String formatSize(long size) {
return Formatter.formatFileSize(this, size);
}
+
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
}
diff --git a/src/com/android/settings/deviceinfo/Status.java b/src/com/android/settings/deviceinfo/Status.java
index a736cc0..99a8975 100644
--- a/src/com/android/settings/deviceinfo/Status.java
+++ b/src/com/android/settings/deviceinfo/Status.java
@@ -32,6 +32,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.preference.Preference;
import android.preference.PreferenceActivity;
+import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
@@ -221,7 +222,13 @@ public class Status extends PreferenceActivity {
}
}
- setSummaryText("number", mPhone.getLine1Number());
+ String rawNumber = mPhone.getLine1Number(); // may be null or empty
+ String formattedNumber = null;
+ if (!TextUtils.isEmpty(rawNumber)) {
+ formattedNumber = PhoneNumberUtils.formatNumber(rawNumber);
+ }
+ // If formattedNumber is null or empty, it'll display as "Unknown".
+ setSummaryText("number", formattedNumber);
mPhoneStateReceiver = new PhoneStateIntentReceiver(this, mHandler);
mPhoneStateReceiver.notifySignalStrength(EVENT_SIGNAL_STRENGTH_CHANGED);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageDetail.java b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
index 737627a..4db968a 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
@@ -18,6 +18,9 @@ package com.android.settings.fuelgauge;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ApplicationErrorReport;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -26,7 +29,9 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Bundle;
+import android.os.Process;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.LayoutInflater;
@@ -35,8 +40,8 @@ import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
-
import com.android.settings.InstalledAppDetails;
+import com.android.settings.ManageApplications;
import com.android.settings.R;
public class PowerUsageDetail extends Activity implements Button.OnClickListener {
@@ -68,6 +73,8 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
public static final int ACTION_WIRELESS_SETTINGS = 4;
public static final int ACTION_APP_DETAILS = 5;
public static final int ACTION_SECURITY_SETTINGS = 6;
+ public static final int ACTION_FORCE_STOP = 7;
+ public static final int ACTION_REPORT = 8;
public static final int USAGE_SINCE_UNPLUGGED = 1;
public static final int USAGE_SINCE_RESET = 2;
@@ -78,6 +85,8 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
public static final String EXTRA_UID = "uid";
public static final String EXTRA_USAGE_SINCE = "since";
public static final String EXTRA_USAGE_DURATION = "duration";
+ public static final String EXTRA_REPORT_DETAILS = "report_details";
+ public static final String EXTRA_REPORT_CHECKIN_DETAILS = "report_checkin_details";
public static final String EXTRA_DETAIL_TYPES = "types"; // Array of usage types (cpu, gps, etc)
public static final String EXTRA_DETAIL_VALUES = "values"; // Array of doubles
public static final String EXTRA_DRAIN_TYPE = "drainType"; // DrainType
@@ -92,6 +101,9 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
private int mUid;
private double[] mValues;
private TextView mTitleView;
+ private ViewGroup mTwoButtonsPanel;
+ private Button mForceStopButton;
+ private Button mReportButton;
private ViewGroup mDetailsParent;
private ViewGroup mControlsParent;
private long mStartTime;
@@ -105,6 +117,9 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
private static final String TAG = "PowerUsageDetail";
private String[] mPackages;
+ ApplicationInfo mApp;
+ ComponentName mInstaller;
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -116,6 +131,7 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
protected void onResume() {
super.onResume();
mStartTime = android.os.Process.getElapsedCpuTime();
+ checkForceStop();
}
@Override
@@ -163,6 +179,11 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
((TextView)findViewById(R.id.battery_percentage))
.setText(String.format("%d%%", percentage));
+ mTwoButtonsPanel = (ViewGroup) findViewById(R.id.two_buttons_panel);
+ mForceStopButton = (Button) findViewById(R.id.left_button);
+ mReportButton = (Button) findViewById(R.id.right_button);
+ mForceStopButton.setEnabled(false);
+
ImageView gaugeImage = (ImageView) findViewById(R.id.gauge);
mGauge = new PercentageBar();
mGauge.percent = gaugeValue;
@@ -178,6 +199,34 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
fillDetailsSection();
fillPackagesSection(mUid);
fillControlsSection(mUid);
+
+ if (mUid >= Process.FIRST_APPLICATION_UID) {
+ mForceStopButton.setText(R.string.force_stop);
+ mForceStopButton.setTag(ACTION_FORCE_STOP);
+ mForceStopButton.setOnClickListener(this);
+ mReportButton.setText(com.android.internal.R.string.report);
+ mReportButton.setTag(ACTION_REPORT);
+ mReportButton.setOnClickListener(this);
+
+ // check if error reporting is enabled in secure settings
+ int enabled = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.SEND_ACTION_APP_ERROR, 0);
+ if (enabled != 0) {
+ if (mPackages != null && mPackages.length > 0) {
+ try {
+ mApp = getPackageManager().getApplicationInfo(mPackages[0], 0);
+ mInstaller = ApplicationErrorReport.getErrorReportReceiver(
+ this, mPackages[0], mApp.flags);
+ } catch (NameNotFoundException e) {
+ }
+ }
+ mReportButton.setEnabled(mInstaller != null);
+ } else {
+ mTwoButtonsPanel.setVisibility(View.GONE);
+ }
+ } else {
+ mTwoButtonsPanel.setVisibility(View.GONE);
+ }
}
public void onClick(View v) {
@@ -201,12 +250,18 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
case ACTION_APP_DETAILS:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClass(this, InstalledAppDetails.class);
- intent.putExtra("com.android.settings.ApplicationPkgName", mPackages[0]);
+ intent.putExtra(ManageApplications.APP_PKG_NAME, mPackages[0]);
startActivity(intent);
break;
case ACTION_SECURITY_SETTINGS:
startActivity(new Intent(Settings.ACTION_SECURITY_SETTINGS));
break;
+ case ACTION_FORCE_STOP:
+ killProcesses();
+ break;
+ case ACTION_REPORT:
+ reportBatteryUse();
+ break;
}
}
@@ -271,7 +326,7 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
}
break;
case SCREEN:
- addControl(R.string.sound_and_display_settings,
+ addControl(R.string.display_settings,
R.string.battery_sugg_display,
ACTION_DISPLAY_SETTINGS);
removeHeader = false;
@@ -330,10 +385,57 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
ActivityManager am = (ActivityManager)getSystemService(
Context.ACTIVITY_SERVICE);
for (int i = 0; i < mPackages.length; i++) {
- am.restartPackage(mPackages[i]);
+ am.forceStopPackage(mPackages[i]);
}
+ checkForceStop();
}
+ private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mForceStopButton.setEnabled(getResultCode() != RESULT_CANCELED);
+ }
+ };
+
+ private void checkForceStop() {
+ if (mPackages == null || mUid < Process.FIRST_APPLICATION_UID) {
+ mForceStopButton.setEnabled(false);
+ return;
+ }
+ Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
+ Uri.fromParts("package", mPackages[0], null));
+ intent.putExtra(Intent.EXTRA_PACKAGES, mPackages);
+ intent.putExtra(Intent.EXTRA_UID, mUid);
+ sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
+ Activity.RESULT_CANCELED, null, null);
+ }
+
+ private void reportBatteryUse() {
+ if (mPackages == null) return;
+
+ ApplicationErrorReport report = new ApplicationErrorReport();
+ report.type = ApplicationErrorReport.TYPE_BATTERY;
+ report.packageName = mPackages[0];
+ report.installerPackageName = mInstaller.getPackageName();
+ report.processName = mPackages[0];
+ report.time = System.currentTimeMillis();
+ report.systemApp = (mApp.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+
+ final Intent intent = getIntent();
+ ApplicationErrorReport.BatteryInfo batteryInfo = new ApplicationErrorReport.BatteryInfo();
+ batteryInfo.usagePercent = intent.getIntExtra(EXTRA_PERCENT, 1);
+ batteryInfo.durationMicros = intent.getLongExtra(EXTRA_USAGE_DURATION, 0);
+ batteryInfo.usageDetails = intent.getStringExtra(EXTRA_REPORT_DETAILS);
+ batteryInfo.checkinDetails = intent.getStringExtra(EXTRA_REPORT_CHECKIN_DETAILS);
+ report.batteryInfo = batteryInfo;
+
+ Intent result = new Intent(Intent.ACTION_APP_ERROR);
+ result.setComponent(mInstaller);
+ result.putExtra(Intent.EXTRA_BUG_REPORT, report);
+ result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(result);
+ }
+
private void fillPackagesSection(int uid) {
if (uid < 1) {
removePackagesSection();
@@ -344,7 +446,7 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
LayoutInflater inflater = getLayoutInflater();
PackageManager pm = getPackageManager();
- final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
+ //final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
mPackages = pm.getPackagesForUid(uid);
if (mPackages == null || mPackages.length < 2) {
removePackagesSection();
@@ -356,13 +458,13 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
try {
ApplicationInfo ai = pm.getApplicationInfo(mPackages[i], 0);
CharSequence label = ai.loadLabel(pm);
- Drawable icon = defaultActivityIcon;
+ //Drawable icon = defaultActivityIcon;
if (label != null) {
mPackages[i] = label.toString();
}
- if (ai.icon != 0) {
- icon = ai.loadIcon(pm);
- }
+ //if (ai.icon != 0) {
+ // icon = ai.loadIcon(pm);
+ //}
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_package_item,
null);
packagesParent.addView(item);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 10ab2d0..5678160 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -48,6 +48,9 @@ import com.android.internal.os.PowerProfile;
import com.android.settings.R;
import com.android.settings.fuelgauge.PowerUsageDetail.DrainType;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -78,6 +81,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
private static final int MIN_POWER_THRESHOLD = 5;
private static final int MAX_ITEMS_TO_LIST = 10;
+ private long mStatsPeriod = 0;
private double mMaxPower = 1;
private double mTotalPower;
private PowerProfile mPowerProfile;
@@ -132,6 +136,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
Math.ceil(sipper.getSortValue() * 100 / mTotalPower));
intent.putExtra(PowerUsageDetail.EXTRA_GAUGE, (int)
Math.ceil(sipper.getSortValue() * 100 / mMaxPower));
+ intent.putExtra(PowerUsageDetail.EXTRA_USAGE_DURATION, mStatsPeriod);
intent.putExtra(PowerUsageDetail.EXTRA_ICON_PACKAGE, sipper.defaultPackageName);
intent.putExtra(PowerUsageDetail.EXTRA_ICON_ID, sipper.iconId);
intent.putExtra(PowerUsageDetail.EXTRA_NO_COVERAGE, sipper.noCoveragePercent);
@@ -165,6 +170,15 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
0
};
+ Writer result = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(result);
+ mStats.dumpLocked(printWriter, "", mStatsType, uid.getUid());
+ intent.putExtra(PowerUsageDetail.EXTRA_REPORT_DETAILS, result.toString());
+
+ result = new StringWriter();
+ printWriter = new PrintWriter(result);
+ mStats.dumpCheckinLocked(printWriter, mStatsType, uid.getUid());
+ intent.putExtra(PowerUsageDetail.EXTRA_REPORT_CHECKIN_DETAILS, result.toString());
}
break;
case CELL:
@@ -303,6 +317,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
}
final double averageCostPerByte = getAverageDataCost();
long uSecTime = mStats.computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
+ mStatsPeriod = uSecTime;
updateStatsPeriod(uSecTime);
SparseArray<? extends Uid> uidStats = mStats.getUidStats();
final int NU = uidStats.size();
diff --git a/src/com/android/settings/vpn/VpnSettings.java b/src/com/android/settings/vpn/VpnSettings.java
index 5f6a207..7b8d433 100644
--- a/src/com/android/settings/vpn/VpnSettings.java
+++ b/src/com/android/settings/vpn/VpnSettings.java
@@ -82,7 +82,7 @@ public class VpnSettings extends PreferenceActivity implements
private static final String PREF_ADD_VPN = "add_new_vpn";
private static final String PREF_VPN_LIST = "vpn_list";
- private static final String PROFILES_ROOT = VpnManager.PROFILES_PATH + "/";
+ private static final String PROFILES_ROOT = VpnManager.getProfilePath() + "/";
private static final String PROFILE_OBJ_FILE = ".pobj";
private static final int REQUEST_ADD_OR_EDIT_PROFILE = 1;
diff --git a/src/com/android/settings/widget/SettingsAppWidgetProvider.java b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
index 3db90cf..939e8e3 100644
--- a/src/com/android/settings/widget/SettingsAppWidgetProvider.java
+++ b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
@@ -30,13 +30,13 @@ import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
+import android.os.AsyncTask;
import android.os.IPowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.util.Log;
import android.widget.RemoteViews;
-import android.widget.Toast;
import com.android.settings.R;
import com.android.settings.bluetooth.LocalBluetoothManager;
@@ -50,7 +50,7 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
new ComponentName("com.android.settings",
"com.android.settings.widget.SettingsAppWidgetProvider");
- private static LocalBluetoothManager mLocalBluetoothManager = null;
+ private static LocalBluetoothManager sLocalBluetoothManager = null;
private static final int BUTTON_WIFI = 0;
private static final int BUTTON_BRIGHTNESS = 1;
@@ -58,9 +58,16 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
private static final int BUTTON_GPS = 3;
private static final int BUTTON_BLUETOOTH = 4;
+ // This widget keeps track of two sets of states:
+ // "3-state": STATE_DISABLED, STATE_ENABLED, STATE_INTERMEDIATE
+ // "5-state": STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON, STATE_TURNING_OFF, STATE_UNKNOWN
private static final int STATE_DISABLED = 0;
private static final int STATE_ENABLED = 1;
- private static final int STATE_INTERMEDIATE = 2;
+ private static final int STATE_TURNING_ON = 2;
+ private static final int STATE_TURNING_OFF = 3;
+ private static final int STATE_UNKNOWN = 4;
+ private static final int STATE_INTERMEDIATE = 5;
+
/**
* Minimum and maximum brightnesses. Don't go to 0 since that makes the display unusable
@@ -69,6 +76,299 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
private static final int MAXIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_ON;
private static final int DEFAULT_BACKLIGHT = (int) (android.os.Power.BRIGHTNESS_ON * 0.4f);
+ private static final StateTracker sWifiState = new WifiStateTracker();
+ private static final StateTracker sBluetoothState = new BluetoothStateTracker();
+
+ /**
+ * The state machine for Wifi and Bluetooth toggling, tracking
+ * reality versus the user's intent.
+ *
+ * This is necessary because reality moves relatively slowly
+ * (turning on &amp; off radio drivers), compared to user's
+ * expectations.
+ */
+ private abstract static class StateTracker {
+ // Is the state in the process of changing?
+ private boolean mInTransition = false;
+ private Boolean mActualState = null; // initially not set
+ private Boolean mIntendedState = null; // initially not set
+
+ // Did a toggle request arrive while a state update was
+ // already in-flight? If so, the mIntendedState needs to be
+ // requested when the other one is done, unless we happened to
+ // arrive at that state already.
+ private boolean mDeferredStateChangeRequestNeeded = false;
+
+ /**
+ * User pressed a button to change the state. Something
+ * should immediately appear to the user afterwards, even if
+ * we effectively do nothing. Their press must be heard.
+ */
+ public final void toggleState(Context context) {
+ int currentState = getTriState(context);
+ boolean newState = false;
+ switch (currentState) {
+ case STATE_ENABLED:
+ newState = false;
+ break;
+ case STATE_DISABLED:
+ newState = true;
+ break;
+ case STATE_INTERMEDIATE:
+ if (mIntendedState != null) {
+ newState = !mIntendedState;
+ }
+ break;
+ }
+ mIntendedState = newState;
+ if (mInTransition) {
+ // We don't send off a transition request if we're
+ // already transitioning. Makes our state tracking
+ // easier, and is probably nicer on lower levels.
+ // (even though they should be able to take it...)
+ mDeferredStateChangeRequestNeeded = true;
+ } else {
+ mInTransition = true;
+ requestStateChange(context, newState);
+ }
+ }
+
+ /**
+ * Update internal state from a broadcast state change.
+ */
+ public abstract void onActualStateChange(Context context, Intent intent);
+
+ /**
+ * Sets the value that we're now in. To be called from onActualStateChange.
+ *
+ * @param newState one of STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON,
+ * STATE_TURNING_OFF, STATE_UNKNOWN
+ */
+ protected final void setCurrentState(Context context, int newState) {
+ final boolean wasInTransition = mInTransition;
+ switch (newState) {
+ case STATE_DISABLED:
+ mInTransition = false;
+ mActualState = false;
+ break;
+ case STATE_ENABLED:
+ mInTransition = false;
+ mActualState = true;
+ break;
+ case STATE_TURNING_ON:
+ mInTransition = true;
+ mActualState = false;
+ break;
+ case STATE_TURNING_OFF:
+ mInTransition = true;
+ mActualState = true;
+ break;
+ }
+
+ if (wasInTransition && !mInTransition) {
+ if (mDeferredStateChangeRequestNeeded) {
+ Log.v(TAG, "processing deferred state change");
+ if (mActualState != null && mIntendedState != null &&
+ mIntendedState.equals(mActualState)) {
+ Log.v(TAG, "... but intended state matches, so no changes.");
+ } else if (mIntendedState != null) {
+ mInTransition = true;
+ requestStateChange(context, mIntendedState);
+ }
+ mDeferredStateChangeRequestNeeded = false;
+ }
+ }
+ }
+
+
+ /**
+ * If we're in a transition mode, this returns true if we're
+ * transitioning towards being enabled.
+ */
+ public final boolean isTurningOn() {
+ return mIntendedState != null && mIntendedState;
+ }
+
+ /**
+ * Returns simplified 3-state value from underlying 5-state.
+ *
+ * @param context
+ * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE
+ */
+ public final int getTriState(Context context) {
+ if (mInTransition) {
+ // If we know we just got a toggle request recently
+ // (which set mInTransition), don't even ask the
+ // underlying interface for its state. We know we're
+ // changing. This avoids blocking the UI thread
+ // during UI refresh post-toggle if the underlying
+ // service state accessor has coarse locking on its
+ // state (to be fixed separately).
+ return STATE_INTERMEDIATE;
+ }
+ switch (getActualState(context)) {
+ case STATE_DISABLED:
+ return STATE_DISABLED;
+ case STATE_ENABLED:
+ return STATE_ENABLED;
+ default:
+ return STATE_INTERMEDIATE;
+ }
+ }
+
+ /**
+ * Gets underlying actual state.
+ *
+ * @param context
+ * @return STATE_ENABLED, STATE_DISABLED, STATE_ENABLING, STATE_DISABLING,
+ * or or STATE_UNKNOWN.
+ */
+ public abstract int getActualState(Context context);
+
+ /**
+ * Actually make the desired change to the underlying radio
+ * API.
+ */
+ protected abstract void requestStateChange(Context context, boolean desiredState);
+ }
+
+ /**
+ * Subclass of StateTracker to get/set Wifi state.
+ */
+ private static final class WifiStateTracker extends StateTracker {
+ @Override
+ public int getActualState(Context context) {
+ WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ if (wifiManager != null) {
+ return wifiStateToFiveState(wifiManager.getWifiState());
+ }
+ return STATE_UNKNOWN;
+ }
+
+ @Override
+ protected void requestStateChange(Context context, final boolean desiredState) {
+ final WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ if (wifiManager == null) {
+ Log.d(TAG, "No wifiManager.");
+ return;
+ }
+
+ // Actually request the wifi change and persistent
+ // settings write off the UI thread, as it can take a
+ // user-noticeable amount of time, especially if there's
+ // disk contention.
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... args) {
+ /**
+ * Disable tethering if enabling Wifi
+ */
+ int wifiApState = wifiManager.getWifiApState();
+ if (desiredState && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
+ (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
+ wifiManager.setWifiApEnabled(null, false);
+ }
+
+ wifiManager.setWifiEnabled(desiredState);
+ return null;
+ }
+ }.execute();
+ }
+
+ @Override
+ public void onActualStateChange(Context context, Intent intent) {
+ if (!WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
+ return;
+ }
+ int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1);
+ setCurrentState(context, wifiStateToFiveState(wifiState));
+ }
+
+ /**
+ * Converts WifiManager's state values into our
+ * Wifi/Bluetooth-common state values.
+ */
+ private static int wifiStateToFiveState(int wifiState) {
+ switch (wifiState) {
+ case WifiManager.WIFI_STATE_DISABLED:
+ return STATE_DISABLED;
+ case WifiManager.WIFI_STATE_ENABLED:
+ return STATE_ENABLED;
+ case WifiManager.WIFI_STATE_DISABLING:
+ return STATE_TURNING_OFF;
+ case WifiManager.WIFI_STATE_ENABLING:
+ return STATE_TURNING_ON;
+ default:
+ return STATE_UNKNOWN;
+ }
+ }
+ }
+
+ /**
+ * Subclass of StateTracker to get/set Bluetooth state.
+ */
+ private static final class BluetoothStateTracker extends StateTracker {
+
+ @Override
+ public int getActualState(Context context) {
+ if (sLocalBluetoothManager == null) {
+ sLocalBluetoothManager = LocalBluetoothManager.getInstance(context);
+ if (sLocalBluetoothManager == null) {
+ return STATE_UNKNOWN; // On emulator?
+ }
+ }
+ return bluetoothStateToFiveState(sLocalBluetoothManager.getBluetoothState());
+ }
+
+ @Override
+ protected void requestStateChange(Context context, final boolean desiredState) {
+ if (sLocalBluetoothManager == null) {
+ Log.d(TAG, "No LocalBluetoothManager");
+ return;
+ }
+ // Actually request the Bluetooth change and persistent
+ // settings write off the UI thread, as it can take a
+ // user-noticeable amount of time, especially if there's
+ // disk contention.
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... args) {
+ sLocalBluetoothManager.setBluetoothEnabled(desiredState);
+ return null;
+ }
+ }.execute();
+ }
+
+ @Override
+ public void onActualStateChange(Context context, Intent intent) {
+ if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
+ return;
+ }
+ int bluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
+ setCurrentState(context, bluetoothStateToFiveState(bluetoothState));
+ }
+
+ /**
+ * Converts BluetoothAdapter's state values into our
+ * Wifi/Bluetooth-common state values.
+ */
+ private static int bluetoothStateToFiveState(int bluetoothState) {
+ switch (bluetoothState) {
+ case BluetoothAdapter.STATE_OFF:
+ return STATE_DISABLED;
+ case BluetoothAdapter.STATE_ON:
+ return STATE_ENABLED;
+ case BluetoothAdapter.STATE_TURNING_ON:
+ return STATE_TURNING_ON;
+ case BluetoothAdapter.STATE_TURNING_OFF:
+ return STATE_TURNING_OFF;
+ default:
+ return STATE_UNKNOWN;
+ }
+ }
+ }
+
+
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
@@ -142,26 +442,53 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
* @param context
*/
private static void updateButtons(RemoteViews views, Context context) {
- switch (getWifiState(context)) {
+ switch (sWifiState.getTriState(context)) {
case STATE_DISABLED:
- views.setImageViewResource(R.id.img_wifi, R.drawable.ic_appwidget_settings_wifi_off);
- views.setImageViewResource(R.id.ind_wifi, R.drawable.appwidget_settings_ind_off_l);
+ views.setImageViewResource(R.id.img_wifi,
+ R.drawable.ic_appwidget_settings_wifi_off);
+ views.setImageViewResource(R.id.ind_wifi,
+ R.drawable.appwidget_settings_ind_off_l);
break;
case STATE_ENABLED:
- views.setImageViewResource(R.id.img_wifi, R.drawable.ic_appwidget_settings_wifi_on);
- views.setImageViewResource(R.id.ind_wifi, R.drawable.appwidget_settings_ind_on_l);
+ views.setImageViewResource(R.id.img_wifi,
+ R.drawable.ic_appwidget_settings_wifi_on);
+ views.setImageViewResource(R.id.ind_wifi,
+ R.drawable.appwidget_settings_ind_on_l);
break;
case STATE_INTERMEDIATE:
- views.setImageViewResource(R.id.img_wifi, R.drawable.ic_appwidget_settings_wifi_off);
- views.setImageViewResource(R.id.ind_wifi, R.drawable.appwidget_settings_ind_mid_l);
+ // In the transitional state, the bottom green bar
+ // shows the tri-state (on, off, transitioning), but
+ // the top dark-gray-or-bright-white logo shows the
+ // user's intent. This is much easier to see in
+ // sunlight.
+ if (sWifiState.isTurningOn()) {
+ views.setImageViewResource(R.id.img_wifi,
+ R.drawable.ic_appwidget_settings_wifi_on);
+ views.setImageViewResource(R.id.ind_wifi,
+ R.drawable.appwidget_settings_ind_mid_l);
+ } else {
+ views.setImageViewResource(R.id.img_wifi,
+ R.drawable.ic_appwidget_settings_wifi_off);
+ views.setImageViewResource(R.id.ind_wifi,
+ R.drawable.appwidget_settings_ind_off_l);
+ }
break;
}
- if (getBrightness(context)) {
- views.setImageViewResource(R.id.img_brightness, R.drawable.ic_appwidget_settings_brightness_on);
- views.setImageViewResource(R.id.ind_brightness, R.drawable.appwidget_settings_ind_on_r);
+ if (getBrightnessMode(context)) {
+ views.setImageViewResource(R.id.img_brightness,
+ R.drawable.ic_appwidget_settings_brightness_auto);
+ views.setImageViewResource(R.id.ind_brightness,
+ R.drawable.appwidget_settings_ind_on_r);
+ } else if (getBrightness(context)) {
+ views.setImageViewResource(R.id.img_brightness,
+ R.drawable.ic_appwidget_settings_brightness_on);
+ views.setImageViewResource(R.id.ind_brightness,
+ R.drawable.appwidget_settings_ind_on_r);
} else {
- views.setImageViewResource(R.id.img_brightness, R.drawable.ic_appwidget_settings_brightness_off);
- views.setImageViewResource(R.id.ind_brightness, R.drawable.appwidget_settings_ind_off_r);
+ views.setImageViewResource(R.id.img_brightness,
+ R.drawable.ic_appwidget_settings_brightness_off);
+ views.setImageViewResource(R.id.ind_brightness,
+ R.drawable.appwidget_settings_ind_off_r);
}
if (getSync(context)) {
views.setImageViewResource(R.id.img_sync, R.drawable.ic_appwidget_settings_sync_on);
@@ -177,18 +504,36 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
views.setImageViewResource(R.id.img_gps, R.drawable.ic_appwidget_settings_gps_off);
views.setImageViewResource(R.id.ind_gps, R.drawable.appwidget_settings_ind_off_c);
}
- switch (getBluetoothState(context)) {
+ switch (sBluetoothState.getTriState(context)) {
case STATE_DISABLED:
- views.setImageViewResource(R.id.img_bluetooth, R.drawable.ic_appwidget_settings_bluetooth_off);
- views.setImageViewResource(R.id.ind_bluetooth, R.drawable.appwidget_settings_ind_off_c);
+ views.setImageViewResource(R.id.img_bluetooth,
+ R.drawable.ic_appwidget_settings_bluetooth_off);
+ views.setImageViewResource(R.id.ind_bluetooth,
+ R.drawable.appwidget_settings_ind_off_c);
break;
case STATE_ENABLED:
- views.setImageViewResource(R.id.img_bluetooth, R.drawable.ic_appwidget_settings_bluetooth_on);
- views.setImageViewResource(R.id.ind_bluetooth, R.drawable.appwidget_settings_ind_on_c);
+ views.setImageViewResource(R.id.img_bluetooth,
+ R.drawable.ic_appwidget_settings_bluetooth_on);
+ views.setImageViewResource(R.id.ind_bluetooth,
+ R.drawable.appwidget_settings_ind_on_c);
break;
case STATE_INTERMEDIATE:
- views.setImageViewResource(R.id.img_bluetooth, R.drawable.ic_appwidget_settings_bluetooth_off);
- views.setImageViewResource(R.id.ind_bluetooth, R.drawable.appwidget_settings_ind_mid_c);
+ // In the transitional state, the bottom green bar
+ // shows the tri-state (on, off, transitioning), but
+ // the top dark-gray-or-bright-white logo shows the
+ // user's intent. This is much easier to see in
+ // sunlight.
+ if (sBluetoothState.isTurningOn()) {
+ views.setImageViewResource(R.id.img_bluetooth,
+ R.drawable.ic_appwidget_settings_bluetooth_on);
+ views.setImageViewResource(R.id.ind_bluetooth,
+ R.drawable.appwidget_settings_ind_mid_c);
+ } else {
+ views.setImageViewResource(R.id.img_bluetooth,
+ R.drawable.ic_appwidget_settings_bluetooth_off);
+ views.setImageViewResource(R.id.ind_bluetooth,
+ R.drawable.appwidget_settings_ind_off_c);
+ }
break;
}
}
@@ -220,11 +565,15 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
- if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
+ if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
+ sWifiState.onActualStateChange(context, intent);
+ } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
+ sBluetoothState.onActualStateChange(context, intent);
+ } else if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
Uri data = intent.getData();
int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
if (buttonId == BUTTON_WIFI) {
- toggleWifi(context);
+ sWifiState.toggleState(context);
} else if (buttonId == BUTTON_BRIGHTNESS) {
toggleBrightness(context);
} else if (buttonId == BUTTON_SYNC) {
@@ -232,45 +581,17 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
} else if (buttonId == BUTTON_GPS) {
toggleGps(context);
} else if (buttonId == BUTTON_BLUETOOTH) {
- toggleBluetooth(context);
+ sBluetoothState.toggleState(context);
}
- }
- // State changes fall through
- updateWidget(context);
- }
-
- /**
- * Gets the state of Wi-Fi
- *
- * @param context
- * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE
- */
- private static int getWifiState(Context context) {
- WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- int wifiState = wifiManager.getWifiState();
- if (wifiState == WifiManager.WIFI_STATE_DISABLED) {
- return STATE_DISABLED;
- } else if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
- return STATE_ENABLED;
} else {
- return STATE_INTERMEDIATE;
+ // Don't fall-through to updating the widget. The Intent
+ // was something unrelated or that our super class took
+ // care of.
+ return;
}
- }
- /**
- * Toggles the state of Wi-Fi
- *
- * @param context
- */
- private void toggleWifi(Context context) {
- WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- int wifiState = getWifiState(context);
- if (wifiState == STATE_ENABLED) {
- wifiManager.setWifiEnabled(false);
- } else if (wifiState == STATE_DISABLED) {
- wifiManager.setWifiEnabled(true);
- }
- Toast.makeText(context, R.string.gadget_toggle_wifi, Toast.LENGTH_SHORT).show();
+ // State changes fall through
+ updateWidget(context);
}
/**
@@ -378,6 +699,27 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
}
/**
+ * Gets state of brightness mode.
+ *
+ * @param context
+ * @return true if auto brightness is on.
+ */
+ private static boolean getBrightnessMode(Context context) {
+ try {
+ IPowerManager power = IPowerManager.Stub.asInterface(
+ ServiceManager.getService("power"));
+ if (power != null) {
+ int brightnessMode = Settings.System.getInt(context.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE);
+ return brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
+ }
+ } catch (Exception e) {
+ Log.d(TAG, "getBrightnessMode: " + e);
+ }
+ return false;
+ }
+
+ /**
* Increases or decreases the brightness.
*
* @param context
@@ -390,25 +732,41 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
ContentResolver cr = context.getContentResolver();
int brightness = Settings.System.getInt(cr,
Settings.System.SCREEN_BRIGHTNESS);
- // Rotate MINIMUM -> DEFAULT -> MAXIMUM
+ int brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
+ //Only get brightness setting if available
+ if (context.getResources().getBoolean(
+ com.android.internal.R.bool.config_automatic_brightness_available)) {
+ brightnessMode = Settings.System.getInt(cr,
+ Settings.System.SCREEN_BRIGHTNESS_MODE);
+ }
+
+ // Rotate AUTO -> MINIMUM -> DEFAULT -> MAXIMUM
// Technically, not a toggle...
- if (brightness < DEFAULT_BACKLIGHT) {
+ if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
+ brightness = MINIMUM_BACKLIGHT;
+ brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
+ } else if (brightness < DEFAULT_BACKLIGHT) {
brightness = DEFAULT_BACKLIGHT;
} else if (brightness < MAXIMUM_BACKLIGHT) {
brightness = MAXIMUM_BACKLIGHT;
} else {
+ brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
brightness = MINIMUM_BACKLIGHT;
}
- power.setBacklightBrightness(brightness);
- Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
+
if (context.getResources().getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available)) {
- // Disable automatic brightness
+ // Set screen brightness mode (automatic or manual)
Settings.System.putInt(context.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
- Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
- // Set it again in case auto brightness was on
+ brightnessMode);
+ } else {
+ // Make sure we set the brightness if automatic mode isn't available
+ brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
+ }
+ if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) {
power.setBacklightBrightness(brightness);
+ Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
}
}
} catch (RemoteException e) {
@@ -417,42 +775,4 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
Log.d(TAG, "toggleBrightness: " + e);
}
}
-
- /**
- * Gets state of bluetooth
- *
- * @param context
- * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE
- */
- private static int getBluetoothState(Context context) {
- if (mLocalBluetoothManager == null) {
- mLocalBluetoothManager = LocalBluetoothManager.getInstance(context);
- if (mLocalBluetoothManager == null) {
- return STATE_INTERMEDIATE; // On emulator?
- }
- }
- int state = mLocalBluetoothManager.getBluetoothState();
- if (state == BluetoothAdapter.STATE_OFF) {
- return STATE_DISABLED;
- } else if (state == BluetoothAdapter.STATE_ON) {
- return STATE_ENABLED;
- } else {
- return STATE_INTERMEDIATE;
- }
- }
-
- /**
- * Toggles the state of bluetooth
- *
- * @param context
- */
- private void toggleBluetooth(Context context) {
- int state = getBluetoothState(context);
- if (state == STATE_ENABLED) {
- mLocalBluetoothManager.setBluetoothEnabled(false);
- } else if (state == STATE_DISABLED) {
- mLocalBluetoothManager.setBluetoothEnabled(true);
- }
- Toast.makeText(context, R.string.gadget_toggle_bluetooth, Toast.LENGTH_SHORT).show();
- }
}
diff --git a/src/com/android/settings/wifi/AccessPoint.java b/src/com/android/settings/wifi/AccessPoint.java
new file mode 100644
index 0000000..141c412
--- /dev/null
+++ b/src/com/android/settings/wifi/AccessPoint.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings.wifi;
+
+import com.android.settings.R;
+
+import android.content.Context;
+import android.net.NetworkInfo.DetailedState;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wifi.ScanResult;
+import android.preference.Preference;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.ImageView;
+
+class AccessPoint extends Preference {
+ private static final int[] STATE_SECURED = {R.attr.state_encrypted};
+ private static final int[] STATE_NONE = {};
+
+ static final int SECURITY_NONE = 0;
+ static final int SECURITY_WEP = 1;
+ static final int SECURITY_PSK = 2;
+ static final int SECURITY_EAP = 3;
+
+ final String ssid;
+ final int security;
+ final int networkId;
+
+ private WifiConfiguration mConfig;
+ private int mRssi;
+ private WifiInfo mInfo;
+ private DetailedState mState;
+ private ImageView mSignal;
+
+ static int getSecurity(WifiConfiguration config) {
+ if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+ return SECURITY_PSK;
+ }
+ if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
+ config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+ return SECURITY_EAP;
+ }
+ return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE;
+ }
+
+ private static int getSecurity(ScanResult result) {
+ if (result.capabilities.contains("WEP")) {
+ return SECURITY_WEP;
+ } else if (result.capabilities.contains("PSK")) {
+ return SECURITY_PSK;
+ } else if (result.capabilities.contains("EAP")) {
+ return SECURITY_EAP;
+ }
+ return SECURITY_NONE;
+ }
+
+ AccessPoint(Context context, WifiConfiguration config) {
+ super(context);
+ setWidgetLayoutResource(R.layout.preference_widget_wifi_signal);
+ ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
+ security = getSecurity(config);
+ networkId = config.networkId;
+ mConfig = config;
+ mRssi = Integer.MAX_VALUE;
+ }
+
+ AccessPoint(Context context, ScanResult result) {
+ super(context);
+ setWidgetLayoutResource(R.layout.preference_widget_wifi_signal);
+ ssid = result.SSID;
+ security = getSecurity(result);
+ networkId = -1;
+ mRssi = result.level;
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ setTitle(ssid);
+ mSignal = (ImageView) view.findViewById(R.id.signal);
+ if (mRssi == Integer.MAX_VALUE) {
+ mSignal.setImageDrawable(null);
+ } else {
+ mSignal.setImageResource(R.drawable.wifi_signal);
+ mSignal.setImageState((security != SECURITY_NONE) ?
+ STATE_SECURED : STATE_NONE, true);
+ }
+ refresh();
+ super.onBindView(view);
+ }
+
+ @Override
+ public int compareTo(Preference preference) {
+ if (!(preference instanceof AccessPoint)) {
+ return 1;
+ }
+ AccessPoint other = (AccessPoint) preference;
+ // Active one goes first.
+ if (mInfo != other.mInfo) {
+ return (mInfo != null) ? -1 : 1;
+ }
+ // Reachable one goes before unreachable one.
+ if ((mRssi ^ other.mRssi) < 0) {
+ return (mRssi != Integer.MAX_VALUE) ? -1 : 1;
+ }
+ // Configured one goes before unconfigured one.
+ if ((networkId ^ other.networkId) < 0) {
+ return (networkId != -1) ? -1 : 1;
+ }
+ // Sort by signal strength.
+ int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi);
+ if (difference != 0) {
+ return difference;
+ }
+ // Sort by ssid.
+ return ssid.compareToIgnoreCase(other.ssid);
+ }
+
+ boolean update(ScanResult result) {
+ // We do not call refresh() since this is called before onBindView().
+ if (ssid.equals(result.SSID) && security == getSecurity(result)) {
+ if (WifiManager.compareSignalLevel(result.level, mRssi) > 0) {
+ mRssi = result.level;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ void update(WifiInfo info, DetailedState state) {
+ boolean reorder = false;
+ if (info != null && networkId != -1 && networkId == info.getNetworkId()) {
+ reorder = (mInfo == null);
+ mRssi = info.getRssi();
+ mInfo = info;
+ mState = state;
+ refresh();
+ } else if (mInfo != null) {
+ reorder = true;
+ mInfo = null;
+ mState = null;
+ refresh();
+ }
+ if (reorder) {
+ notifyHierarchyChanged();
+ }
+ }
+
+ int getLevel() {
+ if (mRssi == Integer.MAX_VALUE) {
+ return -1;
+ }
+ return WifiManager.calculateSignalLevel(mRssi, 4);
+ }
+
+ WifiConfiguration getConfig() {
+ return mConfig;
+ }
+
+ WifiInfo getInfo() {
+ return mInfo;
+ }
+
+ DetailedState getState() {
+ return mState;
+ }
+
+ static String removeDoubleQuotes(String string) {
+ int length = string.length();
+ if ((length > 1) && (string.charAt(0) == '"')
+ && (string.charAt(length - 1) == '"')) {
+ return string.substring(1, length - 1);
+ }
+ return string;
+ }
+
+ static String convertToQuotedString(String string) {
+ return "\"" + string + "\"";
+ }
+
+ private void refresh() {
+ if (mSignal == null) {
+ return;
+ }
+ Context context = getContext();
+ mSignal.setImageLevel(getLevel());
+
+ if (mState != null) {
+ setSummary(Summary.get(context, mState));
+ } else {
+ String status = null;
+ if (mRssi == Integer.MAX_VALUE) {
+ status = context.getString(R.string.wifi_not_in_range);
+ } else if (mConfig != null) {
+ status = context.getString((mConfig.status == WifiConfiguration.Status.DISABLED) ?
+ R.string.wifi_disabled : R.string.wifi_remembered);
+ }
+
+ if (security == SECURITY_NONE) {
+ setSummary(status);
+ } else {
+ String format = context.getString((status == null) ?
+ R.string.wifi_secured : R.string.wifi_secured_with_status);
+ String[] type = context.getResources().getStringArray(R.array.wifi_security);
+ setSummary(String.format(format, type[security], status));
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/wifi/AccessPointDialog.java b/src/com/android/settings/wifi/AccessPointDialog.java
deleted file mode 100644
index 4804d78..0000000
--- a/src/com/android/settings/wifi/AccessPointDialog.java
+++ /dev/null
@@ -1,807 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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 com.android.settings.wifi;
-
-import com.android.settings.R;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.security.Credentials;
-import android.security.KeyStore;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Bundle;
-import android.text.InputType;
-import android.text.TextUtils;
-import android.text.format.Formatter;
-import android.text.method.PasswordTransformationMethod;
-import android.text.method.TransformationMethod;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.Spinner;
-import android.widget.TableLayout;
-import android.widget.TextView;
-
-public class AccessPointDialog extends AlertDialog implements DialogInterface.OnClickListener,
- AdapterView.OnItemSelectedListener, View.OnClickListener {
-
- private static final String TAG = "AccessPointDialog";
- private static final String INSTANCE_KEY_ACCESS_POINT_STATE =
- "com.android.settings.wifi.AccessPointDialog:accessPointState";
- private static final String INSTANCE_KEY_MODE =
- "com.android.settings.wifi.AccessPointDialog:mode";
- private static final String INSTANCE_KEY_CUSTOM_TITLE =
- "com.android.settings.wifi.AccessPointDialog:customTitle";
- private static final String INSTANCE_KEY_AUTO_SECURITY_ALLOWED =
- "com.android.settings.wifi.AccessPointDialog:autoSecurityAllowed";
-
- private static final int POSITIVE_BUTTON = BUTTON1;
- private static final int NEGATIVE_BUTTON = BUTTON2;
- private static final int NEUTRAL_BUTTON = BUTTON3;
-
- /** The dialog should show info connectivity functionality */
- public static final int MODE_INFO = 0;
- /** The dialog should configure the detailed AP properties */
- public static final int MODE_CONFIGURE = 1;
- /** The dialog should have the password field and connect/cancel */
- public static final int MODE_RETRY_PASSWORD = 2;
-
- // These should be matched with the XML. Both arrays in XML depend on this
- // ordering!
- private static final int SECURITY_AUTO = 0;
- private static final int SECURITY_NONE = 1;
- private static final int SECURITY_WEP = 2;
- private static final int SECURITY_PSK = 3;
- private static final int SECURITY_EAP = 4;
-
- private static final int[] WEP_TYPE_VALUES = {
- AccessPointState.WEP_PASSWORD_AUTO, AccessPointState.WEP_PASSWORD_ASCII,
- AccessPointState.WEP_PASSWORD_HEX
- };
- private static final String NOT_APPLICABLE = "N/A";
- private static final String KEYSTORE_HEADER = "keystore://";
-
- // Button positions, default to impossible values
- private int mConnectButtonPos = Integer.MAX_VALUE;
- private int mForgetButtonPos = Integer.MAX_VALUE;
- private int mSaveButtonPos = Integer.MAX_VALUE;
-
- // Client configurable items. Generally, these should be saved in instance state
- private int mMode = MODE_INFO;
- private boolean mAutoSecurityAllowed = true;
- private CharSequence mCustomTitle;
- // This does not need to be saved in instance state.
- private WifiLayer mWifiLayer;
- private AccessPointState mState;
-
- // General views
- private View mView;
- private View mEnterpriseView;
- private TextView mPasswordText;
- private EditText mPasswordEdit;
- private CheckBox mShowPasswordCheckBox;
-
- // Enterprise fields
- private TextView mEapText;
- private Spinner mEapSpinner;
- private TextView mPhase2Text;
- private Spinner mPhase2Spinner;
- private TextView mIdentityText;
- private EditText mIdentityEdit;
- private TextView mAnonymousIdentityText;
- private EditText mAnonymousIdentityEdit;
- private TextView mCaCertText;
- private Spinner mCaCertSpinner;
- private TextView mClientCertText;
- private Spinner mClientCertSpinner;
- private EditText[] mEnterpriseTextFields;
-
-
- // Info-specific views
- private ViewGroup mTable;
-
- // Configure-specific views
- private EditText mSsidEdit;
- private TextView mSsidText;
- private TextView mSecurityText;
- private Spinner mSecuritySpinner;
- private Spinner mWepTypeSpinner;
- private KeyStore mKeyStore;
-
- public AccessPointDialog(Context context, WifiLayer wifiLayer) {
- super(context);
-
- mWifiLayer = wifiLayer;
- mKeyStore = KeyStore.getInstance();
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- onLayout();
- onFill();
-
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public void onRestoreInstanceState(Bundle savedInstanceState) {
- // Set to a class loader that can find AccessPointState
- savedInstanceState.setClassLoader(getClass().getClassLoader());
-
- mState = savedInstanceState.getParcelable(INSTANCE_KEY_ACCESS_POINT_STATE);
- mState.setContext(getContext());
-
- mMode = savedInstanceState.getInt(INSTANCE_KEY_MODE, mMode);
- mAutoSecurityAllowed = savedInstanceState.getBoolean(INSTANCE_KEY_AUTO_SECURITY_ALLOWED,
- mAutoSecurityAllowed);
- mCustomTitle = savedInstanceState.getCharSequence(INSTANCE_KEY_CUSTOM_TITLE);
- if (mCustomTitle != null) {
- setTitle(mCustomTitle);
- }
-
- // This is called last since it depends on the above values
- super.onRestoreInstanceState(savedInstanceState);
-
- if (mShowPasswordCheckBox != null) {
- // Restore the show-password-state on the edit text
- setShowPassword(mShowPasswordCheckBox.isChecked());
- }
- }
-
- @Override
- public Bundle onSaveInstanceState() {
- Bundle bundle = super.onSaveInstanceState();
- bundle.putParcelable(INSTANCE_KEY_ACCESS_POINT_STATE, mState);
- bundle.putInt(INSTANCE_KEY_MODE, mMode);
- bundle.putBoolean(INSTANCE_KEY_AUTO_SECURITY_ALLOWED, mAutoSecurityAllowed);
- bundle.putCharSequence(INSTANCE_KEY_CUSTOM_TITLE, mCustomTitle);
- return bundle;
- }
-
- /**
- * Sets state to show in this dialog.
- *
- * @param state The state.
- */
- public void setState(AccessPointState state) {
- mState = state;
- }
-
- /**
- * Sets the dialog mode.
- * @param mode One of {@link #MODE_CONFIGURE} or {@link #MODE_INFO}
- */
- public void setMode(int mode) {
- mMode = mode;
- }
-
- public void setAutoSecurityAllowed(boolean autoSecurityAllowed) {
- mAutoSecurityAllowed = autoSecurityAllowed;
- }
-
- @Override
- public void setTitle(CharSequence title) {
- super.setTitle(title);
- mCustomTitle = title;
- }
-
- @Override
- public void setTitle(int titleId) {
- setTitle(getContext().getString(titleId));
- }
-
- public void enableEnterpriseFields() {
- setEnterpriseFieldsVisible(true);
- updateCertificateSelection();
- setGenericPasswordVisible(true);
- // Both WPA and WPA2 show the same caption, so either is ok
- updatePasswordCaption(AccessPointState.PSK);
- }
-
- /** Called after flags are set, the dialog's layout/etc should be set up here */
- private void onLayout() {
- final Context context = getContext();
- final String ssid = mState.getHumanReadableSsid();
-
- int positiveButtonResId = 0;
- int negativeButtonResId = R.string.cancel;
- int neutralButtonResId = 0;
-
- if (mCustomTitle == null) {
- // Generic title is the SSID
- // We don't want to trigger this as a custom title, so call super's
- super.setTitle(ssid);
- }
- setInverseBackgroundForced(true);
-
- boolean defaultPasswordVisibility = true;
-
- if (mMode == MODE_CONFIGURE) {
- setLayout(R.layout.wifi_ap_configure);
-
- positiveButtonResId = R.string.wifi_save_config;
- mSaveButtonPos = POSITIVE_BUTTON;
-
- setEnterpriseFieldsVisible(false);
-
- } else if (mMode == MODE_INFO) {
- if (mState.isEnterprise() && !mState.configured) {
- setLayout(R.layout.wifi_ap_configure);
- setEnterpriseFieldsVisible(true);
- } else {
- setLayout(R.layout.wifi_ap_info);
- }
-
- if (mState.isConnectable()) {
- if (mCustomTitle == null) {
- // We don't want to trigger this as a custom title, so call super's
- super.setTitle(context.getString(R.string.connect_to_blank, ssid));
- }
- positiveButtonResId = R.string.connect;
- mConnectButtonPos = POSITIVE_BUTTON;
- }
-
- if (mState.isForgetable()) {
- if (positiveButtonResId == 0) {
- positiveButtonResId = R.string.forget_network;
- mForgetButtonPos = POSITIVE_BUTTON;
- } else {
- neutralButtonResId = R.string.forget_network;
- mForgetButtonPos = NEUTRAL_BUTTON;
- }
- }
- } else if (mMode == MODE_RETRY_PASSWORD) {
- setLayout(R.layout.wifi_ap_retry_password);
-
- positiveButtonResId = R.string.connect;
- mConnectButtonPos = POSITIVE_BUTTON;
-
- setGenericPasswordVisible(true);
- defaultPasswordVisibility = false;
- }
-
- if (defaultPasswordVisibility) {
- if (!mState.configured && mState.seen && mState.hasSecurity()) {
- setGenericPasswordVisible(true);
- } else {
- setGenericPasswordVisible(false);
- }
- }
-
- setButtons(positiveButtonResId, negativeButtonResId, neutralButtonResId);
- }
-
- /** Called when we need to set our member variables to point to the views. */
- private void onReferenceViews(View view) {
- mPasswordText = (TextView) view.findViewById(R.id.password_text);
- mPasswordEdit = (EditText) view.findViewById(R.id.password_edit);
- mSsidText = (TextView) view.findViewById(R.id.ssid_text);
- mSsidEdit = (EditText) view.findViewById(R.id.ssid_edit);
- mSecurityText = (TextView) view.findViewById(R.id.security_text);
- mSecuritySpinner = (Spinner) view.findViewById(R.id.security_spinner);
- mWepTypeSpinner = (Spinner) view.findViewById(R.id.wep_type_spinner);
- mEnterpriseView = mView.findViewById(R.id.enterprise_wrapper);
-
- mShowPasswordCheckBox = (CheckBox) view.findViewById(R.id.show_password_checkbox);
- if (mShowPasswordCheckBox != null) {
- mShowPasswordCheckBox.setOnClickListener(this);
- }
- if (mMode == MODE_CONFIGURE) {
- mSecuritySpinner.setOnItemSelectedListener(this);
- mSecuritySpinner.setPromptId(R.string.security);
- setSpinnerAdapter(mSecuritySpinner, mAutoSecurityAllowed ?
- R.array.wifi_security_entries
- : R.array.wifi_security_without_auto_entries);
- } else if (mMode == MODE_INFO) {
- mTable = (ViewGroup) view.findViewById(R.id.table);
- }
- /* for enterprise one */
- if (mMode == MODE_CONFIGURE ||
- (mState.isEnterprise() && !mState.configured)) {
- setEnterpriseFields(view);
- updateCertificateSelection();
- }
- }
-
- private void updateCertificateSelection() {
- setSpinnerAdapter(mClientCertSpinner, getAllUserCertificateKeys());
- setSpinnerAdapter(mCaCertSpinner, getAllCaCertificateKeys());
-
- mPhase2Spinner.setSelection(getSelectionIndex(
- R.array.wifi_phase2_entries, mState.getPhase2()));
- mEapSpinner.setSelection(getSelectionIndex(
- R.array.wifi_eap_entries, mState.getEap()));
- mClientCertSpinner.setSelection(getSelectionIndex(
- getAllUserCertificateKeys(), mState.getEnterpriseField(
- AccessPointState.CLIENT_CERT)));
- mCaCertSpinner.setSelection(getSelectionIndex(
- getAllCaCertificateKeys(), mState.getEnterpriseField(
- AccessPointState.CA_CERT)));
- }
-
- private String[] getAllCaCertificateKeys() {
- return appendEmptyInSelection(mKeyStore.saw(Credentials.CA_CERTIFICATE));
- }
-
- private String[] getAllUserCertificateKeys() {
- return appendEmptyInSelection(mKeyStore.saw(Credentials.USER_CERTIFICATE));
- }
-
- private String[] appendEmptyInSelection(String[] keys) {
- if (keys == null) {
- return new String[] {NOT_APPLICABLE};
- } else {
- String[] selections = new String[keys.length + 1];
- System.arraycopy(keys, 0, selections, 0, keys.length);
- selections[keys.length] = NOT_APPLICABLE;
- return selections;
- }
- }
-
- private void setEnterpriseFields(View view) {
- mIdentityText = (TextView) view.findViewById(R.id.identity_text);
- mIdentityEdit = (EditText) view.findViewById(R.id.identity_edit);
- mAnonymousIdentityText =
- (TextView) view.findViewById(R.id.anonymous_identity_text);
- mAnonymousIdentityEdit =
- (EditText) view.findViewById(R.id.anonymous_identity_edit);
- mClientCertText =
- (TextView) view.findViewById(R.id.client_certificate_text);
- mCaCertText = (TextView) view.findViewById(R.id.ca_certificate_text);
- mEapText = (TextView) view.findViewById(R.id.eap_text);
- mEapSpinner = (Spinner) view.findViewById(R.id.eap_spinner);
- mEapSpinner.setOnItemSelectedListener(this);
- mEapSpinner.setPromptId(R.string.please_select_eap);
- setSpinnerAdapter(mEapSpinner, R.array.wifi_eap_entries);
-
- mPhase2Text = (TextView) view.findViewById(R.id.phase2_text);
- mPhase2Spinner = (Spinner) view.findViewById(R.id.phase2_spinner);
- mPhase2Spinner.setOnItemSelectedListener(this);
- mPhase2Spinner.setPromptId(R.string.please_select_phase2);
- setSpinnerAdapter(mPhase2Spinner, R.array.wifi_phase2_entries);
-
- mClientCertSpinner =
- (Spinner) view.findViewById(R.id.client_certificate_spinner);
- mClientCertSpinner.setOnItemSelectedListener(this);
- mClientCertSpinner.setPromptId(
- R.string.please_select_client_certificate);
- setSpinnerAdapter(mClientCertSpinner, getAllUserCertificateKeys());
-
- mCaCertSpinner =
- (Spinner) view.findViewById(R.id.ca_certificate_spinner);
- mCaCertSpinner.setOnItemSelectedListener(this);
- mCaCertSpinner.setPromptId(R.string.please_select_ca_certificate);
- setSpinnerAdapter(mCaCertSpinner, getAllCaCertificateKeys());
-
- mEnterpriseTextFields = new EditText[] {
- mIdentityEdit, mAnonymousIdentityEdit
- };
-
- }
-
- private void setSpinnerAdapter(Spinner spinner, String[] items) {
- if (items != null) {
- ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(
- getContext(), android.R.layout.simple_spinner_item, items);
- adapter.setDropDownViewResource(
- android.R.layout.simple_spinner_dropdown_item);
- spinner.setAdapter(adapter);
- }
- }
-
- private void setSpinnerAdapter(Spinner spinner, int arrayResId) {
- setSpinnerAdapter(spinner,
- getContext().getResources().getStringArray(arrayResId));
- }
-
- /** Called when the widgets are in-place waiting to be filled with data */
- private void onFill() {
-
- // Appears in the order added
- if (mMode == MODE_INFO) {
- if (mState.primary) {
- addInfoRow(R.string.wifi_status, mState.getSummarizedStatus());
- addInfoRow(R.string.wifi_link_speed, mState.linkSpeed + WifiInfo.LINK_SPEED_UNITS);
- }
-
- if (mState.seen) {
- addInfoRow(R.string.signal, getSignalResId(mState.signal));
- }
-
- if (mState.security != null) {
- addInfoRow(R.string.security, mState.getHumanReadableSecurity());
- }
-
- if (mState.primary && mState.ipAddress != 0) {
- addInfoRow(R.string.ip_address, Formatter.formatIpAddress(mState.ipAddress));
- }
-
- } else if (mMode == MODE_CONFIGURE) {
- String ssid = mState.getHumanReadableSsid();
- if (!TextUtils.isEmpty(ssid)) {
- mSsidEdit.setText(ssid);
- }
- if (mState.configured) {
- mPasswordEdit.setHint(R.string.wifi_password_unchanged);
- }
- }
-
- updatePasswordCaption(mState.security);
- }
-
- private void updatePasswordCaption(String security) {
- if (mPasswordText != null) {
- if (security != null && security.equals(AccessPointState.WEP)) {
- mPasswordText.setText(R.string.please_type_hex_key);
- } else {
- mPasswordText.setText(R.string.please_type_passphrase);
- }
- }
- }
-
- private void addInfoRow(int nameResId, String value) {
- View rowView = getLayoutInflater().inflate(R.layout.wifi_ap_info_row, mTable, false);
- ((TextView) rowView.findViewById(R.id.name)).setText(nameResId);
- ((TextView) rowView.findViewById(R.id.value)).setText(value);
- mTable.addView(rowView);
- }
-
- private void addInfoRow(int nameResId, int valueResId) {
- addInfoRow(nameResId, getContext().getString(valueResId));
- }
-
- private void setButtons(int positiveResId, int negativeResId, int neutralResId) {
- final Context context = getContext();
-
- if (positiveResId > 0) {
- setButton(context.getString(positiveResId), this);
- }
-
- if (negativeResId > 0) {
- setButton2(context.getString(negativeResId), this);
- }
-
- if (neutralResId > 0) {
- setButton3(context.getString(neutralResId), this);
- }
- }
-
- private void setLayout(int layoutResId) {
- setView(mView = getLayoutInflater().inflate(layoutResId, null));
- onReferenceViews(mView);
- }
-
- public void onClick(DialogInterface dialog, int which) {
- if (which == mForgetButtonPos) {
- handleForget();
- } else if (which == mConnectButtonPos) {
- handleConnect();
- } else if (which == mSaveButtonPos) {
- handleSave();
- }
- }
-
- private void handleForget() {
- if (!replaceStateWithWifiLayerInstance()) return;
- mWifiLayer.forgetNetwork(mState);
- }
-
- private void handleConnect() {
- if (!replaceStateWithWifiLayerInstance()) {
- Log.w(TAG, "Assuming connecting to a new network.");
- }
-
- if (mState.isEnterprise()) {
- if(!mState.configured) {
- updateEnterpriseFields();
- }
- }
- updatePasswordField();
-
- mWifiLayer.connectToNetwork(mState);
- }
-
- /*
- * If the network is secured and they haven't entered a password, popup an
- * error. Allow empty passwords if the state already has a password set
- * (since in that scenario, an empty password means keep the old password).
- */
- private void updatePasswordField() {
-
- String password = getEnteredPassword();
- boolean passwordIsEmpty = TextUtils.isEmpty(password);
- /*
- * When 'retry password', they can not enter a blank password. In any
- * other mode, we let them enter a blank password if the state already
- * has a password.
- */
- if (passwordIsEmpty && (!mState.hasPassword() ||
- mMode == MODE_RETRY_PASSWORD) &&
- (mState.security != null) &&
- !mState.security.equals(AccessPointState.OPEN) &&
- !mState.isEnterprise()) {
- new AlertDialog.Builder(getContext())
- .setTitle(R.string.error_title)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(R.string.wifi_password_incorrect_error)
- .setPositiveButton(android.R.string.ok, null)
- .show();
- return;
- }
-
- if (!passwordIsEmpty) {
- mState.setPassword(password);
- }
- }
-
- private void handleSave() {
- replaceStateWithWifiLayerInstance();
-
- String ssid = mSsidEdit.getText().toString();
- String password = mPasswordEdit.getText().toString();
-
- mState.setSsid(ssid);
-
- int securityType = getSecurityTypeFromSpinner();
-
- if (!TextUtils.isEmpty(password) && (securityType != SECURITY_WEP)) {
- mState.setPassword(password);
- }
-
- switch (securityType) {
- case SECURITY_PSK: {
- mState.setSecurity(AccessPointState.PSK);
- break;
- }
-
- case SECURITY_AUTO: {
- break;
- }
-
- case SECURITY_WEP: {
- mState.setSecurity(AccessPointState.WEP);
- mState.setPassword(password, WEP_TYPE_VALUES[
- mWepTypeSpinner.getSelectedItemPosition()]);
- break;
- }
-
- case SECURITY_EAP:
- mState.setSecurity(AccessPointState.EAP);
- break;
-
- case SECURITY_NONE:
- default:
- mState.setSecurity(AccessPointState.OPEN);
- break;
- }
-
- if (mState.isEnterprise() && !mState.configured) {
- updateEnterpriseFields();
- }
-
- if (!mWifiLayer.saveNetwork(mState)) {
- return;
- }
-
- // Connect right away if they've touched it
- if (!mWifiLayer.connectToNetwork(mState)) {
- return;
- }
-
- }
-
- private int getSelectionIndex(String[] array, String selection) {
- if(selection != null) {
- for (int i = 0 ; i < array.length ; i++) {
- if (selection.contains(array[i])) return i;
- }
- }
- return 0;
- }
-
- private int getSelectionIndex(int arrayResId, String selection) {
- return getSelectionIndex(
- getContext().getResources().getStringArray(arrayResId), selection);
- }
-
- private void updateEnterpriseFields() {
- int i;
- String value;
- for (i = AccessPointState.IDENTITY ;
- i <= AccessPointState.ANONYMOUS_IDENTITY ; i++) {
- value = mEnterpriseTextFields[i].getText().toString();
- if (!TextUtils.isEmpty(value)) {
- mState.setEnterpriseField(i, value);
- }
- }
- Spinner spinner = mClientCertSpinner;
- int index = spinner.getSelectedItemPosition();
- if (index != (spinner.getCount() - 1)) {
- String key = (String) spinner.getSelectedItem();
- mState.setEnterpriseField(AccessPointState.CLIENT_CERT,
- KEYSTORE_HEADER + Credentials.USER_CERTIFICATE + key);
- mState.setEnterpriseField(AccessPointState.PRIVATE_KEY,
- KEYSTORE_HEADER + Credentials.USER_PRIVATE_KEY + key);
- }
- spinner = mCaCertSpinner;
- index = spinner.getSelectedItemPosition();
- if (index != (spinner.getCount() - 1)) {
- String key = (String) spinner.getSelectedItem();
- mState.setEnterpriseField(AccessPointState.CA_CERT,
- KEYSTORE_HEADER + Credentials.CA_CERTIFICATE + key);
- }
- mState.setSecurity(AccessPointState.EAP);
- mState.setEap(mEapSpinner.getSelectedItemPosition());
- mState.setPhase2((String) mPhase2Spinner.getSelectedItem());
- }
-
- /**
- * Replaces our {@link #mState} with the equal WifiLayer instance. This is useful after
- * we unparceled the state previously and before we are calling methods on {@link #mWifiLayer}.
- *
- * @return Whether WifiLayer was able to find an equal state in its set.
- */
- private boolean replaceStateWithWifiLayerInstance() {
- AccessPointState state = mWifiLayer.getWifiLayerApInstance(mState);
- if (state == null) {
- return false;
- }
-
- mState = state;
- return true;
- }
-
- private int getSecurityTypeFromSpinner() {
- int position = mSecuritySpinner.getSelectedItemPosition();
- // If there is no AUTO choice, the position needs 1 added to get
- // to the proper spinner position -> security constants mapping
- return mAutoSecurityAllowed ? position : position + 1;
- }
-
- private String getEnteredPassword() {
- return mPasswordEdit != null ? mPasswordEdit.getText().toString() : null;
- }
-
- /**
- * Call the one you want to hide first.
- */
- private void setWepVisible(boolean visible) {
- setGenericPasswordVisible(visible);
- int visibility = visible ? View.VISIBLE : View.GONE;
- mWepTypeSpinner.setVisibility(visibility);
- }
-
- /**
- * @see #setWepVisible(boolean)
- */
- private void setGenericPasswordVisible(boolean visible) {
- int visibility = visible ? View.VISIBLE : View.GONE;
- mPasswordText.setVisibility(visibility);
- mPasswordEdit.setVisibility(visibility);
- mShowPasswordCheckBox.setVisibility(visibility);
- }
-
- private void setEnterpriseFieldsVisible(boolean visible) {
- int visibility = visible ? View.VISIBLE : View.GONE;
- mEnterpriseView.setVisibility(visibility);
- if (visible) {
- setWepVisible(false);
- }
- if (mMode != MODE_CONFIGURE) {
- mSsidText.setVisibility(View.GONE);
- mSsidEdit.setVisibility(View.GONE);
- mSecurityText.setVisibility(View.GONE);
- mSecuritySpinner.setVisibility(View.GONE);
- }
- }
-
- public void onItemSelected(AdapterView parent, View view, int position, long id) {
- if (parent == mSecuritySpinner) {
- handleSecurityChange(getSecurityTypeFromSpinner());
- }
- }
-
- public void onNothingSelected(AdapterView parent) {
- }
-
- private void handleSecurityChange(int security) {
- setEnterpriseFieldsVisible(false);
- switch (security) {
-
- case SECURITY_NONE: {
- setWepVisible(false);
- setGenericPasswordVisible(false);
- break;
- }
-
- case SECURITY_WEP: {
- setGenericPasswordVisible(false);
- setWepVisible(true);
- updatePasswordCaption(AccessPointState.WEP);
- break;
- }
-
- case SECURITY_AUTO: {
- setWepVisible(false);
- setGenericPasswordVisible(mState.hasSecurity());
- // Shows the generic 'wireless password'
- updatePasswordCaption(AccessPointState.PSK);
- break;
- }
-
- case SECURITY_PSK: {
- setWepVisible(false);
- setGenericPasswordVisible(true);
- // Both WPA and WPA2 show the same caption, so either is ok
- updatePasswordCaption(AccessPointState.PSK);
- break;
- }
- case SECURITY_EAP: {
- // Unlock the keystore if it is not unlocked yet.
- if (mKeyStore.test() != KeyStore.NO_ERROR) {
- Credentials.getInstance().unlock(getContext());
- return;
- }
- enableEnterpriseFields();
- break;
- }
- }
- }
-
- private static int getSignalResId(int signal) {
- switch (WifiManager.calculateSignalLevel(signal, 4)) {
- case 0: {
- return R.string.wifi_signal_0;
- }
- case 1: {
- return R.string.wifi_signal_1;
- }
- case 2: {
- return R.string.wifi_signal_2;
- }
- case 3: {
- return R.string.wifi_signal_3;
- }
- }
-
- return 0;
- }
-
-
- public void onClick(View v) {
- if (v == mShowPasswordCheckBox) {
- setShowPassword(mShowPasswordCheckBox.isChecked());
- }
- }
-
- private void setShowPassword(boolean showPassword) {
- if (mPasswordEdit != null) {
- mPasswordEdit.setInputType(InputType.TYPE_CLASS_TEXT |
- (showPassword ? InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
- : InputType.TYPE_TEXT_VARIATION_PASSWORD));
- }
- }
-
-}
diff --git a/src/com/android/settings/wifi/AccessPointPreference.java b/src/com/android/settings/wifi/AccessPointPreference.java
deleted file mode 100644
index 6dd5492..0000000
--- a/src/com/android/settings/wifi/AccessPointPreference.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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 com.android.settings.wifi;
-
-import com.android.settings.R;
-
-import android.net.wifi.WifiManager;
-import android.preference.Preference;
-import android.view.View;
-import android.widget.ImageView;
-
-public class AccessPointPreference extends Preference implements
- AccessPointState.AccessPointStateCallback {
-
- // UI states
- private static final int[] STATE_ENCRYPTED = { R.attr.state_encrypted };
- private static final int[] STATE_EMPTY = { };
-
- // Signal strength indicator
- private static final int UI_SIGNAL_LEVELS = 4;
-
- private AccessPointState mState;
-
- public AccessPointPreference(WifiSettings wifiSettings, AccessPointState state) {
- super(wifiSettings, null);
-
- mState = state;
-
- setWidgetLayoutResource(R.layout.preference_widget_wifi_signal);
-
- state.setCallback(this);
-
- refresh();
- }
-
- public void refresh() {
- setTitle(mState.getHumanReadableSsid());
- setSummary(mState.getSummarizedStatus());
-
- notifyChanged();
- }
-
- public void refreshAccessPointState() {
- refresh();
-
- // The ordering of access points could have changed due to the state change, so
- // re-evaluate ordering
- notifyHierarchyChanged();
- }
-
- @Override
- protected void onBindView(View view) {
- super.onBindView(view);
-
- ImageView signal = (ImageView) view.findViewById(R.id.signal);
- if (mState.seen) {
- signal.setImageResource(R.drawable.wifi_signal);
- signal.setImageState(mState.hasSecurity() ? STATE_ENCRYPTED : STATE_EMPTY, true);
- signal.setImageLevel(getUiSignalLevel());
- } else {
- signal.setImageDrawable(null);
- }
- }
-
- private int getUiSignalLevel() {
- return mState != null ? WifiManager.calculateSignalLevel(mState.signal, UI_SIGNAL_LEVELS)
- : 0;
- }
-
- /**
- * Returns the {@link AccessPointState} associated with this preference.
- * @return The {@link AccessPointState}.
- */
- public AccessPointState getAccessPointState() {
- return mState;
- }
-
- @Override
- public int compareTo(Preference another) {
- if (!(another instanceof AccessPointPreference)) {
- // Let normal preferences go before us.
- // NOTE: we should only be compared to Preference in our
- // category.
- return 1;
- }
-
- return mState.compareTo(((AccessPointPreference) another).mState);
- }
-
-}
-
diff --git a/src/com/android/settings/wifi/AccessPointState.java b/src/com/android/settings/wifi/AccessPointState.java
deleted file mode 100644
index 5aefa55..0000000
--- a/src/com/android/settings/wifi/AccessPointState.java
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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 com.android.settings.wifi;
-
-import com.android.settings.R;
-
-import android.content.Context;
-import android.net.NetworkInfo;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiConfiguration.AuthAlgorithm;
-import android.net.wifi.WifiConfiguration.GroupCipher;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiConfiguration.PairwiseCipher;
-import android.net.wifi.WifiConfiguration.Protocol;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.Log;
-
-public final class AccessPointState implements Comparable<AccessPointState>, Parcelable {
-
- private static final String TAG = "AccessPointState";
-
- // Constants used for different security types
- public static final String PSK = "PSK";
- public static final String WEP = "WEP";
- public static final String EAP = "EAP";
- public static final String OPEN = "Open";
-
- public static final String[] EAP_METHOD = { "PEAP", "TLS", "TTLS" };
-
- /** String present in capabilities if the scan result is ad-hoc */
- private static final String ADHOC_CAPABILITY = "[IBSS]";
- /** String present in capabilities if the scan result is enterprise secured */
- private static final String ENTERPRISE_CAPABILITY = "-EAP-";
-
- public static final String BSSID_ANY = "any";
- public static final int NETWORK_ID_NOT_SET = -1;
- /** This should be used with care! */
- static final int NETWORK_ID_ANY = -2;
-
- public static final int MATCH_NONE = 0;
- public static final int MATCH_WEAK = 1;
- public static final int MATCH_STRONG = 2;
- public static final int MATCH_EXACT = 3;
-
- // Don't set these directly, use the setters.
- public int networkId;
- public int priority;
- public boolean hiddenSsid;
- public int linkSpeed;
- public int ipAddress;
- public String bssid;
- public String ssid;
- public int signal;
- public boolean primary;
- public boolean seen;
- public boolean configured;
- public NetworkInfo.DetailedState status;
- public String security;
- public boolean disabled;
-
- /**
- * Use this for sorting based on signal strength. It is a heavily-damped
- * time-averaged weighted signal.
- */
- private float signalForSorting = Float.MIN_VALUE;
-
- private static final float DAMPING_FACTOR = 0.2f;
-
- /**
- * This will be a user entered password, and NOT taken from wpa_supplicant
- * (since it would give us *)
- */
- private String mPassword;
- private boolean mConfigHadPassword;
-
- public static final int WEP_PASSWORD_AUTO = 0;
- public static final int WEP_PASSWORD_ASCII = 1;
- public static final int WEP_PASSWORD_HEX = 2;
- private int mWepPasswordType;
-
- /* Enterprise Fields */
- public static final int IDENTITY = 0;
- public static final int ANONYMOUS_IDENTITY = 1;
- public static final int CLIENT_CERT = 2;
- public static final int CA_CERT = 3;
- public static final int PRIVATE_KEY = 4;
- public static final int MAX_ENTRPRISE_FIELD = 5;
- private String mEnterpriseFields[] = new String[MAX_ENTRPRISE_FIELD];
- private String mEap;
- private String mPhase2;
-
- private Context mContext;
-
- /**
- * If > 0, don't refresh (changes are being batched), use
- * {@link #blockRefresh()} and {@link #unblockRefresh()} only.
- */
- private int mBlockRefresh;
- /**
- * This will be set by {@link #requestRefresh} and shouldn't be written to
- * elsewhere.
- */
- private boolean mNeedsRefresh;
-
- private AccessPointStateCallback mCallback;
-
- private StringBuilder mSummaryBuilder = new StringBuilder();
-
- interface AccessPointStateCallback {
- void refreshAccessPointState();
- }
-
- public AccessPointState(Context context) {
- this();
-
- setContext(context);
- }
-
- private AccessPointState() {
- bssid = BSSID_ANY;
- ssid = "";
- networkId = NETWORK_ID_NOT_SET;
- hiddenSsid = false;
- }
-
- void setContext(Context context) {
- mContext = context;
- }
-
- public void setNetworkId(int networkId) {
- this.networkId = networkId;
- }
-
- public void setBssid(String bssid) {
- if (bssid != null) {
- // If the BSSID is a wildcard, do NOT let a specific BSSID replace it
- if (!this.bssid.equals(BSSID_ANY)) {
- this.bssid = bssid;
- }
- }
- }
-
- private String getWpaSupplicantBssid() {
- return bssid.equals(BSSID_ANY) ? null : bssid;
- }
-
- public static String convertToQuotedString(String string) {
- if (TextUtils.isEmpty(string)) {
- return "";
- }
-
- final int lastPos = string.length() - 1;
- if (lastPos < 0 || (string.charAt(0) == '"' && string.charAt(lastPos) == '"')) {
- return string;
- }
-
- return "\"" + string + "\"";
- }
-
- public void setPrimary(boolean primary) {
- if (this.primary != primary) {
- this.primary = primary;
- requestRefresh();
- }
- }
-
- public void setSeen(boolean seen) {
- if (this.seen != seen) {
- this.seen = seen;
- requestRefresh();
- }
- }
-
- public void setDisabled(boolean disabled) {
- if (this.disabled != disabled) {
- this.disabled = disabled;
- requestRefresh();
- }
- }
-
- public void setSignal(int signal) {
-
- if (signalForSorting == Float.MIN_VALUE) {
- signalForSorting = signal;
- } else {
- signalForSorting = (DAMPING_FACTOR * signal) + ((1-DAMPING_FACTOR) * signalForSorting);
- }
-
- if (this.signal != signal) {
- this.signal = signal;
- requestRefresh();
- }
- }
-
- public String getHumanReadableSsid() {
- if (TextUtils.isEmpty(ssid)) {
- return "";
- }
-
- final int lastPos = ssid.length() - 1;
- if (ssid.charAt(0) == '"' && ssid.charAt(lastPos) == '"') {
- return ssid.substring(1, lastPos);
- }
-
- return ssid;
- }
-
- public void setSsid(String ssid) {
- if (ssid != null) {
- this.ssid = convertToQuotedString(ssid);
- requestRefresh();
- }
- }
-
- public void setPriority(int priority) {
- if (this.priority != priority) {
- this.priority = priority;
- requestRefresh();
- }
- }
-
- public void setHiddenSsid(boolean hiddenSsid) {
- if (this.hiddenSsid != hiddenSsid) {
- this.hiddenSsid = hiddenSsid;
- requestRefresh();
- }
- }
-
- public void setLinkSpeed(int linkSpeed) {
- if (this.linkSpeed != linkSpeed) {
- this.linkSpeed = linkSpeed;
- requestRefresh();
- }
- }
-
- public void setIpAddress(int address) {
- if (ipAddress != address) {
- ipAddress = address;
- requestRefresh();
- }
- }
-
- public void setConfigured(boolean configured) {
- if (this.configured != configured) {
- this.configured = configured;
- requestRefresh();
- }
- }
-
- public void setStatus(NetworkInfo.DetailedState status) {
- if (this.status != status) {
- this.status = status;
- requestRefresh();
- }
- }
-
- public boolean isEnterprise() {
- return (AccessPointState.EAP.equals(security));
- }
-
- public void setSecurity(String security) {
- if (TextUtils.isEmpty(this.security) || !this.security.equals(security)) {
- this.security = security;
- requestRefresh();
- }
- }
-
- public boolean hasSecurity() {
- return security != null && !security.contains(OPEN);
- }
-
- public String getHumanReadableSecurity() {
- if (security.equals(OPEN)) return mContext.getString(R.string.wifi_security_open);
- else if (security.equals(WEP)) return mContext.getString(R.string.wifi_security_wep);
- else if (security.equals(PSK)) return mContext.getString(R.string.wifi_security_psk);
- else if (security.equals(EAP)) return mContext.getString(R.string.wifi_security_eap);
-
- return mContext.getString(R.string.wifi_security_unknown);
- }
-
- public void updateFromScanResult(ScanResult scanResult) {
- blockRefresh();
-
- // We don't keep specific AP BSSIDs and instead leave that as wildcard
-
- setSeen(true);
- setSsid(scanResult.SSID);
- if (networkId == NETWORK_ID_NOT_SET) {
- // Since ScanResults don't cross-reference network ID, we set it as a wildcard
- setNetworkId(NETWORK_ID_ANY);
- }
- setSignal(scanResult.level);
- setSecurity(getScanResultSecurity(scanResult));
- unblockRefresh();
- }
-
- /**
- * @return The security of a given {@link ScanResult}.
- */
- public static String getScanResultSecurity(ScanResult scanResult) {
- final String cap = scanResult.capabilities;
- final String[] securityModes = { WEP, PSK, EAP };
- for (int i = securityModes.length - 1; i >= 0; i--) {
- if (cap.contains(securityModes[i])) {
- return securityModes[i];
- }
- }
-
- return OPEN;
- }
-
- /**
- * @return Whether the given ScanResult represents an adhoc network.
- */
- public static boolean isAdhoc(ScanResult scanResult) {
- return scanResult.capabilities.contains(ADHOC_CAPABILITY);
- }
-
- /**
- * @return Whether the given ScanResult has enterprise security.
- */
- public static boolean isEnterprise(ScanResult scanResult) {
- return scanResult.capabilities.contains(ENTERPRISE_CAPABILITY);
- }
-
- public void updateFromWifiConfiguration(WifiConfiguration wifiConfig) {
- if (wifiConfig != null) {
- blockRefresh();
- setBssid(wifiConfig.BSSID);
- setNetworkId(wifiConfig.networkId);
- setPriority(wifiConfig.priority);
- setHiddenSsid(wifiConfig.hiddenSSID);
- setSsid(wifiConfig.SSID);
- setConfigured(true);
- setDisabled(wifiConfig.status == WifiConfiguration.Status.DISABLED);
- parseWifiConfigurationSecurity(wifiConfig);
- unblockRefresh();
- }
- }
-
- public void setPassword(String password) {
- setPassword(password, WEP_PASSWORD_AUTO);
- }
-
- public void setPassword(String password, int wepPasswordType) {
- mPassword = password;
- mWepPasswordType = wepPasswordType;
- }
-
- /* For Enterprise Fields */
- public void setEnterpriseField(int field, String value) {
- if ((value != null) && (field >= 0) && (field < MAX_ENTRPRISE_FIELD)) {
- this.mEnterpriseFields[field] = value;
- requestRefresh();
- }
- }
-
- public void setPhase2(String phase2) {
- if (!TextUtils.isEmpty(phase2) && (!phase2.equals("None"))) {
- mPhase2 = phase2;
- }
- }
-
- public String getPhase2() {
- return mPhase2;
- }
-
- public void setEap(int method) {
- mEap = EAP_METHOD[method];
- requestRefresh();
- }
-
- public String getEap() {
- return mEap;
- }
- public String getEnterpriseField(int field) {
- if(field >=0 && field < MAX_ENTRPRISE_FIELD) {
- return mEnterpriseFields[field];
- }
- return null;
- }
-
- public boolean hasPassword() {
- return !TextUtils.isEmpty(mPassword) || mConfigHadPassword;
- }
-
- private static boolean hasPassword(WifiConfiguration wifiConfig) {
- return !TextUtils.isEmpty(wifiConfig.preSharedKey)
- || !TextUtils.isEmpty(wifiConfig.wepKeys[0])
- || !TextUtils.isEmpty(wifiConfig.wepKeys[1])
- || !TextUtils.isEmpty(wifiConfig.wepKeys[2])
- || !TextUtils.isEmpty(wifiConfig.wepKeys[3]);
- }
-
- private void parseWifiConfigurationSecurity(WifiConfiguration wifiConfig) {
- setSecurity(getWifiConfigurationSecurity(wifiConfig));
- mConfigHadPassword = hasPassword(wifiConfig);
- }
-
- /**
- * @return The security of a given {@link WifiConfiguration}.
- */
- public static String getWifiConfigurationSecurity(WifiConfiguration wifiConfig) {
- if (!TextUtils.isEmpty(wifiConfig.eap.value())) {
- return EAP;
- } else if (!TextUtils.isEmpty(wifiConfig.preSharedKey)) {
- return PSK;
- } else if (!TextUtils.isEmpty(wifiConfig.wepKeys[0])) {
- return WEP;
- }
- return OPEN;
- }
-
- public void updateFromWifiInfo(WifiInfo wifiInfo, NetworkInfo.DetailedState state) {
- if (wifiInfo != null) {
- blockRefresh();
- setBssid(wifiInfo.getBSSID());
- setLinkSpeed(wifiInfo.getLinkSpeed());
- setNetworkId(wifiInfo.getNetworkId());
- setIpAddress(wifiInfo.getIpAddress());
- setSsid(wifiInfo.getSSID());
- if (state != null) {
- setStatus(state);
- }
- setHiddenSsid(wifiInfo.getHiddenSSID());
- unblockRefresh();
- }
- }
-
- /**
- * @return Whether this AP can be connected to at the moment.
- */
- public boolean isConnectable() {
- return !primary && seen;
- }
-
- /**
- * @return Whether this AP can be forgotten at the moment.
- */
- public boolean isForgetable() {
- return configured;
- }
-
- /**
- * Updates the state as if it were never configured.
- * <p>
- * Note: This will not pass the forget call to the Wi-Fi API.
- */
- public void forget() {
- blockRefresh();
- setConfigured(false);
- setNetworkId(NETWORK_ID_NOT_SET);
- setPrimary(false);
- setStatus(null);
- setDisabled(false);
- unblockRefresh();
- }
-
- public void updateWifiConfiguration(WifiConfiguration config) {
- config.BSSID = getWpaSupplicantBssid();
- config.priority = priority;
- config.hiddenSSID = hiddenSsid;
- config.SSID = convertToQuotedString(ssid);
- config.eap.setValue(mEap);
-
- if (!TextUtils.isEmpty(mPhase2)) {
- config.phase2.setValue(convertToQuotedString("auth=" + mPhase2));
- } else {
- config.phase2.setValue(null);
- }
- if (!TextUtils.isEmpty(mEnterpriseFields[IDENTITY])) {
- config.identity.setValue(
- convertToQuotedString(mEnterpriseFields[IDENTITY]));
- } else {
- config.identity.setValue(null);
- }
- if (!TextUtils.isEmpty(mEnterpriseFields[ANONYMOUS_IDENTITY])) {
- config.anonymous_identity.setValue(convertToQuotedString(
- mEnterpriseFields[ANONYMOUS_IDENTITY]));
- } else {
- config.anonymous_identity.setValue(null);
- }
- if (!TextUtils.isEmpty(mEnterpriseFields[CLIENT_CERT])) {
- config.client_cert.setValue(convertToQuotedString(
- mEnterpriseFields[CLIENT_CERT]));
- } else {
- config.client_cert.setValue(null);
- }
- if (!TextUtils.isEmpty(mEnterpriseFields[CA_CERT])) {
- config.ca_cert.setValue(convertToQuotedString(
- mEnterpriseFields[CA_CERT]));
- } else {
- config.ca_cert.setValue(null);
- }
- if (!TextUtils.isEmpty(mEnterpriseFields[PRIVATE_KEY])) {
- config.private_key.setValue(convertToQuotedString(
- mEnterpriseFields[PRIVATE_KEY]));
- } else {
- config.private_key.setValue(null);
- }
- setupSecurity(config);
- }
-
- private void setupSecurity(WifiConfiguration config) {
- config.allowedAuthAlgorithms.clear();
- config.allowedGroupCiphers.clear();
- config.allowedKeyManagement.clear();
- config.allowedPairwiseCiphers.clear();
- config.allowedProtocols.clear();
-
- if (TextUtils.isEmpty(security)) {
- security = OPEN;
- Log.w(TAG, "Empty security, assuming open");
- }
-
- if (security.equals(WEP)) {
- // If password is empty, it should be left untouched
- if (!TextUtils.isEmpty(mPassword)) {
- if (mWepPasswordType == WEP_PASSWORD_AUTO) {
- if (isHexWepKey(mPassword)) {
- config.wepKeys[0] = mPassword;
- } else {
- config.wepKeys[0] = convertToQuotedString(mPassword);
- }
- } else {
- config.wepKeys[0] = mWepPasswordType == WEP_PASSWORD_ASCII
- ? convertToQuotedString(mPassword)
- : mPassword;
- }
- }
- config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
- config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
- config.allowedKeyManagement.set(KeyMgmt.NONE);
- config.wepTxKeyIndex = 0;
- } else if (security.equals(PSK)){
- // If password is empty, it should be left untouched
- if (!TextUtils.isEmpty(mPassword)) {
- if (mPassword.length() == 64 && isHex(mPassword)) {
- // Goes unquoted as hex
- config.preSharedKey = mPassword;
- } else {
- // Goes quoted as ASCII
- config.preSharedKey = convertToQuotedString(mPassword);
- }
- }
- } else if (security.equals(EAP)) {
- config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
- config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
- if (!TextUtils.isEmpty(mPassword)) {
- config.password.setValue(convertToQuotedString(mPassword));
- }
- } else if (security.equals(OPEN)) {
- config.allowedKeyManagement.set(KeyMgmt.NONE);
- }
- }
-
- private static boolean isHexWepKey(String wepKey) {
- final int len = wepKey.length();
-
- // WEP-40, WEP-104, and some vendors using 256-bit WEP (WEP-232?)
- if (len != 10 && len != 26 && len != 58) {
- return false;
- }
-
- return isHex(wepKey);
- }
-
- private static boolean isHex(String key) {
- for (int i = key.length() - 1; i >= 0; i--) {
- final char c = key.charAt(i);
- if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f')) {
- return false;
- }
- }
-
- return true;
- }
-
- public void setCallback(AccessPointStateCallback callback) {
- mCallback = callback;
- }
-
- void blockRefresh() {
- mBlockRefresh++;
- }
-
- void unblockRefresh() {
- if (--mBlockRefresh == 0 && mNeedsRefresh) {
- requestRefresh();
- }
- }
-
- private void requestRefresh() {
- if (mBlockRefresh > 0) {
- mNeedsRefresh = true;
- return;
- }
-
- if (mCallback != null) {
- mCallback.refreshAccessPointState();
- }
-
- mNeedsRefresh = false;
- }
-
- /**
- * {@inheritDoc}
- * @see #hashCode()
- * @see #equals(Object)
- */
- public int matches(int otherNetworkId, String otherBssid, String otherSsid,
- String otherSecurity) {
-
- // Whenever this method is touched, please ensure #equals and #hashCode
- // still work with the changes here!
-
- if (otherSsid == null) {
- if (WifiLayer.LOGV) {
- Log.w(TAG, "BSSID: " + otherBssid + ", SSID: " + otherSsid);
- }
- return MATCH_NONE;
- }
-
- /*
- * If we both have 'security' set, it must match (an open network still
- * has 'security' set to OPEN)
- */
- if (security != null && otherSecurity != null) {
- if (!security.equals(otherSecurity)) {
- return MATCH_NONE;
- }
- }
-
- // WifiConfiguration gives an empty bssid as a BSSID wildcard
- if (TextUtils.isEmpty(otherBssid)) {
- otherBssid = AccessPointState.BSSID_ANY;
- }
-
- final boolean networkIdMatches = networkId == otherNetworkId;
- if (!networkIdMatches && networkId != NETWORK_ID_ANY && otherNetworkId != NETWORK_ID_ANY) {
- // Network IDs don't match (e.g., 1 & 2 or unset & 1) and neither is a wildcard
- return MATCH_NONE;
- }
-
- if (networkIdMatches && otherNetworkId != NETWORK_ID_NOT_SET
- && otherNetworkId != NETWORK_ID_ANY) {
- // Network ID matches (they're set to the same ID)
- return MATCH_EXACT;
- }
-
- // So now, network IDs aren't set or at least one is a wildcard
-
- final boolean bssidMatches = bssid.equals(otherBssid);
- final boolean otherBssidIsWildcard = otherBssid.equals(BSSID_ANY);
- if (bssidMatches && !otherBssidIsWildcard) {
- // BSSID matches (and neither is a wildcard)
- return MATCH_STRONG;
- }
-
- if (!bssidMatches && !bssid.equals(BSSID_ANY) && !otherBssidIsWildcard) {
- // BSSIDs don't match (e.g., 00:24:21:21:42:12 & 42:12:44:21:22:52)
- // and neither is a wildcard
- return MATCH_NONE;
- }
-
- // So now, BSSIDs are both wildcards
-
- final boolean ssidMatches = ssid.equals(otherSsid);
- if (ssidMatches) {
- // SSID matches
- return MATCH_WEAK;
- }
-
- return MATCH_NONE;
- }
-
- /**
- * {@inheritDoc}
- * @see #matches(int, String, String)
- * @see #equals(Object)
- */
- @Override
- public int hashCode() {
- // Two equal() objects must have same hashCode.
- // With Wi-Fi, the broadest match is if two SSIDs are the same. The finer-grained matches
- // imply this (for example, the same network IDs means the same WifiConfiguration which
- // means the same SSID).
- // See #matches for the exact matching algorithm we use.
- return ssid != null ? ssid.hashCode() : 0;
- }
-
- /**
- * {@inheritDoc}
- * @see #matches(int, String, String)
- * @see #hashCode()
- */
- @Override
- public boolean equals(Object o) {
- if (!o.getClass().equals(getClass())) {
- return false;
- }
-
- final AccessPointState other = (AccessPointState) o;
-
- // To see which conditions cause two AccessPointStates to be equal, see
- // where #matches returns MATCH_WEAK or greater.
-
- return matches(other.networkId, other.bssid, other.ssid, other.security) >= MATCH_WEAK;
- }
-
- public int matchesWifiConfiguration(WifiConfiguration wifiConfig) {
- String security = getWifiConfigurationSecurity(wifiConfig);
- return matches(wifiConfig.networkId, wifiConfig.BSSID, wifiConfig.SSID, security);
- }
-
- String getSummarizedStatus() {
- StringBuilder sb = mSummaryBuilder;
- sb.delete(0, sb.length());
-
- if (primary && status != null) {
- buildSummary(sb, WifiStatus.getPrintable(mContext, status), true);
-
- } else if (!seen) {
- buildSummary(sb, mContext.getString(R.string.summary_not_in_range), true);
-
- // Remembered comes second in this case
- if (!primary && configured) {
- buildSummary(sb, mContext.getString(R.string.summary_remembered), true);
- }
-
- } else {
- if (configured && disabled) {
- // The connection failure overrides all in this case
- return mContext.getString(R.string.summary_connection_failed);
- }
-
- // Remembered comes first in this case
- if (!primary && configured) {
- buildSummary(sb, mContext.getString(R.string.summary_remembered), true);
- }
-
- // If it is seen (and not the primary), show the security type
- String verboseSecurity = getVerboseSecurity();
- if (verboseSecurity != null) {
- buildSummary(sb, verboseSecurity, true);
- }
- }
-
- return sb.toString();
- }
-
- private String getVerboseSecurity() {
- if (WEP.equals(security)) {
- return mContext.getString(R.string.wifi_security_verbose_wep);
- } else if (PSK.equals(security)) {
- return mContext.getString(R.string.wifi_security_verbose_psk);
- } else if (EAP.equals(security)) {
- return mContext.getString(R.string.wifi_security_verbose_eap);
- } else {
- return null;
- }
- }
-
- private void buildSummary(StringBuilder sb, String string, boolean autoUpperCaseFirstLetter) {
- if (sb.length() == 0) {
- if (autoUpperCaseFirstLetter && string.length() > 1
- && Character.isLowerCase(string.charAt(0))
- && !Character.isUpperCase(string.charAt(1))) {
- sb.append(Character.toUpperCase(string.charAt(0))).append(string, 1,
- string.length());
- } else {
- sb.append(string);
- }
- } else {
- sb.append(", ");
- sb.append(string);
- }
- }
-
- public int compareTo(AccessPointState other) {
- // This ranks the states for displaying in the AP list, not for
- // connecting to (wpa_supplicant does that using the WifiConfiguration's
- // priority field).
-
- // Clarity > efficiency, of this logic:
- int comparison;
-
- // Primary
- comparison = (other.primary ? 1 : 0) - (primary ? 1 : 0);
- if (comparison != 0) return comparison;
-
- // Currently seen (similar to, but not always the same as within range)
- comparison = (other.seen ? 1 : 0) - (seen ? 1 : 0);
- if (comparison != 0) return comparison;
-
- // Configured
- comparison = (other.configured ? 1 : 0) - (configured ? 1 : 0);
- if (comparison != 0) return comparison;
-
- if (!configured) {
- // Neither are configured
-
- // Open network
- comparison = (hasSecurity() ? 1 : 0) - (other.hasSecurity() ? 1 : 0);
- if (comparison != 0) return comparison;
- }
-
- // Signal strength
- comparison = (int) (other.signalForSorting - signalForSorting);
- if (comparison != 0) return comparison;
-
- // Alphabetical
- return ssid.compareToIgnoreCase(other.ssid);
- }
-
- public String toString() {
- return ssid + " (" + bssid + ", " + networkId + ", " + super.toString() + ")";
- }
-
- /** Implement the Parcelable interface */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(bssid);
- dest.writeInt(configured ? 1 : 0);
- dest.writeInt(ipAddress);
- dest.writeInt(linkSpeed);
- dest.writeInt(networkId);
- dest.writeInt(primary ? 1 : 0);
- dest.writeInt(priority);
- dest.writeInt(hiddenSsid ? 1 : 0);
- dest.writeString(security);
- dest.writeInt(seen ? 1 : 0);
- dest.writeInt(disabled ? 1 : 0);
- dest.writeInt(signal);
- dest.writeString(ssid);
- dest.writeString(status != null ? status.toString() : null);
- dest.writeString(mPassword);
- dest.writeInt(mConfigHadPassword ? 1 : 0);
- dest.writeInt(mWepPasswordType);
- }
-
- /** Implement the Parcelable interface */
- public int describeContents() {
- return 0;
- }
-
- /** Implement the Parcelable interface */
- public static final Creator<AccessPointState> CREATOR =
- new Creator<AccessPointState>() {
- public AccessPointState createFromParcel(Parcel in) {
- AccessPointState state = new AccessPointState();
- state.bssid = in.readString();
- state.configured = in.readInt() == 1;
- state.ipAddress = in.readInt();
- state.linkSpeed = in.readInt();
- state.networkId = in.readInt();
- state.primary = in.readInt() == 1;
- state.priority = in.readInt();
- state.hiddenSsid = in.readInt() == 1;
- state.security = in.readString();
- state.seen = in.readInt() == 1;
- state.disabled = in.readInt() == 1;
- state.signal = in.readInt();
- state.ssid = in.readString();
- String statusStr = in.readString();
- if (statusStr != null) {
- state.status = NetworkInfo.DetailedState.valueOf(statusStr);
- }
- state.mPassword = in.readString();
- state.mConfigHadPassword = in.readInt() == 1;
- state.mWepPasswordType = in.readInt();
- return state;
- }
-
- public AccessPointState[] newArray(int size) {
- return new AccessPointState[size];
- }
- };
-
-
-}
diff --git a/src/com/android/settings/wifi/AdvancedSettings.java b/src/com/android/settings/wifi/AdvancedSettings.java
index cca10da..636e1df 100644
--- a/src/com/android/settings/wifi/AdvancedSettings.java
+++ b/src/com/android/settings/wifi/AdvancedSettings.java
@@ -34,6 +34,7 @@ import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
+import android.os.SystemProperties;
public class AdvancedSettings extends PreferenceActivity
implements Preference.OnPreferenceChangeListener {
@@ -58,6 +59,9 @@ public class AdvancedSettings extends PreferenceActivity
private static final int MENU_ITEM_SAVE = Menu.FIRST;
private static final int MENU_ITEM_CANCEL = Menu.FIRST + 1;
+ //Tracks ro.debuggable (1 on userdebug builds)
+ private static int DEBUGGABLE;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -72,19 +76,24 @@ public class AdvancedSettings extends PreferenceActivity
preference.setOnPreferenceChangeListener(this);
}
-// /*
-// * Fix the Run-time IllegalStateException that ListPreference requires an entries
-// * array and an entryValues array, this exception occurs when user open/close the
-// * slider in the Regulatory domain dialog.
-// */
-// initNumChannelsPreference();
+ DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0);
+
/**
* Remove user control of regulatory domain
- * channel count settings
+ * channel count settings in non userdebug builds
*/
- Preference chanPref = findPreference(KEY_NUM_CHANNELS);
- if (chanPref != null) {
- getPreferenceScreen().removePreference(chanPref);
+ if (DEBUGGABLE == 1) {
+ /*
+ * Fix the Run-time IllegalStateException that ListPreference requires an entries
+ * array and an entryValues array, this exception occurs when user open/close the
+ * slider in the Regulatory domain dialog.
+ */
+ initNumChannelsPreference();
+ } else {
+ Preference chanPref = findPreference(KEY_NUM_CHANNELS);
+ if (chanPref != null) {
+ getPreferenceScreen().removePreference(chanPref);
+ }
}
}
@@ -95,9 +104,11 @@ public class AdvancedSettings extends PreferenceActivity
updateUi();
/**
* Remove user control of regulatory domain
- * channel count settings
+ * channel count settings in non userdebug builds
*/
- //initNumChannelsPreference();
+ if (DEBUGGABLE == 1) {
+ initNumChannelsPreference();
+ }
initSleepPolicyPreference();
refreshWifiInfo();
}
diff --git a/src/com/android/settings/wifi/Summary.java b/src/com/android/settings/wifi/Summary.java
new file mode 100644
index 0000000..6da2fa5
--- /dev/null
+++ b/src/com/android/settings/wifi/Summary.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings.wifi;
+
+import com.android.settings.R;
+
+import android.content.Context;
+import android.net.NetworkInfo.DetailedState;
+import android.text.TextUtils;
+
+class Summary {
+ static String get(Context context, String ssid, DetailedState state) {
+ String[] formats = context.getResources().getStringArray((ssid == null)
+ ? R.array.wifi_status : R.array.wifi_status_with_ssid);
+ int index = state.ordinal();
+
+ if (index >= formats.length || formats[index].length() == 0) {
+ return null;
+ }
+ return String.format(formats[index], ssid);
+ }
+
+ static String get(Context context, DetailedState state) {
+ return get(context, null, state);
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiAPITest.java b/src/com/android/settings/wifi/WifiAPITest.java
new file mode 100644
index 0000000..4a9a075
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiAPITest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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 com.android.settings.wifi;
+
+import com.android.settings.R;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.wifi.WifiManager;
+
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.text.Editable;
+import android.widget.EditText;
+
+
+/**
+ * Provide an interface for testing out the Wifi API
+ */
+public class WifiAPITest extends PreferenceActivity implements
+Preference.OnPreferenceClickListener {
+
+ private static final String TAG = "WifiAPITest";
+ private int netid;
+
+ //============================
+ // Preference/activity member variables
+ //============================
+
+ private static final String KEY_DISCONNECT = "disconnect";
+ private static final String KEY_DISABLE_NETWORK = "disable_network";
+ private static final String KEY_ENABLE_NETWORK = "enable_network";
+
+ private Preference mWifiDisconnect;
+ private Preference mWifiDisableNetwork;
+ private Preference mWifiEnableNetwork;
+
+ private WifiManager mWifiManager;
+
+
+ //============================
+ // Activity lifecycle
+ //============================
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ onCreatePreferences();
+ mWifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
+ }
+
+
+ private void onCreatePreferences() {
+ addPreferencesFromResource(R.layout.wifi_api_test);
+
+ final PreferenceScreen preferenceScreen = getPreferenceScreen();
+
+ mWifiDisconnect = (Preference) preferenceScreen.findPreference(KEY_DISCONNECT);
+ mWifiDisconnect.setOnPreferenceClickListener(this);
+
+ mWifiDisableNetwork = (Preference) preferenceScreen.findPreference(KEY_DISABLE_NETWORK);
+ mWifiDisableNetwork.setOnPreferenceClickListener(this);
+
+ mWifiEnableNetwork = (Preference) preferenceScreen.findPreference(KEY_ENABLE_NETWORK);
+ mWifiEnableNetwork.setOnPreferenceClickListener(this);
+
+ }
+
+ //============================
+ // Preference callbacks
+ //============================
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ super.onPreferenceTreeClick(preferenceScreen, preference);
+ return false;
+ }
+
+ /**
+ * Implements OnPreferenceClickListener interface
+ */
+ public boolean onPreferenceClick(Preference pref) {
+ if (pref == mWifiDisconnect) {
+ mWifiManager.disconnect();
+ } else if (pref == mWifiDisableNetwork) {
+ AlertDialog.Builder alert = new AlertDialog.Builder(this);
+ alert.setTitle("Input");
+ alert.setMessage("Enter Network ID");
+ // Set an EditText view to get user input
+ final EditText input = new EditText(this);
+ alert.setView(input);
+ alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ Editable value = input.getText();
+ netid = Integer.parseInt(value.toString());
+ mWifiManager.disableNetwork(netid);
+ }
+ });
+ alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ // Canceled.
+ }
+ });
+ alert.show();
+ } else if (pref == mWifiEnableNetwork) {
+ AlertDialog.Builder alert = new AlertDialog.Builder(this);
+ alert.setTitle("Input");
+ alert.setMessage("Enter Network ID");
+ // Set an EditText view to get user input
+ final EditText input = new EditText(this);
+ alert.setView(input);
+ alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ Editable value = input.getText();
+ netid = Integer.parseInt(value.toString());
+ mWifiManager.enableNetwork(netid, false);
+ }
+ });
+ alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ // Canceled.
+ }
+ });
+ alert.show();
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiApDialog.java b/src/com/android/settings/wifi/WifiApDialog.java
new file mode 100644
index 0000000..43289d2
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiApDialog.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings.wifi;
+
+import com.android.settings.R;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+/**
+ * Dialog to configure the SSID and security settings
+ * for Access Point operation
+ */
+class WifiApDialog extends AlertDialog implements View.OnClickListener,
+ TextWatcher, AdapterView.OnItemSelectedListener {
+
+ static final int BUTTON_SUBMIT = DialogInterface.BUTTON_POSITIVE;
+
+ private final DialogInterface.OnClickListener mListener;
+
+ private static final int OPEN_INDEX = 0;
+ private static final int WPA_INDEX = 1;
+
+ private View mView;
+ private TextView mSsid;
+ private int mSecurityType = AccessPoint.SECURITY_NONE;
+ private EditText mPassword;
+
+ WifiConfiguration mWifiConfig;
+
+ public WifiApDialog(Context context, DialogInterface.OnClickListener listener,
+ WifiConfiguration wifiConfig) {
+ super(context);
+ mListener = listener;
+ mWifiConfig = wifiConfig;
+ if (wifiConfig != null)
+ mSecurityType = AccessPoint.getSecurity(wifiConfig);
+ }
+
+ public WifiConfiguration getConfig() {
+
+ WifiConfiguration config = new WifiConfiguration();
+
+ /**
+ * TODO: SSID in WifiConfiguration for soft ap
+ * is being stored as a raw string without quotes.
+ * This is not the case on the client side. We need to
+ * make things consistent and clean it up
+ */
+ config.SSID = mSsid.getText().toString();
+
+ switch (mSecurityType) {
+ case AccessPoint.SECURITY_NONE:
+ config.allowedKeyManagement.set(KeyMgmt.NONE);
+ return config;
+
+ case AccessPoint.SECURITY_PSK:
+ config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+ config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
+ if (mPassword.length() != 0) {
+ String password = mPassword.getText().toString();
+ config.preSharedKey = password;
+ }
+ return config;
+ }
+ return null;
+ }
+
+ protected void onCreate(Bundle savedInstanceState) {
+
+ mView = getLayoutInflater().inflate(R.layout.wifi_ap_dialog, null);
+ Spinner mSecurity = ((Spinner) mView.findViewById(R.id.security));
+
+ setView(mView);
+ setInverseBackgroundForced(true);
+
+ Context context = getContext();
+
+ setTitle(R.string.wifi_tether_configure_ap_text);
+ mView.findViewById(R.id.type).setVisibility(View.VISIBLE);
+ mSsid = (TextView) mView.findViewById(R.id.ssid);
+ mPassword = (EditText) mView.findViewById(R.id.password);
+
+ setButton(BUTTON_SUBMIT, context.getString(R.string.wifi_save), mListener);
+ setButton(DialogInterface.BUTTON_NEGATIVE,
+ context.getString(R.string.wifi_cancel), mListener);
+
+ if (mWifiConfig != null) {
+ mSsid.setText(mWifiConfig.SSID);
+ switch (mSecurityType) {
+ case AccessPoint.SECURITY_NONE:
+ mSecurity.setSelection(OPEN_INDEX);
+ break;
+ case AccessPoint.SECURITY_PSK:
+ String str = mWifiConfig.preSharedKey;
+ mPassword.setText(str);
+ mSecurity.setSelection(WPA_INDEX);
+ break;
+ }
+ }
+
+ mSsid.addTextChangedListener(this);
+ mPassword.addTextChangedListener(this);
+ ((CheckBox) mView.findViewById(R.id.show_password)).setOnClickListener(this);
+ mSecurity.setOnItemSelectedListener(this);
+
+ super.onCreate(savedInstanceState);
+
+ showSecurityFields();
+ validate();
+ }
+
+ private void validate() {
+ if ((mSsid != null && mSsid.length() == 0) ||
+ (mSecurityType == AccessPoint.SECURITY_PSK && mPassword.length() < 8)) {
+ getButton(BUTTON_SUBMIT).setEnabled(false);
+ } else {
+ getButton(BUTTON_SUBMIT).setEnabled(true);
+ }
+ }
+
+ public void onClick(View view) {
+ mPassword.setInputType(
+ InputType.TYPE_CLASS_TEXT | (((CheckBox) view).isChecked() ?
+ InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD :
+ InputType.TYPE_TEXT_VARIATION_PASSWORD));
+ }
+
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ public void afterTextChanged(Editable editable) {
+ validate();
+ }
+
+ public void onItemSelected(AdapterView parent, View view, int position, long id) {
+ if(position == OPEN_INDEX)
+ mSecurityType = AccessPoint.SECURITY_NONE;
+ else
+ mSecurityType = AccessPoint.SECURITY_PSK;
+ showSecurityFields();
+ validate();
+ }
+
+ public void onNothingSelected(AdapterView parent) {
+ }
+
+ private void showSecurityFields() {
+ if (mSecurityType == AccessPoint.SECURITY_NONE) {
+ mView.findViewById(R.id.fields).setVisibility(View.GONE);
+ return;
+ }
+ mView.findViewById(R.id.fields).setVisibility(View.VISIBLE);
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiApEnabler.java b/src/com/android/settings/wifi/WifiApEnabler.java
new file mode 100644
index 0000000..e907cf7
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiApEnabler.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings.wifi;
+
+import com.android.settings.R;
+import com.android.settings.WirelessSettings;
+
+import java.util.ArrayList;
+
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.preference.Preference;
+import android.preference.CheckBoxPreference;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Toast;
+
+public class WifiApEnabler implements Preference.OnPreferenceChangeListener {
+ private final Context mContext;
+ private final CheckBoxPreference mCheckBox;
+ private final CharSequence mOriginalSummary;
+
+ private WifiManager mWifiManager;
+ private final IntentFilter mIntentFilter;
+
+ ConnectivityManager mCm;
+ private String[] mWifiRegexs;
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(action)) {
+ handleWifiApStateChanged(intent.getIntExtra(
+ WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED));
+ } else if (ConnectivityManager.ACTION_TETHER_STATE_CHANGED.equals(action)) {
+ ArrayList<String> available = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ ArrayList<String> active = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_ACTIVE_TETHER);
+ ArrayList<String> errored = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_ERRORED_TETHER);
+ updateTetherState(available.toArray(), active.toArray(), errored.toArray());
+ }
+
+ }
+ };
+
+ public WifiApEnabler(Context context, CheckBoxPreference checkBox) {
+ mContext = context;
+ mCheckBox = checkBox;
+ mOriginalSummary = checkBox.getSummary();
+ checkBox.setPersistent(false);
+
+ mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ mCm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ mWifiRegexs = mCm.getTetherableWifiRegexs();
+
+ mIntentFilter = new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+ mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+ }
+
+ public void resume() {
+ mContext.registerReceiver(mReceiver, mIntentFilter);
+ enableWifiCheckBox();
+ mCheckBox.setOnPreferenceChangeListener(this);
+ }
+
+ public void pause() {
+ mContext.unregisterReceiver(mReceiver);
+ mCheckBox.setOnPreferenceChangeListener(null);
+ }
+
+ private void enableWifiCheckBox() {
+ boolean isAirplaneMode = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.AIRPLANE_MODE_ON, 0) != 0;
+ if(!isAirplaneMode) {
+ mCheckBox.setEnabled(true);
+ } else {
+ mCheckBox.setEnabled(false);
+ }
+ }
+
+ public boolean onPreferenceChange(Preference preference, Object value) {
+
+ final ContentResolver cr = mContext.getContentResolver();
+ boolean enable = (Boolean)value;
+
+ /**
+ * Disable Wifi if enabling tethering
+ */
+ int wifiState = mWifiManager.getWifiState();
+ if (enable && ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
+ (wifiState == WifiManager.WIFI_STATE_ENABLED))) {
+ mWifiManager.setWifiEnabled(false);
+ Settings.Secure.putInt(cr, Settings.Secure.WIFI_SAVED_STATE, 1);
+ }
+
+ if (mWifiManager.setWifiApEnabled(null, enable)) {
+ /* Disable here, enabled on receiving success broadcast */
+ mCheckBox.setEnabled(false);
+ } else {
+ mCheckBox.setSummary(R.string.wifi_error);
+ }
+
+ /**
+ * If needed, restore Wifi on tether disable
+ */
+ if (!enable) {
+ int wifiSavedState = 0;
+ try {
+ wifiSavedState = Settings.Secure.getInt(cr, Settings.Secure.WIFI_SAVED_STATE);
+ } catch (Settings.SettingNotFoundException e) {
+ ;
+ }
+ if (wifiSavedState == 1) {
+ mWifiManager.setWifiEnabled(true);
+ Settings.Secure.putInt(cr, Settings.Secure.WIFI_SAVED_STATE, 0);
+ }
+ }
+
+ return false;
+ }
+
+ void updateConfigSummary(WifiConfiguration wifiConfig) {
+ String s = mContext.getString(
+ com.android.internal.R.string.wifi_tether_configure_ssid_default);
+ mCheckBox.setSummary(String.format(
+ mContext.getString(R.string.wifi_tether_enabled_subtext),
+ (wifiConfig == null) ? s : wifiConfig.SSID));
+ }
+
+ private void updateTetherState(Object[] available, Object[] tethered, Object[] errored) {
+ boolean wifiTethered = false;
+ boolean wifiErrored = false;
+
+ for (Object o : tethered) {
+ String s = (String)o;
+ for (String regex : mWifiRegexs) {
+ if (s.matches(regex)) wifiTethered = true;
+ }
+ }
+ for (Object o: errored) {
+ String s = (String)o;
+ for (String regex : mWifiRegexs) {
+ if (s.matches(regex)) wifiErrored = true;
+ }
+ }
+
+ if (wifiTethered) {
+ WifiConfiguration wifiConfig = mWifiManager.getWifiApConfiguration();
+ updateConfigSummary(wifiConfig);
+ } else if (wifiErrored) {
+ mCheckBox.setSummary(R.string.wifi_error);
+ }
+ }
+
+ private void handleWifiApStateChanged(int state) {
+ switch (state) {
+ case WifiManager.WIFI_AP_STATE_ENABLING:
+ mCheckBox.setSummary(R.string.wifi_starting);
+ mCheckBox.setEnabled(false);
+ break;
+ case WifiManager.WIFI_AP_STATE_ENABLED:
+ /**
+ * Summary on enable is handled by tether
+ * broadcast notice
+ */
+ mCheckBox.setChecked(true);
+ /* Doesnt need the airplane check */
+ mCheckBox.setEnabled(true);
+ break;
+ case WifiManager.WIFI_AP_STATE_DISABLING:
+ mCheckBox.setSummary(R.string.wifi_stopping);
+ mCheckBox.setEnabled(false);
+ break;
+ case WifiManager.WIFI_AP_STATE_DISABLED:
+ mCheckBox.setChecked(false);
+ mCheckBox.setSummary(mOriginalSummary);
+ enableWifiCheckBox();
+ break;
+ default:
+ mCheckBox.setChecked(false);
+ mCheckBox.setSummary(R.string.wifi_error);
+ enableWifiCheckBox();
+ }
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiApSettings.java b/src/com/android/settings/wifi/WifiApSettings.java
new file mode 100644
index 0000000..0815238
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiApSettings.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings.wifi;
+
+import com.android.settings.R;
+import android.app.Dialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.preference.CheckBoxPreference;
+import android.provider.Settings;
+import android.util.Log;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+
+/*
+ * Displays preferences for Tethering.
+ */
+public class WifiApSettings extends PreferenceActivity
+ implements DialogInterface.OnClickListener {
+
+ private static final String WIFI_AP_SSID_AND_SECURITY = "wifi_ap_ssid_and_security";
+ private static final String ENABLE_WIFI_AP = "enable_wifi_ap";
+ private static final int CONFIG_SUBTEXT = R.string.wifi_tether_configure_subtext;
+
+ private static final int OPEN_INDEX = 0;
+ private static final int WPA_INDEX = 1;
+
+ private static final int DIALOG_AP_SETTINGS = 1;
+
+ private String[] mSecurityType;
+ private Preference mCreateNetwork;
+ private CheckBoxPreference mEnableWifiAp;
+
+ private WifiApDialog mDialog;
+ private WifiManager mWifiManager;
+ private WifiApEnabler mWifiApEnabler;
+ private WifiConfiguration mWifiConfig = null;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ mWifiConfig = mWifiManager.getWifiApConfiguration();
+ mSecurityType = getResources().getStringArray(R.array.wifi_ap_security);
+
+ addPreferencesFromResource(R.xml.wifi_ap_settings);
+
+ mCreateNetwork = findPreference(WIFI_AP_SSID_AND_SECURITY);
+ mEnableWifiAp = (CheckBoxPreference) findPreference(ENABLE_WIFI_AP);
+
+ mWifiApEnabler = new WifiApEnabler(this, mEnableWifiAp);
+
+ if(mWifiConfig == null) {
+ String s = getString(com.android.internal.R.string.wifi_tether_configure_ssid_default);
+ mCreateNetwork.setSummary(String.format(getString(CONFIG_SUBTEXT),
+ s, mSecurityType[OPEN_INDEX]));
+ } else {
+ mCreateNetwork.setSummary(String.format(getString(CONFIG_SUBTEXT),
+ mWifiConfig.SSID,
+ mWifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
+ mSecurityType[WPA_INDEX] : mSecurityType[OPEN_INDEX]));
+ }
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ if (id == DIALOG_AP_SETTINGS) {
+ mDialog = new WifiApDialog(this, this, mWifiConfig);
+ return mDialog;
+ }
+ return null;
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mWifiApEnabler.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mWifiApEnabler.pause();
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
+ if (preference == mCreateNetwork) {
+ showDialog(DIALOG_AP_SETTINGS);
+ }
+ return true;
+ }
+
+ public void onClick(DialogInterface dialogInterface, int button) {
+
+ if (button == DialogInterface.BUTTON_POSITIVE) {
+ mWifiConfig = mDialog.getConfig();
+ if(mWifiConfig != null) {
+ mWifiManager.setWifiApEnabled(mWifiConfig, true);
+ mCreateNetwork.setSummary(String.format(getString(CONFIG_SUBTEXT),
+ mWifiConfig.SSID,
+ mWifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
+ mSecurityType[WPA_INDEX] : mSecurityType[OPEN_INDEX]));
+ /**
+ * There is no tether notification on changing AP
+ * configuration. Update status with new config.
+ */
+ mWifiApEnabler.updateConfigSummary(mWifiConfig);
+
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiConfigInfo.java b/src/com/android/settings/wifi/WifiConfigInfo.java
new file mode 100644
index 0000000..2ed4f02
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiConfigInfo.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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 com.android.settings.wifi;
+
+import android.app.Activity;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.widget.TextView;
+import android.net.wifi.WifiConfiguration;
+import java.util.List;
+
+import com.android.settings.R;
+
+
+/**
+ * Configuration details saved by the user on the WifiSettings screen
+ */
+public class WifiConfigInfo extends Activity {
+
+ private static final String TAG = "WifiConfigInfo";
+
+ private TextView mConfigList;
+ private WifiManager mWifiManager;
+
+ //============================
+ // Activity lifecycle
+ //============================
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mWifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
+ setContentView(R.layout.wifi_config_info);
+ mConfigList = (TextView) findViewById(R.id.config_list);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ final List<WifiConfiguration> wifiConfigs = mWifiManager.getConfiguredNetworks();
+ StringBuffer configList = new StringBuffer();
+ for (int i = wifiConfigs.size() - 1; i >= 0; i--) {
+ configList.append(wifiConfigs.get(i));
+ }
+ mConfigList.setText(configList);
+ }
+
+}
diff --git a/src/com/android/settings/wifi/WifiDialog.java b/src/com/android/settings/wifi/WifiDialog.java
new file mode 100644
index 0000000..a8bf717
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiDialog.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 com.android.settings.wifi;
+
+import com.android.settings.R;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.net.NetworkInfo.DetailedState;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiInfo;
+import android.os.Bundle;
+import android.security.Credentials;
+import android.security.KeyStore;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.text.format.Formatter;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+class WifiDialog extends AlertDialog implements View.OnClickListener,
+ TextWatcher, AdapterView.OnItemSelectedListener {
+ private static final String KEYSTORE_SPACE = "keystore://";
+
+ static final int BUTTON_SUBMIT = DialogInterface.BUTTON_POSITIVE;
+ static final int BUTTON_FORGET = DialogInterface.BUTTON_NEUTRAL;
+
+ final boolean edit;
+ private final DialogInterface.OnClickListener mListener;
+ private final AccessPoint mAccessPoint;
+
+ private View mView;
+ private TextView mSsid;
+ private int mSecurity;
+ private TextView mPassword;
+
+ private Spinner mEapMethod;
+ private Spinner mEapCaCert;
+ private Spinner mPhase2;
+ private Spinner mEapUserCert;
+ private TextView mEapIdentity;
+ private TextView mEapAnonymous;
+
+ static boolean requireKeyStore(WifiConfiguration config) {
+ String values[] = {config.ca_cert.value(), config.client_cert.value(),
+ config.private_key.value()};
+ for (String value : values) {
+ if (value != null && value.startsWith(KEYSTORE_SPACE)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ WifiDialog(Context context, DialogInterface.OnClickListener listener,
+ AccessPoint accessPoint, boolean edit) {
+ super(context);
+ this.edit = edit;
+ mListener = listener;
+ mAccessPoint = accessPoint;
+ mSecurity = (accessPoint == null) ? AccessPoint.SECURITY_NONE : accessPoint.security;
+ }
+
+ WifiConfiguration getConfig() {
+ if (mAccessPoint != null && mAccessPoint.networkId != -1 && !edit) {
+ return null;
+ }
+
+ WifiConfiguration config = new WifiConfiguration();
+
+ if (mAccessPoint == null) {
+ config.SSID = AccessPoint.convertToQuotedString(
+ mSsid.getText().toString());
+ // If the user adds a network manually, assume that it is hidden.
+ config.hiddenSSID = true;
+ } else if (mAccessPoint.networkId == -1) {
+ config.SSID = AccessPoint.convertToQuotedString(
+ mAccessPoint.ssid);
+ } else {
+ config.networkId = mAccessPoint.networkId;
+ }
+
+ switch (mSecurity) {
+ case AccessPoint.SECURITY_NONE:
+ config.allowedKeyManagement.set(KeyMgmt.NONE);
+ return config;
+
+ case AccessPoint.SECURITY_WEP:
+ config.allowedKeyManagement.set(KeyMgmt.NONE);
+ config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
+ config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
+ if (mPassword.length() != 0) {
+ int length = mPassword.length();
+ String password = mPassword.getText().toString();
+ // WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
+ if ((length == 10 || length == 26 || length == 58) &&
+ password.matches("[0-9A-Fa-f]*")) {
+ config.wepKeys[0] = password;
+ } else {
+ config.wepKeys[0] = '"' + password + '"';
+ }
+ }
+ return config;
+
+ case AccessPoint.SECURITY_PSK:
+ config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+ if (mPassword.length() != 0) {
+ String password = mPassword.getText().toString();
+ if (password.matches("[0-9A-Fa-f]{64}")) {
+ config.preSharedKey = password;
+ } else {
+ config.preSharedKey = '"' + password + '"';
+ }
+ }
+ return config;
+
+ case AccessPoint.SECURITY_EAP:
+ config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+ config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
+ config.eap.setValue((String) mEapMethod.getSelectedItem());
+
+ config.phase2.setValue((mPhase2.getSelectedItemPosition() == 0) ? "" :
+ "auth=" + mPhase2.getSelectedItem());
+ config.ca_cert.setValue((mEapCaCert.getSelectedItemPosition() == 0) ? "" :
+ KEYSTORE_SPACE + Credentials.CA_CERTIFICATE +
+ (String) mEapCaCert.getSelectedItem());
+ config.client_cert.setValue((mEapUserCert.getSelectedItemPosition() == 0) ? "" :
+ KEYSTORE_SPACE + Credentials.USER_CERTIFICATE +
+ (String) mEapUserCert.getSelectedItem());
+ config.private_key.setValue((mEapUserCert.getSelectedItemPosition() == 0) ? "" :
+ KEYSTORE_SPACE + Credentials.USER_PRIVATE_KEY +
+ (String) mEapUserCert.getSelectedItem());
+ config.identity.setValue((mEapIdentity.length() == 0) ? "" :
+ mEapIdentity.getText().toString());
+ config.anonymous_identity.setValue((mEapAnonymous.length() == 0) ? "" :
+ mEapAnonymous.getText().toString());
+ if (mPassword.length() != 0) {
+ config.password.setValue(mPassword.getText().toString());
+ }
+ return config;
+ }
+ return null;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ mView = getLayoutInflater().inflate(R.layout.wifi_dialog, null);
+ setView(mView);
+ setInverseBackgroundForced(true);
+
+ Context context = getContext();
+ Resources resources = context.getResources();
+
+ if (mAccessPoint == null) {
+ setTitle(R.string.wifi_add_network);
+ mView.findViewById(R.id.type).setVisibility(View.VISIBLE);
+ mSsid = (TextView) mView.findViewById(R.id.ssid);
+ mSsid.addTextChangedListener(this);
+ ((Spinner) mView.findViewById(R.id.security)).setOnItemSelectedListener(this);
+ setButton(BUTTON_SUBMIT, context.getString(R.string.wifi_save), mListener);
+ } else {
+ setTitle(mAccessPoint.ssid);
+ ViewGroup group = (ViewGroup) mView.findViewById(R.id.info);
+
+ DetailedState state = mAccessPoint.getState();
+ if (state != null) {
+ addRow(group, R.string.wifi_status, Summary.get(getContext(), state));
+ }
+
+ String[] type = resources.getStringArray(R.array.wifi_security);
+ addRow(group, R.string.wifi_security, type[mAccessPoint.security]);
+
+ int level = mAccessPoint.getLevel();
+ if (level != -1) {
+ String[] signal = resources.getStringArray(R.array.wifi_signal);
+ addRow(group, R.string.wifi_signal, signal[level]);
+ }
+
+ WifiInfo info = mAccessPoint.getInfo();
+ if (info != null) {
+ addRow(group, R.string.wifi_speed, info.getLinkSpeed() + WifiInfo.LINK_SPEED_UNITS);
+ // TODO: fix the ip address for IPv6.
+ int address = info.getIpAddress();
+ if (address != 0) {
+ addRow(group, R.string.wifi_ip_address, Formatter.formatIpAddress(address));
+ }
+ }
+
+ if (mAccessPoint.networkId == -1 || edit) {
+ showSecurityFields();
+ }
+
+ if (edit) {
+ setButton(BUTTON_SUBMIT, context.getString(R.string.wifi_save), mListener);
+ } else {
+ if (state == null && level != -1) {
+ setButton(BUTTON_SUBMIT, context.getString(R.string.wifi_connect), mListener);
+ }
+ if (mAccessPoint.networkId != -1) {
+ setButton(BUTTON_FORGET, context.getString(R.string.wifi_forget), mListener);
+ }
+ }
+ }
+
+ setButton(DialogInterface.BUTTON_NEGATIVE,
+ context.getString(R.string.wifi_cancel), mListener);
+
+ super.onCreate(savedInstanceState);
+
+ if (getButton(BUTTON_SUBMIT) != null) {
+ validate();
+ }
+ }
+
+ private void addRow(ViewGroup group, int name, String value) {
+ View row = getLayoutInflater().inflate(R.layout.wifi_dialog_row, group, false);
+ ((TextView) row.findViewById(R.id.name)).setText(name);
+ ((TextView) row.findViewById(R.id.value)).setText(value);
+ group.addView(row);
+ }
+
+ private void validate() {
+ // TODO: make sure this is complete.
+ if ((mSsid != null && mSsid.length() == 0) ||
+ ((mAccessPoint == null || mAccessPoint.networkId == -1) &&
+ ((mSecurity == AccessPoint.SECURITY_WEP && mPassword.length() == 0) ||
+ (mSecurity == AccessPoint.SECURITY_PSK && mPassword.length() < 8)))) {
+ getButton(BUTTON_SUBMIT).setEnabled(false);
+ } else {
+ getButton(BUTTON_SUBMIT).setEnabled(true);
+ }
+ }
+
+ public void onClick(View view) {
+ mPassword.setInputType(
+ InputType.TYPE_CLASS_TEXT | (((CheckBox) view).isChecked() ?
+ InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD :
+ InputType.TYPE_TEXT_VARIATION_PASSWORD));
+ }
+
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ public void afterTextChanged(Editable editable) {
+ validate();
+ }
+
+ public void onItemSelected(AdapterView parent, View view, int position, long id) {
+ mSecurity = position;
+ showSecurityFields();
+ validate();
+ }
+
+ public void onNothingSelected(AdapterView parent) {
+ }
+
+ private void showSecurityFields() {
+ if (mSecurity == AccessPoint.SECURITY_NONE) {
+ mView.findViewById(R.id.fields).setVisibility(View.GONE);
+ return;
+ }
+ mView.findViewById(R.id.fields).setVisibility(View.VISIBLE);
+
+ if (mPassword == null) {
+ mPassword = (TextView) mView.findViewById(R.id.password);
+ mPassword.addTextChangedListener(this);
+ ((CheckBox) mView.findViewById(R.id.show_password)).setOnClickListener(this);
+
+ if (mAccessPoint != null && mAccessPoint.networkId != -1) {
+ mPassword.setHint(R.string.wifi_unchanged);
+ }
+ }
+
+ if (mSecurity != AccessPoint.SECURITY_EAP) {
+ mView.findViewById(R.id.eap).setVisibility(View.GONE);
+ return;
+ }
+ mView.findViewById(R.id.eap).setVisibility(View.VISIBLE);
+
+ if (mEapMethod == null) {
+ mEapMethod = (Spinner) mView.findViewById(R.id.method);
+ mPhase2 = (Spinner) mView.findViewById(R.id.phase2);
+ mEapCaCert = (Spinner) mView.findViewById(R.id.ca_cert);
+ mEapUserCert = (Spinner) mView.findViewById(R.id.user_cert);
+ mEapIdentity = (TextView) mView.findViewById(R.id.identity);
+ mEapAnonymous = (TextView) mView.findViewById(R.id.anonymous);
+
+ loadCertificates(mEapCaCert, Credentials.CA_CERTIFICATE);
+ loadCertificates(mEapUserCert, Credentials.USER_PRIVATE_KEY);
+
+ if (mAccessPoint != null && mAccessPoint.networkId != -1) {
+ WifiConfiguration config = mAccessPoint.getConfig();
+ setSelection(mEapMethod, config.eap.value());
+ setSelection(mPhase2, config.phase2.value());
+ setCertificate(mEapCaCert, Credentials.CA_CERTIFICATE,
+ config.ca_cert.value());
+ setCertificate(mEapUserCert, Credentials.USER_PRIVATE_KEY,
+ config.private_key.value());
+ mEapIdentity.setText(config.identity.value());
+ mEapAnonymous.setText(config.anonymous_identity.value());
+ }
+ }
+ }
+
+ private void loadCertificates(Spinner spinner, String prefix) {
+ String[] certs = KeyStore.getInstance().saw(prefix);
+ Context context = getContext();
+ String unspecified = context.getString(R.string.wifi_unspecified);
+
+ if (certs == null || certs.length == 0) {
+ certs = new String[] {unspecified};
+ } else {
+ String[] array = new String[certs.length + 1];
+ array[0] = unspecified;
+ System.arraycopy(certs, 0, array, 1, certs.length);
+ certs = array;
+ }
+
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(
+ context, android.R.layout.simple_spinner_item, certs);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(adapter);
+ }
+
+ private void setCertificate(Spinner spinner, String prefix, String cert) {
+ prefix = KEYSTORE_SPACE + prefix;
+ if (cert != null && cert.startsWith(prefix)) {
+ setSelection(spinner, cert.substring(prefix.length()));
+ }
+ }
+
+ private void setSelection(Spinner spinner, String value) {
+ if (value != null) {
+ ArrayAdapter<String> adapter = (ArrayAdapter<String>) spinner.getAdapter();
+ for (int i = adapter.getCount() - 1; i >= 0; --i) {
+ if (value.equals(adapter.getItem(i))) {
+ spinner.setSelection(i);
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java
index 10a672b..ef9f346 100644
--- a/src/com/android/settings/wifi/WifiEnabler.java
+++ b/src/com/android/settings/wifi/WifiEnabler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,174 +16,135 @@
package com.android.settings.wifi;
-import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
-import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
-import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
-import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
-import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
-
import com.android.settings.R;
-import com.android.settings.AirplaneModeEnabler;
+import com.android.settings.WirelessSettings;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.NetworkInfo;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.preference.Preference;
import android.preference.CheckBoxPreference;
import android.provider.Settings;
import android.text.TextUtils;
-import android.util.Config;
-import android.util.Log;
+import android.widget.Toast;
public class WifiEnabler implements Preference.OnPreferenceChangeListener {
-
- private static final boolean LOCAL_LOGD = Config.LOGD || WifiLayer.LOGV;
- private static final String TAG = "SettingsWifiEnabler";
-
private final Context mContext;
- private final WifiManager mWifiManager;
- private final CheckBoxPreference mWifiCheckBoxPref;
+ private final CheckBoxPreference mCheckBox;
private final CharSequence mOriginalSummary;
-
- private final IntentFilter mWifiStateFilter;
- private final BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
+ private final WifiManager mWifiManager;
+ private final IntentFilter mIntentFilter;
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
- handleWifiStateChanged(
- intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WIFI_STATE_UNKNOWN),
- intent.getIntExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE,
- WIFI_STATE_UNKNOWN));
- } else if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
- handleNetworkStateChanged(
- (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO));
+ String action = intent.getAction();
+ if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
+ handleWifiStateChanged(intent.getIntExtra(
+ WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN));
+ } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
+ handleStateChanged(WifiInfo.getDetailedStateOf((SupplicantState)
+ intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
+ } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
+ handleStateChanged(((NetworkInfo) intent.getParcelableExtra(
+ WifiManager.EXTRA_NETWORK_INFO)).getDetailedState());
}
}
};
-
- public WifiEnabler(Context context, WifiManager wifiManager,
- CheckBoxPreference wifiCheckBoxPreference) {
+
+ public WifiEnabler(Context context, CheckBoxPreference checkBox) {
mContext = context;
- mWifiCheckBoxPref = wifiCheckBoxPreference;
- mWifiManager = wifiManager;
-
- mOriginalSummary = wifiCheckBoxPreference.getSummary();
- wifiCheckBoxPreference.setPersistent(false);
-
- mWifiStateFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
- mWifiStateFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ mCheckBox = checkBox;
+ mOriginalSummary = checkBox.getSummary();
+ checkBox.setPersistent(false);
+
+ mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ // The order matters! We really should not depend on this. :(
+ mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+ mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
}
public void resume() {
- int state = mWifiManager.getWifiState();
- // This is the widget enabled state, not the preference toggled state
- mWifiCheckBoxPref.setEnabled(state == WIFI_STATE_ENABLED || state == WIFI_STATE_DISABLED
- || state == WIFI_STATE_UNKNOWN);
-
- mContext.registerReceiver(mWifiStateReceiver, mWifiStateFilter);
- mWifiCheckBoxPref.setOnPreferenceChangeListener(this);
+ // Wi-Fi state is sticky, so just let the receiver update UI
+ mContext.registerReceiver(mReceiver, mIntentFilter);
+ mCheckBox.setOnPreferenceChangeListener(this);
}
public void pause() {
- mContext.unregisterReceiver(mWifiStateReceiver);
- mWifiCheckBoxPref.setOnPreferenceChangeListener(null);
+ mContext.unregisterReceiver(mReceiver);
+ mCheckBox.setOnPreferenceChangeListener(null);
}
public boolean onPreferenceChange(Preference preference, Object value) {
- // Turn on/off Wi-Fi
- setWifiEnabled((Boolean) value);
-
- // Don't update UI to opposite state until we're sure
- return false;
- }
+ boolean enable = (Boolean) value;
- private void setWifiEnabled(final boolean enable) {
- // Disable button
- mWifiCheckBoxPref.setEnabled(false);
-
- if (!mWifiManager.setWifiEnabled(enable)) {
- mWifiCheckBoxPref.setSummary(enable ? R.string.error_starting : R.string.error_stopping);
+ // Show toast message if Wi-Fi is not allowed in airplane mode
+ if (enable && !WirelessSettings
+ .isRadioAllowed(mContext, Settings.System.RADIO_WIFI)) {
+ Toast.makeText(mContext, R.string.wifi_in_airplane_mode,
+ Toast.LENGTH_SHORT).show();
+ return false;
}
- }
-
- private void handleWifiStateChanged(int wifiState, int previousWifiState) {
- if (LOCAL_LOGD) {
- Log.d(TAG, "Received wifi state changed from "
- + getHumanReadableWifiState(previousWifiState) + " to "
- + getHumanReadableWifiState(wifiState));
+ /**
+ * Disable tethering if enabling Wifi
+ */
+ int wifiApState = mWifiManager.getWifiApState();
+ if (enable && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
+ (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
+ mWifiManager.setWifiApEnabled(null, false);
}
-
- if (wifiState == WIFI_STATE_DISABLED || wifiState == WIFI_STATE_ENABLED) {
- mWifiCheckBoxPref.setChecked(wifiState == WIFI_STATE_ENABLED);
- mWifiCheckBoxPref
- .setSummary(wifiState == WIFI_STATE_DISABLED ? mOriginalSummary : null);
-
- mWifiCheckBoxPref.setEnabled(isWifiAllowed(mContext));
-
- } else if (wifiState == WIFI_STATE_DISABLING || wifiState == WIFI_STATE_ENABLING) {
- mWifiCheckBoxPref.setSummary(wifiState == WIFI_STATE_ENABLING ? R.string.wifi_starting
- : R.string.wifi_stopping);
-
- } else if (wifiState == WIFI_STATE_UNKNOWN) {
- int message = R.string.wifi_error;
- if (previousWifiState == WIFI_STATE_ENABLING) message = R.string.error_starting;
- else if (previousWifiState == WIFI_STATE_DISABLING) message = R.string.error_stopping;
-
- mWifiCheckBoxPref.setChecked(false);
- mWifiCheckBoxPref.setSummary(message);
- mWifiCheckBoxPref.setEnabled(true);
+ if (mWifiManager.setWifiEnabled(enable)) {
+ mCheckBox.setEnabled(false);
+ } else {
+ mCheckBox.setSummary(R.string.wifi_error);
}
- }
- private void handleNetworkStateChanged(NetworkInfo networkInfo) {
-
- if (LOCAL_LOGD) {
- Log.d(TAG, "Received network state changed to " + networkInfo);
- }
-
- if (mWifiManager.isWifiEnabled()) {
- String summary = WifiStatus.getStatus(mContext,
- mWifiManager.getConnectionInfo().getSSID(), networkInfo.getDetailedState());
- mWifiCheckBoxPref.setSummary(summary);
- }
+ // Don't update UI to opposite state until we're sure
+ return false;
}
-
- private static boolean isWifiAllowed(Context context) {
- // allowed if we are not in airplane mode
- if (!AirplaneModeEnabler.isAirplaneModeOn(context)) {
- return true;
- }
- // allowed if wifi is not in AIRPLANE_MODE_RADIOS
- String radios = Settings.System.getString(context.getContentResolver(),
- Settings.System.AIRPLANE_MODE_RADIOS);
- if (radios == null || !radios.contains(Settings.System.RADIO_WIFI)) {
- return true;
+
+ private void handleWifiStateChanged(int state) {
+ switch (state) {
+ case WifiManager.WIFI_STATE_ENABLING:
+ mCheckBox.setSummary(R.string.wifi_starting);
+ mCheckBox.setEnabled(false);
+ break;
+ case WifiManager.WIFI_STATE_ENABLED:
+ mCheckBox.setChecked(true);
+ mCheckBox.setSummary(null);
+ mCheckBox.setEnabled(true);
+ break;
+ case WifiManager.WIFI_STATE_DISABLING:
+ mCheckBox.setSummary(R.string.wifi_stopping);
+ mCheckBox.setEnabled(false);
+ break;
+ case WifiManager.WIFI_STATE_DISABLED:
+ mCheckBox.setChecked(false);
+ mCheckBox.setSummary(mOriginalSummary);
+ mCheckBox.setEnabled(true);
+ break;
+ default:
+ mCheckBox.setChecked(false);
+ mCheckBox.setSummary(R.string.wifi_error);
+ mCheckBox.setEnabled(true);
}
- // allowed if wifi is in AIRPLANE_MODE_TOGGLEABLE_RADIOS
- radios = Settings.System.getString(context.getContentResolver(),
- Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
- return (radios != null && radios.contains(Settings.System.RADIO_WIFI));
}
- private static String getHumanReadableWifiState(int wifiState) {
- switch (wifiState) {
- case WIFI_STATE_DISABLED:
- return "Disabled";
- case WIFI_STATE_DISABLING:
- return "Disabling";
- case WIFI_STATE_ENABLED:
- return "Enabled";
- case WIFI_STATE_ENABLING:
- return "Enabling";
- case WIFI_STATE_UNKNOWN:
- return "Unknown";
- default:
- return "Some other state!";
+ private void handleStateChanged(NetworkInfo.DetailedState state) {
+ // WifiInfo is valid if and only if Wi-Fi is enabled.
+ // Here we use the state of the check box as an optimization.
+ if (state != null && mCheckBox.isChecked()) {
+ WifiInfo info = mWifiManager.getConnectionInfo();
+ if (info != null) {
+ mCheckBox.setSummary(Summary.get(mContext, info.getSSID(), state));
+ }
}
}
}
diff --git a/src/com/android/settings/wifi/WifiInfo.java b/src/com/android/settings/wifi/WifiInfo.java
new file mode 100644
index 0000000..291a495
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiInfo.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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 com.android.settings.wifi;
+
+import com.android.settings.R;
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+
+/**
+ * Wifi information menu item on the diagnostic screen
+ */
+public class WifiInfo extends PreferenceActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.testing_wifi_settings);
+ }
+
+}
diff --git a/src/com/android/settings/wifi/WifiLayer.java b/src/com/android/settings/wifi/WifiLayer.java
deleted file mode 100644
index ce518e1..0000000
--- a/src/com/android/settings/wifi/WifiLayer.java
+++ /dev/null
@@ -1,1316 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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 com.android.settings.wifi;
-
-import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
-import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
-
-import com.android.settings.R;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkInfo.State;
-import android.net.wifi.ScanResult;
-import android.net.wifi.SupplicantState;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Config;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-/**
- * Helper class for abstracting Wi-Fi.
- * <p>
- * Client must call {@link #onCreate()}, {@link #onCreatedCallback()},
- * {@link #onPause()}, {@link #onResume()}.
- */
-public class WifiLayer {
-
- private static final String TAG = "SettingsWifiLayer";
- static final boolean LOGV = false || Config.LOGV;
-
- //============================
- // Other member variables
- //============================
-
- private Context mContext;
- private Callback mCallback;
-
- static final int MESSAGE_ATTEMPT_SCAN = 1;
- private Handler mHandler = new MyHandler();
-
- //============================
- // Wifi member variables
- //============================
-
- private WifiManager mWifiManager;
- private IntentFilter mIntentFilter;
- private List<AccessPointState> mApScanList = new ArrayList<AccessPointState>();
- private List<AccessPointState> mApOtherList = new ArrayList<AccessPointState>();
- private AccessPointState mCurrentPrimaryAp;
-
- /** The last access point that we were authenticating with. */
- private AccessPointState mLastAuthenticatingAp;
-
- /** The delay between scans when we're continually scanning. */
- private static final int CONTINUOUS_SCAN_DELAY_MS = 6000;
- /** On failure, the maximum retries for scanning. */
- private static final int SCAN_MAX_RETRY = 5;
- /** On failure, the delay between each scan retry. */
- private static final int SCAN_RETRY_DELAY_MS = 1000;
- /** On failure, the number of retries so far. */
- private int mScanRetryCount = 0;
- /**
- * Whether we're currently obtaining an address. Continuous scanning will be
- * disabled in this state.
- */
- private boolean mIsObtainingAddress;
-
- /**
- * See {@link android.provider.Settings.Secure#WIFI_NUM_OPEN_NETWORKS_KEPT}.
- */
- private int WIFI_NUM_OPEN_NETWORKS_KEPT;
- /**
- * Once the highest priority exceeds this value, all networks will be
- * wrapped around starting at 0. This is so another client of the Wi-Fi
- * API can have access points that aren't managed by us. (If the other
- * client wants lower-priority access points than ours, it can use negative
- * priority.)
- */
- private static final int HIGHEST_PRIORITY_MAX_VALUE = 99999;
- /**
- * Never access directly, only the related methods should.
- */
- private int mNextHighestPriority;
-
- /**
- * This is used to track when the user wants to connect to a specific AP. We
- * disable all other APs, set this to true, and let wpa_supplicant connect.
- * Once we get a network state change, we re-enable the rest of them.
- */
- private boolean mReenableApsOnNetworkStateChange = false;
-
- /**
- * The current supplicant state, as broadcasted.
- */
- private SupplicantState mCurrentSupplicantState;
-
- //============================
- // Inner classes
- //============================
-
- interface Callback {
- void onError(int messageResId);
-
- /**
- * Called when an AP is added or removed.
- *
- * @param ap The AP.
- * @param added {@code true} if added, {@code false} if removed.
- */
- void onAccessPointSetChanged(AccessPointState ap, boolean added);
-
- /**
- * Called when the scanning status changes.
- *
- * @param started {@code true} if the scanning just started,
- * {@code false} if it just ended.
- */
- void onScanningStatusChanged(boolean started);
-
- /**
- * Called when the access points should be enabled or disabled. This is
- * called from both wpa_supplicant being connected/disconnected and Wi-Fi
- * being enabled/disabled.
- *
- * @param enabled {@code true} if they should be enabled, {@code false}
- * if they should be disabled.
- */
- void onAccessPointsStateChanged(boolean enabled);
-
- /**
- * Called when there is trouble authenticating and the retry-password
- * dialog should be shown.
- *
- * @param ap The access point.
- */
- void onRetryPassword(AccessPointState ap);
- }
-
- private BroadcastReceiver mReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
- handleNetworkStateChanged(
- (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO),
- intent.getStringExtra(WifiManager.EXTRA_BSSID));
- } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
- handleScanResultsAvailable();
- } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
- handleSupplicantConnectionChanged(
- intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false));
- } else if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) {
- handleSupplicantStateChanged(
- (SupplicantState) intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE),
- intent.hasExtra(WifiManager.EXTRA_SUPPLICANT_ERROR),
- intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 0));
- } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
- handleWifiStateChanged(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
- WifiManager.WIFI_STATE_UNKNOWN));
- } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
- handleSignalChanged(intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, 0));
- } else if (action.equals(WifiManager.NETWORK_IDS_CHANGED_ACTION)) {
- handleNetworkIdsChanged();
- }
- }
- };
-
- /**
- * If using this class, make sure to call the callbacks of this class, such
- * as {@link #onCreate()}, {@link #onCreatedCallback()},
- * {@link #onPause()}, {@link #onResume()}.
- *
- * @param context The context.
- * @param callback The interface that will be invoked when events from this
- * class are generated.
- */
- public WifiLayer(Context context, Callback callback) {
- mContext = context;
- mCallback = callback;
- }
-
- //============================
- // Lifecycle
- //============================
-
- /**
- * The client MUST call this.
- * <p>
- * This shouldn't have any dependency on the callback.
- */
- public void onCreate() {
- mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
-
- mIntentFilter = new IntentFilter();
- mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
- mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
- mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
- mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
- mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
- mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
-
- WIFI_NUM_OPEN_NETWORKS_KEPT = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT, 10);
- }
-
- /**
- * The client MUST call this.
- * <p>
- * Callback is ready, this can do whatever it wants with it.
- */
- public void onCreatedCallback() {
- if (isWifiEnabled()) {
- refreshAll(false);
- }
- }
-
- /**
- * The client MUST call this.
- *
- * @see android.app.Activity#onResume
- */
- public void onResume() {
- mContext.registerReceiver(mReceiver, mIntentFilter);
-
- if (isWifiEnabled()) {
- // Kick start the continual scan
- queueContinuousScan();
- }
- }
-
- /**
- * The client MUST call this.
- *
- * @see android.app.Activity#onPause
- */
- public void onPause() {
- mContext.unregisterReceiver(mReceiver);
-
- attemptReenableAllAps();
-
- removeFutureScans();
- }
-
- //============================
- // "Public" API
- //============================
-
- /**
- * Returns an AccessPointState instance (that we track locally in WifiLayer)
- * for the given state. First, we check if we track the given instance. If
- * not, we find an equal AccessPointState instance that we track.
- *
- * @param state An AccessPointState instance that does not necessarily have
- * to be one that this WifiLayer class tracks. For example, it
- * could be the result of unparceling.
- * @return An AccessPointState instance that this WifiLayer class tracks.
- */
- public AccessPointState getWifiLayerApInstance(AccessPointState state) {
- synchronized (this) {
-
- if (hasApInstanceLocked(state)) {
- return state;
- }
-
- return findApLocked(state.networkId, state.bssid, state.ssid, state.security);
- }
- }
-
- /**
- * Connects to the network, and creates the Wi-Fi API config if necessary.
- *
- * @param state The state of the network to connect to. This MUST be an
- * instance that was given to you by this class. If you
- * constructed the instance yourself (for example, after
- * unparceling it), you should use
- * {@link #getWifiLayerApInstance(AccessPointState)}.
- * @return Whether the operation was successful.
- */
- public boolean connectToNetwork(AccessPointState state) {
- if (LOGV) {
- Log.v(TAG, "Connecting to " + state);
- }
-
- // Need WifiConfiguration for the AP
- WifiConfiguration config = findConfiguredNetwork(state);
-
- if (LOGV) {
- Log.v(TAG, " Found configured network " + config);
- }
-
- if (config == null) {
- /*
- * Connecting for the first time, need to create it. We will enable
- * and save it below (when we set priority).
- */
- config = addConfiguration(state, 0);
-
- if (config == null) {
- Log.e(TAG, "Config is still null, even after attempting to add it.");
- error(R.string.error_connecting);
- return false;
- }
-
- /*
- * We could reload the configured networks, but instead just
- * shortcut and add this state to our list in memory.
- */
- ensureTrackingState(state);
- } else {
- // Make sure the configuration has the latest from the state
- state.updateWifiConfiguration(config);
- }
-
- // Enable this network before we save to storage
- if (!managerEnableNetwork(state, false)) {
- Log.e(TAG, "Could not enable network ID " + state.networkId);
- error(R.string.error_connecting);
- return false;
- }
-
- /*
- * Give it highest priority, this could cause a network ID change, so do
- * it after any modifications to the network we're connecting to
- */
- setHighestPriorityStateAndSave(state, config);
-
- /*
- * We force supplicant to connect to this network by disabling the
- * others. We do this AFTER we save above so this disabled flag isn't
- * persisted.
- */
- mReenableApsOnNetworkStateChange = true;
- if (!managerEnableNetwork(state, true)) {
- Log.e(TAG, "Could not enable network ID " + state.networkId);
- error(R.string.error_connecting);
- return false;
- }
-
- if (LOGV) {
- Log.v(TAG, " Enabled network " + state.networkId);
- }
-
- if (mCurrentSupplicantState == SupplicantState.DISCONNECTED ||
- mCurrentSupplicantState == SupplicantState.SCANNING) {
- mWifiManager.reconnect();
- }
-
- // Check for too many configured open networks
- if (!state.hasSecurity()) {
- checkForExcessOpenNetworks();
- }
-
- return true;
- }
-
- /**
- * Saves a network, and creates the Wi-Fi API config if necessary.
- *
- * @param state The state of the network to save. If you constructed the
- * instance yourself (for example, after unparceling it), you
- * should use {@link #getWifiLayerApInstance(AccessPointState)}.
- * @return Whether the operation was successful.
- */
- public boolean saveNetwork(AccessPointState state) {
- WifiConfiguration config = findConfiguredNetwork(state);
-
- if (config == null) {
- // if the user is adding a new network, assume that it is hidden
- state.setHiddenSsid(true);
-
- config = addConfiguration(state, ADD_CONFIGURATION_ENABLE);
-
- if (config == null) {
- Log.e(TAG, "Could not save configuration, call to addConfiguration failed.");
- error(R.string.error_saving);
- return false;
- }
-
- } else {
- state.updateWifiConfiguration(config);
- if (mWifiManager.updateNetwork(config) == -1) {
- Log.e(TAG, "Could not update configuration, call to WifiManager failed.");
- error(R.string.error_saving);
- return false;
- }
- }
-
- // Successfully added network, go ahead and persist
- if (!managerSaveConfiguration()) {
- Log.e(TAG, "Could not save configuration, call to WifiManager failed.");
- error(R.string.error_saving);
- return false;
- }
-
- /*
- * It's necessary to update the network id of this state because the network id
- * could have changed after the configuration is saved. For example, if there are
- * more than 10 saved open-networks, some older open-networks will have been be forgotten.
- */
- state.setNetworkId(AccessPointState.NETWORK_ID_ANY);
- config = findConfiguredNetwork(state);
- if (config != null) {
- state.setNetworkId(config.networkId);
- }
-
- /*
- * We could reload the configured networks, but instead just shortcut
- * and add this state to our list in memory
- */
- ensureTrackingState(state);
-
- return true;
- }
-
- /**
- * Forgets a network.
- *
- * @param state The state of the network to forget. If you constructed the
- * instance yourself (for example, after unparceling it), you
- * should use {@link #getWifiLayerApInstance(AccessPointState)}.
- * @return Whether the operation was succesful.
- */
- public boolean forgetNetwork(AccessPointState state) {
- if (!state.configured) {
- Log.w(TAG, "Inconsistent state: Forgetting a network that is not configured.");
- return true;
- }
-
- int oldNetworkId = state.networkId;
- state.forget();
-
- if (!state.seen) {
- // If it is not seen, it should be removed from the UI
- removeApFromUi(state);
- }
-
- synchronized (this) {
- mApOtherList.remove(state);
- // It should not be removed from the scan list, since if it was
- // there that means it's still seen
- }
-
- if (!mWifiManager.removeNetwork(oldNetworkId)) {
- Log.e(TAG, "Removing network " + state.ssid + " (network ID " + oldNetworkId +
- ") failed.");
- return false;
- }
-
- if (!managerSaveConfiguration()) {
- error(R.string.error_saving);
- return false;
- }
-
- return true;
- }
-
- /**
- * This ensures this class is tracking the given state. This means it is in
- * our list of access points, either in the scanned list or in the
- * remembered list.
- *
- * @param state The state that will be checked for tracking, and if not
- * tracking will be added to the remembered list in memory.
- */
- private void ensureTrackingState(AccessPointState state) {
- synchronized (this) {
- if (hasApInstanceLocked(state)) {
- return;
- }
-
- mApOtherList.add(state);
- }
- }
-
- /**
- * Attempts to scan networks. This has a retry mechanism.
- */
- public void attemptScan() {
-
- // Remove any future scans since we're scanning right now
- removeFutureScans();
-
- if (!mWifiManager.isWifiEnabled()) return;
-
- if (!mWifiManager.startScanActive()) {
- postAttemptScan();
- } else {
- mScanRetryCount = 0;
- }
- }
-
- private void queueContinuousScan() {
- mHandler.removeMessages(MESSAGE_ATTEMPT_SCAN);
-
- if (!mIsObtainingAddress) {
- // Don't do continuous scan while in obtaining IP state
- mHandler.sendEmptyMessageDelayed(MESSAGE_ATTEMPT_SCAN, CONTINUOUS_SCAN_DELAY_MS);
- }
- }
-
- private void removeFutureScans() {
- mHandler.removeMessages(MESSAGE_ATTEMPT_SCAN);
- }
-
- public boolean isWifiEnabled() {
- return mWifiManager.isWifiEnabled();
- }
-
- public void error(int messageResId) {
- Log.e(TAG, mContext.getResources().getString(messageResId));
-
- if (mCallback != null) {
- mCallback.onError(messageResId);
- }
- }
-
- //============================
- // Wifi logic
- //============================
-
- private void refreshAll(boolean attemptScan) {
- loadConfiguredAccessPoints();
- refreshStatus();
-
- if (attemptScan) {
- attemptScan();
- }
- }
-
- private void postAttemptScan() {
- onScanningStarted();
-
- if (++mScanRetryCount < SCAN_MAX_RETRY) {
- // Just in case, remove previous ones first
- removeFutureScans();
- mHandler.sendEmptyMessageDelayed(MESSAGE_ATTEMPT_SCAN, SCAN_RETRY_DELAY_MS);
- } else {
- // Show an error once we run out of attempts
- error(R.string.error_scanning);
- onScanningEnded();
- }
- }
-
- private void onScanningStarted() {
- if (mCallback != null) {
- mCallback.onScanningStatusChanged(true);
- }
- }
-
- private void onScanningEnded() {
- queueContinuousScan();
-
- if (mCallback != null) {
- mCallback.onScanningStatusChanged(false);
- }
- }
-
- private void clearApLists() {
- List<AccessPointState> accessPoints = new ArrayList<AccessPointState>();
-
- synchronized(this) {
- // Clear the logic's list of access points
- accessPoints.addAll(mApScanList);
- accessPoints.addAll(mApOtherList);
- mApScanList.clear();
- mApOtherList.clear();
- }
-
- for (int i = accessPoints.size() - 1; i >= 0; i--) {
- removeApFromUi(accessPoints.get(i));
- }
- }
-
- private boolean managerSaveConfiguration() {
- boolean retValue = mWifiManager.saveConfiguration();
-
- /*
- * We need to assume the network IDs have changed, so handle this. Note:
- * we also have a receiver on the broadcast intent in case another wifi
- * framework client caused the change. In this case, we will handle the
- * possible network ID change twice (but it's not too costly).
- */
- handleNetworkIdsChanged();
-
- return retValue;
- }
-
- private boolean managerEnableNetwork(AccessPointState state, boolean disableOthers) {
- if (!mWifiManager.enableNetwork(state.networkId, disableOthers)) {
- return false;
- }
-
- // Enabling was successful, make sure the state is not disabled
- state.setDisabled(false);
-
- return true;
- }
-
- private static final int ADD_CONFIGURATION_ENABLE = 1;
- private static final int ADD_CONFIGURATION_SAVE = 2;
- private WifiConfiguration addConfiguration(AccessPointState state, int flags) {
- // Create and add
- WifiConfiguration config = new WifiConfiguration();
-
- state.updateWifiConfiguration(config);
-
- final int networkId = mWifiManager.addNetwork(config);
- if (networkId == -1) {
- return null;
- }
-
- state.setNetworkId(networkId);
- state.setConfigured(true);
-
- // If we should, then enable it, since it comes disabled by default
- if ((flags & ADD_CONFIGURATION_ENABLE) != 0
- && !managerEnableNetwork(state, false)) {
- return null;
- }
-
- // If we should, then save it
- if ((flags & ADD_CONFIGURATION_SAVE) != 0 && !managerSaveConfiguration()) {
- return null;
- }
-
- if (mCallback != null) {
- mCallback.onAccessPointSetChanged(state, true);
- }
-
- return config;
- }
-
- private WifiConfiguration findConfiguredNetwork(AccessPointState state) {
- final List<WifiConfiguration> wifiConfigs = getConfiguredNetworks();
-
- for (int i = wifiConfigs.size() - 1; i >= 0; i--) {
- final WifiConfiguration wifiConfig = wifiConfigs.get(i);
- if (state.matchesWifiConfiguration(wifiConfig) >= AccessPointState.MATCH_WEAK) {
- return wifiConfig;
- }
- }
-
- return null;
- }
-
- private List<WifiConfiguration> getConfiguredNetworks() {
- final List<WifiConfiguration> wifiConfigs = mWifiManager.getConfiguredNetworks();
- return wifiConfigs;
- }
-
- /**
- * Must call while holding the lock for the list, which is usually the
- * WifiLayer instance.
- */
- private static AccessPointState findApLocked(List<AccessPointState> list, int networkId,
- String bssid, String ssid, String security) {
- AccessPointState ap;
- for (int i = list.size() - 1; i >= 0; i--) {
- ap = list.get(i);
- if (ap.matches(networkId, bssid, ssid, security) >= AccessPointState.MATCH_WEAK) {
- return ap;
- }
- }
-
- return null;
- }
-
- /**
- * Must call while holding the lock for the lists, which is usually this
- * WifiLayer instance.
- */
- private AccessPointState findApLocked(int networkId, String bssid, String ssid,
- String security) {
- AccessPointState ap = findApLocked(mApScanList, networkId, bssid, ssid, security);
- if (ap == null) {
- ap = findApLocked(mApOtherList, networkId, bssid, ssid, security);
- }
- return ap;
- }
-
- /**
- * Returns whether we have the exact instance of the access point state
- * given. This is useful in cases where an AccessPointState has been
- * parceled by the client and the client is attempting to use it to
- * connect/forget/save.
- * <p>
- * Must call while holding the lock for the lists, which is usually this
- * WifiLayer instance.
- */
- private boolean hasApInstanceLocked(AccessPointState state) {
-
- for (int i = mApScanList.size() - 1; i >= 0; i--) {
- if (mApScanList.get(i) == state) {
- return true;
- }
- }
-
- for (int i = mApOtherList.size() - 1; i >= 0; i--) {
- if (mApOtherList.get(i) == state) {
- return true;
- }
- }
-
- return false;
- }
-
- private void loadConfiguredAccessPoints() {
- final List<WifiConfiguration> configs = getConfiguredNetworks();
-
- for (int i = configs.size() - 1; i >= 0; i--) {
- final WifiConfiguration config = configs.get(i);
-
- AccessPointState ap;
- synchronized(this) {
- ap = findApLocked(config.networkId, config.BSSID, config.SSID,
- AccessPointState.getWifiConfigurationSecurity(config));
-
- if (ap != null) {
- // We already know about this one
- continue;
- }
-
- ap = new AccessPointState(mContext);
- ap.updateFromWifiConfiguration(config);
- if (LOGV) Log.v(TAG, "Created " + ap + " in loadConfiguredAccessPoints");
- mApOtherList.add(ap);
- }
-
- // Make sure our next highest priority is greater than this
- checkNextHighestPriority(ap.priority);
-
- if (mCallback != null) {
- mCallback.onAccessPointSetChanged(ap, true);
- }
- }
- }
-
- private AccessPointState getCurrentAp() {
- final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
-
- String ssid = wifiInfo.getSSID();
- if (ssid != null) {
- /*
- * We pass null for security since we have a network ID (i.e., it's
- * not a wildcard), and rely on it matching.
- */
- synchronized (this) {
- return findApLocked(wifiInfo.getNetworkId(), wifiInfo.getBSSID(), ssid, null);
- }
- } else {
- return null;
- }
- }
-
- private void setPrimaryAp(AccessPointState ap) {
- synchronized (this) {
- // Unset other
- if (mCurrentPrimaryAp != null) {
- mCurrentPrimaryAp.setPrimary(false);
- }
-
- mCurrentPrimaryAp = ap;
- }
-
- if (ap != null) {
- ap.setPrimary(true);
- }
- }
-
- private void attemptReenableAllAps() {
- if (mReenableApsOnNetworkStateChange) {
- mReenableApsOnNetworkStateChange = false;
- enableAllAps();
- }
- }
-
- private void enableAllAps() {
- synchronized(this) {
- if (LOGV) {
- Log.v(TAG, " Enabling all APs");
- }
-
- enableApsLocked(mApOtherList);
- enableApsLocked(mApScanList);
- }
- }
-
- private void enableApsLocked(List<AccessPointState> apList) {
- for (int i = apList.size() - 1; i >= 0; i--) {
- AccessPointState state = apList.get(i);
- int networkId = state.networkId;
- if (networkId != AccessPointState.NETWORK_ID_NOT_SET &&
- networkId != AccessPointState.NETWORK_ID_ANY) {
- managerEnableNetwork(state, false);
- }
- }
- }
-
- private void removeApFromUi(AccessPointState ap) {
- if (mCallback != null) {
- mCallback.onAccessPointSetChanged(ap, false);
- }
- }
-
- /**
- * Sets the access point state to the highest priority.
- * <p>
- * If you have a list of configured networks from WifiManager, you probably
- * shouldn't call this until you're done traversing the list.
- *
- * @param state The state to set as the highest priority.
- * @param reusableConfiguration An optional WifiConfiguration that will be
- * given to the WifiManager as updated data for the network ID.
- * This will be filled with the new priority.
- * @return Whether the operation was successful.
- */
- private boolean setHighestPriorityStateAndSave(AccessPointState state,
- WifiConfiguration reusableConfiguration) {
-
- if (!isConsideredForHighestPriority(state)) {
- Log.e(TAG,
- "Could not set highest priority on state because state is not being considered.");
- return false;
- }
-
- if (reusableConfiguration == null) {
- reusableConfiguration = new WifiConfiguration();
- }
-
- int oldPriority = reusableConfiguration.priority;
- reusableConfiguration.priority = getNextHighestPriority();
- reusableConfiguration.networkId = state.networkId;
-
- if (mWifiManager.updateNetwork(reusableConfiguration) == -1) {
- // Rollback priority
- reusableConfiguration.priority = oldPriority;
- Log.e(TAG,
- "Could not set highest priority on state because updating the supplicant network failed.");
- return false;
- }
-
- if (!managerSaveConfiguration()) {
- reusableConfiguration.priority = oldPriority;
- Log.e(TAG,
- "Could not set highest priority on state because saving config failed.");
- return false;
- }
-
- state.priority = reusableConfiguration.priority;
-
- if (LOGV) {
- Log.v(TAG, " Set highest priority to "
- + state.priority + " from " + oldPriority);
- }
-
- return true;
- }
-
- /**
- * Makes sure the next highest priority is larger than the given priority.
- */
- private void checkNextHighestPriority(int priority) {
- if (priority > HIGHEST_PRIORITY_MAX_VALUE || priority < 0) {
- // This is a priority that we aren't managing
- return;
- }
-
- if (mNextHighestPriority <= priority) {
- mNextHighestPriority = priority + 1;
- }
- }
-
- /**
- * Checks if there are too many open networks, and removes the excess ones.
- */
- private void checkForExcessOpenNetworks() {
- synchronized(this) {
- ArrayList<AccessPointState> allAps = getApsSortedByPriorityLocked();
-
- // Walk from highest to lowest priority
- int openConfiguredCount = 0;
- for (int i = allAps.size() - 1; i >= 0; i--) {
- AccessPointState state = allAps.get(i);
- if (state.configured && !state.hasSecurity()) {
- openConfiguredCount++;
- if (openConfiguredCount > WIFI_NUM_OPEN_NETWORKS_KEPT) {
- // Remove this network
- forgetNetwork(state);
- }
- }
- }
- }
- }
-
- private boolean isConsideredForHighestPriority(AccessPointState state) {
- return state.configured && state.networkId != AccessPointState.NETWORK_ID_ANY &&
- state.networkId != AccessPointState.NETWORK_ID_NOT_SET;
- }
-
- /**
- * Gets the next highest priority. If this value is larger than the max,
- * shift all the priorities so the lowest starts at 0.
- * <p>
- * Only
- * {@link #setHighestPriorityStateAndSave(AccessPointState, WifiConfiguration)}
- * should call this.
- *
- * @return The next highest priority to use.
- */
- private int getNextHighestPriority() {
- if (mNextHighestPriority > HIGHEST_PRIORITY_MAX_VALUE) {
- shiftPriorities();
- }
-
- return mNextHighestPriority++;
- }
-
- /**
- * Shift all the priorities so the lowest starts at 0.
- *
- * @return Whether the operation was successful.
- */
- private boolean shiftPriorities() {
- synchronized(this) {
-
- ArrayList<AccessPointState> allAps = getApsSortedByPriorityLocked();
-
- // Re-usable WifiConfiguration for setting priority
- WifiConfiguration updatePriorityConfig = new WifiConfiguration();
-
- // Set new priorities
- mNextHighestPriority = 0;
- int size = allAps.size();
- for (int i = 0; i < size; i++) {
- AccessPointState state = allAps.get(i);
-
- if (!isConsideredForHighestPriority(state)) {
- continue;
- }
-
- if (!setHighestPriorityStateAndSave(state, updatePriorityConfig)) {
- Log.e(TAG,
- "Could not shift priorities because setting the new priority failed.");
- return false;
- }
- }
-
- return true;
- }
- }
-
- private ArrayList<AccessPointState> getApsSortedByPriorityLocked() {
- // Get all of the access points we have
- ArrayList<AccessPointState> allAps = new ArrayList<AccessPointState>(mApScanList.size()
- + mApOtherList.size());
- allAps.addAll(mApScanList);
- allAps.addAll(mApOtherList);
-
- // Sort them based on priority
- Collections.sort(allAps, new Comparator<AccessPointState>() {
- public int compare(AccessPointState object1, AccessPointState object2) {
- return object1.priority - object2.priority;
- }
- });
-
- return allAps;
- }
-
- //============================
- // Status related
- //============================
-
- private void refreshStatus() {
- refreshStatus(null, null);
- }
-
- private void refreshStatus(AccessPointState ap, NetworkInfo.DetailedState detailedState) {
- final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
- if (detailedState == null) {
- detailedState = WifiInfo.getDetailedStateOf(wifiInfo.getSupplicantState());
- }
-
- if (ap == null && WifiStatus.isLiveConnection(detailedState)) {
- /*
- * We pass null for security since we have a network ID (i.e., it's
- * not a wildcard), and rely on it matching.
- */
- synchronized (this) {
- ap = findApLocked(wifiInfo.getNetworkId(), wifiInfo.getBSSID(), wifiInfo
- .getSSID(), null);
- }
- }
-
- if (ap != null) {
- ap.blockRefresh();
-
- // Let the AP get the latest info from the WifiInfo
- ap.updateFromWifiInfo(wifiInfo, detailedState);
-
- // The detailed state from the Intent has more states than the WifiInfo's detailed
- // state can have (for example, DHCP completion). Set the status using
- // the Intent's detailed state.
- ap.setStatus(detailedState);
- ap.unblockRefresh();
- }
- }
-
- //============================
- // Wifi callbacks
- //============================
-
- private void handleNetworkStateChanged(NetworkInfo info, String bssid) {
- final AccessPointState ap = getCurrentAp();
- NetworkInfo.DetailedState detailedState = info.getDetailedState();
-
- if (LOGV) {
- Log.v(TAG, "State change received " + info.toString() + ", or "
- + detailedState + " on " + bssid + " matched to " + ap);
- }
-
- handleDisablingScanWhileObtainingAddress(detailedState);
-
- // This will update the AP with its new info
- refreshStatus(ap, detailedState);
-
- boolean isDisconnected = info.getState().equals(State.DISCONNECTED);
- if (ap != null && info.isConnectedOrConnecting()) {
- setPrimaryAp(ap);
-
- if (LOGV) {
- Log.v(TAG, " Updated " + ap + " to be primary");
- }
-
- } else if (isDisconnected) {
-
- /*
- * When we drop off a network (for example, the router is powered
- * down when we were connected), we received a DISCONNECT event
- * without a BSSID. We should not have a primary AP anymore.
- */
- setPrimaryAp(null);
-
- if (LOGV) {
- Log.v(TAG, " Cleared primary");
- }
-
- } else if (detailedState.equals(DetailedState.FAILED)) {
-
- /*
- * Doh, failed for whatever reason. Unset the primary AP, but set
- * failed status on the AP that failed.
- */
- setPrimaryAp(null);
- ap.setStatus(DetailedState.FAILED);
-
- // Bring up error dialog
- error(R.string.wifi_generic_connection_error);
-
- } else if (LOGV) {
- Log.v(TAG, " Did not update any AP to primary, could have updated "
- + ap + " but we aren't connected or connecting");
- }
-
- if ((ap != null) && (info.isConnected()
- || (detailedState == DetailedState.OBTAINING_IPADDR))) {
- /*
- * Sometimes the scan results do not contain the AP even though it's
- * clearly connected. This may be because we do passive background
- * scanning that isn't as 'strong' as active scanning, so even
- * though a network is nearby, it won't be seen by the passive
- * scanning. If we are connected (or obtaining IP) then we know it
- * is seen.
- */
- ap.setSeen(true);
- }
-
- attemptReenableAllAps();
- }
-
- private void handleDisablingScanWhileObtainingAddress(DetailedState detailedState) {
-
- if (detailedState == DetailedState.OBTAINING_IPADDR) {
- mIsObtainingAddress = true;
-
- // We will not scan while obtaining an IP address
- removeFutureScans();
-
- } else {
- mIsObtainingAddress = false;
-
- // Start continuous scan
- queueContinuousScan();
- }
- }
-
- private void handleScanResultsAvailable() {
- synchronized(this) {
- // In the end, we'll moved the ones no longer seen into the mApOtherList
- List<AccessPointState> oldScanList = mApScanList;
- List<AccessPointState> newScanList =
- new ArrayList<AccessPointState>(oldScanList.size());
-
- List<ScanResult> list = mWifiManager.getScanResults();
- if (list != null) {
- for (int i = list.size() - 1; i >= 0; i--) {
- final ScanResult scanResult = list.get(i);
-
- if (LOGV) {
-// Log.v(TAG, " " + scanResult);
- }
-
- if (scanResult == null) {
- continue;
- }
-
- /*
- * Ignore adhoc, enterprise-secured, or hidden networks.
- * Hidden networks show up with empty SSID.
- */
- if (AccessPointState.isAdhoc(scanResult)
- || TextUtils.isEmpty(scanResult.SSID)) {
- continue;
- }
-
- final String ssid = AccessPointState.convertToQuotedString(scanResult.SSID);
- String security = AccessPointState.getScanResultSecurity(scanResult);
-
- // See if this AP is part of a group of APs (e.g., any large
- // wifi network has many APs, we'll only show one) that we've
- // seen in this scan
- AccessPointState ap = findApLocked(newScanList, AccessPointState.NETWORK_ID_ANY,
- AccessPointState.BSSID_ANY, ssid, security);
-
- // Yup, we've seen this network.
- if (ap != null) {
- // Use the better signal
- if (WifiManager.compareSignalLevel(scanResult.level, ap.signal) > 0) {
- ap.setSignal(scanResult.level);
- }
-
- if (LOGV) {
-// Log.v(TAG, " Already seen, continuing..");
- }
-
- continue;
- }
-
- // Find the AP in either our old scan list, or our non-seen
- // configured networks list
- ap = findApLocked(AccessPointState.NETWORK_ID_ANY, AccessPointState.BSSID_ANY,
- ssid, security);
-
- if (ap != null) {
- // Remove the AP from both (no harm if one doesn't contain it)
- oldScanList.remove(ap);
- mApOtherList.remove(ap);
- } else {
- ap = new AccessPointState(mContext);
-// if (LOGV) Log.v(TAG, "Created " + ap);
- }
-
- // Give it the latest state
- ap.updateFromScanResult(scanResult);
-
- if (mCallback != null) {
- mCallback.onAccessPointSetChanged(ap, true);
- }
-
- newScanList.add(ap);
- }
- }
-
- // oldScanList contains the ones no longer seen
- List<AccessPointState> otherList = mApOtherList;
- for (int i = oldScanList.size() - 1; i >= 0; i--) {
- final AccessPointState ap = oldScanList.get(i);
-
- if (ap.configured) {
-
- // Keep it around, since it is configured
- ap.setSeen(false);
- otherList.add(ap);
-
- } else {
-
- // Remove it since it is not configured and not seen
- removeApFromUi(ap);
- }
- }
-
- mApScanList = newScanList;
- }
-
- onScanningEnded();
- }
-
- private void handleSupplicantConnectionChanged(boolean connected) {
- if (mCallback != null) {
- mCallback.onAccessPointsStateChanged(connected);
- }
-
- if (connected) {
- refreshAll(true);
- }
- }
-
- private void handleWifiStateChanged(int wifiState) {
-
- if (wifiState == WIFI_STATE_ENABLED) {
- loadConfiguredAccessPoints();
- attemptScan();
-
- } else if (wifiState == WIFI_STATE_DISABLED) {
- removeFutureScans();
- if (LOGV) Log.v(TAG, "Clearing AP lists because wifi is disabled");
- clearApLists();
- }
-
- if (mCallback != null) {
- mCallback.onAccessPointsStateChanged(wifiState == WIFI_STATE_ENABLED);
- }
- }
-
- private void handleSignalChanged(int rssi) {
-
- if (mCurrentPrimaryAp != null) {
- mCurrentPrimaryAp.setSignal(rssi);
- }
- }
-
- private void handleSupplicantStateChanged(SupplicantState state, boolean hasError, int error) {
- mCurrentSupplicantState = state;
-
- if (SupplicantState.FOUR_WAY_HANDSHAKE.equals(state)) {
- mLastAuthenticatingAp = getCurrentAp();
- }
-
- if (hasError) {
- handleSupplicantStateError(error);
- }
- }
-
- private void handleSupplicantStateError(int supplicantError) {
- if (supplicantError == WifiManager.ERROR_AUTHENTICATING) {
- if (mCallback != null) {
- if (mLastAuthenticatingAp != null) {
- mCallback.onRetryPassword(mLastAuthenticatingAp);
- }
- }
- }
- }
-
- private void handleNetworkIdsChanged() {
- synchronized (this) {
- final List<WifiConfiguration> configs = getConfiguredNetworks();
-
- for (int i = configs.size() - 1; i >= 0; i--) {
- final WifiConfiguration config = configs.get(i);
-
- AccessPointState ap;
- // Since network IDs have changed, we can't use it to find our previous AP state
- ap = findApLocked(AccessPointState.NETWORK_ID_ANY, config.BSSID, config.SSID,
- AccessPointState.getWifiConfigurationSecurity(config));
-
- if (ap == null) {
- continue;
- }
-
- ap.setNetworkId(config.networkId);
- }
- }
- }
-
- private class MyHandler extends Handler {
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_ATTEMPT_SCAN:
- attemptScan();
- break;
- }
- }
- }
-
-}
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index cac77e3..d389cae 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,463 +19,482 @@ package com.android.settings.wifi;
import com.android.settings.ProgressCategory;
import com.android.settings.R;
-import android.app.Dialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.wifi.ScanResult;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiConfiguration.Status;
+import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
-import android.preference.CheckBoxPreference;
-import android.provider.Settings;
+import android.provider.Settings.Secure;
import android.security.Credentials;
import android.security.KeyStore;
-import android.util.Log;
+import android.text.TextUtils;
import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.widget.AdapterView;
-import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.Toast;
-import java.util.Set;
-import java.util.WeakHashMap;
-
-/**
- * Settings screen for WiFi. This will be launched from the main system settings.
- */
-public class WifiSettings extends PreferenceActivity implements WifiLayer.Callback,
- DialogInterface.OnDismissListener {
-
- private static final String TAG = "WifiSettings";
-
- //============================
- // Preference/activity member variables
- //============================
-
- private static final String INSTANCE_KEY_DIALOG_BUNDLE =
- "com.android.settings.wifi.WifiSettings:dialogBundle";
- /*
- * We don't use Activity's dialog management because AlertDialog isn't fully
- * able to change many of its features after it's been created, and the
- * dialog management only creates once.
- */
- private Dialog mDialog;
-
- private static final String KEY_ONLY_ACCESS_POINTS = "only_access_points";
- private static final String KEY_ADD_OTHER_NETWORK = "add_other_network";
-
- private static final int CONTEXT_MENU_ID_CONNECT = Menu.FIRST;
- private static final int CONTEXT_MENU_ID_FORGET = Menu.FIRST + 1;
- private static final int CONTEXT_MENU_ID_CHANGE_PASSWORD = Menu.FIRST + 2;
+import java.util.ArrayList;
+import java.util.List;
+public class WifiSettings extends PreferenceActivity implements DialogInterface.OnClickListener {
private static final int MENU_ID_SCAN = Menu.FIRST;
private static final int MENU_ID_ADVANCED = Menu.FIRST + 1;
+ private static final int MENU_ID_CONNECT = Menu.FIRST + 2;
+ private static final int MENU_ID_FORGET = Menu.FIRST + 3;
+ private static final int MENU_ID_MODIFY = Menu.FIRST + 4;
- private static final String KEY_WIFI_ENABLED = "wifi_enabled";
- private static final String KEY_OPEN_NETWORK_NOTIFICATIONS_ENABLED =
- "open_network_notifications_enabled";
- private static final String KEY_ACCESS_POINTS = "access_points";
+ private final IntentFilter mFilter;
+ private final BroadcastReceiver mReceiver;
+ private final Scanner mScanner;
- private ProgressCategory mApCategory;
- private CheckBoxPreference mWifiEnabled;
+ private WifiManager mWifiManager;
private WifiEnabler mWifiEnabler;
- private CheckBoxPreference mOpenNetworkNotificationsEnabled;
- private Preference mAddOtherNetwork;
+ private CheckBoxPreference mNotifyOpenNetworks;
+ private ProgressCategory mAccessPoints;
+ private Preference mAddNetwork;
- private WeakHashMap<AccessPointState, AccessPointPreference> mAps;
+ private DetailedState mLastState;
+ private WifiInfo mLastInfo;
+ private int mLastPriority;
- private KeyStore mKeyStore = KeyStore.getInstance();
- private AccessPointState mResumeState = null;
- private int mResumeMode;
+ private boolean mResetNetworks = false;
+ private int mKeyStoreNetworkId = -1;
- //============================
- // Wifi member variables
- //============================
-
- private WifiLayer mWifiLayer;
-
- //============================
- // Activity lifecycle
- //============================
+ private AccessPoint mSelected;
+ private WifiDialog mDialog;
public WifiSettings() {
- mAps = new WeakHashMap<AccessPointState, AccessPointPreference>();
- mWifiLayer = new WifiLayer(this, this);
+ mFilter = new IntentFilter();
+ mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+ mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
+ mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+ mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
+
+ mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ handleEvent(intent);
+ }
+ };
+
+ mScanner = new Scanner();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- onCreatePreferences();
- mWifiLayer.onCreate();
+ mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
- onCreatedWifi();
- mWifiLayer.onCreatedCallback();
- }
-
- private int getPreferenceResource() {
- if (getIntent().getBooleanExtra(KEY_ONLY_ACCESS_POINTS, false)) {
- return R.xml.wifi_access_points;
+ if (getIntent().getBooleanExtra("only_access_points", false)) {
+ addPreferencesFromResource(R.xml.wifi_access_points);
} else {
- return R.xml.wifi_settings;
- }
- }
-
- /**
- * Shouldn't have any dependency on the wifi layer.
- */
- private void onCreatePreferences() {
- addPreferencesFromResource(getPreferenceResource());
-
- final PreferenceScreen preferenceScreen = getPreferenceScreen();
-
- mApCategory = (ProgressCategory) preferenceScreen.findPreference(KEY_ACCESS_POINTS);
- // We don't want the ordering to be the order preferences are added,
- // instead we want*:
- // 1) preferred, visible APs
- // 2) visible APs
- // 3) preferred, APs out of range
- // * this ordering logic is in AccessPointPreference's compareTo
- mApCategory.setOrderingAsAdded(false);
-
- if (!getIntent().getBooleanExtra(KEY_ONLY_ACCESS_POINTS, false)) {
- mWifiEnabled = (CheckBoxPreference) preferenceScreen.findPreference(KEY_WIFI_ENABLED);
- mWifiEnabler = new WifiEnabler(this, (WifiManager) getSystemService(WIFI_SERVICE),
- mWifiEnabled);
-
- mOpenNetworkNotificationsEnabled = (CheckBoxPreference) preferenceScreen
- .findPreference(KEY_OPEN_NETWORK_NOTIFICATIONS_ENABLED);
- mOpenNetworkNotificationsEnabled.setChecked(Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
+ addPreferencesFromResource(R.xml.wifi_settings);
+ mWifiEnabler = new WifiEnabler(this,
+ (CheckBoxPreference) findPreference("enable_wifi"));
+ mNotifyOpenNetworks =
+ (CheckBoxPreference) findPreference("notify_open_networks");
+ mNotifyOpenNetworks.setChecked(Secure.getInt(getContentResolver(),
+ Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
}
- mAddOtherNetwork = preferenceScreen.findPreference(KEY_ADD_OTHER_NETWORK);
+ mAccessPoints = (ProgressCategory) findPreference("access_points");
+ mAccessPoints.setOrderingAsAdded(false);
+ mAddNetwork = findPreference("add_network");
registerForContextMenu(getListView());
}
- private void onCreatedWifi() {
- }
-
@Override
protected void onResume() {
super.onResume();
- mWifiLayer.onResume();
if (mWifiEnabler != null) {
mWifiEnabler.resume();
}
- // do what we should have after keystore is unlocked.
- if (mResumeState != null) {
- if (mKeyStore.test() == KeyStore.NO_ERROR) {
- showAccessPointDialog(mResumeState, mResumeMode);
- }
- mResumeMode = -1;
- mResumeState = null;
- } else {
- if (mResumeMode == AccessPointDialog.MODE_CONFIGURE) {
- if (mKeyStore.test() == KeyStore.NO_ERROR) {
- ((AccessPointDialog) mDialog).enableEnterpriseFields();
- }
- }
+ registerReceiver(mReceiver, mFilter);
+ if (mKeyStoreNetworkId != -1 && KeyStore.getInstance().test() == KeyStore.NO_ERROR) {
+ connect(mKeyStoreNetworkId);
}
+ mKeyStoreNetworkId = -1;
}
@Override
protected void onPause() {
super.onPause();
- mWifiLayer.onPause();
if (mWifiEnabler != null) {
mWifiEnabler.pause();
}
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
-
+ unregisterReceiver(mReceiver);
+ mScanner.pause();
if (mDialog != null) {
mDialog.dismiss();
+ mDialog = null;
+ }
+ if (mResetNetworks) {
+ enableNetworks();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
-
- menu.add(0, MENU_ID_SCAN, 0, R.string.scan_wifi)
- .setIcon(R.drawable.ic_menu_scan_network);
-
- menu.add(0, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)
- .setIcon(android.R.drawable.ic_menu_manage);
-
- return true;
+ menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan)
+ .setIcon(R.drawable.ic_menu_scan_network);
+ menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)
+ .setIcon(android.R.drawable.ic_menu_manage);
+ return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- super.onOptionsItemSelected(item);
-
switch (item.getItemId()) {
-
case MENU_ID_SCAN:
- mWifiLayer.attemptScan();
+ if (mWifiManager.isWifiEnabled()) {
+ mScanner.resume();
+ }
return true;
-
case MENU_ID_ADVANCED:
- Intent intent = new Intent(this, AdvancedSettings.class);
- startActivity(intent);
+ startActivity(new Intent(this, AdvancedSettings.class));
return true;
-
- default:
- return false;
}
+ return super.onOptionsItemSelected(item);
}
@Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
-
- if (mDialog != null) {
- Bundle dialogBundle = mDialog.onSaveInstanceState();
- outState.putBundle(INSTANCE_KEY_DIALOG_BUNDLE, dialogBundle);
- }
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle state) {
- super.onRestoreInstanceState(state);
-
- Bundle dialogBundle = state.getBundle(INSTANCE_KEY_DIALOG_BUNDLE);
- if (dialogBundle != null) {
- mDialog = new AccessPointDialog(this, mWifiLayer);
- mDialog.onRestoreInstanceState(dialogBundle);
- showDialog(mDialog);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public void onDismiss(DialogInterface dialog) {
- if (dialog == mDialog) {
- mDialog = null;
- mResumeMode = -1;
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, v, menuInfo);
-
- AccessPointState state = getStateFromMenuInfo(menuInfo);
- if (state == null) {
- return;
- }
-
- menu.setHeaderTitle(state.getHumanReadableSsid());
-
- if (state.isConnectable()) {
- menu.add(0, CONTEXT_MENU_ID_CONNECT, 0, R.string.wifi_context_menu_connect);
- }
-
- if (state.isForgetable()) {
- menu.add(0, CONTEXT_MENU_ID_FORGET, 1, R.string.wifi_context_menu_forget);
-
- if (state.hasPassword()) {
- menu.add(0, CONTEXT_MENU_ID_CHANGE_PASSWORD, 2,
- R.string.wifi_context_menu_change_password);
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
+ if (info instanceof AdapterContextMenuInfo) {
+ Preference preference = (Preference) getListView().getItemAtPosition(
+ ((AdapterContextMenuInfo) info).position);
+
+ if (preference instanceof AccessPoint) {
+ mSelected = (AccessPoint) preference;
+ menu.setHeaderTitle(mSelected.ssid);
+ if (mSelected.getLevel() != -1 && mSelected.getState() == null) {
+ menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
+ }
+ if (mSelected.networkId != -1) {
+ menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget);
+ if (mSelected.security != AccessPoint.SECURITY_NONE) {
+ menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify);
+ }
+ }
}
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
-
- AccessPointState state = getStateFromMenuInfo(item.getMenuInfo());
- if (state == null) {
- return false;
+ if (mSelected == null) {
+ return super.onContextItemSelected(item);
}
-
switch (item.getItemId()) {
-
- case CONTEXT_MENU_ID_CONNECT:
- connectToNetwork(state);
+ case MENU_ID_CONNECT:
+ if (mSelected.networkId != -1) {
+ if (!requireKeyStore(mSelected.getConfig())) {
+ connect(mSelected.networkId);
+ }
+ } else if (mSelected.security == AccessPoint.SECURITY_NONE) {
+ // Shortcut for open networks.
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = AccessPoint.convertToQuotedString(mSelected.ssid);
+ config.allowedKeyManagement.set(KeyMgmt.NONE);
+ int networkId = mWifiManager.addNetwork(config);
+ mWifiManager.enableNetwork(networkId, false);
+ connect(networkId);
+ } else {
+ showDialog(mSelected, false);
+ }
return true;
-
- case CONTEXT_MENU_ID_FORGET:
- mWifiLayer.forgetNetwork(state);
+ case MENU_ID_FORGET:
+ forget(mSelected.networkId);
return true;
-
- case CONTEXT_MENU_ID_CHANGE_PASSWORD:
- showAccessPointDialog(state, AccessPointDialog.MODE_CONFIGURE);
+ case MENU_ID_MODIFY:
+ showDialog(mSelected, true);
return true;
-
- default:
- return false;
}
+ return super.onContextItemSelected(item);
}
- /**
- * Decides what needs to happen to connect to a particular access point. If
- * it is secured and doesn't already have a password, it will bring up a
- * password box. Otherwise it will just connect.
- */
- private void connectToNetwork(AccessPointState state) {
- if (state.hasSecurity() && !state.hasPassword()) {
- showAccessPointDialog(state, AccessPointDialog.MODE_INFO);
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
+ if (preference instanceof AccessPoint) {
+ mSelected = (AccessPoint) preference;
+ showDialog(mSelected, false);
+ } else if (preference == mAddNetwork) {
+ mSelected = null;
+ showDialog(null, true);
+ } else if (preference == mNotifyOpenNetworks) {
+ Secure.putInt(getContentResolver(),
+ Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ mNotifyOpenNetworks.isChecked() ? 1 : 0);
} else {
- mWifiLayer.connectToNetwork(state);
+ return super.onPreferenceTreeClick(screen, preference);
}
+ return true;
}
- private AccessPointState getStateFromMenuInfo(ContextMenuInfo menuInfo) {
- if ((menuInfo == null) || !(menuInfo instanceof AdapterContextMenuInfo)) {
- return null;
- }
+ public void onClick(DialogInterface dialogInterface, int button) {
+ if (button == WifiDialog.BUTTON_FORGET && mSelected != null) {
+ forget(mSelected.networkId);
+ } else if (button == WifiDialog.BUTTON_SUBMIT && mDialog != null) {
+ WifiConfiguration config = mDialog.getConfig();
- AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo;
- Preference pref = (Preference) getPreferenceScreen().getRootAdapter().getItem(
- adapterMenuInfo.position);
- if (pref == null || !(pref instanceof AccessPointPreference)) {
- return null;
+ if (config == null) {
+ if (mSelected != null && !requireKeyStore(mSelected.getConfig())) {
+ connect(mSelected.networkId);
+ }
+ } else if (config.networkId != -1) {
+ if (mSelected != null) {
+ mWifiManager.updateNetwork(config);
+ saveNetworks();
+ }
+ } else {
+ int networkId = mWifiManager.addNetwork(config);
+ if (networkId != -1) {
+ mWifiManager.enableNetwork(networkId, false);
+ config.networkId = networkId;
+ if (mDialog.edit || requireKeyStore(config)) {
+ saveNetworks();
+ } else {
+ connect(networkId);
+ }
+ }
+ }
}
-
- return ((AccessPointPreference) pref).getAccessPointState();
}
- //============================
- // Preference callbacks
- //============================
-
- @Override
- public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
- super.onPreferenceTreeClick(preferenceScreen, preference);
-
- if (preference == mAddOtherNetwork) {
- showAddOtherNetworkDialog();
- } else if (preference == mOpenNetworkNotificationsEnabled) {
- Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
- mOpenNetworkNotificationsEnabled.isChecked() ? 1 : 0);
- } else if (preference instanceof AccessPointPreference) {
- AccessPointState state = ((AccessPointPreference) preference).getAccessPointState();
- showAccessPointDialog(state, AccessPointDialog.MODE_INFO);
+ private void showDialog(AccessPoint accessPoint, boolean edit) {
+ if (mDialog != null) {
+ mDialog.dismiss();
}
-
- return false;
+ mDialog = new WifiDialog(this, this, accessPoint, edit);
+ mDialog.show();
}
- //============================
- // Wifi-related
- //============================
-
- public WifiLayer getWifiLayer() {
- return mWifiLayer;
+ private boolean requireKeyStore(WifiConfiguration config) {
+ if (WifiDialog.requireKeyStore(config) &&
+ KeyStore.getInstance().test() != KeyStore.NO_ERROR) {
+ mKeyStoreNetworkId = config.networkId;
+ Credentials.getInstance().unlock(this);
+ return true;
+ }
+ return false;
}
- private void showAddOtherNetworkDialog() {
- AccessPointDialog dialog = new AccessPointDialog(this, mWifiLayer);
- dialog.setState(new AccessPointState(this));
- dialog.setMode(AccessPointDialog.MODE_CONFIGURE);
- dialog.setTitle(R.string.wifi_add_other_network);
- dialog.setAutoSecurityAllowed(false);
- mResumeMode = AccessPointDialog.MODE_CONFIGURE;
- showDialog(dialog);
+ private void forget(int networkId) {
+ mWifiManager.removeNetwork(networkId);
+ saveNetworks();
}
- public void showAccessPointDialog(AccessPointState state, int mode) {
- if (state.isEnterprise() && mKeyStore.test() != KeyStore.NO_ERROR) {
- Credentials.getInstance().unlock(this);
- mResumeState = state;
- mResumeMode = mode;
+ private void connect(int networkId) {
+ if (networkId == -1) {
return;
}
- AccessPointDialog dialog = new AccessPointDialog(this, mWifiLayer);
- dialog.setMode(mode);
- dialog.setState(state);
- showDialog(dialog);
- }
- private void showDialog(Dialog dialog) {
- // Have only one dialog open at a time
- if (mDialog != null) {
- mDialog.dismiss();
+ // Reset the priority of each network if it goes too high.
+ if (mLastPriority > 1000000) {
+ for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) {
+ AccessPoint accessPoint = (AccessPoint) mAccessPoints.getPreference(i);
+ if (accessPoint.networkId != -1) {
+ WifiConfiguration config = new WifiConfiguration();
+ config.networkId = accessPoint.networkId;
+ config.priority = 0;
+ mWifiManager.updateNetwork(config);
+ }
+ }
+ mLastPriority = 0;
}
- mDialog = dialog;
- if (dialog != null) {
- dialog.setOnDismissListener(this);
- dialog.show();
- }
+ // Set to the highest priority and save the configuration.
+ WifiConfiguration config = new WifiConfiguration();
+ config.networkId = networkId;
+ config.priority = ++mLastPriority;
+ mWifiManager.updateNetwork(config);
+ saveNetworks();
+
+ // Connect to network by disabling others.
+ mWifiManager.enableNetwork(networkId, true);
+ mWifiManager.reconnect();
+ mResetNetworks = true;
}
- //============================
- // Wifi callbacks
- //============================
-
- public void onError(int messageResId) {
- Toast.makeText(this, messageResId, Toast.LENGTH_LONG).show();
+ private void enableNetworks() {
+ for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) {
+ WifiConfiguration config = ((AccessPoint) mAccessPoints.getPreference(i)).getConfig();
+ if (config != null && config.status != Status.ENABLED) {
+ mWifiManager.enableNetwork(config.networkId, false);
+ }
+ }
+ mResetNetworks = false;
}
- public void onScanningStatusChanged(boolean started) {
- mApCategory.setProgress(started);
+ private void saveNetworks() {
+ // Always save the configuration with all networks enabled.
+ enableNetworks();
+ mWifiManager.saveConfiguration();
+ updateAccessPoints();
}
- public void onAccessPointSetChanged(AccessPointState ap, boolean added) {
+ private void updateAccessPoints() {
+ List<AccessPoint> accessPoints = new ArrayList<AccessPoint>();
- AccessPointPreference pref = mAps.get(ap);
+ List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+ if (configs != null) {
+ mLastPriority = 0;
+ for (WifiConfiguration config : configs) {
+ if (config.priority > mLastPriority) {
+ mLastPriority = config.priority;
+ }
- if (WifiLayer.LOGV) {
- Log.v(TAG, "onAccessPointSetChanged with " + ap + " and "
- + (added ? "added" : "removed") + ", found pref " + pref);
+ // Shift the status to make enableNetworks() more efficient.
+ if (config.status == Status.CURRENT) {
+ config.status = Status.ENABLED;
+ } else if (mResetNetworks && config.status == Status.DISABLED) {
+ config.status = Status.CURRENT;
+ }
+
+ AccessPoint accessPoint = new AccessPoint(this, config);
+ accessPoint.update(mLastInfo, mLastState);
+ accessPoints.add(accessPoint);
+ }
}
- if (added) {
+ List<ScanResult> results = mWifiManager.getScanResults();
+ if (results != null) {
+ for (ScanResult result : results) {
+ // Ignore hidden and ad-hoc networks.
+ if (result.SSID == null || result.SSID.length() == 0 ||
+ result.capabilities.contains("[IBSS]")) {
+ continue;
+ }
- if (pref == null) {
- pref = new AccessPointPreference(this, ap);
- mAps.put(ap, pref);
- } else {
- pref.setEnabled(true);
+ boolean found = false;
+ for (AccessPoint accessPoint : accessPoints) {
+ if (accessPoint.update(result)) {
+ found = true;
+ }
+ }
+ if (!found) {
+ accessPoints.add(new AccessPoint(this, result));
+ }
}
+ }
- mApCategory.addPreference(pref);
+ mAccessPoints.removeAll();
+ for (AccessPoint accessPoint : accessPoints) {
+ mAccessPoints.addPreference(accessPoint);
+ }
+ }
+ private void handleEvent(Intent intent) {
+ String action = intent.getAction();
+ if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
+ updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_UNKNOWN));
+ } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
+ updateAccessPoints();
+ } else if (WifiManager.NETWORK_IDS_CHANGED_ACTION.equals(action)) {
+ if (mSelected != null && mSelected.networkId != -1) {
+ mSelected = null;
+ }
+ updateAccessPoints();
+ } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
+ updateConnectionState(WifiInfo.getDetailedStateOf((SupplicantState)
+ intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
+ } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
+ updateConnectionState(((NetworkInfo) intent.getParcelableExtra(
+ WifiManager.EXTRA_NETWORK_INFO)).getDetailedState());
+ } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
+ updateConnectionState(null);
+ }
+ }
+
+ private void updateConnectionState(DetailedState state) {
+ /* sticky broadcasts can call this when wifi is disabled */
+ if (!mWifiManager.isWifiEnabled()) {
+ mScanner.pause();
+ return;
+ }
+
+ if (state == DetailedState.OBTAINING_IPADDR) {
+ mScanner.pause();
} else {
+ mScanner.resume();
+ }
- mAps.remove(ap);
+ mLastInfo = mWifiManager.getConnectionInfo();
+ if (state != null) {
+ mLastState = state;
+ }
- if (pref != null) {
- mApCategory.removePreference(pref);
- }
+ for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) {
+ ((AccessPoint) mAccessPoints.getPreference(i)).update(mLastInfo, mLastState);
+ }
+ if (mResetNetworks && (state == DetailedState.CONNECTED ||
+ state == DetailedState.DISCONNECTED || state == DetailedState.FAILED)) {
+ updateAccessPoints();
+ enableNetworks();
}
}
- public void onAccessPointsStateChanged(boolean enabled) {
- if (enabled) {
- mApCategory.setEnabled(true);
+ private void updateWifiState(int state) {
+ if (state == WifiManager.WIFI_STATE_ENABLED) {
+ mScanner.resume();
+ updateAccessPoints();
} else {
- mApCategory.removeAll();
- mAps.clear();
+ mScanner.pause();
+ mAccessPoints.removeAll();
}
-
- mAddOtherNetwork.setEnabled(enabled);
}
- public void onRetryPassword(AccessPointState ap) {
+ private class Scanner extends Handler {
+ private int mRetry = 0;
- if ((mDialog != null) && mDialog.isShowing()) {
- // If we're already showing a dialog, ignore this request
- return;
+ void resume() {
+ if (!hasMessages(0)) {
+ sendEmptyMessage(0);
+ }
}
- showAccessPointDialog(ap, AccessPointDialog.MODE_RETRY_PASSWORD);
- }
+ void pause() {
+ mRetry = 0;
+ mAccessPoints.setProgress(false);
+ removeMessages(0);
+ }
+ @Override
+ public void handleMessage(Message message) {
+ if (mWifiManager.startScanActive()) {
+ mRetry = 0;
+ } else if (++mRetry >= 3) {
+ mRetry = 0;
+ Toast.makeText(WifiSettings.this, R.string.wifi_fail_to_scan,
+ Toast.LENGTH_LONG).show();
+ return;
+ }
+ mAccessPoints.setProgress(mRetry != 0);
+ sendEmptyMessageDelayed(0, 6000);
+ }
+ }
}
diff --git a/src/com/android/settings/wifi/WifiStatus.java b/src/com/android/settings/wifi/WifiStatus.java
deleted file mode 100644
index e10ab8d..0000000
--- a/src/com/android/settings/wifi/WifiStatus.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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 com.android.settings.wifi;
-
-import com.android.settings.R;
-
-import android.content.Context;
-import android.net.NetworkInfo;
-import android.text.TextUtils;
-
-public class WifiStatus {
- public static String getStatus(Context context, String ssid,
- NetworkInfo.DetailedState detailedState) {
-
- if (!TextUtils.isEmpty(ssid) && isLiveConnection(detailedState)) {
- return getPrintableFragment(context, detailedState, ssid);
- } else {
- return getPrintable(context, detailedState);
- }
- }
-
- public static boolean isLiveConnection(NetworkInfo.DetailedState detailedState) {
- return detailedState != NetworkInfo.DetailedState.DISCONNECTED
- && detailedState != NetworkInfo.DetailedState.FAILED
- && detailedState != NetworkInfo.DetailedState.IDLE
- && detailedState != NetworkInfo.DetailedState.SCANNING;
- }
-
- public static String getPrintable(Context context,
- NetworkInfo.DetailedState detailedState) {
-
- switch (detailedState) {
- case AUTHENTICATING:
- return context.getString(R.string.status_authenticating);
- case CONNECTED:
- return context.getString(R.string.status_connected);
- case CONNECTING:
- return context.getString(R.string.status_connecting);
- case DISCONNECTED:
- return context.getString(R.string.status_disconnected);
- case DISCONNECTING:
- return context.getString(R.string.status_disconnecting);
- case FAILED:
- return context.getString(R.string.status_failed);
- case OBTAINING_IPADDR:
- return context.getString(R.string.status_obtaining_ip);
- case SCANNING:
- return context.getString(R.string.status_scanning);
- default:
- return null;
- }
- }
-
- public static String getPrintableFragment(Context context,
- NetworkInfo.DetailedState detailedState, String apName) {
-
- String fragment = null;
- switch (detailedState) {
- case AUTHENTICATING:
- fragment = context.getString(R.string.fragment_status_authenticating);
- break;
- case CONNECTED:
- fragment = context.getString(R.string.fragment_status_connected);
- break;
- case CONNECTING:
- fragment = context.getString(R.string.fragment_status_connecting);
- break;
- case DISCONNECTED:
- fragment = context.getString(R.string.fragment_status_disconnected);
- break;
- case DISCONNECTING:
- fragment = context.getString(R.string.fragment_status_disconnecting);
- break;
- case FAILED:
- fragment = context.getString(R.string.fragment_status_failed);
- break;
- case OBTAINING_IPADDR:
- fragment = context.getString(R.string.fragment_status_obtaining_ip);
- break;
- case SCANNING:
- fragment = context.getString(R.string.fragment_status_scanning);
- break;
- }
-
- return String.format(fragment, apName);
- }
-
-}
diff --git a/src/com/android/settings/wifi/WifiStatusTest.java b/src/com/android/settings/wifi/WifiStatusTest.java
new file mode 100644
index 0000000..1b23834
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiStatusTest.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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 com.android.settings.wifi;
+
+import com.android.settings.R;
+import android.net.wifi.ScanResult;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import java.util.List;
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.NetworkInfo;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.TextView;
+import java.io.IOException;
+import java.net.UnknownHostException;
+
+
+/**
+ * Show the current status details of Wifi related fields
+ */
+public class WifiStatusTest extends Activity {
+
+ private static final String TAG = "WifiStatusTest";
+
+ private Button updateButton;
+ private TextView mWifiState;
+ private TextView mNetworkState;
+ private TextView mSupplicantState;
+ private TextView mRSSI;
+ private TextView mBSSID;
+ private TextView mSSID;
+ private TextView mHiddenSSID;
+ private TextView mIPAddr;
+ private TextView mMACAddr;
+ private TextView mNetworkId;
+ private TextView mLinkSpeed;
+ private TextView mScanList;
+
+
+ private TextView mPingIpAddr;
+ private TextView mPingHostname;
+ private TextView mHttpClientTest;
+ private Button pingTestButton;
+
+ private String mPingIpAddrResult;
+ private String mPingHostnameResult;
+ private String mHttpClientTestResult;
+
+
+ private WifiManager mWifiManager;
+ private IntentFilter mWifiStateFilter;
+
+
+ //============================
+ // Activity lifecycle
+ //============================
+
+ private final BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+ handleWifiStateChanged(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_UNKNOWN));
+ } else if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+ handleNetworkStateChanged(
+ (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO));
+ } else if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+ handleScanResultsAvailable();
+ } else if (intent.getAction().equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
+ /* TODO: handle supplicant connection change later */
+ } else if (intent.getAction().equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) {
+ handleSupplicantStateChanged(
+ (SupplicantState) intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE),
+ intent.hasExtra(WifiManager.EXTRA_SUPPLICANT_ERROR),
+ intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 0));
+ } else if (intent.getAction().equals(WifiManager.RSSI_CHANGED_ACTION)) {
+ handleSignalChanged(intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, 0));
+ } else if (intent.getAction().equals(WifiManager.NETWORK_IDS_CHANGED_ACTION)) {
+ /* TODO: handle network id change info later */
+ } else {
+ Log.e(TAG, "Received an unknown Wifi Intent");
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mWifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
+
+ mWifiStateFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ mWifiStateFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ mWifiStateFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+ mWifiStateFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+ mWifiStateFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
+ mWifiStateFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+
+ registerReceiver(mWifiStateReceiver, mWifiStateFilter);
+
+ setContentView(R.layout.wifi_status_test);
+
+ updateButton = (Button) findViewById(R.id.update);
+ updateButton.setOnClickListener(updateButtonHandler);
+
+ mWifiState = (TextView) findViewById(R.id.wifi_state);
+ mNetworkState = (TextView) findViewById(R.id.network_state);
+ mSupplicantState = (TextView) findViewById(R.id.supplicant_state);
+ mRSSI = (TextView) findViewById(R.id.rssi);
+ mBSSID = (TextView) findViewById(R.id.bssid);
+ mSSID = (TextView) findViewById(R.id.ssid);
+ mHiddenSSID = (TextView) findViewById(R.id.hidden_ssid);
+ mIPAddr = (TextView) findViewById(R.id.ipaddr);
+ mMACAddr = (TextView) findViewById(R.id.macaddr);
+ mNetworkId = (TextView) findViewById(R.id.networkid);
+ mLinkSpeed = (TextView) findViewById(R.id.link_speed);
+ mScanList = (TextView) findViewById(R.id.scan_list);
+
+
+ mPingIpAddr = (TextView) findViewById(R.id.pingIpAddr);
+ mPingHostname = (TextView) findViewById(R.id.pingHostname);
+ mHttpClientTest = (TextView) findViewById(R.id.httpClientTest);
+
+ pingTestButton = (Button) findViewById(R.id.ping_test);
+ pingTestButton.setOnClickListener(mPingButtonHandler);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ registerReceiver(mWifiStateReceiver, mWifiStateFilter);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ unregisterReceiver(mWifiStateReceiver);
+ }
+
+ OnClickListener mPingButtonHandler = new OnClickListener() {
+ public void onClick(View v) {
+ updatePingState();
+ }
+ };
+
+ OnClickListener updateButtonHandler = new OnClickListener() {
+ public void onClick(View v) {
+ final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+
+ setWifiStateText(mWifiManager.getWifiState());
+ mBSSID.setText(wifiInfo.getBSSID());
+ mHiddenSSID.setText(String.valueOf(wifiInfo.getHiddenSSID()));
+ int ipAddr = wifiInfo.getIpAddress();
+ StringBuffer ipBuf = new StringBuffer();
+ ipBuf.append(ipAddr & 0xff).append('.').
+ append((ipAddr >>>= 8) & 0xff).append('.').
+ append((ipAddr >>>= 8) & 0xff).append('.').
+ append((ipAddr >>>= 8) & 0xff);
+
+ mIPAddr.setText(ipBuf);
+ mLinkSpeed.setText(String.valueOf(wifiInfo.getLinkSpeed())+" Mbps");
+ mMACAddr.setText(wifiInfo.getMacAddress());
+ mNetworkId.setText(String.valueOf(wifiInfo.getNetworkId()));
+ mRSSI.setText(String.valueOf(wifiInfo.getRssi()));
+ mSSID.setText(wifiInfo.getSSID());
+
+ SupplicantState supplicantState = wifiInfo.getSupplicantState();
+ setSupplicantStateText(supplicantState);
+ }
+ };
+
+ private void setSupplicantStateText(SupplicantState supplicantState) {
+ if(SupplicantState.FOUR_WAY_HANDSHAKE.equals(supplicantState)) {
+ mSupplicantState.setText("FOUR WAY HANDSHAKE");
+ } else if(SupplicantState.ASSOCIATED.equals(supplicantState)) {
+ mSupplicantState.setText("ASSOCIATED");
+ } else if(SupplicantState.ASSOCIATING.equals(supplicantState)) {
+ mSupplicantState.setText("ASSOCIATING");
+ } else if(SupplicantState.COMPLETED.equals(supplicantState)) {
+ mSupplicantState.setText("COMPLETED");
+ } else if(SupplicantState.DISCONNECTED.equals(supplicantState)) {
+ mSupplicantState.setText("DISCONNECTED");
+ } else if(SupplicantState.DORMANT.equals(supplicantState)) {
+ mSupplicantState.setText("DORMANT");
+ } else if(SupplicantState.GROUP_HANDSHAKE.equals(supplicantState)) {
+ mSupplicantState.setText("GROUP HANDSHAKE");
+ } else if(SupplicantState.INACTIVE.equals(supplicantState)) {
+ mSupplicantState.setText("INACTIVE");
+ } else if(SupplicantState.INVALID.equals(supplicantState)) {
+ mSupplicantState.setText("INVALID");
+ } else if(SupplicantState.SCANNING.equals(supplicantState)) {
+ mSupplicantState.setText("SCANNING");
+ } else if(SupplicantState.UNINITIALIZED.equals(supplicantState)) {
+ mSupplicantState.setText("UNINITIALIZED");
+ } else {
+ mSupplicantState.setText("BAD");
+ Log.e(TAG, "supplicant state is bad");
+ }
+ }
+
+ private void setWifiStateText(int wifiState) {
+ String wifiStateString;
+ switch(wifiState) {
+ case WifiManager.WIFI_STATE_DISABLING:
+ wifiStateString = getString(R.string.wifi_state_disabling);
+ break;
+ case WifiManager.WIFI_STATE_DISABLED:
+ wifiStateString = getString(R.string.wifi_state_disabled);
+ break;
+ case WifiManager.WIFI_STATE_ENABLING:
+ wifiStateString = getString(R.string.wifi_state_enabling);
+ break;
+ case WifiManager.WIFI_STATE_ENABLED:
+ wifiStateString = getString(R.string.wifi_state_enabled);
+ break;
+ case WifiManager.WIFI_STATE_UNKNOWN:
+ wifiStateString = getString(R.string.wifi_state_unknown);
+ break;
+ default:
+ wifiStateString = "BAD";
+ Log.e(TAG, "wifi state is bad");
+ break;
+ }
+
+ mWifiState.setText(wifiStateString);
+ }
+
+ private void handleSignalChanged(int rssi) {
+ mRSSI.setText(String.valueOf(rssi));
+ }
+
+ private void handleWifiStateChanged(int wifiState) {
+ setWifiStateText(wifiState);
+ }
+
+ private void handleScanResultsAvailable() {
+ List<ScanResult> list = mWifiManager.getScanResults();
+
+ StringBuffer scanList = new StringBuffer();
+ if (list != null) {
+ for (int i = list.size() - 1; i >= 0; i--) {
+ final ScanResult scanResult = list.get(i);
+
+ if (scanResult == null) {
+ continue;
+ }
+
+ if (TextUtils.isEmpty(scanResult.SSID)) {
+ continue;
+ }
+
+ scanList.append(scanResult.SSID+" ");
+ }
+ }
+ mScanList.setText(scanList);
+ }
+
+ private void handleSupplicantStateChanged(SupplicantState state, boolean hasError, int error) {
+ if (hasError) {
+ mSupplicantState.setText("ERROR AUTHENTICATING");
+ } else {
+ setSupplicantStateText(state);
+ }
+ }
+
+ private void handleNetworkStateChanged(NetworkInfo networkInfo) {
+ if (mWifiManager.isWifiEnabled()) {
+ String summary = Summary.get(this, mWifiManager.getConnectionInfo().getSSID(),
+ networkInfo.getDetailedState());
+ mNetworkState.setText(summary);
+ }
+ }
+
+ private final void updatePingState() {
+ final Handler handler = new Handler();
+ // Set all to unknown since the threads will take a few secs to update.
+ mPingIpAddrResult = getResources().getString(R.string.radioInfo_unknown);
+ mPingHostnameResult = getResources().getString(R.string.radioInfo_unknown);
+ mHttpClientTestResult = getResources().getString(R.string.radioInfo_unknown);
+
+ mPingIpAddr.setText(mPingIpAddrResult);
+ mPingHostname.setText(mPingHostnameResult);
+ mHttpClientTest.setText(mHttpClientTestResult);
+
+ final Runnable updatePingResults = new Runnable() {
+ public void run() {
+ mPingIpAddr.setText(mPingIpAddrResult);
+ mPingHostname.setText(mPingHostnameResult);
+ mHttpClientTest.setText(mHttpClientTestResult);
+ }
+ };
+ Thread ipAddrThread = new Thread() {
+ @Override
+ public void run() {
+ pingIpAddr();
+ handler.post(updatePingResults);
+ }
+ };
+ ipAddrThread.start();
+
+ Thread hostnameThread = new Thread() {
+ @Override
+ public void run() {
+ pingHostname();
+ handler.post(updatePingResults);
+ }
+ };
+ hostnameThread.start();
+
+ Thread httpClientThread = new Thread() {
+ @Override
+ public void run() {
+ httpClientTest();
+ handler.post(updatePingResults);
+ }
+ };
+ httpClientThread.start();
+ }
+
+ /**
+ * The ping functions have been borrowed from Radio diagnostic app to
+ * enable quick access on the wifi status screen
+ */
+ private final void pingIpAddr() {
+ try {
+ // TODO: Hardcoded for now, make it UI configurable
+ String ipAddress = "74.125.47.104";
+ Process p = Runtime.getRuntime().exec("ping -c 1 -w 100 " + ipAddress);
+ int status = p.waitFor();
+ if (status == 0) {
+ mPingIpAddrResult = "Pass";
+ } else {
+ mPingIpAddrResult = "Fail: IP addr not reachable";
+ }
+ } catch (IOException e) {
+ mPingIpAddrResult = "Fail: IOException";
+ } catch (InterruptedException e) {
+ mPingIpAddrResult = "Fail: InterruptedException";
+ }
+ }
+
+ private final void pingHostname() {
+ try {
+ // TODO: Hardcoded for now, make it UI configurable
+ Process p = Runtime.getRuntime().exec("ping -c 1 -w 100 www.google.com");
+ int status = p.waitFor();
+ if (status == 0) {
+ mPingHostnameResult = "Pass";
+ } else {
+ mPingHostnameResult = "Fail: Host unreachable";
+ }
+ } catch (UnknownHostException e) {
+ mPingHostnameResult = "Fail: Unknown Host";
+ } catch (IOException e) {
+ mPingHostnameResult= "Fail: IOException";
+ } catch (InterruptedException e) {
+ mPingHostnameResult = "Fail: InterruptedException";
+ }
+ }
+
+ private void httpClientTest() {
+ HttpClient client = new DefaultHttpClient();
+ try {
+ // TODO: Hardcoded for now, make it UI configurable
+ HttpGet request = new HttpGet("http://www.google.com");
+ HttpResponse response = client.execute(request);
+ if (response.getStatusLine().getStatusCode() == 200) {
+ mHttpClientTestResult = "Pass";
+ } else {
+ mHttpClientTestResult = "Fail: Code: " + String.valueOf(response);
+ }
+ request.abort();
+ } catch (IOException e) {
+ mHttpClientTestResult = "Fail: IOException";
+ }
+ }
+
+}