diff options
Diffstat (limited to 'src')
29 files changed, 1805 insertions, 287 deletions
diff --git a/src/com/android/settings/ActivityPicker.java b/src/com/android/settings/ActivityPicker.java new file mode 100644 index 0000000..47e005f --- /dev/null +++ b/src/com/android/settings/ActivityPicker.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * 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.LauncherActivity; +import android.content.Intent; +import android.os.Parcelable; +import android.view.View; +import android.widget.ListView; + +/** + * Displays a list of all activities matching the incoming {@link Intent.EXTRA_INTENT} + * query, along with any applicable icons. + */ +public class ActivityPicker extends LauncherActivity { + + @Override + protected Intent getTargetIntent() { + Intent intent = this.getIntent(); + Intent targetIntent = new Intent(Intent.ACTION_MAIN, null); + targetIntent.addCategory(Intent.CATEGORY_DEFAULT); + + // Use a custom title for this dialog, if provided + if (intent.hasExtra(Intent.EXTRA_TITLE)) { + String title = intent.getStringExtra(Intent.EXTRA_TITLE); + setTitle(title); + } + + Parcelable parcel = intent.getParcelableExtra(Intent.EXTRA_INTENT); + if (parcel instanceof Intent) { + targetIntent = (Intent) parcel; + } + + return targetIntent; + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + Intent intent = intentForPosition(position); + setResult(RESULT_OK, intent); + finish(); + } + +} diff --git a/src/com/android/settings/ApnSettings.java b/src/com/android/settings/ApnSettings.java index 83efa3f..aab529c 100644 --- a/src/com/android/settings/ApnSettings.java +++ b/src/com/android/settings/ApnSettings.java @@ -25,6 +25,7 @@ import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceCategory; +import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.provider.Telephony; import android.text.TextUtils; @@ -61,7 +62,7 @@ public class ApnSettings extends PreferenceActivity { mCursor = managedQuery(Telephony.Carriers.CONTENT_URI, new String[] { "_id", "name", "apn"}, null, Telephony.Carriers.DEFAULT_SORT_ORDER); - PreferenceCategory apnList = (PreferenceCategory) findPreference("apn_list"); + PreferenceGroup apnList = (PreferenceGroup) findPreference("apn_list"); apnList.removeAll(); mCursor.moveToFirst(); diff --git a/src/com/android/settings/BatteryHistory.java b/src/com/android/settings/BatteryHistory.java deleted file mode 100644 index 7e077d5..0000000 --- a/src/com/android/settings/BatteryHistory.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2006 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 java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintWriter; - -import com.android.internal.app.IBatteryStats; - -import android.app.Activity; -import android.os.BatteryStats; -import android.os.Bundle; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.util.Log; -import android.widget.TextView; - -public class BatteryHistory extends Activity { - private static final String TAG = "BatteryHistory"; - TextView mTextView; - IBatteryStats mBatteryInfo; - - private String getDump(BatteryStats stats) { - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - PrintWriter pw = new PrintWriter(out, true); - stats.dumpLocked(null, pw, null); - pw.flush(); - pw.close(); - out.close(); - return new String(out.toByteArray(), 0); - } catch (IOException e) { - return "IOException"; - } - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - Log.i(TAG, "onCreate"); - setContentView(R.layout.battery_history); - mTextView = (TextView) findViewById(R.id.text); - mBatteryInfo = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); - try { - BatteryStats stats = mBatteryInfo.getStatistics(); - String s = getDump(stats); - mTextView.setText(s); - } catch (RemoteException e) { - mTextView.setText("Got RemoteException"); - Log.e(TAG, "RemoteException:", e); - } - } -} diff --git a/src/com/android/settings/DateTimeSettings.java b/src/com/android/settings/DateTimeSettings.java index ead38d1..e78215a 100644 --- a/src/com/android/settings/DateTimeSettings.java +++ b/src/com/android/settings/DateTimeSettings.java @@ -192,6 +192,7 @@ public class DateTimeSettings } } + @Override public Dialog onCreateDialog(int id) { Dialog d; @@ -226,6 +227,7 @@ public class DateTimeSettings return d; } + @Override public void onPrepareDialog(int id, Dialog d) { switch (id) { case DIALOG_DATEPICKER: { @@ -250,10 +252,13 @@ public class DateTimeSettings } } + @Override public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { if (preference == mDatePref) { showDialog(DIALOG_DATEPICKER); } else if (preference == mTimePref) { + // The 24-hour mode may have changed, so recreate the dialog + removeDialog(DIALOG_TIMEPICKER); showDialog(DIALOG_TIMEPICKER); } else if (preference == mTime24Pref) { set24Hour(((CheckBoxPreference)mTime24Pref).isChecked()); diff --git a/src/com/android/settings/DeviceInfoSettings.java b/src/com/android/settings/DeviceInfoSettings.java index 5d72afc..3697319 100644 --- a/src/com/android/settings/DeviceInfoSettings.java +++ b/src/com/android/settings/DeviceInfoSettings.java @@ -20,6 +20,7 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.os.Build; import android.os.Bundle; import android.os.SystemProperties; import android.preference.Preference; @@ -54,10 +55,10 @@ public class DeviceInfoSettings extends PreferenceActivity { addPreferencesFromResource(R.xml.device_info_settings); - setSummary("firmware_version", "ro.build.version.release"); - setSummary("baseband_version", "gsm.version.baseband"); - setSummary("device_model", "ro.product.model"); - setSummary("build_number", "ro.build.version.incremental"); + setStringSummary("firmware_version", Build.VERSION.RELEASE); + setValueSummary("baseband_version", "gsm.version.baseband"); + setStringSummary("device_model", Build.MODEL); + setStringSummary("build_number", Build.DISPLAY); findPreference("kernel_version").setSummary(getFormattedKernelVersion()); /* @@ -79,13 +80,22 @@ public class DeviceInfoSettings extends PreferenceActivity { Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY); } - private void setSummary(String preference, String property) { + private void setStringSummary(String preference, String value) { + try { + findPreference(preference).setSummary(value); + } catch (RuntimeException e) { + findPreference(preference).setSummary( + getResources().getString(R.string.device_info_default)); + } + } + + private void setValueSummary(String preference, String property) { try { findPreference(preference).setSummary( SystemProperties.get(property, getResources().getString(R.string.device_info_default))); } catch (RuntimeException e) { - + } } diff --git a/src/com/android/settings/GadgetPickActivity.java b/src/com/android/settings/GadgetPickActivity.java new file mode 100644 index 0000000..09e0fc7 --- /dev/null +++ b/src/com/android/settings/GadgetPickActivity.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings; + +import android.app.LauncherActivity; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.gadget.GadgetInfo; +import android.gadget.GadgetManager; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.View; +import android.widget.ListView; +import android.util.Log; + +import java.util.List; +import java.util.ArrayList; + +public class GadgetPickActivity extends LauncherActivity +{ + private static final String TAG = "GadgetPickActivity"; + + GadgetManager mGadgetManager; + int mGadgetId; + int mHostId; + + public GadgetPickActivity() { + mGadgetManager = GadgetManager.getInstance(this); + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + Bundle extras = getIntent().getExtras(); + mHostId = extras.getInt(GadgetManager.EXTRA_HOST_ID); + mGadgetId = extras.getInt(GadgetManager.EXTRA_GADGET_ID); + + setResultData(RESULT_CANCELED); + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) + { + Intent intent = intentForPosition(position); + mGadgetManager.bindGadgetId(mGadgetId, intent.getComponent()); + setResultData(RESULT_OK); + finish(); + } + + @Override + public List<ListItem> makeListItems() { + List<GadgetInfo> installed = mGadgetManager.getInstalledProviders(); + PackageManager pm = getPackageManager(); + + Drawable defaultIcon = null; + IconResizer resizer = new IconResizer(); + + ArrayList<ListItem> result = new ArrayList(); + final int N = installed.size(); + for (int i=0; i<N; i++) { + GadgetInfo info = installed.get(i); + + LauncherActivity.ListItem item = new LauncherActivity.ListItem(); + item.packageName = info.provider.getPackageName(); + item.className = info.provider.getClassName(); + + item.label = info.label; + if (info.icon != 0) { + Drawable d = pm.getDrawable( item.packageName, info.icon, null); + if (d != null) { + item.icon = resizer.createIconThumbnail(d); + } else { + Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon) + + " for package: " + item.packageName); + } + } + if (item.icon == null) { + // (including error case above) + if (defaultIcon == null) { + // TODO: Load standard icon. + } + item.icon = defaultIcon; + } + + result.add(item); + } + return result; + } + + void setResultData(int code) { + Intent result = new Intent(); + result.putExtra(GadgetManager.EXTRA_GADGET_ID, mGadgetId); + setResult(code, result); + } +} + diff --git a/src/com/android/settings/InstalledAppDetails.java b/src/com/android/settings/InstalledAppDetails.java index 04121bb..d4dfe97 100644 --- a/src/com/android/settings/InstalledAppDetails.java +++ b/src/com/android/settings/InstalledAppDetails.java @@ -66,6 +66,7 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene private Button mActivitiesButton; private boolean mCanUninstall; private boolean localLOGV=Config.LOGV || false; + private TextView mAppSnippetSize; private TextView mTotalSize; private TextView mAppSize; private TextView mDataSize; @@ -76,6 +77,7 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene private TextView mCacheSize; private Button mClearCacheButton; private ClearCacheObserver mClearCacheObserver; + private Button mForceStopButton; PackageStats mSizeInfo; private Button mManageSpaceButton; @@ -227,10 +229,8 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene appName = getString(_UNKNOWN_APP); } ((TextView)findViewById(R.id.app_name)).setText(appName); - CharSequence appDesc = mAppInfo.loadDescription(mPm); - if(appDesc != null) { - ((TextView)findViewById(R.id.app_description)).setText(appDesc); - } + mAppSnippetSize = ((TextView)findViewById(R.id.app_size)); + mAppSnippetSize.setText(totalSizeStr); //TODO download str and download url //set values on views mTotalSize = (TextView)findViewById(R.id.total_size_text); @@ -255,6 +255,8 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene mCachePanel = findViewById(R.id.cache_panel); mCacheSize = (TextView) findViewById(R.id.cache_size_text); mClearCacheButton = (Button) findViewById(R.id.clear_cache_button); + mForceStopButton = (Button) findViewById(R.id.force_stop_button); + mForceStopButton.setOnClickListener(this); //clear activities mActivitiesButton = (Button)findViewById(R.id.clear_activities_button); @@ -326,13 +328,17 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene long newTot = newPs.cacheSize+newPs.codeSize+newPs.dataSize; if(mSizeInfo == null) { mSizeInfo = newPs; - mTotalSize.setText(getSizeStr(newTot)); + String str = getSizeStr(newTot); + mTotalSize.setText(str); + mAppSnippetSize.setText(str); mAppSize.setText(getSizeStr(newPs.codeSize)); mDataSize.setText(getSizeStr(newPs.dataSize+newPs.cacheSize)); } else { long oldTot = mSizeInfo.cacheSize+mSizeInfo.codeSize+mSizeInfo.dataSize; if(newTot != oldTot) { - mTotalSize.setText(getSizeStr(newTot)); + String str = getSizeStr(newTot); + mTotalSize.setText(str); + mAppSnippetSize.setText(str); changed = true; } if(newPs.codeSize != mSizeInfo.codeSize) { @@ -446,6 +452,10 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene mClearCacheObserver = new ClearCacheObserver(); } mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver); + } else if (v == mForceStopButton) { + ActivityManager am = (ActivityManager)getSystemService( + Context.ACTIVITY_SERVICE); + am.restartPackage(packageName); } } diff --git a/src/com/android/settings/LanguageSettings.java b/src/com/android/settings/LanguageSettings.java index 2777777..b406df6 100644 --- a/src/com/android/settings/LanguageSettings.java +++ b/src/com/android/settings/LanguageSettings.java @@ -17,6 +17,7 @@ package com.android.settings; import android.content.ContentResolver; +import android.content.res.Configuration; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceActivity; @@ -58,11 +59,17 @@ public class LanguageSettings extends PreferenceActivity { removePreference(findPreference("language_category")); } - ContentResolver resolver = getContentResolver(); - for (int i = 0; i < mSettingsUiKey.length; i++) { - CheckBoxPreference pref = (CheckBoxPreference) findPreference(mSettingsUiKey[i]); - pref.setChecked(System.getInt(resolver, mSettingsSystemId[i], - mSettingsDefault[i]) > 0); + Configuration config = getResources().getConfiguration(); + if (config.keyboard != Configuration.KEYBOARD_QWERTY) { + getPreferenceScreen().removePreference( + getPreferenceScreen().findPreference("hardkeyboard_category")); + } else { + ContentResolver resolver = getContentResolver(); + for (int i = 0; i < mSettingsUiKey.length; i++) { + CheckBoxPreference pref = (CheckBoxPreference) findPreference(mSettingsUiKey[i]); + pref.setChecked(System.getInt(resolver, mSettingsSystemId[i], + mSettingsDefault[i]) > 0); + } } } diff --git a/src/com/android/settings/LocalePicker.java b/src/com/android/settings/LocalePicker.java index 9ee8260..386d7e0 100644 --- a/src/com/android/settings/LocalePicker.java +++ b/src/com/android/settings/LocalePicker.java @@ -73,14 +73,14 @@ public class LocalePicker extends ListActivity { int len = s.length(); if (len == 2) { Locale l = new Locale(s); - preprocess[finalSize++] = new Loc(l.getDisplayLanguage(), l); + preprocess[finalSize++] = new Loc(toTitleCase(l.getDisplayLanguage()), l); } else 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(l.getDisplayLanguage(), l); + preprocess[finalSize++] = new Loc(toTitleCase(l.getDisplayLanguage()), l); } else { // check previous entry: // same lang and no country -> overwrite it with a lang-only name @@ -91,17 +91,17 @@ public class LocalePicker extends ListActivity { String prevCountry = preprocess[finalSize-1].locale.getCountry(); if (prevCountry.length() == 0) { preprocess[finalSize-1].locale = l; - preprocess[finalSize-1].label = l.getDisplayLanguage(); + preprocess[finalSize-1].label = toTitleCase(l.getDisplayLanguage()); } else { - preprocess[finalSize-1].label = preprocess[finalSize-1].locale.getDisplayName(); - preprocess[finalSize++] = new Loc(l.getDisplayName(), l); + preprocess[finalSize-1].label = toTitleCase(preprocess[finalSize-1].locale.getDisplayName()); + preprocess[finalSize++] = new Loc(toTitleCase(l.getDisplayName()), l); } } else { String displayName; if (s.equals("zz_ZZ")) { displayName = "Pseudo..."; } else { - displayName = l.getDisplayLanguage(); + displayName = toTitleCase(l.getDisplayLanguage()); } preprocess[finalSize++] = new Loc(displayName, l); } @@ -118,6 +118,14 @@ public class LocalePicker extends ListActivity { getListView().setAdapter(adapter); } + private static String toTitleCase(String s) { + if (s.length() == 0) { + return s; + } + + return Character.toUpperCase(s.charAt(0)) + s.substring(1); + } + @Override public void onResume() { super.onResume(); diff --git a/src/com/android/settings/ManageApplications.java b/src/com/android/settings/ManageApplications.java index f1550f9..e5311ae 100644 --- a/src/com/android/settings/ManageApplications.java +++ b/src/com/android/settings/ManageApplications.java @@ -17,8 +17,8 @@ package com.android.settings; import com.android.settings.R; -import android.app.Activity; import android.app.ActivityManager; +import android.app.AlertDialog; import android.app.ListActivity; import android.app.ProgressDialog; import android.content.BroadcastReceiver; @@ -90,7 +90,8 @@ import java.util.TreeMap; * InstalledAppDetailsActivity to avoid recomputation of the package size information. */ public class ManageApplications extends ListActivity implements - OnItemClickListener, DialogInterface.OnCancelListener { + OnItemClickListener, DialogInterface.OnCancelListener, + DialogInterface.OnClickListener { // TAG for this activity private static final String TAG = "ManageApplications"; @@ -119,6 +120,9 @@ public class ManageApplications extends ListActivity implements public static final int FILTER_APPS_ALL = MENU_OPTIONS_BASE + 2; public static final int FILTER_APPS_THIRD_PARTY = MENU_OPTIONS_BASE + 3; public static final int FILTER_APPS_RUNNING = MENU_OPTIONS_BASE + 4; + public static final int FILTER_OPTIONS = MENU_OPTIONS_BASE + 5; + // Alert Dialog presented to user to find out the filter option + AlertDialog.Builder mAlertDlgBuilder; // sort order private int mSortOrder = SORT_ORDER_ALPHA; // Filter value @@ -295,11 +299,7 @@ public class ManageApplications extends ListActivity implements // end computation here mDoneIniting = true; mAppInfoAdapter.sortList(mSortOrder); - //load resources now - if(mResourceThread.isAlive()) { - mResourceThread.interrupt(); - } - mResourceThread.loadAllResources(mAppInfoAdapter.getAppList()); + setProgressBarIndeterminateVisibility(false); } } break; @@ -381,7 +381,15 @@ public class ManageApplications extends ListActivity implements Log.w(TAG, "Error loading icons for applications"); } else { mAppInfoAdapter.updateAppsResourceInfo(iconMap); - setProgressBarIndeterminateVisibility(false); + } + // initiate compute pkg sizes + if (localLOGV) Log.i(TAG, "Initiating compute sizes for first time"); + mObserver = new PkgSizeObserver(); + if (mAppInfoAdapter.getCount() > 0) { + mObserver.invokeGetSizeInfo(mAppInfoAdapter.getApplicationInfo(0), + COMPUTE_PKG_SIZE_DONE); + } else { + mDoneIniting = true; } default: break; @@ -398,7 +406,15 @@ public class ManageApplications extends ListActivity implements if (filterOption == FILTER_APPS_THIRD_PARTY) { List<ApplicationInfo> appList =new ArrayList<ApplicationInfo> (); for (ApplicationInfo appInfo : installedAppList) { + boolean flag = false; if ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { + // Updated system app + flag = true; + } else if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + // Non-system app + flag = true; + } + if (flag) { appList.add(appInfo); } } @@ -457,14 +473,11 @@ public class ManageApplications extends ListActivity implements // register receiver mReceiver = new PackageIntentReceiver(); mReceiver.registerReceiver(); - // initiate compute pkg sizes - if (localLOGV) Log.i(TAG, "Initiating compute sizes for first time"); - mObserver = new PkgSizeObserver(); - if(appList.size() > 0) { - mObserver.invokeGetSizeInfo(appList.get(0), COMPUTE_PKG_SIZE_DONE); - } else { - mDoneIniting = true; + //load resources now + if(mResourceThread.isAlive()) { + mResourceThread.interrupt(); } + mResourceThread.loadAllResources(appList); } // internal structure used to track added and deleted packages when @@ -717,7 +730,9 @@ public class ManageApplications extends ListActivity implements if(mInfo.appIcon != null) { holder.appIcon.setImageDrawable(mInfo.appIcon); } - holder.appSize.setText(mInfo.appSize); + if (mInfo.appSize != null) { + holder.appSize.setText(mInfo.appSize); + } } else { Log.w(TAG, "No info for package:"+appInfo.packageName+" in property map"); } @@ -1123,9 +1138,7 @@ public class ManageApplications extends ListActivity implements .setIcon(android.R.drawable.ic_menu_sort_alphabetically); menu.add(0, SORT_ORDER_SIZE, 2, R.string.sort_order_size) .setIcon(android.R.drawable.ic_menu_sort_by_size); - menu.add(0, FILTER_APPS_ALL, 3, R.string.filter_apps_all); - menu.add(0, FILTER_APPS_RUNNING, 4, R.string.filter_apps_running); - menu.add(0, FILTER_APPS_THIRD_PARTY, 5, R.string.filter_apps_third_party); + menu.add(0, FILTER_OPTIONS, 3, R.string.filter); return true; } @@ -1134,11 +1147,7 @@ public class ManageApplications extends ListActivity implements if (mDoneIniting) { menu.findItem(SORT_ORDER_ALPHA).setVisible(mSortOrder != SORT_ORDER_ALPHA); menu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder != SORT_ORDER_SIZE); - menu.findItem(FILTER_APPS_ALL).setVisible(mFilterApps != FILTER_APPS_ALL); - menu.findItem(FILTER_APPS_THIRD_PARTY).setVisible( - mFilterApps != FILTER_APPS_THIRD_PARTY); - menu.findItem(FILTER_APPS_RUNNING).setVisible( - mFilterApps != FILTER_APPS_RUNNING); + menu.findItem(FILTER_OPTIONS).setVisible(true); return true; } return false; @@ -1147,7 +1156,20 @@ public class ManageApplications extends ListActivity implements @Override public boolean onOptionsItemSelected(MenuItem item) { int menuId = item.getItemId(); - sendMessageToHandler(REORDER_LIST, menuId); + if ((menuId == SORT_ORDER_ALPHA) || (menuId == SORT_ORDER_SIZE)) { + sendMessageToHandler(REORDER_LIST, menuId); + } else if (menuId == FILTER_OPTIONS) { + if (mAlertDlgBuilder == null) { + mAlertDlgBuilder = new AlertDialog.Builder(this). + setTitle(R.string.filter_dlg_title). + setNeutralButton(R.string.cancel, this). + setSingleChoiceItems(new CharSequence[] {getText(R.string.filter_apps_all), + getText(R.string.filter_apps_running), + getText(R.string.filter_apps_third_party)}, + -1, this); + } + mAlertDlgBuilder.show(); + } return true; } @@ -1162,4 +1184,24 @@ public class ManageApplications extends ListActivity implements mLoadingDlg = null; finish(); } + + public void onClick(DialogInterface dialog, int which) { + int newOption; + switch (which) { + // Make sure that values of 0, 1, 2 match options all, running, third_party when + // created via the AlertDialog.Builder + case 0: + newOption = FILTER_APPS_ALL; + break; + case 1: + newOption = FILTER_APPS_RUNNING; + break; + case 2: + newOption = FILTER_APPS_THIRD_PARTY; + break; + default: + return; + } + sendMessageToHandler(REORDER_LIST, newOption); + } } diff --git a/src/com/android/settings/MediaFormat.java b/src/com/android/settings/MediaFormat.java new file mode 100644 index 0000000..3594572 --- /dev/null +++ b/src/com/android/settings/MediaFormat.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings; + +import com.android.internal.widget.LockPatternUtils; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.IMountService; +import android.os.ServiceManager; +import android.os.SystemProperties; +import android.os.Environment; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; + +/** + * Confirm and execute a format of the sdcard. + * Multiple confirmations are required: first, a general "are you sure + * you want to do this?" prompt, followed by a keyguard pattern trace if the user + * has defined one, followed by a final strongly-worded "THIS WILL ERASE EVERYTHING + * ON THE SD CARD" prompt. If at any time the phone is allowed to go to sleep, is + * locked, et cetera, then the confirmation sequence is abandoned. + */ +public class MediaFormat extends Activity { + + private static final int KEYGUARD_REQUEST = 55; + + private LayoutInflater mInflater; + private LockPatternUtils mLockUtils; + + private View mInitialView; + private Button mInitiateButton; + + private View mFinalView; + private Button mFinalButton; + + /** + * The user has gone through the multiple confirmation, so now we go ahead + * and invoke the Mount Service to format the SD card. + */ + private Button.OnClickListener mFinalClickListener = new Button.OnClickListener() { + public void onClick(View v) { + + // Those monkeys kept committing suicide, so we add this property + // to disable going through with the format + if (!TextUtils.isEmpty(SystemProperties.get("ro.monkey"))) { + return; + } + IMountService service = + IMountService.Stub.asInterface(ServiceManager.getService("mount")); + if (service != null) { + try { + service.formatMedia(Environment.getExternalStorageDirectory().toString()); + } catch (android.os.RemoteException e) { + // Intentionally blank - there's nothing we can do here + Log.w("MediaFormat", "Unable to invoke IMountService.formatMedia()"); + } + } else { + Log.w("MediaFormat", "Unable to locate IMountService"); + } + finish(); + } + }; + + /** + * Keyguard validation is run using the standard {@link ConfirmLockPattern} + * component as a subactivity + */ + private void runKeyguardConfirmation() { + final Intent intent = new Intent(); + intent.setClassName("com.android.settings", + "com.android.settings.ConfirmLockPattern"); + // supply header and footer text in the intent + intent.putExtra(ConfirmLockPattern.HEADER_TEXT, + getText(R.string.media_format_gesture_prompt)); + intent.putExtra(ConfirmLockPattern.FOOTER_TEXT, + getText(R.string.media_format_gesture_explanation)); + startActivityForResult(intent, KEYGUARD_REQUEST); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode != KEYGUARD_REQUEST) { + return; + } + + // If the user entered a valid keyguard trace, present the final + // confirmation prompt; otherwise, go back to the initial state. + if (resultCode == Activity.RESULT_OK) { + establishFinalConfirmationState(); + } else { + establishInitialState(); + } + } + + /** + * If the user clicks to begin the reset sequence, we next require a + * keyguard confirmation if the user has currently enabled one. If there + * is no keyguard available, we simply go to the final confirmation prompt. + */ + private Button.OnClickListener mInitiateListener = new Button.OnClickListener() { + public void onClick(View v) { + if (mLockUtils.isLockPatternEnabled()) { + runKeyguardConfirmation(); + } else { + establishFinalConfirmationState(); + } + } + }; + + /** + * Configure the UI for the final confirmation interaction + */ + private void establishFinalConfirmationState() { + if (mFinalView == null) { + mFinalView = mInflater.inflate(R.layout.media_format_final, null); + mFinalButton = + (Button) mFinalView.findViewById(R.id.execute_media_format); + mFinalButton.setOnClickListener(mFinalClickListener); + } + + setContentView(mFinalView); + } + + /** + * In its initial state, the activity presents a button for the user to + * click in order to initiate a confirmation sequence. This method is + * called from various other points in the code to reset the activity to + * this base state. + * + * <p>Reinflating views from resources is expensive and prevents us from + * caching widget pointers, so we use a single-inflate pattern: we lazy- + * inflate each view, caching all of the widget pointers we'll need at the + * time, then simply reuse the inflated views directly whenever we need + * to change contents. + */ + private void establishInitialState() { + if (mInitialView == null) { + mInitialView = mInflater.inflate(R.layout.media_format_primary, null); + mInitiateButton = + (Button) mInitialView.findViewById(R.id.initiate_media_format); + mInitiateButton.setOnClickListener(mInitiateListener); + } + + setContentView(mInitialView); + } + + @Override + protected void onCreate(Bundle savedState) { + super.onCreate(savedState); + + mInitialView = null; + mFinalView = null; + mInflater = LayoutInflater.from(this); + mLockUtils = new LockPatternUtils(getContentResolver()); + + establishInitialState(); + } + + /** Abandon all progress through the confirmation sequence by returning + * to the initial view any time the activity is interrupted (e.g. by + * idle timeout). + */ + @Override + public void onPause() { + super.onPause(); + + establishInitialState(); + } + +} diff --git a/src/com/android/settings/RadioInfo.java b/src/com/android/settings/RadioInfo.java index b1ad777..b7ff28a 100644 --- a/src/com/android/settings/RadioInfo.java +++ b/src/com/android/settings/RadioInfo.java @@ -119,10 +119,12 @@ public class RadioInfo extends Activity { private TextView mPingHostname; private TextView mHttpClientTest; private TextView cipherState; + private TextView dnsCheckState; private EditText smsc; private Button radioPowerButton; private Button qxdmLogButton; private Button cipherToggleButton; + private Button dnsCheckToggleButton; private Button pingTestButton; private Button updateSmscButton; private Button refreshSmscButton; @@ -428,6 +430,7 @@ public class RadioInfo extends Activity { received = (TextView) findViewById(R.id.received); cipherState = (TextView) findViewById(R.id.ciphState); smsc = (EditText) findViewById(R.id.smsc); + dnsCheckState = (TextView) findViewById(R.id.dnsCheckState); mPingIpAddr = (TextView) findViewById(R.id.pingIpAddr); mPingHostname = (TextView) findViewById(R.id.pingHostname); @@ -454,6 +457,8 @@ public class RadioInfo extends Activity { updateSmscButton.setOnClickListener(mUpdateSmscButtonHandler); refreshSmscButton = (Button) findViewById(R.id.refresh_smsc); refreshSmscButton.setOnClickListener(mRefreshSmscButtonHandler); + dnsCheckToggleButton = (Button) findViewById(R.id.dns_check_toggle); + dnsCheckToggleButton.setOnClickListener(mDnsCheckButtonHandler); mPhoneStateReceiver = new PhoneStateIntentReceiver(this, mHandler); mPhoneStateReceiver.notifySignalStrength(EVENT_SIGNAL_STRENGTH_CHANGED); @@ -490,6 +495,7 @@ public class RadioInfo extends Activity { updateQxdmState(null); updateProperties(); updateCiphState(); + updateDnsCheckState(); Log.i(TAG, "[RadioInfo] onResume: register phone & data intents"); @@ -614,6 +620,12 @@ public class RadioInfo extends Activity { cipherState.setText(getCiphPref() ? "Ciphering ON" : "Ciphering OFF"); } + private void updateDnsCheckState() { + GSMPhone gsmPhone = (GSMPhone) phone; + dnsCheckState.setText(gsmPhone.isDnsCheckDisabled() ? + "0.0.0.0 allowed" :"0.0.0.0 not allowed"); + } + private final void updateSignalStrength() { int state = @@ -806,10 +818,10 @@ public class RadioInfo extends Activity { Resources r = getResources(); try { - int txPackets = netstat.getTxPackets(); - int rxPackets = netstat.getRxPackets(); - int txBytes = netstat.getTxBytes(); - int rxBytes = netstat.getRxBytes(); + long txPackets = netstat.getMobileTxPackets(); + long rxPackets = netstat.getMobileRxPackets(); + long txBytes = netstat.getMobileTxBytes(); + long rxBytes = netstat.getMobileRxBytes(); String packets = r.getString(R.string.radioInfo_display_packets); String bytes = r.getString(R.string.radioInfo_display_bytes); @@ -1114,6 +1126,14 @@ public class RadioInfo extends Activity { } }; + OnClickListener mDnsCheckButtonHandler = new OnClickListener() { + public void onClick(View v) { + GSMPhone gsmPhone = (GSMPhone) phone; + gsmPhone.disableDnsCheck(!gsmPhone.isDnsCheckDisabled()); + updateDnsCheckState(); + } + }; + OnClickListener mPingButtonHandler = new OnClickListener() { public void onClick(View v) { updatePingState(); diff --git a/src/com/android/settings/SdCardErrorReceiver.java b/src/com/android/settings/SdCardErrorReceiver.java deleted file mode 100644 index ba35a3c..0000000 --- a/src/com/android/settings/SdCardErrorReceiver.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings; - -import android.content.Context; -import android.content.Intent; -import android.content.BroadcastReceiver; -import android.util.Log; -import android.widget.Toast; - - -/** - * Glue class: connects AlarmAlert IntentReceiver to AlarmAlert - * activity. Passes through Alarm ID. - */ -public class SdCardErrorReceiver extends BroadcastReceiver { - - private static final String TAG = "SdCardErrorReceiver"; - - @Override public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - final int duration = 3500; - if (action.equals(Intent.ACTION_MEDIA_BAD_REMOVAL)) { - Toast.makeText(context, R.string.sdcard_removal_alert_title, duration).show(); - } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTABLE)) { - Toast.makeText(context, R.string.sdcard_unmountable_alert_title, duration).show(); - } else { - Log.e(TAG, "unknown intent"); - } - } -} diff --git a/src/com/android/settings/SdCardSettings.java b/src/com/android/settings/SdCardSettings.java index d10166a..b6935a2 100644 --- a/src/com/android/settings/SdCardSettings.java +++ b/src/com/android/settings/SdCardSettings.java @@ -60,6 +60,9 @@ public class SdCardSettings extends Activity Button unmountButton = (Button)findViewById(R.id.sdcard_unmount); unmountButton.setOnClickListener(mUnmountButtonHandler); + Button formatButton = (Button)findViewById(R.id.sdcard_format); + formatButton.setOnClickListener(mFormatButtonHandler); + mTotalSize = (TextView)findViewById(R.id.total); mUsedSize = (TextView)findViewById(R.id.used); mAvailableSize = (TextView)findViewById(R.id.available); @@ -69,6 +72,8 @@ public class SdCardSettings extends Activity intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED); intentFilter.addAction(Intent.ACTION_MEDIA_SHARED); + intentFilter.addAction(Intent.ACTION_MEDIA_CHECKING); + intentFilter.addAction(Intent.ACTION_MEDIA_NOFS); intentFilter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL); intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED); intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED); @@ -198,6 +203,15 @@ public class SdCardSettings extends Activity } }; + OnClickListener mFormatButtonHandler = new OnClickListener() { + public void onClick(View v) { + try { + mMountService.formatMedia(Environment.getExternalStorageDirectory().toString()); + } catch (RemoteException ex) { + } + } + }; + private int mStatus; private IMountService mMountService; diff --git a/src/com/android/settings/SoundAndDisplaySettings.java b/src/com/android/settings/SoundAndDisplaySettings.java index 134e84f..53912e3 100644 --- a/src/com/android/settings/SoundAndDisplaySettings.java +++ b/src/com/android/settings/SoundAndDisplaySettings.java @@ -25,6 +25,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; import android.os.Bundle; +import android.os.IMountService; import android.os.RemoteException; import android.os.ServiceManager; import android.preference.ListPreference; @@ -49,8 +50,21 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements private static final String KEY_DTMF_TONE = "dtmf_tone"; private static final String KEY_SOUND_EFFECTS = "sound_effects"; private static final String KEY_ANIMATIONS = "animations"; + private static final String KEY_PLAY_MEDIA_NOTIFICATION_SOUNDS = "play_media_notification_sounds"; private CheckBoxPreference mSilent; + + private CheckBoxPreference mPlayMediaNotificationSounds; + + private IMountService mMountService = null; + + /* + * If we are currently in one of the silent modes (the ringer mode is set to either + * "silent mode" or "vibrate mode"), then toggling the "Phone vibrate" + * preference will switch between "silent mode" and "vibrate mode". + * Otherwise, it will adjust the normal ringer mode's ring or ring+vibrate + * setting. + */ private CheckBoxPreference mVibrate; private CheckBoxPreference mDtmfTone; private CheckBoxPreference mSoundEffects; @@ -64,14 +78,7 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - - int ringerMode = intent - .getIntExtra(AudioManager.EXTRA_RINGER_MODE, AudioManager.RINGER_MODE_NORMAL); - boolean isSilentMode = ringerMode != AudioManager.RINGER_MODE_NORMAL; - - if (mSilent.isChecked() != isSilentMode) { - mSilent.setChecked(isSilentMode); - } + updateState(false); } }; @@ -82,10 +89,14 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); + + mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount")); addPreferencesFromResource(R.xml.sound_and_display_settings); mSilent = (CheckBoxPreference) findPreference(KEY_SILENT); + mPlayMediaNotificationSounds = (CheckBoxPreference) findPreference(KEY_PLAY_MEDIA_NOTIFICATION_SOUNDS); + mVibrate = (CheckBoxPreference) findPreference(KEY_VIBRATE); mDtmfTone = (CheckBoxPreference) findPreference(KEY_DTMF_TONE); mDtmfTone.setPersistent(false); @@ -123,17 +134,28 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements } private void updateState(boolean force) { - final boolean silent = mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; - final boolean phoneVibrate = mAudioManager - .getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER) - == AudioManager.VIBRATE_SETTING_ON; + final int ringerMode = mAudioManager.getRingerMode(); + final boolean silentOrVibrateMode = + ringerMode != AudioManager.RINGER_MODE_NORMAL; - if (silent != mSilent.isChecked() || force) { - mSilent.setChecked(silent); + if (silentOrVibrateMode != mSilent.isChecked() || force) { + mSilent.setChecked(silentOrVibrateMode); } - - if (phoneVibrate != mVibrate.isChecked() || force) { - mVibrate.setChecked(phoneVibrate); + + try { + mPlayMediaNotificationSounds.setChecked(mMountService.getPlayNotificationSounds()); + } catch (RemoteException e) { + } + + boolean vibrateSetting; + if (silentOrVibrateMode) { + vibrateSetting = ringerMode == AudioManager.RINGER_MODE_VIBRATE; + } else { + vibrateSetting = mAudioManager.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER) + == AudioManager.VIBRATE_SETTING_ON; + } + if (vibrateSetting != mVibrate.isChecked() || force) { + mVibrate.setChecked(vibrateSetting); } boolean animations = true; @@ -161,12 +183,26 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements final boolean silent = mSilent.isChecked(); mAudioManager.setRingerMode(silent ? AudioManager.RINGER_MODE_SILENT : AudioManager.RINGER_MODE_NORMAL); + updateState(false); + } else if (preference == mPlayMediaNotificationSounds) { + try { + mMountService.setPlayNotificationSounds(mPlayMediaNotificationSounds.isChecked()); + } catch (RemoteException e) { + } } else if (preference == mVibrate) { final boolean vibrate = mVibrate.isChecked(); - mAudioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER, - vibrate ? AudioManager.VIBRATE_SETTING_ON - : AudioManager.VIBRATE_SETTING_OFF); + final boolean silent = mSilent.isChecked(); + + if (silent) { + mAudioManager.setRingerMode(vibrate ? AudioManager.RINGER_MODE_VIBRATE : + AudioManager.RINGER_MODE_SILENT); + } else { + mAudioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER, + vibrate ? AudioManager.VIBRATE_SETTING_ON + : AudioManager.VIBRATE_SETTING_OFF); + } + } else if (preference == mDtmfTone) { Settings.System.putInt(getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING, mDtmfTone.isChecked() ? 1 : 0); diff --git a/src/com/android/settings/UsageStats.java b/src/com/android/settings/UsageStats.java new file mode 100755 index 0000000..89caa54 --- /dev/null +++ b/src/com/android/settings/UsageStats.java @@ -0,0 +1,249 @@ + + +/** + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package com.android.settings; + +import com.android.internal.app.IUsageStats; +import com.android.settings.R; +import android.app.Activity; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; +import com.android.internal.os.PkgUsageStats; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.AdapterView.OnItemSelectedListener; + +/** + * Activity to display package usage statistics. + */ +public class UsageStats extends Activity implements OnItemSelectedListener { + private static final String TAG="UsageStatsActivity"; + private static final boolean localLOGV = true; + private Spinner mTypeSpinner; + private ListView mListView; + private IUsageStats mUsageStatsService; + private LayoutInflater mInflater; + private UsageStatsAdapter mAdapter; + private PackageManager mPm; + + public static class AppNameComparator implements Comparator<PkgUsageStats> { + Map<String, CharSequence> mAppLabelList; + AppNameComparator(Map<String, CharSequence> appList) { + mAppLabelList = appList; + } + public final int compare(PkgUsageStats a, PkgUsageStats b) { + String alabel = mAppLabelList.get(a.packageName).toString(); + String blabel = mAppLabelList.get(b.packageName).toString(); + return alabel.compareTo(blabel); + } + } + + public static class LaunchCountComparator implements Comparator<PkgUsageStats> { + public final int compare(PkgUsageStats a, PkgUsageStats b) { + // return by descending order + return b.launchCount - a.launchCount; + } + } + + public static class UsageTimeComparator implements Comparator<PkgUsageStats> { + public final int compare(PkgUsageStats a, PkgUsageStats b) { + long ret = a.usageTime-b.usageTime; + if (ret == 0) { + return 0; + } + if (ret < 0) { + return 1; + } + return -1; + } + } + + // View Holder used when displaying views + static class AppViewHolder { + TextView pkgName; + TextView launchCount; + TextView usageTime; + } + + class UsageStatsAdapter extends BaseAdapter { + // Constants defining order for display order + private static final int _DISPLAY_ORDER_USAGE_TIME = 0; + private static final int _DISPLAY_ORDER_LAUNCH_COUNT = 1; + private static final int _DISPLAY_ORDER_APP_NAME = 2; + + private int mDisplayOrder = _DISPLAY_ORDER_USAGE_TIME; + private List<PkgUsageStats> mUsageStats; + private LaunchCountComparator mLaunchCountComparator; + private UsageTimeComparator mUsageTimeComparator; + private AppNameComparator mAppLabelComparator; + private HashMap<String, CharSequence> mAppLabelMap; + + UsageStatsAdapter() { + mUsageStats = new ArrayList<PkgUsageStats>(); + mAppLabelMap = new HashMap<String, CharSequence>(); + PkgUsageStats[] stats; + try { + stats = mUsageStatsService.getAllPkgUsageStats(); + } catch (RemoteException e) { + Log.e(TAG, "Failed initializing usage stats service"); + return; + } + if (stats == null) { + return; + } + for (PkgUsageStats ps : stats) { + mUsageStats.add(ps); + // load application labels for each application + CharSequence label; + try { + ApplicationInfo appInfo = mPm.getApplicationInfo(ps.packageName, 0); + label = appInfo.loadLabel(mPm); + } catch (NameNotFoundException e) { + label = ps.packageName; + } + mAppLabelMap.put(ps.packageName, label); + } + // Sort list + mLaunchCountComparator = new LaunchCountComparator(); + mUsageTimeComparator = new UsageTimeComparator(); + mAppLabelComparator = new AppNameComparator(mAppLabelMap); + sortList(); + } + public int getCount() { + return mUsageStats.size(); + } + + public Object getItem(int position) { + return mUsageStats.get(position); + } + + public long getItemId(int position) { + return position; + } + + public View getView(int position, View convertView, ViewGroup parent) { + // A ViewHolder keeps references to children views to avoid unneccessary calls + // to findViewById() on each row. + AppViewHolder holder; + + // When convertView is not null, we can reuse it directly, there is no need + // to reinflate it. We only inflate a new View when the convertView supplied + // by ListView is null. + if (convertView == null) { + convertView = mInflater.inflate(R.layout.usage_stats_item, null); + + // Creates a ViewHolder and store references to the two children views + // we want to bind data to. + holder = new AppViewHolder(); + holder.pkgName = (TextView) convertView.findViewById(R.id.package_name); + holder.launchCount = (TextView) convertView.findViewById(R.id.launch_count); + holder.usageTime = (TextView) convertView.findViewById(R.id.usage_time); + convertView.setTag(holder); + } else { + // Get the ViewHolder back to get fast access to the TextView + // and the ImageView. + holder = (AppViewHolder) convertView.getTag(); + } + + // Bind the data efficiently with the holder + PkgUsageStats pkgStats = mUsageStats.get(position); + if (pkgStats != null) { + CharSequence label = mAppLabelMap.get(pkgStats.packageName); + holder.pkgName.setText(label); + holder.launchCount.setText(String.valueOf(pkgStats.launchCount)); + holder.usageTime.setText(String.valueOf(pkgStats.usageTime)+" ms"); + } else { + Log.w(TAG, "No usage stats info for package:"+pkgStats.packageName); + } + return convertView; + } + + void sortList(int sortOrder) { + if (mDisplayOrder == sortOrder) { + // do nothing + return; + } + mDisplayOrder= sortOrder; + sortList(); + } + private void sortList() { + if (mDisplayOrder == _DISPLAY_ORDER_USAGE_TIME) { + if (localLOGV) Log.i(TAG, "Sorting by usage time"); + Collections.sort(mUsageStats, mUsageTimeComparator); + } else if (mDisplayOrder == _DISPLAY_ORDER_LAUNCH_COUNT) { + if (localLOGV) Log.i(TAG, "Sorting launch count"); + Collections.sort(mUsageStats, mLaunchCountComparator); + } else if (mDisplayOrder == _DISPLAY_ORDER_APP_NAME) { + if (localLOGV) Log.i(TAG, "Sorting by application name"); + Collections.sort(mUsageStats, mAppLabelComparator); + } + notifyDataSetChanged(); + } + } + + /** Called when the activity is first created. */ + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + mUsageStatsService = IUsageStats.Stub.asInterface(ServiceManager.getService("usagestats")); + if (mUsageStatsService == null) { + Log.e(TAG, "Failed to retrieve usagestats service"); + return; + } + mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mPm = getPackageManager(); + + setContentView(R.layout.usage_stats); + mTypeSpinner = (Spinner) findViewById(R.id.typeSpinner); + mTypeSpinner.setOnItemSelectedListener(this); + + mListView = (ListView) findViewById(R.id.pkg_list); + // Initialize the inflater + + mAdapter = new UsageStatsAdapter(); + mListView.setAdapter(mAdapter); + } + + public void onItemSelected(AdapterView<?> parent, View view, int position, + long id) { + mAdapter.sortList(position); + } + + public void onNothingSelected(AdapterView<?> parent) { + // do nothing + } +} + diff --git a/src/com/android/settings/UserDictionarySettings.java b/src/com/android/settings/UserDictionarySettings.java index 5d3c8ac..8b86a6b 100644 --- a/src/com/android/settings/UserDictionarySettings.java +++ b/src/com/android/settings/UserDictionarySettings.java @@ -21,6 +21,7 @@ import android.app.Dialog; import android.app.ListActivity; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.database.Cursor; import android.os.Bundle; import android.provider.UserDictionary; @@ -54,6 +55,8 @@ public class UserDictionarySettings extends ListActivity { + UserDictionary.Words.LOCALE + " is null"; private static final String DELETE_SELECTION = UserDictionary.Words.WORD + "=?"; + + private static final String EXTRA_WORD = "word"; private static final int CONTEXT_MENU_EDIT = Menu.FIRST; private static final int CONTEXT_MENU_DELETE = Menu.FIRST + 1; @@ -87,6 +90,16 @@ public class UserDictionarySettings extends ListActivity { } @Override + protected void onResume() { + super.onResume(); + if (getIntent().getAction().equals("com.android.settings.USER_DICTIONARY_INSERT")) { + String word = getIntent().getStringExtra(EXTRA_WORD); + if (word != null) { + showAddOrEditDialog(word); + } + } + } + @Override protected void onRestoreInstanceState(Bundle state) { super.onRestoreInstanceState(state); mDialogEditingWord = state.getString(INSTANCE_KEY_DIALOG_EDITING_WORD); @@ -207,7 +220,7 @@ public class UserDictionarySettings extends ListActivity { // TODO: present UI for picking whether to add word to all locales, or current. UserDictionary.Words.addWord(this, word.toString(), - 1, UserDictionary.Words.LOCALE_TYPE_ALL); + 128, UserDictionary.Words.LOCALE_TYPE_ALL); mCursor.requery(); } diff --git a/src/com/android/settings/battery_history/BatteryHistory.java b/src/com/android/settings/battery_history/BatteryHistory.java new file mode 100644 index 0000000..19302a5 --- /dev/null +++ b/src/com/android/settings/battery_history/BatteryHistory.java @@ -0,0 +1,645 @@ +/* + * Copyright (C) 2006 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.battery_history; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import com.android.internal.app.IBatteryStats; +import com.android.settings.R; + +import android.app.Activity; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.BatteryStats; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.os.BatteryStats.Timer; +import android.os.BatteryStats.Uid; +import android.util.Log; +import android.util.SparseArray; +import android.view.KeyEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.AdapterView.OnItemSelectedListener; + +public class BatteryHistory extends Activity implements OnClickListener, OnItemSelectedListener { + private static final String TAG = "BatteryHistory"; + + 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; + + // Must be in sync with the values in res/values/array.xml (id battery_history_type_spinner) + private static final int CPU_USAGE = 0; + private static final int NETWORK_USAGE = 1; + private static final int SENSOR_USAGE = 2; + private static final int SCREEN_ON = 3; + private static final int WAKE_LOCKS = 4; + + // App names to use as labels for the shared UIDs that contain them + private final HashSet<String> mKnownApps = new HashSet<String>(); + + private BatteryStats mStats; + private int mWhich = BatteryStats.STATS_UNPLUGGED; + private int mType = CPU_USAGE; + + private GraphableButton[] mButtons; + IBatteryStats mBatteryInfo; + + private List<CpuUsage> mCpuUsage = new ArrayList<CpuUsage>(); + private List<NetworkUsage> mNetworkUsage = new ArrayList<NetworkUsage>(); + private List<SensorUsage> mSensorUsage = new ArrayList<SensorUsage>(); + private long mScreenOnTime; + + private LinearLayout mGraphLayout; + private LinearLayout mTextLayout; + private TextView mMessageText; + private TextView mDetailsText; + private Button mDetailsBackButton; + private Spinner mTypeSpinner; + private Spinner mWhichSpinner; + + private boolean mDetailsShown = false; + + private static String getLabel(String packageName, PackageManager pm) { + try { + ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); + CharSequence label = ai.loadLabel(pm); + if (label != null) { + return label.toString(); + } + } catch (NameNotFoundException e) { + return packageName; + } + + return ""; + } + + void formatTime(double millis, StringBuilder sb) { + 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)); + } + } + + abstract class Graphable implements Comparable<Graphable> { + protected String mName; + protected boolean mUniqueName; + protected String[] mPackageNames; + + public abstract String getLabel(); + public abstract double getSortValue(); + public abstract double[] getValues(); + public abstract void getInfo(StringBuilder info); + + public int compareTo(Graphable o) { + double t = getSortValue(); + double ot = o.getSortValue(); + if (t < ot) { + // Largest first + return 1; + } else if (t > ot) { + return -1; + } else { + return 0; + } + } + + // Side effects: sets mName and mUniqueName + void getNameForUid(int uid) { + PackageManager pm = getPackageManager(); + mPackageNames = pm.getPackagesForUid(uid); + // Convert package names to user-facing labels where possible + for (int i = 0; i < mPackageNames.length; i++) { + mPackageNames[i] = BatteryHistory.getLabel(mPackageNames[i], pm); + } + + if (mPackageNames.length == 1) { + mName = mPackageNames[0]; + mUniqueName = true; + } else { + mName = getString(R.string.battery_history_uid, uid); // Default name + // If one of the names for this UID is in mKnownApps, use it + for (String name : mPackageNames) { + if (mKnownApps.contains(name)) { + mName = name; + break; + } + } + } + } + } + + class CpuUsage extends Graphable { + double[] mUsage; + long mStarts; + + public CpuUsage(String name, long userTime, long systemTime, long starts) { + PackageManager pm = BatteryHistory.this.getPackageManager(); + mName = BatteryHistory.getLabel(name, pm); + mUsage = new double[2]; + + mUsage[0] = userTime; + mUsage[1] = userTime + systemTime; + mStarts = starts; + } + + public String getLabel() { + return mName; + } + + public double getSortValue() { + return mUsage[1]; + } + + public double[] getValues() { + return mUsage; + } + + public void getInfo(StringBuilder info) { + info.append(getString(R.string.battery_history_cpu_usage, mName)); + info.append("\n\n"); + info.append(getString(R.string.battery_history_user_time)); + formatTime(mUsage[0] * 10, info); + info.append('\n'); + info.append(getString(R.string.battery_history_system_time)); + formatTime((mUsage[1] - mUsage[0]) * 10, info); + info.append('\n'); + info.append(getString(R.string.battery_history_total_time)); + formatTime((mUsage[1]) * 10, info); + info.append('\n'); + info.append(getString(R.string.battery_history_starts, mStarts)); + } + } + + class NetworkUsage extends Graphable { + double[] mUsage; + + public NetworkUsage(int uid, long received, long sent) { + getNameForUid(uid); + + mUsage = new double[2]; + mUsage[0] = received; + mUsage[1] = received + sent; + } + + public String getLabel() { + return mName; + } + + public double getSortValue() { + return mUsage[1]; + } + + public double[] getValues() { + return mUsage; + } + + public void getInfo(StringBuilder info) { + info.append(getString(R.string.battery_history_network_usage, mName)); + info.append("\n\n"); + info.append(getString(R.string.battery_history_bytes_received, (long) mUsage[0])); + info.append('\n'); + info.append(getString(R.string.battery_history_bytes_sent, + (long) mUsage[1] - (long) mUsage[0])); + info.append('\n'); + info.append(getString(R.string.battery_history_bytes_total, (long) mUsage[1])); + + if (!mUniqueName) { + info.append("\n\n"); + info.append(getString(R.string.battery_history_packages_sharing_this_uid)); + info.append('\n'); + + PackageManager pm = BatteryHistory.this.getPackageManager(); + List<String> names = new ArrayList<String>(); + for (String name : mPackageNames) { + names.add(BatteryHistory.getLabel(name, pm)); + } + Collections.sort(names); + for (String name : names) { + info.append(" "); + info.append(name); + info.append('\n'); + } + } + } + } + + class SensorUsage extends Graphable { + int mSensorNumber; + double[] mUsage; + HashMap<Integer,Integer> mCounts; + + public SensorUsage(int sensorNumber, String sensorName, long totalTime, + HashMap<Integer,Integer> counts) { + mName = sensorName; + mSensorNumber = sensorNumber; + + mUsage = new double[1]; + mUsage[0] = totalTime; + + mCounts = counts; + } + + public String getLabel() { + return mName; + } + + public double getSortValue() { + return mUsage[0]; + } + + public double[] getValues() { + return mUsage; + } + + public void getInfo(StringBuilder info) { + info.append(getString(R.string.battery_history_sensor)); + info.append(mName); + info.append("\n\n"); + info.append(getString(R.string.battery_history_total_time)); + formatTime(mUsage[0], info); + info.append("\n\n"); + + PackageManager pm = getPackageManager(); + String[] packageNames = null; + for (Map.Entry<Integer,Integer> ent : mCounts.entrySet()) { + int uid = ent.getKey().intValue(); + int count = ent.getValue().intValue(); + packageNames = pm.getPackagesForUid(uid).clone(); + + if (packageNames.length == 1) { + info.append(getString(R.string.battery_history_sensor_usage, + count, packageNames[0])); + } else { + info.append(getString(R.string.battery_history_sensor_usage_multi, count)); + info.append("\n"); + // Convert package names to user-facing labels where possible + for (int i = 0; i < packageNames.length; i++) { + info.append(" "); + info.append(BatteryHistory.getLabel(packageNames[i], pm)); + info.append("\n"); + } + } + } + } + } + + private List<? extends Graphable> getGraphRecords() { + switch (mType) { + case CPU_USAGE: return mCpuUsage; + case NETWORK_USAGE : return mNetworkUsage; + case SENSOR_USAGE: return mSensorUsage; + case SCREEN_ON: return null; + case WAKE_LOCKS: + default: + return (List<? extends Graphable>) null; // TODO + } + } + + private void displayScreenUsage() { + mMessageText.setVisibility(View.VISIBLE); + StringBuilder sb = new StringBuilder(); + sb.append(getString(R.string.battery_history_screen_on)); + sb.append("\n\n"); + sb.append(getString(R.string.battery_history_screen_on_battery)); + sb.append(' '); + formatTime((double) mStats.getBatteryScreenOnTime(), sb); + sb.append('\n'); + sb.append(getString(R.string.battery_history_screen_on_plugged)); + sb.append(' '); + formatTime((double) mStats.getPluggedScreenOnTime(), sb); + sb.append('\n'); + mMessageText.setText(sb.toString()); + } + + private void displayGraph() { + Log.i(TAG, "displayGraph"); + + // Hide the UI and selectively enable it below + mMessageText.setVisibility(View.GONE); + for (int i = 0; i < mButtons.length; i++) { + mButtons[i].setVisibility(View.INVISIBLE); + } + + if (mType == SCREEN_ON) { + displayScreenUsage(); + return; + } + + double maxValue = -Double.MAX_VALUE; + + List<? extends Graphable> records = getGraphRecords(); + for (Graphable g : records) { + double[] values = g.getValues(); + maxValue = Math.max(maxValue, values[values.length - 1]); + } + + int[] colors = new int[2]; + colors[0] = 0xff0000ff; + colors[1] = 0xffff0000; + + for (int i = 0; i < mButtons.length; i++) { + mButtons[i].setVisibility(View.INVISIBLE); + } + + int numRecords = Math.min(records.size(), mButtons.length); + if (numRecords == 0) { + mMessageText.setVisibility(View.VISIBLE); + mMessageText.setText(R.string.battery_history_no_data); + } else { + for (int i = 0; i < numRecords; i++) { + Graphable r = records.get(i); + + mButtons[i].setText(r.getLabel()); + mButtons[i].setValues(r.getValues(), maxValue); + mButtons[i].setVisibility(View.VISIBLE); + } + } + } + + private void hideDetails() { + mTextLayout.setVisibility(View.GONE); + mGraphLayout.setVisibility(View.VISIBLE); + mDetailsShown = false; + } + + private void showDetails(int id) { + mGraphLayout.setVisibility(View.GONE); + mTextLayout.setVisibility(View.VISIBLE); + + StringBuilder info = new StringBuilder(); + List<? extends Graphable> records = getGraphRecords(); + if (id < records.size()) { + Graphable record = records.get(id); + record.getInfo(info); + } else { + info.append(getString(R.string.battery_history_details_for, id)); + } + mDetailsText.setText(info.toString()); + mDetailsShown = true; + } + + private void processCpuUsage() { + mCpuUsage.clear(); + + SparseArray<? extends Uid> uidStats = mStats.getUidStats(); + final int NU = uidStats.size(); + for (int iu = 0; iu < NU; iu++) { + Uid u = uidStats.valueAt(iu); + + Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); + if (processStats.size() > 0) { + for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent + : processStats.entrySet()) { + + Uid.Proc ps = ent.getValue(); + long userTime = ps.getUserTime(mWhich); + long systemTime = ps.getSystemTime(mWhich); + long starts = ps.getStarts(mWhich); + + if (userTime != 0 || systemTime != 0) { + mCpuUsage.add(new CpuUsage(ent.getKey(), userTime, systemTime, starts)); + } + } + } + } + Collections.sort(mCpuUsage); + } + + private void processNetworkUsage() { + mNetworkUsage.clear(); + + SparseArray<? extends Uid> uidStats = mStats.getUidStats(); + final int NU = uidStats.size(); + for (int iu = 0; iu < NU; iu++) { + Uid u = uidStats.valueAt(iu); + + long received = u.getTcpBytesReceived(mWhich); + long sent = u.getTcpBytesSent(mWhich); + if (received + sent > 0) { + mNetworkUsage.add(new NetworkUsage(u.getUid(), received, sent)); + } + } + Collections.sort(mNetworkUsage); + } + + class SensorRecord { + String name; + long totalTime; + HashMap<Integer,Integer> counts = new HashMap<Integer,Integer>(); + } + + private void processSensorUsage() { + mSensorUsage.clear(); + + HashMap<Integer,SensorRecord> records = new HashMap<Integer,SensorRecord>(); + + long uSecTime = SystemClock.elapsedRealtime() * 1000; + final long uSecNow = mStats.getBatteryUptime(uSecTime); + + SparseArray<? extends Uid> uidStats = mStats.getUidStats(); + final int NU = uidStats.size(); + for (int iu = 0; iu < NU; iu++) { + Uid u = uidStats.valueAt(iu); + int uid = u.getUid(); + + Map<Integer, ? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats(); + if (sensorStats.size() > 0) { + for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent + : sensorStats.entrySet()) { + + Uid.Sensor se = ent.getValue(); + String name = se.getName(); + int sensorNumber = ent.getKey(); + 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); + + SensorRecord record = records.get(sensorNumber); + if (record == null) { + record = new SensorRecord(); + } + record.name = name; + record.totalTime += totalTime; + Integer c = record.counts.get(uid); + if (c == null) { + record.counts.put(uid, count); + } else { + record.counts.put(uid, c.intValue() + count); + } + records.put(sensorNumber, record); + } + } + } + } + + for (Map.Entry<Integer,SensorRecord> record : records.entrySet()) { + int sensorNumber = record.getKey().intValue(); + SensorRecord r = record.getValue(); + mSensorUsage.add(new SensorUsage(sensorNumber, r.name, r.totalTime, r.counts)); + } + Collections.sort(mSensorUsage); + } + + private void processScreenOn() { + // Do nothing + } + + private void collectStatistics() { + processCpuUsage(); + processNetworkUsage(); + processSensorUsage(); + processScreenOn(); + } + + private void refresh() { + try { + mStats = mBatteryInfo.getStatistics(); + collectStatistics(); + displayGraph(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException:", e); + } + } + + public void onClick(View v) { + if (v == mDetailsBackButton) { + hideDetails(); + return; + } + + int id = ((Integer) v.getTag()).intValue(); + showDetails(id); + } + + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK && mDetailsShown) { + hideDetails(); + return true; + } + return super.onKeyDown(keyCode, event); + } + + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + if (parent.equals(mTypeSpinner)) { + mType = position; + switch (position) { + case CPU_USAGE: + mWhichSpinner.setEnabled(true); + break; + case NETWORK_USAGE: + mWhichSpinner.setEnabled(true); + break; + case SENSOR_USAGE: + mWhichSpinner.setEnabled(true); + break; + case SCREEN_ON: + mWhichSpinner.setEnabled(false); + break; + case WAKE_LOCKS: + break; + } + } else if (parent.equals(mWhichSpinner)) { + mWhich = position; + } + + refresh(); + } + + public void onNothingSelected(AdapterView<?> parent) { + // Do nothing + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + Log.i(TAG, "onCreate"); + + String knownApps = getString(R.string.battery_history_known_apps); + String[] knownAppNames = knownApps.split(";"); + for (String name : knownAppNames) { + mKnownApps.add(name); + } + + setContentView(R.layout.battery_history); + + mGraphLayout = (LinearLayout) findViewById(R.id.graphLayout); + mTextLayout = (LinearLayout) findViewById(R.id.textLayout); + mDetailsText = (TextView) findViewById(R.id.detailsText); + mMessageText = (TextView) findViewById(R.id.messageText); + + mTypeSpinner = (Spinner) findViewById(R.id.typeSpinner); + mTypeSpinner.setOnItemSelectedListener(this); + + mWhichSpinner = (Spinner) findViewById(R.id.whichSpinner); + mWhichSpinner.setOnItemSelectedListener(this); + + mButtons = new GraphableButton[8]; + mButtons[0] = (GraphableButton) findViewById(R.id.button0); + mButtons[1] = (GraphableButton) findViewById(R.id.button1); + mButtons[2] = (GraphableButton) findViewById(R.id.button2); + mButtons[3] = (GraphableButton) findViewById(R.id.button3); + mButtons[4] = (GraphableButton) findViewById(R.id.button4); + mButtons[5] = (GraphableButton) findViewById(R.id.button5); + mButtons[6] = (GraphableButton) findViewById(R.id.button6); + mButtons[7] = (GraphableButton) findViewById(R.id.button7); + + for (int i = 0; i < mButtons.length; i++) { + mButtons[i].setTag(i); + mButtons[i].setOnClickListener(this); + } + + mBatteryInfo = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); + refresh(); + } +} diff --git a/src/com/android/settings/battery_history/GraphableButton.java b/src/com/android/settings/battery_history/GraphableButton.java new file mode 100644 index 0000000..39028d0 --- /dev/null +++ b/src/com/android/settings/battery_history/GraphableButton.java @@ -0,0 +1,55 @@ +package com.android.settings.battery_history; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.util.Log; +import android.widget.Button; + +public class GraphableButton extends Button { + private static final String TAG = "GraphableButton"; + + static Paint[] sPaint = new Paint[2]; + static { + sPaint[0] = new Paint(); + sPaint[0].setStyle(Paint.Style.FILL); + sPaint[0].setColor(Color.BLUE); + + sPaint[1] = new Paint(); + sPaint[1].setStyle(Paint.Style.FILL); + sPaint[1].setColor(Color.RED); + } + + double[] mValues; + + public GraphableButton(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setValues(double[] values, double maxValue) { + mValues = values.clone(); + for (int i = 0; i < values.length; i++) { + mValues[i] /= maxValue; + } + } + + @Override + public void onDraw(Canvas canvas) { + Log.i(TAG, "onDraw: w = " + getWidth() + ", h = " + getHeight()); + + int xmin = getPaddingLeft(); + int xmax = getWidth() - getPaddingRight(); + int ymin = getPaddingTop(); + int ymax = getHeight() - getPaddingBottom(); + + int startx = xmin; + for (int i = 0; i < mValues.length; i++) { + int endx = xmin + (int) (mValues[i] * (xmax - xmin)); + canvas.drawRect(startx, ymin, endx, ymax, sPaint[i]); + startx = endx; + } + super.onDraw(canvas); + } +} diff --git a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java index facb763..a51f9b5 100644 --- a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java +++ b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.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; @@ -56,14 +57,12 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - /* - * TODO: remove this once the BT framework broadcasts the - * MODE_CHANGED action when going into MODE_OFF. - */ - int mode = BluetoothIntent.DISABLED_ACTION.equals(intent.getAction()) - ? BluetoothDevice.MODE_OFF - : intent.getIntExtra(BluetoothIntent.MODE, BluetoothDevice.MODE_UNKNOWN); - handleModeChanged(mode); + if (BluetoothIntent.SCAN_MODE_CHANGED_ACTION.equals(intent.getAction())) { + int mode = intent.getIntExtra(BluetoothIntent.SCAN_MODE, BluetoothError.ERROR); + if (mode != BluetoothError.ERROR) { + handleModeChanged(mode); + } + } } }; @@ -92,12 +91,12 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan return; } - IntentFilter filter = new IntentFilter(BluetoothIntent.MODE_CHANGED_ACTION); + IntentFilter filter = new IntentFilter(BluetoothIntent.SCAN_MODE_CHANGED_ACTION); filter.addAction(BluetoothIntent.DISABLED_ACTION); mContext.registerReceiver(mReceiver, filter); mCheckBoxPreference.setOnPreferenceChangeListener(this); - handleModeChanged(mLocalManager.getBluetoothManager().getMode()); + handleModeChanged(mLocalManager.getBluetoothManager().getScanMode()); } public void pause() { @@ -132,11 +131,9 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan long endTimestamp = System.currentTimeMillis() + timeout * 1000; persistDiscoverableEndTimestamp(endTimestamp); - manager.setMode(BluetoothDevice.MODE_DISCOVERABLE); - handleModeChanged(BluetoothDevice.MODE_DISCOVERABLE); - + manager.setScanMode(BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE); } else { - manager.setMode(BluetoothDevice.MODE_CONNECTABLE); + manager.setScanMode(BluetoothDevice.SCAN_MODE_CONNECTABLE); } } @@ -160,7 +157,7 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan Log.v(TAG, "Got mode changed: " + mode); } - if (mode == BluetoothDevice.MODE_DISCOVERABLE) { + if (mode == BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { mCheckBoxPreference.setChecked(true); updateCountdownSummary(); @@ -170,8 +167,8 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan } private void updateCountdownSummary() { - int mode = mLocalManager.getBluetoothManager().getMode(); - if (mode != BluetoothDevice.MODE_DISCOVERABLE) { + int mode = mLocalManager.getBluetoothManager().getScanMode(); + if (mode != BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { return; } diff --git a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java index fe64d13..a588013 100644 --- a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java +++ b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java @@ -52,31 +52,39 @@ public class BluetoothEventRedirector { if (action.equals(BluetoothIntent.ENABLED_ACTION)) { mManager.setBluetoothStateInt(ExtendedBluetoothState.ENABLED); + } else if (action.equals(BluetoothIntent.DISABLED_ACTION)) { mManager.setBluetoothStateInt(ExtendedBluetoothState.DISABLED); } else if (action.equals(BluetoothIntent.DISCOVERY_STARTED_ACTION)) { mManager.onScanningStateChanged(true); + } else if (action.equals(BluetoothIntent.DISCOVERY_COMPLETED_ACTION)) { mManager.onScanningStateChanged(false); } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION)) { short rssi = intent.getShortExtra(BluetoothIntent.RSSI, Short.MIN_VALUE); mManager.getLocalDeviceManager().onDeviceAppeared(address, rssi); + } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION)) { mManager.getLocalDeviceManager().onDeviceDisappeared(address); + } else if (action.equals(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION)) { mManager.getLocalDeviceManager().onDeviceNameUpdated(address); + } else if (action.equals(BluetoothIntent.BOND_STATE_CHANGED_ACTION)) { int bondState = intent.getIntExtra(BluetoothIntent.BOND_STATE, BluetoothError.ERROR); mManager.getLocalDeviceManager().onBondingStateChanged(address, bondState); if (bondState == BluetoothDevice.BOND_NOT_BONDED) { int reason = intent.getIntExtra(BluetoothIntent.REASON, BluetoothError.ERROR); - Log.w(TAG, address + " unbonded with reason " + reason + - ", TODO: handle this nicely in the UI"); //TODO - mManager.getLocalDeviceManager().onBondingError(address); + if (reason == BluetoothDevice.UNBOND_REASON_AUTH_FAILED || + reason == BluetoothDevice.UNBOND_REASON_AUTH_REJECTED || + reason == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN) { + mManager.getLocalDeviceManager().onBondingError(address, reason); + } } + } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) { mManager.getLocalDeviceManager().onProfileStateChanged(address); @@ -96,6 +104,10 @@ public class BluetoothEventRedirector { oldState == BluetoothA2dp.STATE_CONNECTING) { mManager.getLocalDeviceManager().onConnectingError(address); } + + } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION)) { + mManager.getLocalDeviceManager().onBtClassChanged(address); + } } }; @@ -124,6 +136,7 @@ public class BluetoothEventRedirector { // Fine-grained state broadcasts filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION); filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION); + filter.addAction(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION); mManager.getContext().registerReceiver(mBroadcastReceiver, filter); } diff --git a/src/com/android/settings/bluetooth/BluetoothPinDialog.java b/src/com/android/settings/bluetooth/BluetoothPinDialog.java index 291d0c1..a8e7737 100644 --- a/src/com/android/settings/bluetooth/BluetoothPinDialog.java +++ b/src/com/android/settings/bluetooth/BluetoothPinDialog.java @@ -18,13 +18,19 @@ package com.android.settings.bluetooth; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothIntent; +import android.content.BroadcastReceiver; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.IntentFilter; import android.os.Bundle; +import android.text.Editable; import android.text.InputFilter; -import android.text.method.DigitsKeyListener; +import android.text.TextWatcher; +import android.text.InputFilter.LengthFilter; import android.util.Log; import android.view.View; +import android.widget.Button; import android.widget.EditText; import android.widget.TextView; @@ -36,12 +42,31 @@ import com.android.settings.R; * BluetoothPinDialog asks the user to enter a PIN for pairing with a remote * Bluetooth device. It is an activity that appears as a dialog. */ -public class BluetoothPinDialog extends AlertActivity implements DialogInterface.OnClickListener { +public class BluetoothPinDialog extends AlertActivity implements DialogInterface.OnClickListener, + TextWatcher { private static final String TAG = "BluetoothPinDialog"; private LocalBluetoothManager mLocalManager; private String mAddress; private EditText mPinView; + private Button mOkButton; + + private static final String INSTANCE_KEY_PAIRING_CANCELED = "received_pairing_canceled"; + private boolean mReceivedPairingCanceled; + + private BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (!BluetoothIntent.PAIRING_CANCEL_ACTION.equals(intent.getAction())) { + return; + } + + String address = intent.getStringExtra(BluetoothIntent.ADDRESS); + if (address == null || address.equals(mAddress)) { + onReceivedPairingCanceled(); + } + } + }; @Override protected void onCreate(Bundle savedInstanceState) { @@ -69,6 +94,39 @@ public class BluetoothPinDialog extends AlertActivity implements DialogInterface p.mNegativeButtonText = getString(android.R.string.cancel); p.mNegativeButtonListener = this; setupAlert(); + + mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); + mOkButton.setEnabled(false); + + /* + * Leave this registered through pause/resume since we still want to + * finish the activity in the background if pairing is canceled. + */ + registerReceiver(mReceiver, new IntentFilter(BluetoothIntent.PAIRING_CANCEL_ACTION)); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + + mReceivedPairingCanceled = savedInstanceState.getBoolean(INSTANCE_KEY_PAIRING_CANCELED); + if (mReceivedPairingCanceled) { + onReceivedPairingCanceled(); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putBoolean(INSTANCE_KEY_PAIRING_CANCELED, mReceivedPairingCanceled); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + unregisterReceiver(mReceiver); } private View createView() { @@ -79,9 +137,32 @@ public class BluetoothPinDialog extends AlertActivity implements DialogInterface messageView.setText(getString(R.string.bluetooth_enter_pin_msg, name)); mPinView = (EditText) view.findViewById(R.id.text); + mPinView.addTextChangedListener(this); + // Maximum of 10 characters in a PIN + mPinView.setFilters(new InputFilter[] { new LengthFilter(10) }); return view; } + + public void afterTextChanged(Editable s) { + if (s.length() > 0) { + mOkButton.setEnabled(true); + } + } + + private void onReceivedPairingCanceled() { + mReceivedPairingCanceled = true; + + TextView messageView = (TextView) findViewById(R.id.message); + messageView.setText(getString(R.string.bluetooth_pairing_error_message, + mLocalManager.getLocalDeviceManager().getName(mAddress))); + + mPinView.setEnabled(false); + mPinView.clearFocus(); + mPinView.removeTextChangedListener(this); + + mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false); + } private void onPair(String pin) { byte[] pinBytes = BluetoothDevice.convertPinToBytes(pin); @@ -94,7 +175,7 @@ public class BluetoothPinDialog extends AlertActivity implements DialogInterface } private void onCancel() { - mLocalManager.getBluetoothManager().cancelPin(mAddress); + mLocalManager.getBluetoothManager().cancelBondProcess(mAddress); } public void onClick(DialogInterface dialog, int which) { @@ -109,4 +190,12 @@ public class BluetoothPinDialog extends AlertActivity implements DialogInterface } } + /* Not used */ + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + /* Not used */ + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + } diff --git a/src/com/android/settings/bluetooth/ConnectSpecificProfilesActivity.java b/src/com/android/settings/bluetooth/ConnectSpecificProfilesActivity.java index 23a43bd..f2f3bdf 100644 --- a/src/com/android/settings/bluetooth/ConnectSpecificProfilesActivity.java +++ b/src/com/android/settings/bluetooth/ConnectSpecificProfilesActivity.java @@ -25,10 +25,7 @@ import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceGroup; -import android.preference.PreferenceScreen; import android.text.TextUtils; -import android.widget.ImageView; -import android.widget.TextView; import android.util.Log; /** @@ -114,7 +111,7 @@ public class ConnectSpecificProfilesActivity extends PreferenceActivity mManager.setForegroundActivity(this); mDevice.registerCallback(this); - refresh(true); + refresh(); } @Override @@ -169,7 +166,7 @@ public class ConnectSpecificProfilesActivity extends PreferenceActivity } private void onOnlineModeCheckedStateChanged(boolean checked) { - switchModes(checked, false); + setOnlineMode(checked, true); } private void onProfileCheckedStateChanged(Profile profile, boolean checked) { @@ -187,39 +184,34 @@ public class ConnectSpecificProfilesActivity extends PreferenceActivity } public void onDeviceAttributesChanged(LocalBluetoothDevice device) { - refresh(false); + refresh(); } - private void refresh(boolean forceRefresh) { - // The online mode could have changed - updateOnlineMode(forceRefresh); + private void refresh() { + // We are in 'online mode' if we are connected, connecting, or disconnecting + setOnlineMode(mDevice.isConnected() || mDevice.isBusy(), false); refreshProfiles(); - refreshOnlineModePreference(); } - private void updateOnlineMode(boolean force) { - // Connected or Connecting (and Disconnecting, which is fine) - boolean onlineMode = mDevice.isConnected() || mDevice.isBusy(); - switchModes(onlineMode, force); - } - /** * Switches between online/offline mode. * * @param onlineMode Whether to be in online mode, or offline mode. + * @param takeAction Whether to take action (i.e., connect or disconnect) + * based on the new online mode. */ - private void switchModes(boolean onlineMode, boolean force) { - if (mOnlineMode != onlineMode || force) { - mOnlineMode = onlineMode; + private void setOnlineMode(boolean onlineMode, boolean takeAction) { + mOnlineMode = onlineMode; + if (takeAction) { if (onlineMode) { mDevice.connect(); } else { mDevice.disconnect(); } - - refreshOnlineModePreference(); } + + refreshOnlineModePreference(); } private void refreshOnlineModePreference() { diff --git a/src/com/android/settings/bluetooth/LocalBluetoothDevice.java b/src/com/android/settings/bluetooth/LocalBluetoothDevice.java index 26ddbf2..009ba5e 100644 --- a/src/com/android/settings/bluetooth/LocalBluetoothDevice.java +++ b/src/com/android/settings/bluetooth/LocalBluetoothDevice.java @@ -60,8 +60,6 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> { private boolean mVisible; - private int mBondState; - private final LocalBluetoothManager mLocalManager; private List<Callback> mCallbacks = new ArrayList<Callback>(); @@ -144,6 +142,9 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> { public void connect() { if (!ensurePaired()) return; + // Reset the only-show-one-error-dialog tracking variable + mIsConnectingErrorPossible = true; + Context context = mLocalManager.getContext(); boolean hasAtLeastOnePreferredProfile = false; for (Profile profile : mProfiles) { @@ -151,7 +152,7 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> { LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); if (profileManager.isPreferred(mAddress)) { hasAtLeastOnePreferredProfile = true; - connect(profile); + connectInt(profile); } } @@ -163,23 +164,31 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> { private void connectAndPreferAllProfiles() { if (!ensurePaired()) return; + // Reset the only-show-one-error-dialog tracking variable + mIsConnectingErrorPossible = true; + Context context = mLocalManager.getContext(); for (Profile profile : mProfiles) { LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); profileManager.setPreferred(mAddress, true); - connect(profile); + connectInt(profile); } } public void connect(Profile profile) { + // Reset the only-show-one-error-dialog tracking variable + mIsConnectingErrorPossible = true; + connectInt(profile); + } + + public void connectInt(Profile profile) { if (!ensurePaired()) return; LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); int status = profileManager.getConnectionStatus(mAddress); if (!SettingsBtStatus.isConnectionStatusConnected(status)) { - mIsConnectingErrorPossible = true; if (profileManager.connect(mAddress) != BluetoothDevice.RESULT_SUCCESS) { showConnectingError(); } @@ -211,9 +220,9 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> { manager.cancelDiscovery(); } - if (mLocalManager.createBonding(mAddress)) { - //TODO: consider removing this line - UI will update through Intent - setBondState(BluetoothDevice.BOND_BONDING); + if (!mLocalManager.getBluetoothManager().createBond(mAddress)) { + mLocalManager.showError(mAddress, R.string.bluetooth_error_title, + R.string.bluetooth_pairing_error_message); } } @@ -235,11 +244,7 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> { BluetoothDevice manager = mLocalManager.getBluetoothManager(); fetchName(); - mBtClass = manager.getRemoteClass(mAddress); - - LocalBluetoothProfileManager.fill(mBtClass, mProfiles); - - mBondState = manager.getBondState(mAddress); + fetchBtClass(); mVisible = false; @@ -283,14 +288,7 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> { } public int getBondState() { - return mBondState; - } - - void setBondState(int bondState) { - if (mBondState != bondState) { - mBondState = bondState; - dispatchAttributesChanged(); - } + return mLocalManager.getBluetoothManager().getBondState(mAddress); } void setRssi(short rssi) { @@ -355,6 +353,24 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> { } } + /** + * Fetches a new value for the cached BT class. + */ + private void fetchBtClass() { + mBtClass = mLocalManager.getBluetoothManager().getRemoteClass(mAddress); + mProfiles.clear(); + LocalBluetoothProfileManager.fill(mBtClass, mProfiles); + } + + /** + * Refreshes the UI for the BT class, including fetching the latest value + * for the class. + */ + public void refreshBtClass() { + fetchBtClass(); + dispatchAttributesChanged(); + } + public int getSummary() { // TODO: clean up int oneOffSummary = getOneOffSummary(); @@ -425,17 +441,15 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> { // No context menu if it is busy (none of these items are applicable if busy) if (isBusy()) return; - // No context menu if there are no profiles - if (mProfiles.size() == 0) return; - int bondState = getBondState(); boolean isConnected = isConnected(); + boolean hasProfiles = mProfiles.size() > 0; menu.setHeaderTitle(getName()); if (isConnected) { menu.add(0, CONTEXT_ITEM_DISCONNECT, 0, R.string.bluetooth_device_context_disconnect); - } else { + } else if (hasProfiles) { // For connection action, show either "Connect" or "Pair & connect" int connectString = (bondState == BluetoothDevice.BOND_NOT_BONDED) ? R.string.bluetooth_device_context_pair_connect @@ -538,8 +552,8 @@ public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> { if (comparison != 0) return comparison; // Paired above not paired - comparison = (another.mBondState == BluetoothDevice.BOND_BONDED ? 1 : 0) - - (mBondState == BluetoothDevice.BOND_BONDED ? 1 : 0); + comparison = (another.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0) - + (getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0); if (comparison != 0) return comparison; // Visible above not visible diff --git a/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java b/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java index a751656..6bb2b4a 100644 --- a/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java +++ b/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java @@ -45,19 +45,23 @@ public class LocalBluetoothDeviceManager { readPairedDevices(); } - private synchronized void readPairedDevices() { + private synchronized boolean readPairedDevices() { BluetoothDevice manager = mLocalManager.getBluetoothManager(); String[] bondedAddresses = manager.listBonds(); - if (bondedAddresses == null) return; + if (bondedAddresses == null) return false; + boolean deviceAdded = false; for (String address : bondedAddresses) { LocalBluetoothDevice device = findDevice(address); if (device == null) { device = new LocalBluetoothDevice(mLocalManager.getContext(), address); mDevices.add(device); - dispatchDeviceAdded(device); + dispatchDeviceAdded(device); + deviceAdded = true; } } + + return deviceAdded; } public synchronized List<LocalBluetoothDevice> getDevicesCopy() { @@ -157,23 +161,33 @@ public class LocalBluetoothDeviceManager { public synchronized void onBondingStateChanged(String address, int bondState) { LocalBluetoothDevice device = findDevice(address); if (device == null) { - Log.e(TAG, "Got bonding state changed for " + address + - ", but we have no record of that device."); + if (!readPairedDevices()) { + Log.e(TAG, "Got bonding state changed for " + address + + ", but we have no record of that device."); + } return; } - device.setBondState(bondState); //TODO: might be unecessary - checkForDeviceRemoval(device); + device.refresh(); if (bondState == BluetoothDevice.BOND_BONDED) { // Auto-connect after pairing device.connect(); } } - - public synchronized void onBondingError(String address) { + + /** + * Called when there is a bonding error. + * + * @param address The address of the remote device. + * @param reason The reason, one of the error reasons from + * BluetoothDevice.UNBOND_REASON_* + */ + public synchronized void onBondingError(String address, int reason) { mLocalManager.showError(address, R.string.bluetooth_error_title, - R.string.bluetooth_pairing_error_message); + (reason == BluetoothDevice.UNBOND_REASON_AUTH_FAILED) ? + R.string.bluetooth_pairing_pin_error_message : + R.string.bluetooth_pairing_error_message); } public synchronized void onProfileStateChanged(String address) { @@ -205,4 +219,11 @@ public class LocalBluetoothDeviceManager { checkForDeviceRemoval(device); } } + + public synchronized void onBtClassChanged(String address) { + LocalBluetoothDevice device = findDevice(address); + if (device != null) { + device.refreshBtClass(); + } + } } diff --git a/src/com/android/settings/bluetooth/LocalBluetoothManager.java b/src/com/android/settings/bluetooth/LocalBluetoothManager.java index f8275b5..4fd708e 100644 --- a/src/com/android/settings/bluetooth/LocalBluetoothManager.java +++ b/src/com/android/settings/bluetooth/LocalBluetoothManager.java @@ -226,10 +226,6 @@ public class LocalBluetoothManager { } } - public boolean createBonding(String address) { - return mManager.createBond(address); - } - public void showError(String address, int titleResId, int messageResId) { LocalBluetoothDevice device = mLocalDeviceManager.findDevice(address); if (device == null) return; diff --git a/src/com/android/settings/deviceinfo/Memory.java b/src/com/android/settings/deviceinfo/Memory.java index 86e6423..adfe88c 100644 --- a/src/com/android/settings/deviceinfo/Memory.java +++ b/src/com/android/settings/deviceinfo/Memory.java @@ -48,11 +48,13 @@ public class Memory extends PreferenceActivity { private static final String MEMORY_SD_UNMOUNT = "memory_sd_unmount"; + private static final String MEMORY_SD_FORMAT = "memory_sd_format"; private Resources mRes; private Preference mSdSize; private Preference mSdAvail; private Preference mSdUnmount; + private Preference mSdFormat; // Access using getMountService() private IMountService mMountService = null; @@ -67,6 +69,7 @@ public class Memory extends PreferenceActivity { mSdSize = findPreference(MEMORY_SD_SIZE); mSdAvail = findPreference(MEMORY_SD_AVAIL); mSdUnmount = findPreference(MEMORY_SD_UNMOUNT); + mSdFormat = findPreference(MEMORY_SD_FORMAT); } @Override @@ -109,6 +112,11 @@ public class Memory extends PreferenceActivity { if (preference == mSdUnmount) { unmount(); return true; + } else if (preference == mSdFormat) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setClass(this, com.android.settings.MediaFormat.class); + startActivity(intent); + return true; } return false; @@ -134,7 +142,7 @@ public class Memory extends PreferenceActivity { updateMemoryStatus(); } } - + private void updateMemoryStatus() { String status = Environment.getExternalStorageState(); String readOnly = ""; @@ -143,6 +151,8 @@ public class Memory extends PreferenceActivity { readOnly = mRes.getString(R.string.read_only); } + mSdFormat.setEnabled(false); + if (status.equals(Environment.MEDIA_MOUNTED)) { try { File path = Environment.getExternalStorageDirectory(); @@ -164,6 +174,14 @@ public class Memory extends PreferenceActivity { mSdSize.setSummary(mRes.getString(R.string.sd_unavailable)); mSdAvail.setSummary(mRes.getString(R.string.sd_unavailable)); mSdUnmount.setEnabled(false); + + if (status.equals(Environment.MEDIA_UNMOUNTED) || + status.equals(Environment.MEDIA_NOFS) || + status.equals(Environment.MEDIA_UNMOUNTABLE) ) { + mSdFormat.setEnabled(true); + } + + } File path = Environment.getDataDirectory(); diff --git a/src/com/android/settings/deviceinfo/Status.java b/src/com/android/settings/deviceinfo/Status.java index b7aceb1..98aa12b 100644 --- a/src/com/android/settings/deviceinfo/Status.java +++ b/src/com/android/settings/deviceinfo/Status.java @@ -30,6 +30,7 @@ import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.NetStat; import android.preference.Preference; import android.preference.PreferenceActivity; import android.telephony.PhoneStateListener; @@ -64,10 +65,11 @@ public class Status extends PreferenceActivity { private static final String KEY_WIFI_MAC_ADDRESS = "wifi_mac_address"; private static final String KEY_BT_ADDRESS = "bt_address"; + private static final String KEY_NETWORK_TRAFFIC_STATS = "network_traffic_stats"; private static final int EVENT_SIGNAL_STRENGTH_CHANGED = 200; private static final int EVENT_SERVICE_STATE_CHANGED = 300; - - private static final int EVENT_FIX_UPTIME = 500; + + private static final int EVENT_UPDATE_STATS = 500; private TelephonyManager mTelephonyManager; private Phone mPhone = null; @@ -108,9 +110,10 @@ public class Status extends PreferenceActivity { status.updateServiceState(serviceState); break; - case EVENT_FIX_UPTIME: + case EVENT_UPDATE_STATS: status.updateTimes(); - sendMessageDelayed(obtainMessage(EVENT_FIX_UPTIME), 1000); + status.setNetworkTrafficStats(); + sendEmptyMessageDelayed(EVENT_UPDATE_STATS, 1000); break; } } @@ -196,7 +199,7 @@ public class Status extends PreferenceActivity { setWifiStatus(); setBtStatus(); - } + } @Override protected void onResume() { @@ -212,7 +215,7 @@ public class Status extends PreferenceActivity { mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE); - mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_FIX_UPTIME), 0); + mHandler.sendEmptyMessage(EVENT_UPDATE_STATS); } @Override @@ -222,7 +225,7 @@ public class Status extends PreferenceActivity { mPhoneStateReceiver.unregisterIntent(); mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); unregisterReceiver(mBatteryInfoReceiver); - mHandler.removeMessages(EVENT_FIX_UPTIME); + mHandler.removeMessages(EVENT_UPDATE_STATS); } /** @@ -349,6 +352,17 @@ public class Status extends PreferenceActivity { } } + private void setNetworkTrafficStats() { + long txPkts = NetStat.getTotalTxPkts(); + long txBytes = NetStat.getTotalTxBytes(); + long rxPkts = NetStat.getTotalRxPkts(); + long rxBytes = NetStat.getTotalRxBytes(); + + Preference netStatsPref = findPreference(KEY_NETWORK_TRAFFIC_STATS); + netStatsPref.setSummary(getString(R.string.status_network_traffic_summary, + txPkts, txBytes, rxPkts, rxBytes)); + } + void updateTimes() { long at = SystemClock.uptimeMillis() / 1000; long ut = SystemClock.elapsedRealtime() / 1000; diff --git a/src/com/android/settings/quicklaunch/QuickLaunchSettings.java b/src/com/android/settings/quicklaunch/QuickLaunchSettings.java index 2ec685d..4d44524 100644 --- a/src/com/android/settings/quicklaunch/QuickLaunchSettings.java +++ b/src/com/android/settings/quicklaunch/QuickLaunchSettings.java @@ -16,8 +16,6 @@ package com.android.settings.quicklaunch; -import com.android.settings.R; - import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; @@ -28,10 +26,9 @@ import android.os.Bundle; import android.os.Handler; import android.preference.Preference; import android.preference.PreferenceActivity; -import android.preference.PreferenceCategory; +import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.provider.Settings.Bookmarks; -import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -40,6 +37,8 @@ import android.view.KeyEvent; import android.view.View; import android.widget.AdapterView; +import com.android.settings.R; + /** * Settings activity for quick launch. * <p> @@ -76,7 +75,7 @@ public class QuickLaunchSettings extends PreferenceActivity implements private SparseBooleanArray mBookmarkedShortcuts; /** Preference category to hold the shortcut preferences. */ - private PreferenceCategory mShortcutCategory; + private PreferenceGroup mShortcutGroup; /** Mapping of a shortcut to its preference. */ private SparseArray<ShortcutPreference> mShortcutToPreference; @@ -93,7 +92,7 @@ public class QuickLaunchSettings extends PreferenceActivity implements addPreferencesFromResource(R.xml.quick_launch_settings); - mShortcutCategory = (PreferenceCategory) findPreference(KEY_SHORTCUT_CATEGORY); + mShortcutGroup = (PreferenceGroup) findPreference(KEY_SHORTCUT_CATEGORY); mShortcutToPreference = new SparseArray<ShortcutPreference>(); mBookmarksObserver = new BookmarksObserver(mUiHandler); initShortcutPreferences(); @@ -252,7 +251,7 @@ public class QuickLaunchSettings extends PreferenceActivity implements private ShortcutPreference createPreference(char shortcut) { ShortcutPreference pref = new ShortcutPreference(QuickLaunchSettings.this, shortcut); - mShortcutCategory.addPreference(pref); + mShortcutGroup.addPreference(pref); mShortcutToPreference.put(shortcut, pref); return pref; } |