diff options
Diffstat (limited to 'src/com/android')
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; } |