summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/settings/AccessibilitySettings.java276
-rw-r--r--src/com/android/settings/ApnEditor.java2
-rw-r--r--src/com/android/settings/ApnSettings.java2
-rw-r--r--src/com/android/settings/ApplicationSettings.java8
-rw-r--r--src/com/android/settings/DateTimeSettings.java5
-rw-r--r--src/com/android/settings/IccLockSettings.java (renamed from src/com/android/settings/SimLockSettings.java)103
-rw-r--r--src/com/android/settings/InstalledAppDetails.java283
-rw-r--r--src/com/android/settings/LocalePicker.java51
-rw-r--r--src/com/android/settings/RadioInfo.java54
-rw-r--r--src/com/android/settings/SecuritySettings.java117
-rw-r--r--src/com/android/settings/Settings.java2
-rw-r--r--src/com/android/settings/TextToSpeechSettings.java122
-rw-r--r--src/com/android/settings/battery_history/BatteryHistory.java8
-rw-r--r--src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java10
-rw-r--r--src/com/android/settings/bluetooth/BluetoothEnabler.java5
-rw-r--r--src/com/android/settings/bluetooth/BluetoothEventRedirector.java14
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothDevice.java98
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java30
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothManager.java18
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java19
-rw-r--r--src/com/android/settings/deviceinfo/Status.java7
-rw-r--r--src/com/android/settings/fuelgauge/PowerGaugePreference.java119
-rw-r--r--src/com/android/settings/fuelgauge/PowerUsageDetail.java156
-rw-r--r--src/com/android/settings/fuelgauge/PowerUsageSummary.java494
-rw-r--r--src/com/android/settings/widget/SettingsAppWidgetProvider.java404
-rw-r--r--src/com/android/settings/wifi/AccessPointDialog.java320
-rw-r--r--src/com/android/settings/wifi/AccessPointState.java105
-rw-r--r--src/com/android/settings/wifi/Keystore.java81
-rw-r--r--src/com/android/settings/wifi/WifiLayer.java1
29 files changed, 2488 insertions, 426 deletions
diff --git a/src/com/android/settings/AccessibilitySettings.java b/src/com/android/settings/AccessibilitySettings.java
new file mode 100644
index 0000000..45602bc
--- /dev/null
+++ b/src/com/android/settings/AccessibilitySettings.java
@@ -0,0 +1,276 @@
+/*
+ * 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;
+
+import android.app.AlertDialog;
+import android.app.Service;
+import android.content.DialogInterface;
+import android.content.pm.ServiceInfo;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.view.accessibility.AccessibilityManager;
+
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Activity with the accessibility settings.
+ */
+public class AccessibilitySettings extends PreferenceActivity {
+ private final String TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX =
+ "toggle_accessibility_service_checkbox";
+
+ private static final String ACCESSIBILITY_SERVICES_CATEGORY =
+ "accessibility_services_category";
+
+ private CheckBoxPreference mToggleCheckBox;
+
+ private Map<String, ServiceInfo> mAccessibilityServices =
+ new LinkedHashMap<String, ServiceInfo>();
+
+ private TextUtils.SimpleStringSplitter mStringColonSplitter =
+ new TextUtils.SimpleStringSplitter(':');
+
+ private PreferenceGroup mAccessibilityServicesCategory;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ addPreferencesFromResource(R.xml.accessibility_settings);
+
+ mToggleCheckBox = (CheckBoxPreference) findPreference(
+ TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX);
+
+ addAccessibilitServicePreferences();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ final HashSet<String> enabled = new HashSet<String>();
+ String settingValue = Settings.Secure.getString(getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ if (settingValue != null) {
+ TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
+ splitter.setString(settingValue);
+ while (splitter.hasNext()) {
+ enabled.add(splitter.next());
+ }
+ }
+
+ Map<String, ServiceInfo> accessibilityServices = mAccessibilityServices;
+
+ for (String key : accessibilityServices.keySet()) {
+ CheckBoxPreference preference = (CheckBoxPreference) findPreference(key);
+ if (preference != null) {
+ preference.setChecked(enabled.contains(key));
+ }
+ }
+
+ int serviceState = Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 0);
+
+ if (!accessibilityServices.isEmpty()) {
+ if (serviceState == 1) {
+ mToggleCheckBox.setChecked(true);
+ mToggleCheckBox.setSummaryOn(R.string.disable_accessibility_service_summary);
+ } else {
+ mToggleCheckBox.setSummaryOff(R.string.enable_accessibility_service_summary);
+ setAccessibilityServicePreferencesState(false);
+ }
+ mToggleCheckBox.setEnabled(true);
+ } else {
+ if (serviceState == 1) {
+ // no service and accessibility is enabled => disable
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 0);
+ setAccessibilityServicePreferencesState(false);
+ }
+ mToggleCheckBox.setSummaryOff(R.string.no_accessibility_services_summary);
+ mToggleCheckBox.setEnabled(false);
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ persistEnabledAccessibilityServices();
+ }
+
+ /**
+ * Sets the state of the preferences for enabling/disabling AccessibilityServices.
+ *
+ * @param isEnabled If to enable or disable the preferences.
+ */
+ private void setAccessibilityServicePreferencesState(boolean isEnabled) {
+ if (mAccessibilityServicesCategory == null) {
+ return;
+ }
+
+ int count = mAccessibilityServicesCategory.getPreferenceCount();
+ for (int i = 0; i < count; i++) {
+ mAccessibilityServicesCategory.getPreference(i).setEnabled(isEnabled);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ final String key = preference.getKey();
+
+ if (TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX.equals(key)) {
+ boolean isChecked = ((CheckBoxPreference) preference).isChecked();
+ handleEnableAccessibilityStateChange((CheckBoxPreference) preference);
+ } else if (preference instanceof CheckBoxPreference) {
+ handleEnableAccessibilityServiceStateChange((CheckBoxPreference) preference);
+ }
+
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
+ }
+
+ /**
+ * Handles the change of the accessibility enabled setting state.
+ *
+ * @param preference The preference for enabling/disabling accessibility.
+ */
+ private void handleEnableAccessibilityStateChange(CheckBoxPreference preference) {
+ if (preference.isChecked()) {
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 1);
+ setAccessibilityServicePreferencesState(true);
+ } else {
+ final CheckBoxPreference checkBoxPreference = preference;
+ AlertDialog dialog = (new AlertDialog.Builder(this))
+ .setTitle(android.R.string.dialog_alert_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(getString(R.string.accessibility_service_disable_warning))
+ .setCancelable(true)
+ .setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 0);
+ setAccessibilityServicePreferencesState(false);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ checkBoxPreference.setChecked(true);
+ }
+ })
+ .create();
+ dialog.show();
+ }
+ }
+
+ /**
+ * Handles the change of the preference for enabling/disabling an AccessibilityService.
+ *
+ * @param preference The preference.
+ */
+ private void handleEnableAccessibilityServiceStateChange(CheckBoxPreference preference) {
+ if (preference.isChecked()) {
+ final CheckBoxPreference checkBoxPreference = preference;
+ AlertDialog dialog = (new AlertDialog.Builder(this))
+ .setTitle(android.R.string.dialog_alert_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(getString(R.string.accessibility_service_security_warning,
+ mAccessibilityServices.get(preference.getKey())
+ .applicationInfo.loadLabel(getPackageManager())))
+ .setCancelable(true)
+ .setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ checkBoxPreference.setChecked(true);
+ persistEnabledAccessibilityServices();
+ }
+ })
+ .setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ checkBoxPreference.setChecked(false);
+ }
+ })
+ .create();
+ dialog.show();
+ } else {
+ persistEnabledAccessibilityServices();
+ }
+ }
+
+ /**
+ * Persists the Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES setting.
+ * The AccessibilityManagerService watches this property and manages the
+ * AccessibilityServices.
+ */
+ private void persistEnabledAccessibilityServices() {
+ StringBuilder builder = new StringBuilder(256);
+
+ int firstEnabled = -1;
+ for (String key : mAccessibilityServices.keySet()) {
+ CheckBoxPreference preference = (CheckBoxPreference) findPreference(key);
+ if (preference.isChecked()) {
+ builder.append(key);
+ builder.append(':');
+ }
+ }
+
+ Settings.Secure.putString(getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, builder.toString());
+ }
+
+ /**
+ * Adds {@link CheckBoxPreference} for enabling or disabling an accessibility services.
+ */
+ private void addAccessibilitServicePreferences() {
+ AccessibilityManager accessibilityManager =
+ (AccessibilityManager) getSystemService(Service.ACCESSIBILITY_SERVICE);
+
+ List<ServiceInfo> installedServices = accessibilityManager.getAccessibilityServiceList();
+
+ mAccessibilityServicesCategory =
+ (PreferenceGroup) findPreference(ACCESSIBILITY_SERVICES_CATEGORY);
+
+ if (installedServices.isEmpty()) {
+ getPreferenceScreen().removePreference(mAccessibilityServicesCategory);
+ mAccessibilityServicesCategory = null;
+ return;
+ }
+
+ for (int i = 0, count = installedServices.size(); i < count; ++i) {
+ ServiceInfo serviceInfo = installedServices.get(i);
+ String key = serviceInfo.packageName + "/" + serviceInfo.name;
+
+ mAccessibilityServices.put(key, serviceInfo);
+
+ CheckBoxPreference preference = new CheckBoxPreference(this);
+ preference.setKey(key);
+ preference.setTitle(serviceInfo.loadLabel(getPackageManager()));
+ mAccessibilityServicesCategory.addPreference(preference);
+ }
+ }
+}
diff --git a/src/com/android/settings/ApnEditor.java b/src/com/android/settings/ApnEditor.java
index f1fa2ef..0bd91a8 100644
--- a/src/com/android/settings/ApnEditor.java
+++ b/src/com/android/settings/ApnEditor.java
@@ -202,7 +202,7 @@ public class ApnEditor extends PreferenceActivity
mApnType.setText(mCursor.getString(TYPE_INDEX));
if (mNewApn) {
String numeric =
- SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC);
+ SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC);
// MCC is first 3 chars and then in 2 - 3 chars of MNC
if (numeric != null && numeric.length() > 4) {
// Country code
diff --git a/src/com/android/settings/ApnSettings.java b/src/com/android/settings/ApnSettings.java
index ecfdb24..2624990 100644
--- a/src/com/android/settings/ApnSettings.java
+++ b/src/com/android/settings/ApnSettings.java
@@ -146,7 +146,7 @@ public class ApnSettings extends PreferenceActivity implements
private void fillList() {
String where = "numeric=\""
- + android.os.SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC, "")
+ + android.os.SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "")
+ "\"";
Cursor cursor = managedQuery(Telephony.Carriers.CONTENT_URI, new String[] {
diff --git a/src/com/android/settings/ApplicationSettings.java b/src/com/android/settings/ApplicationSettings.java
index 85fe11f..6a8aa81 100644
--- a/src/com/android/settings/ApplicationSettings.java
+++ b/src/com/android/settings/ApplicationSettings.java
@@ -53,6 +53,14 @@ public class ApplicationSettings extends PreferenceActivity implements
}
@Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (mWarnInstallApps != null) {
+ mWarnInstallApps.dismiss();
+ }
+ }
+
+ @Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference == mToggleAppInstallation) {
if (mToggleAppInstallation.isChecked()) {
diff --git a/src/com/android/settings/DateTimeSettings.java b/src/com/android/settings/DateTimeSettings.java
index 1b9fecb..d6e85c4 100644
--- a/src/com/android/settings/DateTimeSettings.java
+++ b/src/com/android/settings/DateTimeSettings.java
@@ -109,14 +109,14 @@ public class DateTimeSettings
mTimePref.setEnabled(!autoEnabled);
mDatePref.setEnabled(!autoEnabled);
mTimeZone.setEnabled(!autoEnabled);
-
- getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
protected void onResume() {
super.onResume();
+
+ getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
((CheckBoxPreference)mTime24Pref).setChecked(is24Hour());
@@ -134,6 +134,7 @@ public class DateTimeSettings
protected void onPause() {
super.onPause();
unregisterReceiver(mIntentReceiver);
+ getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}
private void updateTimeAndDateDisplay() {
diff --git a/src/com/android/settings/SimLockSettings.java b/src/com/android/settings/IccLockSettings.java
index 286e3d6..18beb32 100644
--- a/src/com/android/settings/SimLockSettings.java
+++ b/src/com/android/settings/IccLockSettings.java
@@ -22,35 +22,36 @@ import android.os.AsyncResult;
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.CheckBoxPreference;
import android.preference.PreferenceScreen;
+import android.widget.Toast;
+
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
-import android.widget.Toast;
/**
- * Implements the preference screen to enable/disable SIM lock and
- * also the dialogs to change the SIM PIN. In the former case, enabling/disabling
- * the SIM lock will prompt the user for the current PIN.
+ * Implements the preference screen to enable/disable ICC lock and
+ * also the dialogs to change the ICC PIN. In the former case, enabling/disabling
+ * the ICC lock will prompt the user for the current PIN.
* In the Change PIN case, it prompts the user for old pin, new pin and new pin
* again before attempting to change it. Calls the SimCard interface to execute
* these operations.
*
*/
-public class SimLockSettings extends PreferenceActivity
+public class IccLockSettings extends PreferenceActivity
implements EditPinPreference.OnPinEnteredListener {
private static final int OFF_MODE = 0;
- // State when enabling/disabling SIM lock
- private static final int SIM_LOCK_MODE = 1;
+ // State when enabling/disabling ICC lock
+ private static final int ICC_LOCK_MODE = 1;
// State when entering the old pin
- private static final int SIM_OLD_MODE = 2;
+ private static final int ICC_OLD_MODE = 2;
// State when entering the new pin - first time
- private static final int SIM_NEW_MODE = 3;
+ private static final int ICC_NEW_MODE = 3;
// State when entering the new pin - second time
- private static final int SIM_REENTER_MODE = 4;
+ private static final int ICC_REENTER_MODE = 4;
// Keys in xml file
private static final String PIN_DIALOG = "sim_pin";
@@ -70,7 +71,7 @@ public class SimLockSettings extends PreferenceActivity
private String mOldPin;
private String mNewPin;
private String mError;
- // Are we trying to enable or disable SIM lock?
+ // Are we trying to enable or disable ICC lock?
private boolean mToState;
private Phone mPhone;
@@ -81,19 +82,19 @@ public class SimLockSettings extends PreferenceActivity
private Resources mRes;
// For async handler to identify request type
- private static final int ENABLE_SIM_PIN_COMPLETE = 100;
- private static final int CHANGE_SIM_PIN_COMPLETE = 101;
+ private static final int ENABLE_ICC_PIN_COMPLETE = 100;
+ private static final int CHANGE_ICC_PIN_COMPLETE = 101;
- // For replies from SimCard interface
+ // For replies from IccCard interface
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
AsyncResult ar = (AsyncResult) msg.obj;
switch (msg.what) {
- case ENABLE_SIM_PIN_COMPLETE:
- simLockChanged(ar.exception == null);
+ case ENABLE_ICC_PIN_COMPLETE:
+ iccLockChanged(ar.exception == null);
break;
- case CHANGE_SIM_PIN_COMPLETE:
- simPinChanged(ar.exception == null);
+ case CHANGE_ICC_PIN_COMPLETE:
+ iccPinChanged(ar.exception == null);
break;
}
@@ -102,24 +103,24 @@ public class SimLockSettings extends PreferenceActivity
};
// For top-level settings screen to query
- static boolean isSimLockEnabled() {
- return PhoneFactory.getDefaultPhone().getSimCard().getSimLockEnabled();
+ static boolean isIccLockEnabled() {
+ return PhoneFactory.getDefaultPhone().getIccCard().getIccLockEnabled();
}
static String getSummary(Context context) {
Resources res = context.getResources();
- String summary = isSimLockEnabled()
- ? res.getString(R.string.sim_lock_on)
+ String summary = isIccLockEnabled()
+ ? res.getString(R.string.sim_lock_on)
: res.getString(R.string.sim_lock_off);
return summary;
}
-
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
+
addPreferencesFromResource(R.xml.sim_lock_settings);
-
+
mPinDialog = (EditPinPreference) findPreference(PIN_DIALOG);
mPinToggle = (CheckBoxPreference) findPreference(PIN_TOGGLE);
if (savedInstanceState != null && savedInstanceState.containsKey(DIALOG_STATE)) {
@@ -142,7 +143,7 @@ public class SimLockSettings extends PreferenceActivity
protected void onResume() {
super.onResume();
- mPinToggle.setChecked(mPhone.getSimCard().getSimLockEnabled());
+ mPinToggle.setChecked(mPhone.getIccCard().getIccLockEnabled());
if (mDialogState != OFF_MODE) {
showPinDialog();
@@ -182,21 +183,21 @@ public class SimLockSettings extends PreferenceActivity
mPinDialog.setText(mPin);
String message = "";
switch (mDialogState) {
- case SIM_LOCK_MODE:
+ case ICC_LOCK_MODE:
message = mRes.getString(R.string.sim_enter_pin);
mPinDialog.setDialogTitle(mToState
? mRes.getString(R.string.sim_enable_sim_lock)
: mRes.getString(R.string.sim_disable_sim_lock));
break;
- case SIM_OLD_MODE:
+ case ICC_OLD_MODE:
message = mRes.getString(R.string.sim_enter_old);
mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
break;
- case SIM_NEW_MODE:
+ case ICC_NEW_MODE:
message = mRes.getString(R.string.sim_enter_new);
mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
break;
- case SIM_REENTER_MODE:
+ case ICC_REENTER_MODE:
message = mRes.getString(R.string.sim_reenter_new);
mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
break;
@@ -222,26 +223,26 @@ public class SimLockSettings extends PreferenceActivity
return;
}
switch (mDialogState) {
- case SIM_LOCK_MODE:
- tryChangeSimLockState();
+ case ICC_LOCK_MODE:
+ tryChangeIccLockState();
break;
- case SIM_OLD_MODE:
+ case ICC_OLD_MODE:
mOldPin = mPin;
- mDialogState = SIM_NEW_MODE;
+ mDialogState = ICC_NEW_MODE;
mError = null;
mPin = null;
showPinDialog();
break;
- case SIM_NEW_MODE:
+ case ICC_NEW_MODE:
mNewPin = mPin;
- mDialogState = SIM_REENTER_MODE;
+ mDialogState = ICC_REENTER_MODE;
mPin = null;
showPinDialog();
break;
- case SIM_REENTER_MODE:
+ case ICC_REENTER_MODE:
if (!mPin.equals(mNewPin)) {
mError = mRes.getString(R.string.sim_pins_dont_match);
- mDialogState = SIM_NEW_MODE;
+ mDialogState = ICC_NEW_MODE;
mPin = null;
showPinDialog();
} else {
@@ -258,21 +259,21 @@ public class SimLockSettings extends PreferenceActivity
mToState = mPinToggle.isChecked();
// Flip it back and pop up pin dialog
mPinToggle.setChecked(!mToState);
- mDialogState = SIM_LOCK_MODE;
+ mDialogState = ICC_LOCK_MODE;
showPinDialog();
}
return true;
}
- private void tryChangeSimLockState() {
- // Try to change sim lock. If it succeeds, toggle the lock state and
+ private void tryChangeIccLockState() {
+ // Try to change icc lock. If it succeeds, toggle the lock state and
// reset dialog state. Else inject error message and show dialog again.
- Message callback = Message.obtain(mHandler, ENABLE_SIM_PIN_COMPLETE);
- mPhone.getSimCard().setSimLockEnabled(mToState, mPin, callback);
+ Message callback = Message.obtain(mHandler, ENABLE_ICC_PIN_COMPLETE);
+ mPhone.getIccCard().setIccLockEnabled(mToState, mPin, callback);
}
- private void simLockChanged(boolean success) {
+ private void iccLockChanged(boolean success) {
if (success) {
mPinToggle.setChecked(mToState);
} else {
@@ -283,14 +284,14 @@ public class SimLockSettings extends PreferenceActivity
resetDialogState();
}
- private void simPinChanged(boolean success) {
+ private void iccPinChanged(boolean success) {
if (!success) {
// TODO: I18N
- Toast.makeText(this, mRes.getString(R.string.sim_change_failed),
+ Toast.makeText(this, mRes.getString(R.string.sim_change_failed),
Toast.LENGTH_SHORT)
.show();
} else {
- Toast.makeText(this, mRes.getString(R.string.sim_change_succeeded),
+ Toast.makeText(this, mRes.getString(R.string.sim_change_succeeded),
Toast.LENGTH_SHORT)
.show();
@@ -299,8 +300,8 @@ public class SimLockSettings extends PreferenceActivity
}
private void tryChangePin() {
- Message callback = Message.obtain(mHandler, CHANGE_SIM_PIN_COMPLETE);
- mPhone.getSimCard().changeSimLockPassword(mOldPin,
+ Message callback = Message.obtain(mHandler, CHANGE_ICC_PIN_COMPLETE);
+ mPhone.getIccCard().changeIccLockPassword(mOldPin,
mNewPin, callback);
}
@@ -314,7 +315,7 @@ public class SimLockSettings extends PreferenceActivity
private void resetDialogState() {
mError = null;
- mDialogState = SIM_OLD_MODE; // Default for when Change PIN is clicked
+ mDialogState = ICC_OLD_MODE; // Default for when Change PIN is clicked
mPin = "";
setDialogValues();
}
diff --git a/src/com/android/settings/InstalledAppDetails.java b/src/com/android/settings/InstalledAppDetails.java
index 327874b..5a4e672 100644
--- a/src/com/android/settings/InstalledAppDetails.java
+++ b/src/com/android/settings/InstalledAppDetails.java
@@ -22,13 +22,16 @@ import com.android.settings.R;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
+import android.app.Dialog;
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.IPackageStatsObserver;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -36,6 +39,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.os.RemoteException;
import android.text.format.Formatter;
import android.util.Config;
import android.util.Log;
@@ -64,9 +68,8 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
private ApplicationInfo mAppInfo;
private Button mAppButton;
private Button mActivitiesButton;
- private boolean mCanUninstall;
- private boolean localLOGV=Config.LOGV || false;
- private TextView mAppSnippetSize;
+ private boolean localLOGV = false;
+ private TextView mAppVersion;
private TextView mTotalSize;
private TextView mAppSize;
private TextView mDataSize;
@@ -100,10 +103,18 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
private CharSequence mComputingStr;
private CharSequence mAppButtonText;
+ // Dialog identifiers used in showDialog
+ private static final int DLG_BASE = 0;
+ private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
+ 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;
@@ -127,14 +138,6 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
}
};
- private boolean isUninstallable() {
- if (((mAppInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) &&
- ((mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0)) {
- return false;
- }
- return true;
- }
-
class ClearUserDataObserver extends IPackageDataObserver.Stub {
public void onRemoveCompleted(final String packageName, final boolean succeeded) {
final Message msg = mHandler.obtainMessage(CLEAR_USER_DATA);
@@ -154,7 +157,7 @@ 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);
@@ -170,40 +173,13 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
return Formatter.formatFileSize(this, size);
}
- private void setAppBtnState() {
- boolean visible = false;
- if(mCanUninstall) {
- //app can clear user data
- if((mAppInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
- == ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) {
- mAppButtonText = getText(R.string.clear_user_data_text);
- mAppButtonState = AppButtonStates.CLEAR_DATA;
- visible = true;
- } else {
- //hide button if diableClearUserData is set
- visible = false;
- mAppButtonState = AppButtonStates.NONE;
- }
- } else {
- visible = true;
- mAppButtonState = AppButtonStates.UNINSTALL;
- mAppButtonText = getText(R.string.uninstall_text);
- }
- if(visible) {
- mAppButton.setText(mAppButtonText);
- mAppButton.setVisibility(View.VISIBLE);
- } else {
- mAppButton.setVisibility(View.GONE);
- }
- }
-
/** Called when the activity is first created. */
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
- //get package manager
+ // Get package manager
mPm = getPackageManager();
- //get application's name from intent
+ // Get application's name from intent
Intent intent = getIntent();
final String packageName = intent.getStringExtra(ManageApplications.APP_PKG_NAME);
mComputingStr = getText(R.string.computing_size);
@@ -212,45 +188,31 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
totalSizeStr = appSizeStr = dataSizeStr = mComputingStr;
if(localLOGV) Log.i(TAG, "Have to compute package sizes");
mSizeObserver = new PkgSizeObserver();
- mPm.getPackageSizeInfo(packageName, mSizeObserver);
-
try {
mAppInfo = mPm.getApplicationInfo(packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
} catch (NameNotFoundException e) {
Log.e(TAG, "Exception when retrieving package:"+packageName, e);
- displayErrorDialog(R.string.app_not_found_dlg_text, true, true);
- }
- setContentView(R.layout.installed_app_details);
- ((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);
+ showDialogInner(DLG_APP_NOT_FOUND);
+ return;
}
- ((TextView)findViewById(R.id.app_name)).setText(appName);
- mAppSnippetSize = ((TextView)findViewById(R.id.app_size));
- mAppSnippetSize.setText(totalSizeStr);
+ setContentView(R.layout.installed_app_details);
//TODO download str and download url
- //set values on views
+ // Set default values on sizes
mTotalSize = (TextView)findViewById(R.id.total_size_text);
mTotalSize.setText(totalSizeStr);
mAppSize = (TextView)findViewById(R.id.application_size_text);
mAppSize.setText(appSizeStr);
mDataSize = (TextView)findViewById(R.id.data_size_text);
mDataSize.setText(dataSizeStr);
-
+ // Get AppButton
mAppButton = ((Button)findViewById(R.id.uninstall_button));
- //determine if app is a system app
- mCanUninstall = !isUninstallable();
- if(localLOGV) Log.i(TAG, "Is systemPackage "+mCanUninstall);
- setAppBtnState();
+ // Get ManageSpaceButton
mManageSpaceButton = (Button)findViewById(R.id.manage_space_button);
if(mAppInfo.manageSpaceActivityName != null) {
mManageSpaceButton.setVisibility(View.VISIBLE);
mManageSpaceButton.setOnClickListener(this);
}
-
// Cache section
mCachePanel = findViewById(R.id.cache_panel);
mCacheSize = (TextView) findViewById(R.id.cache_size_text);
@@ -258,17 +220,16 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
mClearCacheButton = (Button) findViewById(R.id.clear_cache_button);
mForceStopButton = (Button) findViewById(R.id.force_stop_button);
mForceStopButton.setOnClickListener(this);
-
- //clear activities
+ // 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
+ // Intent list cannot be null. so pass empty list
List<IntentFilter> intentList = new ArrayList<IntentFilter>();
mPm.getPreferredActivities(intentList, prefActList, packageName);
if(localLOGV) Log.i(TAG, "Have "+prefActList.size()+" number of activities in prefered list");
TextView autoLaunchView = (TextView)findViewById(R.id.auto_launch);
if(prefActList.size() <= 0) {
- //disable clear activities button
+ // Disable clear activities button
autoLaunchView.setText(R.string.auto_launch_disable_text);
mActivitiesButton.setEnabled(false);
} else {
@@ -276,7 +237,7 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
mActivitiesButton.setOnClickListener(this);
}
- // security permissions section
+ // Security permissions section
LinearLayout permsView = (LinearLayout) findViewById(R.id.permissions_section);
AppSecurityPermissions asp = new AppSecurityPermissions(this, packageName);
if(asp.getPermissionCount() > 0) {
@@ -290,21 +251,85 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
}
}
- private void displayErrorDialog(int msgId, final boolean finish, final boolean changed) {
- //display confirmation dialog
- new AlertDialog.Builder(this)
- .setTitle(getString(R.string.app_not_found_dlg_title))
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(getString(msgId))
- .setNeutralButton(getString(R.string.dlg_ok),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- //force to recompute changed value
- setIntentAndFinish(finish, changed);
- }
+ 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) {
+ // Version number of application
+ mAppVersion = ((TextView)findViewById(R.id.app_version));
+ if (pkgInfo != null) {
+ mAppVersion.setVisibility(View.VISIBLE);
+ mAppVersion.setText(getString(R.string.version_text,
+ String.valueOf(pkgInfo.versionCode)));
+ } else {
+ mAppVersion.setVisibility(View.GONE);
+ }
+ }
+
+ // 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);
}
- )
- .show();
+ }
+ } else {
+ mAppButtonState = AppButtonStates.UNINSTALL;
+ mAppButtonText = getText(R.string.uninstall_text);
+ }
+ if(visible) {
+ mAppButton.setText(mAppButtonText);
+ mAppButton.setVisibility(View.VISIBLE);
+ } else {
+ mAppButton.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ PackageInfo pkgInfo;
+ // 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, 0);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Exception when retrieving package:" + mAppInfo.packageName, e);
+ showDialogInner(DLG_APP_NOT_FOUND);
+ return;
+ }
+ refreshAppAttributes(pkgInfo);
}
private void setIntentAndFinish(boolean finish, boolean appChanged) {
@@ -331,7 +356,6 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
mSizeInfo = newPs;
String str = getSizeStr(newTot);
mTotalSize.setText(str);
- mAppSnippetSize.setText(str);
mAppSize.setText(getSizeStr(newPs.codeSize));
mDataSize.setText(getSizeStr(newPs.dataSize));
mCacheSize.setText(getSizeStr(newPs.cacheSize));
@@ -340,7 +364,6 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
if(newTot != oldTot) {
String str = getSizeStr(newTot);
mTotalSize.setText(str);
- mAppSnippetSize.setText(str);
changed = true;
}
if(newPs.codeSize != mSizeInfo.codeSize) {
@@ -415,14 +438,76 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
if(!res) {
- //doesnt initiate clear. some error. should not happen but just log error for now
+ // Clearing data failed for some obscure reason. Just log error for now
Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
- displayErrorDialog(R.string.clear_data_failed, false, false);
+ showDialogInner(DLG_CANNOT_CLEAR_DATA);
} else {
mAppButton.setText(R.string.recompute_size);
}
}
+ private void showDialogInner(int id) {
+ //removeDialog(id);
+ showDialog(id);
+ }
+
+ @Override
+ public Dialog onCreateDialog(int id) {
+ 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)
+ .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)
+ .create();
+ case DLG_APP_NOT_FOUND:
+ return new AlertDialog.Builder(this)
+ .setTitle(getString(R.string.app_not_found_dlg_title))
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(getString(R.string.app_not_found_dlg_title))
+ .setNeutralButton(getString(R.string.dlg_ok),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ //force to recompute changed value
+ setIntentAndFinish(true, true);
+ }
+ })
+ .create();
+ case DLG_CANNOT_CLEAR_DATA:
+ return new AlertDialog.Builder(this)
+ .setTitle(getString(R.string.clear_failed_dlg_title))
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(getString(R.string.clear_failed_dlg_text))
+ .setNeutralButton(R.string.dlg_ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ //force to recompute changed value
+ setIntentAndFinish(false, false);
+ }
+ })
+ .create();
+ }
+ return null;
+ }
+
+ private void uninstallPkg(String packageName) {
+ // Create new intent to launch Uninstaller activity
+ Uri packageURI = Uri.parse("package:"+packageName);
+ Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
+ startActivity(uninstallIntent);
+ setIntentAndFinish(true, true);
+ }
+
/*
* Method implementing functionality of buttons clicked
* @see android.view.View.OnClickListener#onClick(android.view.View)
@@ -430,21 +515,12 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
public void onClick(View v) {
String packageName = mAppInfo.packageName;
if(v == mAppButton) {
- if(mCanUninstall) {
- //display confirmation dialog
- 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)
- .show();
- } else {
- //create new intent to launch Uninstaller activity
- Uri packageURI = Uri.parse("package:"+packageName);
- Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
- startActivity(uninstallIntent);
- setIntentAndFinish(true, true);
+ if (mAppButtonState == AppButtonStates.CLEAR_DATA) {
+ showDialogInner(DLG_CLEAR_DATA);
+ } else if (mAppButtonState == AppButtonStates.FACTORY_RESET) {
+ showDialogInner(DLG_FACTORY_RESET);
+ } else if (mAppButtonState == AppButtonStates.UNINSTALL) {
+ uninstallPkg(packageName);
}
} else if(v == mActivitiesButton) {
mPm.clearPackagePreferredActivities(packageName);
@@ -468,8 +544,13 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
public void onClick(DialogInterface dialog, int which) {
if(which == AlertDialog.BUTTON_POSITIVE) {
- //invoke uninstall or clear user data based on sysPackage
- initiateClearUserDataForSysPkg();
+ 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);
+ }
} else {
//cancel do nothing just retain existing screen
}
diff --git a/src/com/android/settings/LocalePicker.java b/src/com/android/settings/LocalePicker.java
index 386d7e0..ecd9689 100644
--- a/src/com/android/settings/LocalePicker.java
+++ b/src/com/android/settings/LocalePicker.java
@@ -30,6 +30,7 @@ import android.widget.ListView;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
+import java.text.Collator;
import java.util.Arrays;
import java.util.Locale;
@@ -38,7 +39,9 @@ public class LocalePicker extends ListActivity {
Loc[] mLocales;
- private static class Loc {
+ private static class Loc implements Comparable {
+ static Collator sCollator = Collator.getInstance();
+
String label;
Locale locale;
@@ -51,6 +54,10 @@ public class LocalePicker extends ListActivity {
public String toString() {
return this.label;
}
+
+ public int compareTo(Object o) {
+ return sCollator.compare(this.label, ((Loc) o).label);
+ }
}
int getContentView() {
@@ -71,38 +78,42 @@ public class LocalePicker extends ListActivity {
for (int i = 0 ; i < origSize; i++ ) {
String s = locales[i];
int len = s.length();
- if (len == 2) {
- Locale l = new Locale(s);
- preprocess[finalSize++] = new Loc(toTitleCase(l.getDisplayLanguage()), l);
- } else if (len == 5) {
+ if (len == 5) {
String language = s.substring(0, 2);
String country = s.substring(3, 5);
Locale l = new Locale(language, country);
if (finalSize == 0) {
- preprocess[finalSize++] = new Loc(toTitleCase(l.getDisplayLanguage()), l);
+ Log.v(TAG, "adding initial "+
+ toTitleCase(l.getDisplayLanguage(l)));
+ preprocess[finalSize++] =
+ new Loc(toTitleCase(l.getDisplayLanguage(l)), l);
} else {
// check previous entry:
- // same lang and no country -> overwrite it with a lang-only name
- // same lang and a country -> upgrade to full name and
+ // same lang and a country -> upgrade to full name and
// insert ours with full name
// diff lang -> insert ours with lang-only name
- if (preprocess[finalSize-1].locale.getLanguage().equals(language)) {
- String prevCountry = preprocess[finalSize-1].locale.getCountry();
- if (prevCountry.length() == 0) {
- preprocess[finalSize-1].locale = l;
- preprocess[finalSize-1].label = toTitleCase(l.getDisplayLanguage());
- } else {
- preprocess[finalSize-1].label = toTitleCase(preprocess[finalSize-1].locale.getDisplayName());
- preprocess[finalSize++] = new Loc(toTitleCase(l.getDisplayName()), l);
- }
+ if (preprocess[finalSize-1].locale.getLanguage().equals(
+ language)) {
+ Log.v(TAG, "backing up and fixing "+
+ preprocess[finalSize-1].label+" to "+
+ preprocess[finalSize-1].locale.
+ getDisplayName(l));
+ preprocess[finalSize-1].label = toTitleCase(
+ preprocess[finalSize-1].
+ locale.getDisplayName(l));
+ Log.v(TAG, " and adding "+
+ toTitleCase(l.getDisplayName(l)));
+ preprocess[finalSize++] =
+ new Loc(toTitleCase(l.getDisplayName(l)), l);
} else {
String displayName;
if (s.equals("zz_ZZ")) {
displayName = "Pseudo...";
} else {
- displayName = toTitleCase(l.getDisplayLanguage());
+ displayName = toTitleCase(l.getDisplayLanguage(l));
}
+ Log.v(TAG, "adding "+displayName);
preprocess[finalSize++] = new Loc(displayName, l);
}
}
@@ -112,9 +123,11 @@ public class LocalePicker extends ListActivity {
for (int i = 0; i < finalSize ; i++) {
mLocales[i] = preprocess[i];
}
+ Arrays.sort(mLocales);
int layoutId = R.layout.locale_picker_item;
int fieldId = R.id.locale;
- ArrayAdapter<Loc> adapter = new ArrayAdapter<Loc>(this, layoutId, fieldId, mLocales);
+ ArrayAdapter<Loc> adapter =
+ new ArrayAdapter<Loc>(this, layoutId, fieldId, mLocales);
getListView().setAdapter(adapter);
}
diff --git a/src/com/android/settings/RadioInfo.java b/src/com/android/settings/RadioInfo.java
index 5df9313..79327f2 100644
--- a/src/com/android/settings/RadioInfo.java
+++ b/src/com/android/settings/RadioInfo.java
@@ -94,7 +94,7 @@ public class RadioInfo extends Activity {
private static final int MENU_ITEM_TOGGLE_DATA = 5;
private static final int MENU_ITEM_TOGGLE_DATA_ON_BOOT = 6;
- private TextView mImei;
+ private TextView mDeviceId; //DeviceId is the IMEI in GSM and the MEID in CDMA
private TextView number;
private TextView callState;
private TextView operatorName;
@@ -405,7 +405,7 @@ public class RadioInfo extends Activity {
mTelephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
phone = PhoneFactory.getDefaultPhone();
- mImei = (TextView) findViewById(R.id.imei);
+ mDeviceId= (TextView) findViewById(R.id.imei);
number = (TextView) findViewById(R.id.number);
callState = (TextView) findViewById(R.id.call);
operatorName = (TextView) findViewById(R.id.operator);
@@ -518,7 +518,8 @@ public class RadioInfo extends Activity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, MENU_ITEM_SELECT_BAND, 0, R.string.radio_info_band_mode_label).setOnMenuItemClickListener(mSelectBandCallback)
+ menu.add(0, MENU_ITEM_SELECT_BAND, 0, R.string.radio_info_band_mode_label)
+ .setOnMenuItemClickListener(mSelectBandCallback)
.setAlphabeticShortcut('b');
menu.add(1, MENU_ITEM_VIEW_ADN, 0,
R.string.radioInfo_menu_viewADN).setOnMenuItemClickListener(mViewADNCallback);
@@ -531,14 +532,14 @@ public class RadioInfo extends Activity {
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, R.string.radioInfo_menu_disableDataOnBoot).setOnMenuItemClickListener(
+ mToggleDataOnBoot);
return true;
}
@Override
- public boolean onPrepareOptionsMenu(Menu menu)
- {
+ public boolean onPrepareOptionsMenu(Menu menu) {
// Get the TOGGLE DATA menu item in the right state.
MenuItem item = menu.findItem(MENU_ITEM_TOGGLE_DATA);
int state = mTelephonyManager.getDataState();
@@ -575,11 +576,10 @@ public class RadioInfo extends Activity {
}
private void updatePowerState() {
- //log("updatePowerState");
String buttonText = isRadioOn() ?
getString(R.string.turn_off_radio) :
getString(R.string.turn_on_radio);
- radioPowerButton.setText(buttonText);
+ radioPowerButton.setText(buttonText);
}
private void updateQxdmState(Boolean newQxdmStatus) {
@@ -619,24 +619,24 @@ public class RadioInfo extends Activity {
}
private void updateDnsCheckState() {
- GSMPhone gsmPhone = (GSMPhone) phone;
- dnsCheckState.setText(gsmPhone.isDnsCheckDisabled() ?
+ dnsCheckState.setText(phone.isDnsCheckDisabled() ?
"0.0.0.0 allowed" :"0.0.0.0 not allowed");
}
-
+
private final void
updateSignalStrength() {
- int state =
- mPhoneStateReceiver.getServiceState().getState();
+ // TODO PhoneStateIntentReceiver is deprecated and PhoneStateListener
+ // should probably used instead.
+ int state = mPhoneStateReceiver.getServiceState().getState();
Resources r = getResources();
if ((ServiceState.STATE_OUT_OF_SERVICE == state) ||
(ServiceState.STATE_POWER_OFF == state)) {
dBm.setText("0");
}
-
+
int signalDbm = mPhoneStateReceiver.getSignalStrengthDbm();
-
+
if (-1 == signalDbm) signalDbm = 0;
int signalAsu = mPhoneStateReceiver.getSignalStrength();
@@ -650,11 +650,15 @@ public class RadioInfo extends Activity {
}
private final void updateLocation(CellLocation location) {
- GsmCellLocation loc = (GsmCellLocation)location;
- Resources r = getResources();
+ int lac = -1;
+ int cid = -1;
+ if (location instanceof GsmCellLocation) {
+ GsmCellLocation loc = (GsmCellLocation)location;
+ lac = loc.getLac();
+ cid = loc.getCid();
+ }
- int lac = loc.getLac();
- int cid = loc.getCid();
+ Resources r = getResources();
mLocation.setText(r.getString(R.string.radioInfo_lac) + " = "
+ ((lac == -1) ? "unknown" : Integer.toHexString(lac))
@@ -782,8 +786,9 @@ public class RadioInfo extends Activity {
s = phone.getDeviceId();
if (s == null) s = r.getString(R.string.radioInfo_unknown);
- mImei.setText(s);
+ mDeviceId.setText(s);
+
s = phone.getLine1Number();
if (s == null) s = r.getString(R.string.radioInfo_unknown);
number.setText(s);
@@ -1030,7 +1035,7 @@ public class RadioInfo extends Activity {
private MenuItem.OnMenuItemClickListener mViewSDNCallback = new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
Intent intent = new Intent(
- Intent.ACTION_VIEW, Uri.parse("content://sim/sdn"));
+ Intent.ACTION_VIEW, Uri.parse("content://icc/sdn"));
// XXX We need to specify the component here because if we don't
// the activity manager will try to resolve the type by calling
// the content provider, which causes it to be loaded in a process
@@ -1085,7 +1090,7 @@ public class RadioInfo extends Activity {
private MenuItem.OnMenuItemClickListener mGetPdpList = new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
- phone.getPdpContextList(null);
+ phone.getDataCallList(null);
return true;
}
};
@@ -1122,8 +1127,7 @@ public class RadioInfo extends Activity {
OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
public void onClick(View v) {
- GSMPhone gsmPhone = (GSMPhone) phone;
- gsmPhone.disableDnsCheck(!gsmPhone.isDnsCheckDisabled());
+ phone.disableDnsCheck(!phone.isDnsCheckDisabled());
updateDnsCheckState();
}
};
@@ -1170,7 +1174,7 @@ public class RadioInfo extends Activity {
mPreferredNetworkHandler = new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView parent, View v, int pos, long id) {
Message msg = mHandler.obtainMessage(EVENT_SET_PREFERRED_TYPE_DONE);
- if (pos>=0 && pos<=2) {
+ if (pos>=0 && pos<=7) { //IS THIS NEEDED to extend to the entire range of values
phone.setPreferredNetworkType(pos, msg);
}
}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 6858fd3..166fa44 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -18,11 +18,11 @@ package com.android.settings;
import android.app.Activity;
-import android.app.AlertDialog;
+import android.content.ContentQueryMap;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.database.Cursor;
import android.location.LocationManager;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
@@ -34,13 +34,15 @@ import android.provider.Settings;
import android.util.Config;
import android.util.Log;
+import java.util.Observable;
+import java.util.Observer;
+
import com.android.internal.widget.LockPatternUtils;
/**
* Gesture lock pattern settings.
*/
-public class SecuritySettings extends PreferenceActivity
- implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
+public class SecuritySettings extends PreferenceActivity {
// Lock Settings
@@ -64,10 +66,16 @@ public class SecuritySettings extends PreferenceActivity
private CheckBoxPreference mNetwork;
private CheckBoxPreference mGps;
- private LocationManager mLocationManager;
-
- // To track whether Agree was clicked in the Network location warning dialog
- private boolean mOkClicked;
+
+ // 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 final class SettingsObserver implements Observer {
+ public void update(Observable o, Object arg) {
+ updateToggles();
+ }
+ }
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -77,14 +85,18 @@ public class SecuritySettings extends PreferenceActivity
mLockPatternUtils = new LockPatternUtils(getContentResolver());
createPreferenceHierarchy();
-
- // Get the available location providers
- mLocationManager = (LocationManager)
- getSystemService(Context.LOCATION_SERVICE);
mNetwork = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_NETWORK);
mGps = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_GPS);
updateToggles();
+
+ // listen for Location Manager settings changes
+ Cursor settingsCursor = getContentResolver().query(Settings.Secure.CONTENT_URI, null,
+ "(" + Settings.System.NAME + "=?)",
+ new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
+ null);
+ mContentQueryMap = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, null);
+ mContentQueryMap.addObserver(new SettingsObserver());
}
private PreferenceScreen createPreferenceHierarchy() {
@@ -128,7 +140,7 @@ public class SecuritySettings extends PreferenceActivity
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.SimLockSettings");
+ intent.setClassName("com.android.settings", "com.android.settings.IccLockSettings");
simLockPreferences.setIntent(intent);
PreferenceCategory simLockCat = new PreferenceCategory(this);
@@ -189,87 +201,24 @@ public class SecuritySettings extends PreferenceActivity
Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD,
mShowPassword.isChecked() ? 1 : 0);
} else if (preference == mNetwork) {
- //normally called on the toggle click
- if (mNetwork.isChecked()) {
- // Show a warning to the user that location data will be shared
- mOkClicked = false;
- new AlertDialog.Builder(this).setMessage(
- getResources().getString(R.string.location_warning_message))
- .setTitle(R.string.location_warning_title)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setPositiveButton(R.string.agree, this)
- .setNegativeButton(R.string.disagree, this)
- .show()
- .setOnDismissListener(this);
- } else {
- updateProviders();
- }
+ Settings.Secure.setLocationProviderEnabled(getContentResolver(),
+ LocationManager.NETWORK_PROVIDER, mNetwork.isChecked());
} else if (preference == mGps) {
- updateProviders();
+ Settings.Secure.setLocationProviderEnabled(getContentResolver(),
+ LocationManager.GPS_PROVIDER, mGps.isChecked());
}
return false;
}
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- updateProviders();
- mOkClicked = true;
- } else {
- // Reset the toggle
- mNetwork.setChecked(false);
- }
- }
-
- public void onDismiss(DialogInterface dialog) {
- // Assuming that onClick gets called first
- if (!mOkClicked) {
- mNetwork.setChecked(false);
- }
- }
-
/*
* Creates toggles for each available location provider
*/
private void updateToggles() {
- String providers = getAllowedProviders();
- mNetwork.setChecked(providers.contains(LocationManager.NETWORK_PROVIDER));
- mGps.setChecked(providers.contains(LocationManager.GPS_PROVIDER));
- }
-
- private void updateProviders() {
- String preferredProviders = "";
- if (mNetwork.isChecked()) {
- preferredProviders += LocationManager.NETWORK_PROVIDER;
- }
- if (mGps.isChecked()) {
- preferredProviders += "," + LocationManager.GPS_PROVIDER;
- }
- setProviders(preferredProviders);
- }
-
- private void setProviders(String providers) {
- // Update the secure setting LOCATION_PROVIDERS_ALLOWED
- Settings.Secure.putString(getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED, providers);
- if (Config.LOGV) {
- Log.v("Location Accuracy", "Setting LOCATION_PROVIDERS_ALLOWED = " + providers);
- }
- // Inform the location manager about the changes
- mLocationManager.updateProviders();
- }
-
- /**
- * @return string containing a list of providers that have been enabled for use
- */
- private String getAllowedProviders() {
- String allowedProviders =
- Settings.Secure.getString(getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
- if (allowedProviders == null) {
- allowedProviders = "";
- }
- return allowedProviders;
+ mNetwork.setChecked(Settings.Secure.isLocationProviderEnabled(
+ getContentResolver(), LocationManager.NETWORK_PROVIDER));
+ mGps.setChecked(Settings.Secure.isLocationProviderEnabled(
+ getContentResolver(), LocationManager.GPS_PROVIDER));
}
private boolean isToggled(Preference pref) {
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 0c4545e..4f888ff 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -26,6 +26,7 @@ public class Settings extends PreferenceActivity {
private static final String KEY_PARENT = "parent";
private static final String KEY_CALL_SETTINGS = "call_settings";
private static final String KEY_SYNC_SETTINGS = "sync_settings";
+ private static final String KEY_SEARCH_SETTINGS = "search_settings";
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -35,6 +36,7 @@ public class Settings extends PreferenceActivity {
PreferenceGroup parent = (PreferenceGroup) findPreference(KEY_PARENT);
Utils.updatePreferenceToSpecificActivityOrRemove(this, parent, KEY_SYNC_SETTINGS, 0);
+ Utils.updatePreferenceToSpecificActivityOrRemove(this, parent, KEY_SEARCH_SETTINGS, 0);
}
@Override
diff --git a/src/com/android/settings/TextToSpeechSettings.java b/src/com/android/settings/TextToSpeechSettings.java
new file mode 100644
index 0000000..02fc06d
--- /dev/null
+++ b/src/com/android/settings/TextToSpeechSettings.java
@@ -0,0 +1,122 @@
+/*
+ * 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;
+
+import static android.provider.Settings.Secure.TTS_USE_DEFAULTS;
+import static android.provider.Settings.Secure.TTS_DEFAULT_RATE;
+import static android.provider.Settings.Secure.TTS_DEFAULT_PITCH;
+
+import android.content.ContentResolver;
+import android.os.Bundle;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.CheckBoxPreference;
+import android.provider.Settings;
+import android.util.Log;
+
+public class TextToSpeechSettings extends PreferenceActivity implements
+ Preference.OnPreferenceChangeListener {
+
+ private static final String TAG = "TextToSpeechSettings";
+
+ /** If there is no setting in the provider, use this. */
+ private static final int FALLBACK_TTS_DEFAULT_RATE = 100; // 1x
+ private static final int FALLBACK_TTS_DEFAULT_PITCH = 100;// 1x
+ private static final int FALLBACK_TTS_USE_DEFAULTS = 1;
+
+ private static final String KEY_TTS_USE_DEFAULT =
+ "toggle_use_default_tts_settings";
+ private static final String KEY_TTS_DEFAULT_RATE = "tts_default_rate";
+ private static final String KEY_TTS_DEFAULT_PITCH = "tts_default_pitch";
+
+ private CheckBoxPreference mUseDefaultPref = null;
+ private ListPreference mDefaultRatePref = null;
+ private ListPreference mDefaultPitchPref = null;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ addPreferencesFromResource(R.xml.tts_settings);
+
+ initDefaultSettings();
+ }
+
+
+ private void initDefaultSettings() {
+ ContentResolver resolver = getContentResolver();
+
+ // "Use Defaults"
+ mUseDefaultPref =
+ (CheckBoxPreference) findPreference(KEY_TTS_USE_DEFAULT);
+ mUseDefaultPref.setChecked(Settings.System.getInt(resolver,
+ TTS_USE_DEFAULTS,
+ FALLBACK_TTS_USE_DEFAULTS) == 1 ? true : false);
+ mUseDefaultPref.setOnPreferenceChangeListener(this);
+
+ // Default rate
+ mDefaultRatePref =
+ (ListPreference) findPreference(KEY_TTS_DEFAULT_RATE);
+ mDefaultRatePref.setValue(String.valueOf(Settings.System.getInt(
+ resolver, TTS_DEFAULT_RATE, FALLBACK_TTS_DEFAULT_RATE)));
+ mDefaultRatePref.setOnPreferenceChangeListener(this);
+
+ // Default pitch
+ mDefaultPitchPref =
+ (ListPreference) findPreference(KEY_TTS_DEFAULT_PITCH);
+ mDefaultPitchPref.setValue(String.valueOf(Settings.System.getInt(
+ resolver, TTS_DEFAULT_PITCH, FALLBACK_TTS_DEFAULT_PITCH)));
+ mDefaultPitchPref.setOnPreferenceChangeListener(this);
+
+ }
+
+
+ public boolean onPreferenceChange(Preference preference, Object objValue) {
+ if (KEY_TTS_USE_DEFAULT.equals(preference.getKey())) {
+ // "Use Defaults"
+ int value = (Boolean)objValue ? 1 : 0;
+ Settings.System.putInt(getContentResolver(), TTS_USE_DEFAULTS,
+ value);
+ Log.i(TAG, "TTS use default settings is "+objValue.toString());
+ } else if (KEY_TTS_DEFAULT_RATE.equals(preference.getKey())) {
+ // Default rate
+ int value = Integer.parseInt((String) objValue);
+ try {
+ Settings.System.putInt(getContentResolver(),
+ TTS_DEFAULT_RATE, value);
+ Log.i(TAG, "TTS default rate is "+value);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "could not persist default TTS rate setting", e);
+ }
+ } else if (KEY_TTS_DEFAULT_PITCH.equals(preference.getKey())) {
+ // Default pitch
+ int value = Integer.parseInt((String) objValue);
+ try {
+ Settings.System.putInt(getContentResolver(),
+ TTS_DEFAULT_PITCH, value);
+ Log.i(TAG, "TTS default pitch is "+value);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "could not persist default TTS pitch setting", e);
+ }
+ }
+
+ return true;
+ }
+
+}
diff --git a/src/com/android/settings/battery_history/BatteryHistory.java b/src/com/android/settings/battery_history/BatteryHistory.java
index ad6479a..06f38ae 100644
--- a/src/com/android/settings/battery_history/BatteryHistory.java
+++ b/src/com/android/settings/battery_history/BatteryHistory.java
@@ -607,8 +607,8 @@ public class BatteryHistory extends Activity implements OnClickListener, OnItemS
Timer timer = se.getSensorTime();
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTime(uSecNow, mWhich) + 500) / 1000;
- int count = timer.getCount(mWhich);
+ long totalTime = (timer.getTotalTimeLocked(uSecNow, mWhich) + 500) / 1000;
+ int count = timer.getCountLocked(mWhich);
if (handle == BatteryStats.Uid.Sensor.GPS) {
timeGps += totalTime;
countGps += count;
@@ -655,8 +655,8 @@ public class BatteryHistory extends Activity implements OnClickListener, OnItemS
Timer timer = wl.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL);
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
- time += (timer.getTotalTime(uSecNow, mWhich) + 500) / 1000;
- count += timer.getCount(mWhich);
+ time += (timer.getTotalTimeLocked(uSecNow, mWhich) + 500) / 1000;
+ count += timer.getCountLocked(mWhich);
}
}
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java
index d458c5f..58fb569 100644
--- a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java
+++ b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java
@@ -30,7 +30,6 @@ import android.os.Handler;
import android.os.SystemProperties;
import android.preference.Preference;
import android.preference.CheckBoxPreference;
-import android.util.Log;
/**
* BluetoothDiscoverableEnabler is a helper to manage the "Discoverable"
@@ -39,7 +38,6 @@ import android.util.Log;
*/
public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChangeListener {
private static final String TAG = "BluetoothDiscoverableEnabler";
- private static final boolean V = LocalBluetoothManager.V;
private static final String SYSTEM_PROPERTY_DISCOVERABLE_TIMEOUT =
"debug.bt.discoverable_time";
@@ -109,10 +107,6 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan
}
public boolean onPreferenceChange(Preference preference, Object value) {
- if (V) {
- Log.v(TAG, "Preference changed to " + value);
- }
-
// Turn on/off BT discoverability
setEnabled((Boolean) value);
@@ -155,10 +149,6 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan
}
private void handleModeChanged(int mode) {
- if (V) {
- Log.v(TAG, "Got mode changed: " + mode);
- }
-
if (mode == BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
mCheckBoxPreference.setChecked(true);
updateCountdownSummary();
diff --git a/src/com/android/settings/bluetooth/BluetoothEnabler.java b/src/com/android/settings/bluetooth/BluetoothEnabler.java
index 82961b8..af2722f 100644
--- a/src/com/android/settings/bluetooth/BluetoothEnabler.java
+++ b/src/com/android/settings/bluetooth/BluetoothEnabler.java
@@ -19,6 +19,7 @@ package com.android.settings.bluetooth;
import com.android.settings.R;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -48,7 +49,9 @@ public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- handleStateChanged(mLocalManager.getBluetoothState());
+ int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
+ BluetoothError.ERROR);
+ handleStateChanged(state);
}
};
diff --git a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
index 71b91d3..af64c98 100644
--- a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
+++ b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
@@ -18,8 +18,8 @@ package com.android.settings.bluetooth;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothError;
+import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -27,6 +27,8 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
+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
@@ -89,9 +91,8 @@ public class BluetoothEventRedirector {
Log.i(TAG, "Failed to connect BT headset");
}
- boolean transientState = !(newState == BluetoothHeadset.STATE_CONNECTED
- || newState == BluetoothHeadset.STATE_DISCONNECTED);
- mManager.getLocalDeviceManager().onProfileStateChanged(address,transientState);
+ mManager.getLocalDeviceManager().onProfileStateChanged(address,
+ Profile.HEADSET, newState);
} else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
int newState = intent.getIntExtra(BluetoothA2dp.SINK_STATE, 0);
@@ -101,9 +102,8 @@ public class BluetoothEventRedirector {
Log.i(TAG, "Failed to connect BT A2DP");
}
- boolean transientState = !(newState == BluetoothA2dp.STATE_CONNECTED
- || newState == BluetoothA2dp.STATE_DISCONNECTED);
- mManager.getLocalDeviceManager().onProfileStateChanged(address, transientState);
+ mManager.getLocalDeviceManager().onProfileStateChanged(address,
+ Profile.A2DP, newState);
} else if (action.equals(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION)) {
mManager.getLocalDeviceManager().onBtClassChanged(address);
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothDevice.java b/src/com/android/settings/bluetooth/LocalBluetoothDevice.java
index 86b1d69..5259d7b 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothDevice.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothDevice.java
@@ -16,9 +16,6 @@
package com.android.settings.bluetooth;
-import com.android.settings.R;
-import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
-
import android.app.AlertDialog;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -32,6 +29,9 @@ import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
+import com.android.settings.R;
+import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
+
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
@@ -47,6 +47,8 @@ import java.util.List;
*/
public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> {
private static final String TAG = "LocalBluetoothDevice";
+ private static final boolean D = LocalBluetoothManager.D;
+ private static final boolean V = LocalBluetoothManager.V;
private static final int CONTEXT_ITEM_CONNECT = Menu.FIRST + 1;
private static final int CONTEXT_ITEM_DISCONNECT = Menu.FIRST + 2;
@@ -124,18 +126,21 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> {
private static LinkedList<BluetoothJob> workQueue = new LinkedList<BluetoothJob>();
private void queueCommand(BluetoothJob job) {
- Log.d(TAG, workQueue.toString());
+ if (D) {
+ Log.d(TAG, workQueue.toString());
+ }
synchronized (workQueue) {
boolean processNow = pruneQueue(job);
// Add job to queue
- Log.d(TAG, "Adding: " + job.toString());
+ if (D) {
+ Log.d(TAG, "Adding: " + job.toString());
+ }
workQueue.add(job);
// if there's nothing pending from before, send the command to bt
// framework immediately.
if (workQueue.size() == 1 || processNow) {
- Log.d(TAG, "workQueue.size() == 1 || TimeOut -> process command now");
// If the failed to process, just drop it from the queue.
// There will be no callback to remove this from the queue.
processCommands();
@@ -156,7 +161,9 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> {
&& existingJob.command == BluetoothCommand.CONNECT
&& existingJob.device.mAddress.equals(job.device.mAddress)
&& existingJob.profile == job.profile) {
- Log.d(TAG, "Removed because of a pending disconnect. " + existingJob);
+ if (D) {
+ Log.d(TAG, "Removed because of a pending disconnect. " + existingJob);
+ }
it.remove();
continue;
}
@@ -165,7 +172,6 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> {
// Defensive Code: Remove any job that older than a preset time.
// We never got a call back. It is better to have overlapping
// calls than to get stuck.
- Log.d(TAG, "Age:" + (now - existingJob.timeSent));
if (existingJob.timeSent != 0
&& (now - existingJob.timeSent) >= MAX_WAIT_TIME_FOR_FRAMEWORK) {
Log.w(TAG, "Timeout. Removing Job:" + existingJob.toString());
@@ -191,45 +197,59 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> {
}
if (successful) {
- Log.d(TAG, "Command sent successfully:" + job.toString());
- } else {
- Log.d(TAG, "Framework rejected command immediately:" + job.toString());
+ if (D) {
+ Log.d(TAG, "Command sent successfully:" + job.toString());
+ }
+ } else if (V) {
+ Log.v(TAG, "Framework rejected command immediately:" + job.toString());
}
-
- } else {
+ } else if (D) {
Log.d(TAG, "Job already has a sent time. Skip. " + job.toString());
}
return successful;
}
- public void onProfileStateChanged() {
- Log.d(TAG, "onProfileStateChanged:" + workQueue.toString());
- BluetoothJob job = workQueue.peek();
- if (job == null) {
- Log.v(TAG, "Yikes, onProfileStateChanged called but job queue is empty. "
- + "(Okay for device initiated actions and BluetoothA2dpService initiated "
- + "Auto-connections)");
- return;
- } else if (job.device.mAddress != mAddress) {
- // This can happen in 2 cases: 1) BT device initiated pairing and
- // 2) disconnects of one headset that's triggered by connects of
- // another.
- Log.v(TAG, "onProfileStateChanged called. The addresses differ. this.mAddress="
- + mAddress + " workQueue.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.
- return;
+ public void onProfileStateChanged(Profile profile, int newProfileState) {
+ if (D) {
+ Log.d(TAG, "onProfileStateChanged:" + workQueue.toString());
+ }
+
+ int newState = LocalBluetoothProfileManager.getProfileManager(mLocalManager,
+ profile).convertState(newProfileState);
+
+ if (newState == SettingsBtStatus.CONNECTION_STATUS_CONNECTED) {
+ if (!mProfiles.contains(profile)) {
+ mProfiles.add(profile);
}
- } else {
- // Remove the first item and process the next one
- Log.d(TAG, "LocalBluetoothDevice.onProfileStateChanged() called. MAC addr matched");
- workQueue.poll();
}
- processCommands();
+ /* Ignore the transient states e.g. connecting, disconnecting */
+ if (newState == SettingsBtStatus.CONNECTION_STATUS_CONNECTED ||
+ newState == SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED) {
+ BluetoothJob job = workQueue.peek();
+ if (job == null) {
+ return;
+ } else if (job.device.mAddress != mAddress) {
+ // This can happen in 2 cases: 1) BT device initiated pairing and
+ // 2) disconnects of one headset that's triggered by connects of
+ // another.
+ if (D) {
+ Log.d(TAG, "mAddresses:" + mAddress + " != 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.
+ return;
+ }
+ } else {
+ // Remove the first item and process the next one
+ workQueue.poll();
+ }
+
+ processCommands();
+ }
}
/*
@@ -240,7 +260,9 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> {
* notification when it finishes processing a command
*/
private void processCommands() {
- Log.d(TAG, "processCommands:" + workQueue.toString());
+ if (D) {
+ Log.d(TAG, "processCommands:" + workQueue.toString());
+ }
Iterator<BluetoothJob> it = workQueue.iterator();
while (it.hasNext()) {
BluetoothJob job = it.next();
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java b/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java
index 9527980..2c70fd2 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java
@@ -21,6 +21,7 @@ import android.util.Log;
import com.android.settings.R;
import com.android.settings.bluetooth.LocalBluetoothManager.Callback;
+import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
import java.util.ArrayList;
import java.util.List;
@@ -181,19 +182,30 @@ public class LocalBluetoothDeviceManager {
* BluetoothDevice.UNBOND_REASON_*
*/
public synchronized void onBondingError(String address, int reason) {
- mLocalManager.showError(address, R.string.bluetooth_error_title,
- (reason == BluetoothDevice.UNBOND_REASON_AUTH_FAILED) ?
- R.string.bluetooth_pairing_pin_error_message :
- R.string.bluetooth_pairing_error_message);
+ int errorMsg;
+
+ switch(reason) {
+ case BluetoothDevice.UNBOND_REASON_AUTH_FAILED:
+ errorMsg = R.string.bluetooth_pairing_pin_error_message;
+ break;
+ case BluetoothDevice.UNBOND_REASON_AUTH_REJECTED:
+ errorMsg = R.string.bluetooth_pairing_rejected_error_message;
+ break;
+ case BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN:
+ errorMsg = R.string.bluetooth_pairing_device_down_error_message;
+ break;
+ default:
+ errorMsg = R.string.bluetooth_pairing_error_message;
+ }
+ mLocalManager.showError(address, R.string.bluetooth_error_title, errorMsg);
}
- public synchronized void onProfileStateChanged(String address, boolean transientState) {
+ public synchronized void onProfileStateChanged(String address, Profile profile,
+ int newProfileState) {
LocalBluetoothDevice device = findDevice(address);
if (device == null) return;
-
- if (!transientState) {
- device.onProfileStateChanged();
- }
+
+ device.onProfileStateChanged(profile, newProfileState);
device.refresh();
}
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothManager.java b/src/com/android/settings/bluetooth/LocalBluetoothManager.java
index 1a848b2..2e84338 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothManager.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothManager.java
@@ -30,6 +30,7 @@ import android.bluetooth.BluetoothIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.util.Config;
import android.util.Log;
import android.widget.Toast;
@@ -40,7 +41,8 @@ import android.widget.Toast;
*/
public class LocalBluetoothManager {
private static final String TAG = "LocalBluetoothManager";
- static final boolean V = true;
+ static final boolean V = Config.LOGV;
+ static final boolean D = Config.LOGD && false;
private static final String SHARED_PREFERENCES_NAME = "bluetooth_settings";
@@ -199,9 +201,17 @@ public class LocalBluetoothManager {
}
private void syncBluetoothState() {
- setBluetoothStateInt(mManager.isEnabled()
- ? BluetoothDevice.BLUETOOTH_STATE_ON
- : BluetoothDevice.BLUETOOTH_STATE_OFF);
+ int bluetoothState;
+
+ if (mManager != null) {
+ bluetoothState = mManager.isEnabled()
+ ? BluetoothDevice.BLUETOOTH_STATE_ON
+ : BluetoothDevice.BLUETOOTH_STATE_OFF;
+ } else {
+ bluetoothState = BluetoothError.ERROR;
+ }
+
+ setBluetoothStateInt(bluetoothState);
}
public void setBluetoothEnabled(boolean enabled) {
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
index 24563a7..b396732 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
@@ -16,17 +16,14 @@
package com.android.settings.bluetooth;
-import com.android.settings.R;
-
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothClass;
-import android.content.Context;
-import android.content.SharedPreferences;
import android.os.Handler;
import android.text.TextUtils;
+import com.android.settings.R;
+
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -102,6 +99,8 @@ public abstract class LocalBluetoothProfileManager {
public abstract int getSummary(String address);
+ public abstract int convertState(int a2dpState);
+
public abstract boolean isPreferred(String address);
public abstract void setPreferred(String address, boolean preferred);
@@ -176,7 +175,8 @@ public abstract class LocalBluetoothProfileManager {
preferred ? BluetoothA2dp.PRIORITY_AUTO : BluetoothA2dp.PRIORITY_OFF);
}
- private static int convertState(int a2dpState) {
+ @Override
+ public int convertState(int a2dpState) {
switch (a2dpState) {
case BluetoothA2dp.STATE_CONNECTED:
return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
@@ -217,7 +217,9 @@ public abstract class LocalBluetoothProfileManager {
*/
String address = mService.getHeadsetAddress();
if (TextUtils.isEmpty(address)) return;
- mLocalManager.getLocalDeviceManager().onProfileStateChanged(address, true);
+ mLocalManager.getLocalDeviceManager()
+ .onProfileStateChanged(address, Profile.HEADSET,
+ BluetoothHeadset.STATE_CONNECTED);
}
});
}
@@ -273,7 +275,8 @@ public abstract class LocalBluetoothProfileManager {
preferred ? BluetoothHeadset.PRIORITY_AUTO : BluetoothHeadset.PRIORITY_OFF);
}
- private static int convertState(int headsetState) {
+ @Override
+ public int convertState(int headsetState) {
switch (headsetState) {
case BluetoothHeadset.STATE_CONNECTED:
return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
diff --git a/src/com/android/settings/deviceinfo/Status.java b/src/com/android/settings/deviceinfo/Status.java
index 9162d25..ece5346 100644
--- a/src/com/android/settings/deviceinfo/Status.java
+++ b/src/com/android/settings/deviceinfo/Status.java
@@ -50,7 +50,7 @@ import java.lang.ref.WeakReference;
* # Phone Number
* # Network
* # Roaming
- * # IMEI
+ * # Device Id (IMEI in GSM and MEID in CDMA)
* # Network type
* # Signal Strength
* # Battery Strength : TODO
@@ -181,7 +181,9 @@ public class Status extends PreferenceActivity {
mSignalStrength = findPreference("signal_strength");
mUptime = findPreference("up_time");
+ //NOTE "imei" is the "Device ID" since it represents the IMEI in GSM and the MEID in CDMA
setSummaryText("imei", mPhone.getDeviceId());
+
setSummaryText("imei_sv",
((TelephonyManager) getSystemService(TELEPHONY_SERVICE))
.getDeviceSoftwareVersion());
@@ -301,6 +303,9 @@ public class Status extends PreferenceActivity {
}
void updateSignalStrength() {
+ // TODO PhoneStateIntentReceiver is deprecated and PhoneStateListener
+ // should probably used instead.
+
// not loaded in some versions of the code (e.g., zaku)
if (mSignalStrength != null) {
int state =
diff --git a/src/com/android/settings/fuelgauge/PowerGaugePreference.java b/src/com/android/settings/fuelgauge/PowerGaugePreference.java
new file mode 100644
index 0000000..0bfa12d
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/PowerGaugePreference.java
@@ -0,0 +1,119 @@
+/*
+ * 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.fuelgauge;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+import android.preference.Preference;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.settings.R;
+import com.android.settings.fuelgauge.PowerUsageSummary.BatterySipper;
+
+/**
+ * Custom preference for displaying power consumption as a bar and an icon on the left for the
+ * subsystem/app type.
+ *
+ */
+public class PowerGaugePreference extends Preference {
+
+ private Drawable mIcon;
+ private GaugeDrawable mGauge;
+ private double mValue;
+ private BatterySipper mInfo;
+
+ public PowerGaugePreference(Context context, Drawable icon, BatterySipper info) {
+ super(context);
+ setLayoutResource(R.layout.preference_powergauge);
+ mIcon = icon;
+ mGauge = new GaugeDrawable();
+ mGauge.bar = context.getResources().getDrawable(R.drawable.app_gauge);
+ mInfo = info;
+ }
+
+ /**
+ * Sets the width of the gauge in percentage (0 - 100)
+ * @param percent
+ */
+ void setGaugeValue(double percent) {
+ mValue = percent;
+ mGauge.percent = mValue;
+ }
+
+ BatterySipper getInfo() {
+ return mInfo;
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+
+ ImageView appIcon = (ImageView) view.findViewById(R.id.appIcon);
+ if (mIcon == null) {
+ mIcon = getContext().getResources().getDrawable(android.R.drawable.sym_def_app_icon);
+ }
+ appIcon.setImageDrawable(mIcon);
+
+ ImageView appGauge = (ImageView) view.findViewById(R.id.appGauge);
+ appGauge.setImageDrawable(mGauge);
+ }
+
+ static class GaugeDrawable extends Drawable {
+ Drawable bar;
+ double percent;
+ int lastWidth = -1;
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (lastWidth == -1) {
+ lastWidth = getBarWidth();
+ bar.setBounds(0, 0, lastWidth, bar.getIntrinsicHeight());
+ }
+ bar.draw(canvas);
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ // Ignore
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ // Ignore
+ }
+
+ private int getBarWidth() {
+ int width = (int) ((this.getBounds().width() * percent) / 100);
+ int intrinsicWidth = bar.getIntrinsicWidth();
+ return Math.max(width, intrinsicWidth);
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return bar.getIntrinsicHeight();
+ }
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageDetail.java b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
new file mode 100644
index 0000000..eeb8663
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
@@ -0,0 +1,156 @@
+/*
+ * 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.fuelgauge;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.settings.R;
+
+public class PowerUsageDetail extends Activity {
+
+ public static final int USAGE_SINCE_UNPLUGGED = 1;
+ public static final int USAGE_SINCE_RESET = 2;
+
+ public static final String EXTRA_TITLE = "title";
+ public static final String EXTRA_PERCENT = "percent";
+ public static final String EXTRA_USAGE_SINCE = "since";
+ public static final String EXTRA_USAGE_DURATION = "duration";
+ public static final String EXTRA_DETAIL_TYPES = "types";
+ public static final String EXTRA_DETAIL_VALUES = "values";
+
+ private static final int SECONDS_PER_MINUTE = 60;
+ private static final int SECONDS_PER_HOUR = 60 * 60;
+ private static final int SECONDS_PER_DAY = 24 * 60 * 60;
+
+ private static final boolean DEBUG = true;
+ private String mTitle;
+ private double mPercentage;
+ private int mUsageSince;
+ private int[] mTypes;
+ private double[] mValues;
+ private TextView mTitleView;
+ private ViewGroup mDetailsParent;
+ private long mStartTime;
+
+ private static final String TAG = "PowerUsageDetail";
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.power_usage_details);
+ createDetails();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mStartTime = android.os.Process.getElapsedCpuTime();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ private void createDetails() {
+ final Intent intent = getIntent();
+ mTitle = intent.getStringExtra(EXTRA_TITLE);
+ mPercentage = intent.getDoubleExtra(EXTRA_PERCENT, -1);
+ mUsageSince = intent.getIntExtra(EXTRA_USAGE_SINCE, USAGE_SINCE_UNPLUGGED);
+
+ mTypes = intent.getIntArrayExtra(EXTRA_DETAIL_TYPES);
+ mValues = intent.getDoubleArrayExtra(EXTRA_DETAIL_VALUES);
+
+ mTitleView = (TextView) findViewById(R.id.name);
+ mTitleView.setText(mTitle);
+ // TODO: I18N
+ ((TextView)findViewById(R.id.battery_percentage))
+ .setText(String.format("%3.2f%% of battery usage since last unplugged", mPercentage));
+
+ mDetailsParent = (ViewGroup) findViewById(R.id.details);
+ LayoutInflater inflater = getLayoutInflater();
+ if (mTypes != null && mValues != null) {
+ for (int i = 0; i < mTypes.length; i++) {
+ // Only add an item if the time is greater than zero
+ if (mValues[i] <= 0) continue;
+ final String label = getString(mTypes[i]);
+ String value = null;
+ switch (mTypes[i]) {
+ case R.string.usage_type_data_recv:
+ case R.string.usage_type_data_send:
+ value = formatBytes(mValues[i]);
+ break;
+ default:
+ value = formatTime(mValues[i]);
+ }
+ ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text,
+ null);
+ mDetailsParent.addView(item);
+ TextView labelView = (TextView) item.findViewById(R.id.label);
+ TextView valueView = (TextView) item.findViewById(R.id.value);
+ labelView.setText(label);
+ valueView.setText(value);
+ }
+ }
+ }
+
+ private String formatTime(double millis) {
+ StringBuilder sb = new StringBuilder();
+ int seconds = (int) Math.floor(millis / 1000);
+
+ int days = 0, hours = 0, minutes = 0;
+ if (seconds > SECONDS_PER_DAY) {
+ days = seconds / SECONDS_PER_DAY;
+ seconds -= days * SECONDS_PER_DAY;
+ }
+ if (seconds > SECONDS_PER_HOUR) {
+ hours = seconds / SECONDS_PER_HOUR;
+ seconds -= hours * SECONDS_PER_HOUR;
+ }
+ if (seconds > SECONDS_PER_MINUTE) {
+ minutes = seconds / SECONDS_PER_MINUTE;
+ seconds -= minutes * SECONDS_PER_MINUTE;
+ }
+ if (days > 0) {
+ sb.append(getString(R.string.battery_history_days, days, hours, minutes, seconds));
+ } else if (hours > 0) {
+ sb.append(getString(R.string.battery_history_hours, hours, minutes, seconds));
+ } else if (minutes > 0) {
+ sb.append(getString(R.string.battery_history_minutes, minutes, seconds));
+ } else {
+ sb.append(getString(R.string.battery_history_seconds, seconds));
+ }
+ return sb.toString();
+ }
+
+ private String formatBytes(double bytes) {
+ // TODO: I18N
+ if (bytes > 1000 * 1000) {
+ return String.format("%.2f MB", ((int) (bytes / 1000)) / 1000f);
+ } else if (bytes > 1024) {
+ return String.format("%.2f KB", ((int) (bytes / 10)) / 100f);
+ } else {
+ return String.format("%d bytes", (int) bytes);
+ }
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
new file mode 100644
index 0000000..296a9c7
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -0,0 +1,494 @@
+/*
+ * 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.fuelgauge;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.drawable.Drawable;
+import android.hardware.SensorManager;
+import android.os.BatteryStats;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.BatteryStats.Timer;
+import android.os.BatteryStats.Uid;
+import android.os.BatteryStats.Uid.Sensor;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.PowerProfile;
+import com.android.settings.R;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Displays a list of apps and subsystems that consume power, ordered by how much power was
+ * consumed since the last time it was unplugged.
+ */
+public class PowerUsageSummary extends PreferenceActivity {
+
+ private static final boolean DEBUG = true;
+
+ private static final String TAG = "PowerUsageSummary";
+
+ private static final int MENU_STATS_TYPE = Menu.FIRST;
+ private static final int MENU_STATS_REFRESH = Menu.FIRST + 1;
+
+ enum DrainType {
+ IDLE,
+ CELL,
+ PHONE,
+ WIFI,
+ BLUETOOTH,
+ SCREEN,
+ APP
+ }
+
+ IBatteryStats mBatteryInfo;
+ BatteryStatsImpl mStats;
+ private List<BatterySipper> mUsageList = new ArrayList<BatterySipper>();
+
+ private PreferenceGroup mAppListGroup;
+
+ private int mStatsType = BatteryStats.STATS_UNPLUGGED;
+
+ private static final int MIN_POWER_THRESHOLD = 5;
+ private static final int MAX_ITEMS_TO_LIST = 10;
+
+ private double mMaxPower = 1;
+ private double mTotalPower;
+
+ private boolean mScaleByMax = true;
+
+ private PowerProfile mPowerProfile;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ addPreferencesFromResource(R.xml.power_usage_summary);
+ mBatteryInfo = IBatteryStats.Stub.asInterface(
+ ServiceManager.getService("batteryinfo"));
+ mAppListGroup = getPreferenceScreen();
+ mPowerProfile = new PowerProfile(this, "power_profile_default");
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ updateAppsList();
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ PowerGaugePreference pgp = (PowerGaugePreference) preference;
+ BatterySipper sipper = pgp.getInfo();
+ Intent intent = new Intent(this, PowerUsageDetail.class);
+ intent.putExtra(PowerUsageDetail.EXTRA_TITLE, sipper.mLabel);
+ intent.putExtra(PowerUsageDetail.EXTRA_PERCENT, sipper.getSortValue() * 100 / mTotalPower);
+
+ switch (sipper.mDrainType) {
+ case APP:
+ {
+ Uid uid = sipper.mUid;
+ int[] types = new int[] {
+ R.string.usage_type_cpu,
+ R.string.usage_type_cpu_foreground,
+ R.string.usage_type_gps,
+ R.string.usage_type_data_send,
+ R.string.usage_type_data_recv,
+ R.string.usage_type_audio,
+ R.string.usage_type_video,
+ };
+ double[] values = new double[] {
+ sipper.mCpuTime,
+ sipper.mCpuFgTime,
+ sipper.mGpsTime,
+ uid != null? uid.getTcpBytesSent(mStatsType) : 0,
+ uid != null? uid.getTcpBytesReceived(mStatsType) : 0,
+ 0,
+ 0
+ };
+ intent.putExtra(PowerUsageDetail.EXTRA_DETAIL_TYPES, types);
+ intent.putExtra(PowerUsageDetail.EXTRA_DETAIL_VALUES, values);
+
+ }
+ break;
+ }
+ startActivity(intent);
+
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ /*
+ menu.add(0, MENU_STATS_TYPE, 0, R.string.menu_stats_total)
+ .setIcon(com.android.internal.R.drawable.ic_menu_info_details)
+ .setAlphabeticShortcut('t');
+ */
+ menu.add(0, MENU_STATS_REFRESH, 0, R.string.menu_stats_refresh)
+ .setIcon(com.android.internal.R.drawable.ic_menu_refresh)
+ .setAlphabeticShortcut('r');
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ /*
+ menu.findItem(MENU_STATS_TYPE).setTitle(mStatsType == BatteryStats.STATS_TOTAL
+ ? R.string.menu_stats_unplugged
+ : R.string.menu_stats_total);
+ */
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_STATS_TYPE:
+ if (mStatsType == BatteryStats.STATS_TOTAL) {
+ mStatsType = BatteryStats.STATS_UNPLUGGED;
+ } else {
+ mStatsType = BatteryStats.STATS_TOTAL;
+ }
+ updateAppsList();
+ return true;
+ case MENU_STATS_REFRESH:
+ mStats = null;
+ updateAppsList();
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private void updateAppsList() {
+ if (mStats == null) {
+ load();
+ }
+ mMaxPower = 0;
+ mTotalPower = 0;
+
+ mAppListGroup.removeAll();
+ mUsageList.clear();
+ processAppUsage();
+ processMiscUsage();
+
+ mAppListGroup.setOrderingAsAdded(false);
+
+ Collections.sort(mUsageList);
+ for (BatterySipper g : mUsageList) {
+ if (g.getSortValue() < MIN_POWER_THRESHOLD) continue;
+ double percent = ((g.getSortValue() / mTotalPower) * 100);
+ PowerGaugePreference pref = new PowerGaugePreference(this, g.getIcon(), g);
+ double scaleByMax = (g.getSortValue() * 100) / mMaxPower;
+ pref.setSummary(g.getLabel() + " ( " + String.format("%3.2f", percent) + "% )");
+ pref.setOrder(Integer.MAX_VALUE - (int) g.getSortValue()); // Invert the order
+ pref.setGaugeValue(mScaleByMax ? scaleByMax : percent);
+ mAppListGroup.addPreference(pref);
+ if (mAppListGroup.getPreferenceCount() > MAX_ITEMS_TO_LIST) break;
+ }
+ }
+
+ private void processAppUsage() {
+ SensorManager sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
+ final int which = mStatsType;
+ final double powerCpuNormal = mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_NORMAL);
+ long uSecTime = mStats.computeBatteryRealtime(SystemClock.elapsedRealtime(), which) * 1000;
+ SparseArray<? extends Uid> uidStats = mStats.getUidStats();
+ final int NU = uidStats.size();
+ if (DEBUG) Log.i(TAG, "uidStats size = " + NU);
+ for (int iu = 0; iu < NU; iu++) {
+ Uid u = uidStats.valueAt(iu);
+ double power = 0;
+ //mUsageList.add(new AppUsage(u.getUid(), new double[] {power}));
+ Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
+ long cpuTime = 0;
+ long cpuFgTime = 0;
+ long gpsTime = 0;
+ if (processStats.size() > 0) {
+ for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
+ : processStats.entrySet()) {
+
+ Uid.Proc ps = ent.getValue();
+ long userTime = ps.getUserTime(which);
+ long systemTime = ps.getSystemTime(which);
+ long foregroundTime = ps.getForegroundTime(which);
+ cpuFgTime += foregroundTime * 10; // convert to millis
+ if (DEBUG) Log.i(TAG, "CPU Fg time for " + u.getUid() + " = " + foregroundTime);
+ cpuTime = (userTime + systemTime) * 10; // convert to millis
+ power += cpuTime * powerCpuNormal;
+
+ }
+ }
+ if (cpuFgTime > cpuTime) {
+ if (DEBUG && cpuFgTime > cpuTime + 10000) {
+ Log.i(TAG, "WARNING! Cputime is more than 10 seconds behind Foreground time");
+ }
+ cpuTime = cpuFgTime; // Statistics may not have been gathered yet.
+ }
+ power /= 1000;
+
+ Map<Integer, ? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
+ for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> sensorEntry
+ : sensorStats.entrySet()) {
+ Uid.Sensor sensor = sensorEntry.getValue();
+ int sensorType = sensor.getHandle();
+ BatteryStats.Timer timer = sensor.getSensorTime();
+ long sensorTime = timer.getTotalTimeLocked(uSecTime, which) / 1000;
+ double multiplier = 0;
+ switch (sensorType) {
+ case Uid.Sensor.GPS:
+ multiplier = mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_ON);
+ gpsTime = sensorTime;
+ break;
+ default:
+ android.hardware.Sensor sensorData =
+ sensorManager.getDefaultSensor(sensorType);
+ if (sensorData != null) {
+ multiplier = sensorData.getPower();
+ if (DEBUG) {
+ Log.i(TAG, "Got sensor " + sensorData.getName() + " with power = "
+ + multiplier);
+ }
+ }
+ }
+ power += (multiplier * sensorTime) / 1000;
+ }
+ if (power != 0) {
+ BatterySipper app = new BatterySipper(null, DrainType.APP, 0, u,
+ new double[] {power});
+ app.mCpuTime = cpuTime;
+ app.mGpsTime = gpsTime;
+ app.mCpuFgTime = cpuFgTime;
+ mUsageList.add(app);
+ }
+ if (power > mMaxPower) mMaxPower = power;
+ mTotalPower += power;
+ if (DEBUG) Log.i(TAG, "Added power = " + power);
+ }
+ }
+
+ private double getPhoneOnPower(long uSecNow) {
+ return mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
+ * mStats.getPhoneOnTime(uSecNow, mStatsType) / 1000 / 1000;
+ }
+
+ private double getScreenOnPower(long uSecNow) {
+ double power = 0;
+ power += mStats.getScreenOnTime(uSecNow, mStatsType)
+ * mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON) / 1000; // millis
+ final double screenFullPower =
+ mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
+ for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+ double screenBinPower = screenFullPower * (i + 0.5f)
+ / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
+ long brightnessTime = mStats.getScreenBrightnessTime(i, uSecNow, mStatsType) / 1000;
+ power += screenBinPower * brightnessTime;
+ if (DEBUG) {
+ Log.i(TAG, "Screen bin power = " + (int) screenBinPower + ", time = "
+ + brightnessTime);
+ }
+ }
+ return power / 1000;
+ }
+
+ private double getRadioPower(long uSecNow, int which) {
+ double power = 0;
+ final int BINS = BatteryStats.NUM_SIGNAL_STRENGTH_BINS;
+ for (int i = 0; i < BINS; i++) {
+ power += mStats.getPhoneSignalStrengthTime(i, uSecNow, which) / 1000 / 1000 *
+ mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ON)
+ * ((BINS - i) / (double) BINS);
+ }
+ return power;
+ }
+
+ private void processMiscUsage() {
+ final int which = mStatsType;
+ long uSecTime = SystemClock.elapsedRealtime() * 1000;
+ final long uSecNow = mStats.computeBatteryRealtime(uSecTime, which);
+ final long timeSinceUnplugged = uSecNow;
+ if (DEBUG) {
+ Log.i(TAG, "Uptime since last unplugged = " + (timeSinceUnplugged / 1000));
+ }
+
+ double phoneOnPower = getPhoneOnPower(uSecNow);
+ addEntry(getString(R.string.power_phone), DrainType.PHONE,
+ android.R.drawable.ic_menu_call, phoneOnPower);
+
+ double screenOnPower = getScreenOnPower(uSecNow);
+ addEntry(getString(R.string.power_screen), DrainType.SCREEN,
+ android.R.drawable.ic_menu_view, screenOnPower);
+
+ double wifiPower = (mStats.getWifiOnTime(uSecNow, which) * 0 /* TODO */
+ * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)
+ + mStats.getWifiRunningTime(uSecNow, which)
+ * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / 1000 / 1000;
+ addEntry(getString(R.string.power_wifi), DrainType.WIFI,
+ R.drawable.ic_wifi_signal_4, wifiPower);
+
+ double idlePower = ((timeSinceUnplugged - mStats.getScreenOnTime(uSecNow, mStatsType))
+ * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE)) / 1000 / 1000;
+ addEntry(getString(R.string.power_idle), DrainType.IDLE,
+ android.R.drawable.ic_lock_power_off, idlePower);
+
+ double radioPower = getRadioPower(uSecNow, which);
+ addEntry(getString(R.string.power_cell), DrainType.CELL,
+ android.R.drawable.ic_menu_sort_by_size, radioPower);
+ }
+
+ private void addEntry(String label, DrainType drainType, int iconId, double power) {
+ if (power > mMaxPower) mMaxPower = power;
+ mTotalPower += power;
+ BatterySipper bs = new BatterySipper(label, drainType, iconId, null, new double[] {power});
+ mUsageList.add(bs);
+ }
+
+ private void load() {
+ try {
+ byte[] data = mBatteryInfo.getStatistics();
+ Parcel parcel = Parcel.obtain();
+ parcel.unmarshall(data, 0, data.length);
+ parcel.setDataPosition(0);
+ mStats = com.android.internal.os.BatteryStatsImpl.CREATOR
+ .createFromParcel(parcel);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException:", e);
+ }
+ }
+
+ class BatterySipper implements Comparable<BatterySipper> {
+ String mLabel;
+ Drawable mIcon;
+ Uid mUid;
+ double mValue;
+ double[] mValues;
+ DrainType mDrainType;
+ long mCpuTime;
+ long mGpsTime;
+ long mCpuFgTime;
+
+ BatterySipper(String label, DrainType drainType, int iconId, Uid uid, double[] values) {
+ mValues = values;
+ mLabel = label;
+ mDrainType = drainType;
+ if (iconId > 0) {
+ mIcon = getResources().getDrawable(iconId);
+ }
+ if (mValues != null) mValue = mValues[0];
+ //if (uid > 0 && (mLabel == null || mIcon == null) // TODO:
+ if ((label == null || iconId == 0) && uid!= null) {
+ getNameForUid(uid.getUid());
+ }
+ mUid = uid;
+ }
+
+ double getSortValue() {
+ return mValue;
+ }
+
+ double[] getValues() {
+ return mValues;
+ }
+
+ Drawable getIcon() {
+ return mIcon;
+ }
+
+ public int compareTo(BatterySipper other) {
+ // Return the flipped value because we want the items in descending order
+ return (int) (other.getSortValue() - getSortValue());
+ }
+
+ String getLabel() {
+ return mLabel;
+ }
+
+ /**
+ * Sets mLabel and mIcon
+ * @param uid Uid of the application
+ */
+ void getNameForUid(int uid) {
+ // TODO: Do this on a separate thread
+ PackageManager pm = getPackageManager();
+ String[] packages = pm.getPackagesForUid(uid);
+ if (packages == null) {
+ mLabel = Integer.toString(uid);
+ return;
+ }
+
+ String[] packageNames = new String[packages.length];
+ System.arraycopy(packages, 0, packageNames, 0, packages.length);
+
+ // Convert package names to user-facing labels where possible
+ for (int i = 0; i < packageNames.length; i++) {
+ //packageNames[i] = PowerUsageSummary.getLabel(packageNames[i], pm);
+ try {
+ ApplicationInfo ai = pm.getApplicationInfo(packageNames[i], 0);
+ CharSequence label = ai.loadLabel(pm);
+ if (label != null) {
+ packageNames[i] = label.toString();
+ }
+ if (mIcon == null) {
+ mIcon = ai.loadIcon(pm);
+ }
+ } catch (NameNotFoundException e) {
+ }
+ }
+
+ if (packageNames.length == 1) {
+ mLabel = packageNames[0];
+ } else {
+ // Look for an official name for this UID.
+ for (String name : packages) {
+ try {
+ PackageInfo pi = pm.getPackageInfo(name, 0);
+ if (pi.sharedUserLabel != 0) {
+ CharSequence nm = pm.getText(name,
+ pi.sharedUserLabel, pi.applicationInfo);
+ if (nm != null) {
+ mLabel = nm.toString();
+ break;
+ }
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/settings/widget/SettingsAppWidgetProvider.java b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
new file mode 100644
index 0000000..002816f
--- /dev/null
+++ b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
@@ -0,0 +1,404 @@
+/*
+ * 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.widget;
+
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.bluetooth.BluetoothDevice;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IContentService;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.location.LocationManager;
+import android.net.ConnectivityManager;
+import android.net.Uri;
+import android.net.wifi.WifiManager;
+import android.os.IHardwareService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.widget.RemoteViews;
+import com.android.settings.R;
+import com.android.settings.bluetooth.LocalBluetoothManager;
+
+/**
+ * Provides control of power-related settings from a widget.
+ */
+public class SettingsAppWidgetProvider extends AppWidgetProvider {
+ static final String TAG = "SettingsAppWidgetProvider";
+
+ static final ComponentName THIS_APPWIDGET =
+ new ComponentName("com.android.settings",
+ "com.android.settings.widget.SettingsAppWidgetProvider");
+
+ private static LocalBluetoothManager mLocalBluetoothManager = null;
+
+ private static final int BUTTON_WIFI = 0;
+ private static final int BUTTON_BRIGHTNESS = 1;
+ private static final int BUTTON_SYNC = 2;
+ private static final int BUTTON_GPS = 3;
+ private static final int BUTTON_BLUETOOTH = 4;
+
+ private static final int STATE_DISABLED = 0;
+ private static final int STATE_ENABLED = 1;
+ private static final int STATE_INTERMEDIATE = 2;
+
+ /**
+ * Minimum and maximum brightnesses. Don't go to 0 since that makes the display unusable
+ */
+ private static final int MINIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_DIM + 10;
+ 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);
+
+ @Override
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager,
+ int[] appWidgetIds) {
+ // Update each requested appWidgetId
+ RemoteViews view = buildUpdate(context, -1);
+
+ for (int i = 0; i < appWidgetIds.length; i++) {
+ appWidgetManager.updateAppWidget(appWidgetIds[i], view);
+ }
+ }
+
+ @Override
+ public void onEnabled(Context context) {
+ PackageManager pm = context.getPackageManager();
+ pm.setComponentEnabledSetting(
+ new ComponentName("com.android.settings", ".widget.SettingsAppWidgetProvider"),
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP);
+ }
+
+ @Override
+ public void onDisabled(Context context) {
+ Class clazz = com.android.settings.widget.SettingsAppWidgetProvider.class;
+ PackageManager pm = context.getPackageManager();
+ pm.setComponentEnabledSetting(
+ new ComponentName("com.android.settings", ".widget.SettingsAppWidgetProvider"),
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ }
+
+ /**
+ * Load image for given widget and build {@link RemoteViews} for it.
+ */
+ static RemoteViews buildUpdate(Context context, int appWidgetId) {
+ RemoteViews views = new RemoteViews(context.getPackageName(),
+ R.layout.widget);
+ views.setOnClickPendingIntent(R.id.btn_wifi, getLaunchPendingIntent(context, appWidgetId,
+ BUTTON_WIFI));
+ views.setOnClickPendingIntent(R.id.btn_brightness,
+ getLaunchPendingIntent(context,
+ appWidgetId, BUTTON_BRIGHTNESS));
+ views.setOnClickPendingIntent(R.id.btn_sync,
+ getLaunchPendingIntent(context,
+ appWidgetId, BUTTON_SYNC));
+ views.setOnClickPendingIntent(R.id.btn_gps,
+ getLaunchPendingIntent(context, appWidgetId, BUTTON_GPS));
+ views.setOnClickPendingIntent(R.id.btn_bluetooth,
+ getLaunchPendingIntent(context,
+ appWidgetId, BUTTON_BLUETOOTH));
+
+ updateButtons(views, context);
+ return views;
+ }
+
+ /**
+ * Updates the widget when something changes, or when a button is pushed.
+ *
+ * @param context
+ */
+ public static void updateWidget(Context context) {
+ RemoteViews views = buildUpdate(context, -1);
+ // Update specific list of appWidgetIds if given, otherwise default to all
+ final AppWidgetManager gm = AppWidgetManager.getInstance(context);
+ gm.updateAppWidget(THIS_APPWIDGET, views);
+ }
+
+ /**
+ * Updates the buttons based on the underlying states of wifi, etc.
+ *
+ * @param views The RemoteViews to update.
+ * @param context
+ */
+ private static void updateButtons(RemoteViews views, Context context) {
+ switch (getWifiState(context)) {
+ case STATE_DISABLED:
+ views.setImageViewResource(R.id.btn_wifi, R.drawable.widget_btn_wifi_off);
+ break;
+ case STATE_ENABLED:
+ views.setImageViewResource(R.id.btn_wifi, R.drawable.widget_btn_wifi);
+ break;
+ case STATE_INTERMEDIATE:
+ views.setImageViewResource(R.id.btn_wifi, R.drawable.widget_btn_wifi_gray);
+ break;
+ }
+ if (getBrightness(context)) {
+ views.setImageViewResource(R.id.btn_brightness, R.drawable.widget_btn_brightness);
+ } else {
+ views.setImageViewResource(R.id.btn_brightness, R.drawable.widget_btn_brightness_off);
+ }
+ if (getBackgroundDataState(context)) {
+ views.setImageViewResource(R.id.btn_sync, R.drawable.widget_btn_sync);
+ } else {
+ views.setImageViewResource(R.id.btn_sync, R.drawable.widget_btn_sync_off);
+ }
+ if (getGpsState(context)) {
+ views.setImageViewResource(R.id.btn_gps, R.drawable.widget_btn_gps);
+ } else {
+ views.setImageViewResource(R.id.btn_gps, R.drawable.widget_btn_gps_off);
+ }
+ switch (getBluetoothState(context)) {
+ case STATE_DISABLED:
+ views.setImageViewResource(R.id.btn_bluetooth, R.drawable.widget_btn_bluetooth_off);
+ break;
+ case STATE_ENABLED:
+ views.setImageViewResource(R.id.btn_bluetooth, R.drawable.widget_btn_bluetooth);
+ break;
+ case STATE_INTERMEDIATE:
+ views.setImageViewResource(R.id.btn_bluetooth, R.drawable.widget_btn_bluetooth_gray);
+ break;
+ }
+ }
+
+ /**
+ * Creates PendingIntent to notify the widget of a button click.
+ *
+ * @param context
+ * @param appWidgetId
+ * @return
+ */
+ private static PendingIntent getLaunchPendingIntent(Context context, int appWidgetId, int buttonId) {
+ Intent launchIntent = new Intent();
+ launchIntent.setClass(context, SettingsAppWidgetProvider.class);
+ launchIntent.addCategory(Intent.CATEGORY_ALTERNATIVE);
+ launchIntent.setData(Uri.parse("custom:" + buttonId));
+ PendingIntent pi = PendingIntent.getBroadcast(context, 0 /* no requestCode */,
+ launchIntent, 0 /* no flags */);
+ return pi;
+ }
+
+ /**
+ * Receives and processes a button pressed intent or state change.
+ *
+ * @param context
+ * @param intent Indicates the pressed button.
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ super.onReceive(context, intent);
+ if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
+ Uri data = intent.getData();
+ int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
+ if (buttonId == BUTTON_WIFI) {
+ toggleWifi(context);
+ } else if (buttonId == BUTTON_BRIGHTNESS) {
+ toggleBrightness(context);
+ } else if (buttonId == BUTTON_SYNC) {
+ toggleBackgroundData(context);
+ } else if (buttonId == BUTTON_GPS) {
+ toggleGps(context);
+ } else if (buttonId == BUTTON_BLUETOOTH) {
+ toggleBluetooth(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;
+ }
+ }
+
+ /**
+ * 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);
+ mLocalBluetoothManager.setBluetoothEnabled(true);
+ }
+ }
+
+ /**
+ * Gets the state of background data.
+ *
+ * @param context
+ * @return true if enabled
+ */
+ private static boolean getBackgroundDataState(Context context) {
+ ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ return connManager.getBackgroundDataSetting();
+ }
+
+ /**
+ * Toggle background data and sync tickles.
+ *
+ * @param context
+ */
+ private void toggleBackgroundData(Context context) {
+ ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ boolean sync = getBackgroundDataState(context);
+ connManager.setBackgroundDataSetting(!sync);
+
+ IContentService contentService = ContentResolver.getContentService();
+ try {
+ contentService.setListenForNetworkTickles(!sync);
+ } catch (RemoteException e) {
+ Log.d(TAG, "toggleBackgroundData: " + e);
+ }
+ }
+
+ /**
+ * Gets the state of GPS location.
+ *
+ * @param context
+ * @return true if enabled.
+ */
+ private static boolean getGpsState(Context context) {
+ ContentResolver resolver = context.getContentResolver();
+ return Settings.Secure.isLocationProviderEnabled(resolver, LocationManager.GPS_PROVIDER);
+ }
+
+ /**
+ * Toggles the state of GPS.
+ *
+ * @param context
+ */
+ private void toggleGps(Context context) {
+ ContentResolver resolver = context.getContentResolver();
+ boolean enabled = getGpsState(context);
+ Settings.Secure.setLocationProviderEnabled(resolver, LocationManager.GPS_PROVIDER, !enabled);
+ }
+
+ /**
+ * Gets state of brightness.
+ *
+ * @param context
+ * @return true if more than moderately bright.
+ */
+ private static boolean getBrightness(Context context) {
+ try {
+ IHardwareService hardware = IHardwareService.Stub.asInterface(
+ ServiceManager.getService("hardware"));
+ if (hardware != null) {
+ int brightness = Settings.System.getInt(context.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS);
+ return brightness > 100;
+ }
+ } catch (Exception e) {
+ Log.d(TAG, "getBrightness: " + e);
+ }
+ return false;
+ }
+
+ /**
+ * Increases or decreases the brightness.
+ *
+ * @param context
+ */
+ private void toggleBrightness(Context context) {
+ try {
+ IHardwareService hardware = IHardwareService.Stub.asInterface(
+ ServiceManager.getService("hardware"));
+ if (hardware != null) {
+ ContentResolver cr = context.getContentResolver();
+ int brightness = Settings.System.getInt(cr,
+ Settings.System.SCREEN_BRIGHTNESS);
+ // Rotate MINIMUM -> DEFAULT -> MAXIMUM
+ // Technically, not a toggle...
+ if (brightness < DEFAULT_BACKLIGHT) {
+ brightness = DEFAULT_BACKLIGHT;
+ } else if (brightness < MAXIMUM_BACKLIGHT) {
+ brightness = MAXIMUM_BACKLIGHT;
+ } else {
+ brightness = MINIMUM_BACKLIGHT;
+ }
+ hardware.setBacklights(brightness);
+ Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
+ brightness = Settings.System.getInt(cr,
+ Settings.System.SCREEN_BRIGHTNESS);
+ }
+ } catch (RemoteException e) {
+ Log.d(TAG, "toggleBrightness: " + e);
+ } catch (Settings.SettingNotFoundException e) {
+ 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 == BluetoothDevice.BLUETOOTH_STATE_OFF) {
+ return STATE_DISABLED;
+ } else if (state == BluetoothDevice.BLUETOOTH_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);
+ }
+ }
+}
diff --git a/src/com/android/settings/wifi/AccessPointDialog.java b/src/com/android/settings/wifi/AccessPointDialog.java
index 919f7fc..dc2b389 100644
--- a/src/com/android/settings/wifi/AccessPointDialog.java
+++ b/src/com/android/settings/wifi/AccessPointDialog.java
@@ -21,6 +21,7 @@ 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.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
@@ -71,6 +72,8 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
private static final int SECURITY_WEP = 2;
private static final int SECURITY_WPA_PERSONAL = 3;
private static final int SECURITY_WPA2_PERSONAL = 4;
+ private static final int SECURITY_WPA_EAP = 5;
+ private static final int SECURITY_IEEE8021X = 6;
private static final int[] WEP_TYPE_VALUES = {
AccessPointState.WEP_PASSWORD_AUTO, AccessPointState.WEP_PASSWORD_ASCII,
@@ -92,15 +95,39 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
// 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 mClientCertText;
+ private Spinner mClientCertSpinner;
+ private TextView mCaCertText;
+ private Spinner mCaCertSpinner;
+ private TextView mPrivateKeyText;
+ private Spinner mPrivateKeySpinner;
+ private TextView mPrivateKeyPasswdText;
+ private EditText mPrivateKeyPasswdEdit;
+ private EditText[] mEnterpriseTextFields;
+ private Spinner[] mEnterpriseSpinnerFields;
+
// Info-specific views
private ViewGroup mTable;
// Configure-specific views
private EditText mSsidEdit;
+ private TextView mSsidText;
+ private TextView mSecurityText;
private Spinner mSecuritySpinner;
private Spinner mWepTypeSpinner;
@@ -208,9 +235,17 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
positiveButtonResId = R.string.wifi_save_config;
mSaveButtonPos = POSITIVE_BUTTON;
-
+
+ setEnterpriseFieldsVisible(false);
+
} else if (mMode == MODE_INFO) {
- setLayout(R.layout.wifi_ap_info);
+ if (isEnterprise() && !mState.configured) {
+ setLayout(R.layout.wifi_ap_configure);
+ defaultPasswordVisibility = false;
+ setEnterpriseFieldsVisible(true);
+ } else {
+ setLayout(R.layout.wifi_ap_info);
+ }
if (mState.isConnectable()) {
if (mCustomTitle == null) {
@@ -251,41 +286,131 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
setButtons(positiveButtonResId, negativeButtonResId, neutralButtonResId);
}
+ private boolean isEnterprise() {
+
+ if(AccessPointState.WPA_EAP.equals(mState.security) ||
+ AccessPointState.IEEE8021X.equals(mState.security)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
/** 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) {
- mSsidEdit = (EditText) view.findViewById(R.id.ssid_edit);
- mSecuritySpinner = (Spinner) view.findViewById(R.id.security_spinner);
mSecuritySpinner.setOnItemSelectedListener(this);
- setSecuritySpinnerAdapter();
- mWepTypeSpinner = (Spinner) view.findViewById(R.id.wep_type_spinner);
-
+ 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 || (isEnterprise() && !mState.configured)) {
+ setEnterpriseFields(view);
+ mEapSpinner.setSelection(getSelectionIndex(
+ R.array.wifi_eap_entries, mState.getEap()));
+ Keystore ks = Keystore.getInstance();
+ mClientCertSpinner.setSelection(getSelectionIndex(
+ ks.getAllCertificateKeys(), mState.getEnterpriseField(
+ AccessPointState.CLIENT_CERT)));
+ mCaCertSpinner.setSelection(getSelectionIndex(
+ ks.getAllCertificateKeys(), mState.getEnterpriseField(
+ AccessPointState.CA_CERT)));
+ mPrivateKeySpinner.setSelection(getSelectionIndex(
+ ks.getAllUserkeyKeys(), mState.getEnterpriseField(
+ AccessPointState.PRIVATE_KEY)));
+ }
}
-
- private void setSecuritySpinnerAdapter() {
- Context context = getContext();
- int arrayResId = mAutoSecurityAllowed ? R.array.wifi_security_entries
- : R.array.wifi_security_without_auto_entries;
- ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(context,
- android.R.layout.simple_spinner_item,
- context.getResources().getStringArray(arrayResId));
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- mSecuritySpinner.setAdapter(adapter);
+ 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);
+ mPrivateKeyText = (TextView) view.findViewById(R.id.private_key_text);
+ mPrivateKeyPasswdText =
+ (TextView) view.findViewById(R.id.private_key_passwd_text);
+ mPrivateKeyPasswdEdit =
+ (EditText) view.findViewById(R.id.private_key_passwd_edit);
+ 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);
+
+ Keystore ks = Keystore.getInstance();
+
+ mClientCertSpinner =
+ (Spinner) view.findViewById(R.id.client_certificate_spinner);
+ mClientCertSpinner.setOnItemSelectedListener(this);
+ mClientCertSpinner.setPromptId(
+ R.string.please_select_client_certificate);
+ setSpinnerAdapter(mClientCertSpinner, ks.getAllCertificateKeys());
+
+ mCaCertSpinner =
+ (Spinner) view.findViewById(R.id.ca_certificate_spinner);
+ mCaCertSpinner.setOnItemSelectedListener(this);
+ mCaCertSpinner.setPromptId(R.string.please_select_ca_certificate);
+ setSpinnerAdapter(mCaCertSpinner, ks.getAllCertificateKeys());
+
+ mPrivateKeySpinner =
+ (Spinner) view.findViewById(R.id.private_key_spinner);
+ mPrivateKeySpinner.setOnItemSelectedListener(this);
+ mPrivateKeySpinner.setPromptId(R.string.please_select_private_key);
+ setSpinnerAdapter(mPrivateKeySpinner, ks.getAllUserkeyKeys());
+
+ mEnterpriseTextFields = new EditText[] {
+ mIdentityEdit, mAnonymousIdentityEdit, mPrivateKeyPasswdEdit
+ };
+
+ mEnterpriseSpinnerFields = new Spinner[] {
+ mClientCertSpinner, mCaCertSpinner, mPrivateKeySpinner
+ };
+
+ }
+
+ 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() {
@@ -381,39 +506,51 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
if (!replaceStateWithWifiLayerInstance()) {
Log.w(TAG, "Assuming connecting to a new network.");
}
-
- /*
- * 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).
- */
- 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)) {
- 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);
+
+ if (isEnterprise()) {
+ if(!mState.configured) {
+ updateEnterpriseFields(
+ AccessPointState.WPA_EAP.equals(mState.security) ?
+ SECURITY_WPA_EAP : SECURITY_IEEE8021X);
+ }
+ } else {
+ updatePasswordField();
}
-
- mWifiLayer.connectToNetwork(mState);
+ 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)) {
+ 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();
@@ -471,6 +608,61 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
}
+ 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 securityType) {
+ int i;
+ Keystore ks = Keystore.getInstance();
+ for (i = AccessPointState.IDENTITY ;
+ i < AccessPointState.MAX_ENTRPRISE_FIELD ; i++) {
+ String value;
+ if (i <= AccessPointState.PRIVATE_KEY_PASSWD) {
+ value = mEnterpriseTextFields[i].getText().toString();
+ } else {
+ Spinner spinner = mEnterpriseSpinnerFields[i -
+ AccessPointState.CLIENT_CERT];
+
+ if (i != AccessPointState.PRIVATE_KEY) {
+ value = ks.getCertificate(ks.getAllCertificateKeys()
+ [spinner.getSelectedItemPosition()]);
+ } else {
+ value = ks.getUserkey(ks.getAllUserkeyKeys()
+ [spinner.getSelectedItemPosition()]);
+ }
+ }
+ if (!TextUtils.isEmpty(value)) {
+ mState.setEnterpriseField(i, value);
+ }
+ }
+
+ switch (securityType) {
+ case SECURITY_WPA_EAP: {
+ mState.setSecurity(AccessPointState.WPA_EAP);
+ mState.setEap(mEapSpinner.getSelectedItemPosition());
+ break;
+ }
+ case SECURITY_IEEE8021X: {
+ mState.setSecurity(AccessPointState.IEEE8021X);
+ mState.setEap(mEapSpinner.getSelectedItemPosition());
+ break;
+ }
+ default:
+ mState.setSecurity(AccessPointState.OPEN);
+ }
+ }
+
/**
* 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}.
@@ -516,7 +708,22 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
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);
+ setGenericPasswordVisible(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());
@@ -527,7 +734,7 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
}
private void handleSecurityChange(int security) {
-
+ setEnterpriseFieldsVisible(false);
switch (security) {
case SECURITY_NONE: {
@@ -559,6 +766,11 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
updatePasswordCaption(AccessPointState.WPA);
break;
}
+ case SECURITY_WPA_EAP:
+ case SECURITY_IEEE8021X: {
+ setEnterpriseFieldsVisible(true);
+ break;
+ }
}
}
diff --git a/src/com/android/settings/wifi/AccessPointState.java b/src/com/android/settings/wifi/AccessPointState.java
index 2569802..d050767 100644
--- a/src/com/android/settings/wifi/AccessPointState.java
+++ b/src/com/android/settings/wifi/AccessPointState.java
@@ -43,6 +43,12 @@ public final class AccessPointState implements Comparable<AccessPointState>, Par
public static final String WEP = "WEP";
public static final String OPEN = "Open";
+ /* For EAP Enterprise fields */
+ public static final String WPA_EAP = "WPA-EAP";
+ public static final String IEEE8021X = "IEEE8021X";
+
+ 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 */
@@ -93,7 +99,19 @@ public final class AccessPointState implements Comparable<AccessPointState>, Par
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 PRIVATE_KEY_PASSWD = 2;
+ public static final int CLIENT_CERT = 3;
+ public static final int CA_CERT = 4;
+ public static final int PRIVATE_KEY = 5;
+ public static final int MAX_ENTRPRISE_FIELD = 6;
+ private String mEnterpriseFields[] = new String[MAX_ENTRPRISE_FIELD];
+ private String mEap;
+ private String mPhase2;
+
private Context mContext;
/**
@@ -275,7 +293,9 @@ public final class AccessPointState implements Comparable<AccessPointState>, Par
else if (security.equals(WEP)) return mContext.getString(R.string.wifi_security_wep);
else if (security.equals(WPA)) return mContext.getString(R.string.wifi_security_wpa);
else if (security.equals(WPA2)) return mContext.getString(R.string.wifi_security_wpa2);
-
+ else if (security.equals(WPA_EAP)) return mContext.getString(R.string.wifi_security_wpa_eap);
+ else if (security.equals(IEEE8021X)) return mContext.getString(R.string.wifi_security_ieee8021x);
+
return mContext.getString(R.string.wifi_security_unknown);
}
@@ -300,7 +320,7 @@ public final class AccessPointState implements Comparable<AccessPointState>, Par
*/
public static String getScanResultSecurity(ScanResult scanResult) {
final String cap = scanResult.capabilities;
- final String[] securityModes = { WEP, WPA, WPA2 };
+ final String[] securityModes = { WEP, WPA, WPA2, WPA_EAP, IEEE8021X };
for (int i = securityModes.length - 1; i >= 0; i--) {
if (cap.contains(securityModes[i])) {
return securityModes[i];
@@ -347,7 +367,30 @@ public final class AccessPointState implements Comparable<AccessPointState>, Par
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 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;
}
@@ -382,6 +425,10 @@ public final class AccessPointState implements Comparable<AccessPointState>, Par
} else {
return OPEN;
}
+ } else if (wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
+ return WPA_EAP;
+ } else if (wifiConfig.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+ return IEEE8021X;
} else if (wifiConfig.allowedProtocols.get(Protocol.RSN)) {
return WPA2;
} else if (wifiConfig.allowedProtocols.get(Protocol.WPA)) {
@@ -442,7 +489,43 @@ public final class AccessPointState implements Comparable<AccessPointState>, Par
config.priority = priority;
config.hiddenSSID = hiddenSsid;
config.SSID = convertToQuotedString(ssid);
-
+ config.eap = mEap;
+ if (!TextUtils.isEmpty(mEnterpriseFields[IDENTITY])) {
+ config.identity =
+ convertToQuotedString(mEnterpriseFields[IDENTITY]);
+ } else {
+ config.identity = null;
+ }
+ if (!TextUtils.isEmpty(mEnterpriseFields[ANONYMOUS_IDENTITY])) {
+ config.anonymousIdentity = convertToQuotedString(
+ mEnterpriseFields[ANONYMOUS_IDENTITY]);
+ } else {
+ config.anonymousIdentity = null;
+ }
+ if (!TextUtils.isEmpty(mEnterpriseFields[CLIENT_CERT])) {
+ config.clientCert = convertToQuotedString(
+ mEnterpriseFields[CLIENT_CERT]);
+ } else {
+ config.clientCert = null;
+ }
+ if (!TextUtils.isEmpty(mEnterpriseFields[CA_CERT])) {
+ config.caCert = convertToQuotedString(
+ mEnterpriseFields[CA_CERT]);
+ } else {
+ config.caCert = null;
+ }
+ if (!TextUtils.isEmpty(mEnterpriseFields[PRIVATE_KEY])) {
+ config.privateKey = convertToQuotedString(
+ mEnterpriseFields[PRIVATE_KEY]);
+ } else {
+ config.privateKey = null;
+ }
+ if (!TextUtils.isEmpty(mEnterpriseFields[PRIVATE_KEY_PASSWD])) {
+ config.privateKeyPasswd = convertToQuotedString(
+ mEnterpriseFields[PRIVATE_KEY_PASSWD]);
+ } else {
+ config.privateKeyPasswd = null;
+ }
setupSecurity(config);
}
@@ -509,6 +592,14 @@ public final class AccessPointState implements Comparable<AccessPointState>, Par
} else if (security.equals(OPEN)) {
config.allowedKeyManagement.set(KeyMgmt.NONE);
+ } else if (security.equals(WPA_EAP)) {
+ config.allowedGroupCiphers.set(GroupCipher.TKIP);
+ config.allowedGroupCiphers.set(GroupCipher.CCMP);
+ config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+ } else if (security.equals(IEEE8021X)) {
+ config.allowedGroupCiphers.set(GroupCipher.TKIP);
+ config.allowedGroupCiphers.set(GroupCipher.CCMP);
+ config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
}
}
@@ -716,6 +807,10 @@ public final class AccessPointState implements Comparable<AccessPointState>, Par
return mContext.getString(R.string.wifi_security_verbose_wpa2);
} else if (OPEN.equals(security)) {
return mContext.getString(R.string.wifi_security_verbose_open);
+ } else if (WPA_EAP.equals(security)) {
+ return mContext.getString(R.string.wifi_security_verbose_wpa_eap);
+ } else if (IEEE8021X.equals(security)) {
+ return mContext.getString(R.string.wifi_security_verbose_ieee8021x);
} else {
return null;
}
diff --git a/src/com/android/settings/wifi/Keystore.java b/src/com/android/settings/wifi/Keystore.java
new file mode 100644
index 0000000..68af868
--- /dev/null
+++ b/src/com/android/settings/wifi/Keystore.java
@@ -0,0 +1,81 @@
+package com.android.settings.wifi;
+
+import android.util.Log;
+
+import java.io.File;
+
+/**
+ */
+public abstract class Keystore {
+ public static final String TAG = "Keystore";
+
+ private static final String PACKAGE_PREFIX =
+ Keystore.class.getPackage().getName() + ".";
+
+ public static final String ACTION_KEYSTORE_CERTIFICATES =
+ PACKAGE_PREFIX + "CERTIFICATES";
+ public static final String ACTION_KEYSTORE_USERKEYS =
+ PACKAGE_PREFIX + "USERKEYS";
+
+ /**
+ */
+ public static Keystore getInstance() {
+ return new FileKeystore();
+ }
+
+ /**
+ */
+ public abstract String getUserkey(String key);
+
+ /**
+ */
+ public abstract String getCertificate(String key);
+
+ /**
+ */
+ public abstract String[] getAllCertificateKeys();
+
+ /**
+ */
+ public abstract String[] getAllUserkeyKeys();
+
+ private static class FileKeystore extends Keystore {
+ private static final String PATH = "/data/misc/keystore/";
+ private static final String USERKEY_PATH = PATH + "userkeys/";
+ private static final String CERT_PATH = PATH + "certs/";
+
+ @Override
+ public String getUserkey(String key) {
+ String path = USERKEY_PATH + key;
+ return (new File(path).exists() ? path : null);
+ }
+
+ @Override
+ public String getCertificate(String key) {
+ String path = CERT_PATH + key;
+ return (new File(path).exists() ? path : null);
+ }
+
+ @Override
+ public String[] getAllCertificateKeys() {
+ File dir = new File(CERT_PATH);
+ if (dir.exists()) {
+ return dir.list();
+ } else {
+ Log.v(TAG, "-------- cert directory does not exist!");
+ return null;
+ }
+ }
+
+ @Override
+ public String[] getAllUserkeyKeys() {
+ File dir = new File(USERKEY_PATH);
+ if (dir.exists()) {
+ return dir.list();
+ } else {
+ Log.v(TAG, "-------- userkey directory does not exist!");
+ return null;
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiLayer.java b/src/com/android/settings/wifi/WifiLayer.java
index b0857d2..751a5a3 100644
--- a/src/com/android/settings/wifi/WifiLayer.java
+++ b/src/com/android/settings/wifi/WifiLayer.java
@@ -1133,7 +1133,6 @@ public class WifiLayer {
* Hidden networks show up with empty SSID.
*/
if (AccessPointState.isAdhoc(scanResult)
- || AccessPointState.isEnterprise(scanResult)
|| TextUtils.isEmpty(scanResult.SSID)) {
continue;
}