Code drop from //branches/cupcake/...@124589

This commit is contained in:
The Android Open Source Project
2008-12-17 18:06:01 -08:00
parent de2d9f5f10
commit abc48f80d8
97 changed files with 11385 additions and 7016 deletions

View File

@@ -100,9 +100,10 @@ public class AirplaneModeEnabler implements Preference.OnPreferenceChangeListene
*/
private void onAirplaneModeChanged() {
ServiceState serviceState = mPhoneStateReceiver.getServiceState();
boolean isPhoneOff = serviceState.getState() == ServiceState.STATE_POWER_OFF;
mCheckBoxPref.setChecked(isPhoneOff);
mCheckBoxPref.setSummary(R.string.airplane_mode_summary);
boolean airplaneModeEnabled = serviceState.getState() == ServiceState.STATE_POWER_OFF;
mCheckBoxPref.setChecked(airplaneModeEnabled);
mCheckBoxPref.setSummary(airplaneModeEnabled ? null :
mContext.getString(R.string.airplane_mode_summary));
mCheckBoxPref.setEnabled(true);
}

View File

@@ -63,6 +63,8 @@ public class ApnEditor extends PreferenceActivity
private EditTextPreference mMmsProxy;
private EditTextPreference mMmsPort;
private EditTextPreference mApnType;
private String mCurMnc;
private String mCurMcc;
private Uri mUri;
private Cursor mCursor;
@@ -210,6 +212,8 @@ public class ApnEditor extends PreferenceActivity
// Auto populate MNC and MCC for new entries, based on what SIM reports
mMcc.setText(mcc);
mMnc.setText(mnc);
mCurMnc = mnc;
mCurMcc = mcc;
}
}
}
@@ -338,6 +342,12 @@ public class ApnEditor extends PreferenceActivity
values.put(Telephony.Carriers.NUMERIC, mcc + mnc);
if (mCurMnc != null && mCurMcc != null) {
if (mCurMnc.equals(mnc) && mCurMcc.equals(mcc)) {
values.put(Telephony.Carriers.CURRENT, 1);
}
}
getContentResolver().update(mUri, values, null, null);
return true;

View File

@@ -27,6 +27,7 @@ import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.provider.Telephony;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
@@ -68,12 +69,16 @@ public class ApnSettings extends PreferenceActivity {
String name = mCursor.getString(NAME_INDEX);
String apn = mCursor.getString(APN_INDEX);
Preference pref = new Preference((Context) this);
pref.setKey(mCursor.getString(ID_INDEX));
pref.setTitle(name);
pref.setSummary(apn);
pref.setPersistent(false);
apnList.addPreference(pref);
if (name != null && apn != null && TextUtils.getTrimmedLength(name) > 0
&& TextUtils.getTrimmedLength(apn) > 0) {
Preference pref = new Preference((Context) this);
pref.setKey(mCursor.getString(ID_INDEX));
pref.setTitle(name);
pref.setSummary(apn);
pref.setPersistent(false);
apnList.addPreference(pref);
}
mCursor.moveToNext();
}
}

View File

@@ -18,6 +18,7 @@ package com.android.settings;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
@@ -29,6 +30,7 @@ public class ApplicationSettings extends PreferenceActivity implements
DialogInterface.OnClickListener {
private static final String KEY_TOGGLE_INSTALL_APPLICATIONS = "toggle_install_applications";
private static final String KEY_QUICK_LAUNCH = "quick_launch";
private CheckBoxPreference mToggleAppInstallation;
@@ -42,7 +44,12 @@ public class ApplicationSettings extends PreferenceActivity implements
mToggleAppInstallation = (CheckBoxPreference) findPreference(KEY_TOGGLE_INSTALL_APPLICATIONS);
mToggleAppInstallation.setChecked(isNonMarketAppsAllowed());
if (getResources().getConfiguration().keyboard == Configuration.KEYBOARD_NOKEYS) {
// No hard keyboard, remove the setting for quick launch
Preference quickLaunchSetting = findPreference(KEY_QUICK_LAUNCH);
getPreferenceScreen().removePreference(quickLaunchSetting);
}
}
@Override
@@ -68,13 +75,13 @@ public class ApplicationSettings extends PreferenceActivity implements
private void setNonMarketAppsAllowed(boolean enabled) {
// Change the system setting
Settings.System.putInt(getContentResolver(), Settings.System.INSTALL_NON_MARKET_APPS,
Settings.Secure.putInt(getContentResolver(), Settings.Secure.INSTALL_NON_MARKET_APPS,
enabled ? 1 : 0);
}
private boolean isNonMarketAppsAllowed() {
return Settings.System.getInt(getContentResolver(),
Settings.System.INSTALL_NON_MARKET_APPS, 0) > 0;
return Settings.Secure.getInt(getContentResolver(),
Settings.Secure.INSTALL_NON_MARKET_APPS, 0) > 0;
}
private void warnAppInstallation() {

View File

@@ -29,7 +29,7 @@ import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.pim.DateUtils;
import android.text.format.DateUtils;
import android.widget.TextView;
import com.android.internal.app.IBatteryStats;

View File

@@ -1,93 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class BluetoothDataEntry extends Activity implements OnKeyListener {
private Bundle extras;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.bluetooth_data_entry);
mDataLabel = (TextView)findViewById(R.id.dataLabel);
mDataEntry = (EditText)findViewById(R.id.dataEntry);
mConfirmButton = (Button)findViewById(R.id.confirmButton);
mCancelButton = (Button)findViewById(R.id.cancelButton);
mDataEntry.setOnKeyListener(this);
Intent intent = getIntent();
String label = null;
{
String labelExtra = intent.getStringExtra("label");
if (labelExtra != null) {
label = labelExtra;
}
}
extras = intent.getBundleExtra("extras");
if (label != null && label.length() > 0) {
mDataLabel.setText(label);
}
mConfirmButton.setOnClickListener(new ConfirmButtonListener());
mCancelButton.setOnClickListener(new CancelButtonListener());
}
private class ConfirmButtonListener implements OnClickListener {
public void onClick(View v) {
activityResult(RESULT_OK, mDataEntry.getText().toString(), extras);
}
}
private class CancelButtonListener implements OnClickListener {
public void onClick(View v) {
activityResult(RESULT_CANCELED, null, null);
}
}
protected void activityResult(int result, String data, Bundle extras) {
setResult(result, (new Intent()).setAction(data).putExtras(extras));
finish();
}
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
|| keyCode == KeyEvent.KEYCODE_ENTER) {
activityResult(RESULT_OK, mDataEntry.getText().toString(), extras);
return true;
}
return false;
}
protected TextView mDataLabel;
protected EditText mDataEntry;
protected Button mConfirmButton;
protected Button mCancelButton;
}

View File

@@ -1,72 +0,0 @@
package com.android.settings;
import android.content.Context;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import java.util.Map;
/**
* This class extends Preference to display bluetooth status icons. One
* icon specifies the connection/pairing status that is right-aligned.
* An optional headset icon can be added to its left as well.
*/
public class BluetoothListItem extends Preference {
private boolean mIsHeadset;
private int mWeight;
public BluetoothListItem(Context context, AttributeSet attrs) {
super(context, attrs);
setWidgetLayoutResource(R.layout.preference_widget_btdevice_status);
}
private void updateIcons(View view) {
ImageView headsetView = (ImageView) view.findViewById(R.id.device_headset);
headsetView.setVisibility(mIsHeadset ? View.VISIBLE : View.GONE);
}
@Override
public void onBindView(View view) {
super.onBindView(view);
updateIcons(view);
}
/**
* Set whether the device is of headset type
* @param headset whether or not the headset icon should be shown
*/
public void setHeadset(boolean headset) {
mIsHeadset = headset;
notifyChanged();
}
/**
* Sets the weight for ordering by signal strength or importance
* @param weight the ordering weight
*/
public void setWeight(int weight) {
mWeight = weight;
}
/**
* Returns the currently set ordering weight
* @return the current ordering weight
*/
public int getWeight() {
return mWeight;
}
@Override
public int compareTo(Preference another) {
int diff = ((BluetoothListItem)another).mWeight - mWeight;
// Let the new one be after the old one, if they are the same weight
// TODO: Implement a more reliable way to consistently order items of
// the same weight
if (diff == 0) diff = 1;
return diff;
}
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings;
import android.app.NotificationManager;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class BluetoothPINEntry extends BluetoothDataEntry {
private BluetoothDevice mBluetooth;
private String mAddress;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Intent intent = getIntent();
if (!intent.getAction().equals(BluetoothIntent.PAIRING_REQUEST_ACTION))
{
Log.e(this.getClass().getName(),
"Error: this activity may be started only with intent " +
BluetoothIntent.PAIRING_REQUEST_ACTION);
finish();
}
// Cancel the notification, if any
NotificationManager manager = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(0xb100ceee);
mAddress = intent.getStringExtra(BluetoothIntent.ADDRESS);
mBluetooth = (BluetoothDevice)getSystemService(BLUETOOTH_SERVICE);
String remoteName = mBluetooth.getRemoteName(mAddress);
if (remoteName == null) {
remoteName = mAddress;
}
mDataLabel.setText(getString(R.string.bluetooth_enter_pin_msg) + remoteName);
}
@Override
public void activityResult(int result, String data, Bundle extras) {
switch (result) {
case RESULT_OK:
byte[] pin = BluetoothDevice.convertPinToBytes(mDataEntry.getText().toString());
if (pin == null) {
return;
}
mBluetooth.setPin(mAddress, pin);
break;
case RESULT_CANCELED:
mBluetooth.cancelPin(mAddress);
break;
}
finish();
}
}

View File

@@ -1,80 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
/**
* This class handles the Bluetooth pairing PIN request from the bluetooth service
* It checks if the BluetoothSettings activity is currently visible and lets that
* activity handle the request. Otherwise it puts a Notification in the status bar,
* which can be clicked to bring up the PIN entry dialog.
*/
public class BluetoothPinRequest extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BluetoothIntent.PAIRING_REQUEST_ACTION)) {
if (BluetoothSettings.isRunning()) {
// Let the BluetoothSettings activity handle it
return;
} else {
Resources res = context.getResources();
String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
Notification pair = new Notification(
android.R.drawable.stat_sys_data_bluetooth,
res.getString(R.string.bluetooth_notif_ticker),
System.currentTimeMillis());
Intent pinIntent = new Intent();
pinIntent.setClass(context, BluetoothPINEntry.class);
pinIntent.putExtra(BluetoothIntent.ADDRESS, address);
pinIntent.setAction(BluetoothIntent.PAIRING_REQUEST_ACTION);
PendingIntent pending = PendingIntent.getActivity(context, 0,
pinIntent, PendingIntent.FLAG_ONE_SHOT);
String name = intent.getStringExtra(BluetoothIntent.NAME);
if (name == null) {
BluetoothDevice bluetooth =
(BluetoothDevice)context.getSystemService(Context.BLUETOOTH_SERVICE);
name = bluetooth.getRemoteName(address);
if (name == null) {
name = address;
}
}
pair.setLatestEventInfo(context,
res.getString(R.string.bluetooth_notif_title),
res.getString(R.string.bluetooth_notif_message) + name,
pending);
NotificationManager manager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(0xb100ceee, pair);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -45,6 +45,17 @@ import java.util.List;
*/
public class ChooseLockPattern extends Activity implements View.OnClickListener{
/**
* Used by the choose lock pattern wizard to indicate the wizard is
* finished, and each activity in the wizard should finish.
* <p>
* Previously, each activity in the wizard would finish itself after
* starting the next activity. However, this leads to broken 'Back'
* behavior. So, now an activity does not finish itself until it gets this
* result.
*/
static final int RESULT_FINISHED = RESULT_FIRST_USER;
// how long after a confirmation message is shown before moving on
static final int INFORMATION_MSG_TIMEOUT_MS = 3000;
@@ -298,6 +309,8 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
mLockPatternView.clearPattern();
updateStage(Stage.Introduction);
} else if (mUiStage.leftMode == LeftButtonMode.Cancel) {
// They are canceling the entire wizard
setResult(RESULT_FINISHED);
finish();
} else {
throw new IllegalStateException("left footer button pressed, but stage of " +
@@ -368,6 +381,7 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
}
if (resultCode != Activity.RESULT_OK) {
setResult(RESULT_FINISHED);
finish();
}
updateStage(Stage.Introduction);
@@ -475,6 +489,8 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
mLockPatternUtils.setLockPatternEnabled(true);
mLockPatternUtils.setVisiblePatternEnabled(true);
}
setResult(RESULT_FINISHED);
finish();
}
}

View File

@@ -25,6 +25,7 @@ import android.view.View;
import android.widget.ImageView;
public class ChooseLockPatternExample extends Activity implements View.OnClickListener {
private static final int REQUESTCODE_CHOOSE = 1;
private static final long START_DELAY = 1000;
protected static final String TAG = "Settings";
private View mNextButton;
@@ -59,15 +60,24 @@ public class ChooseLockPatternExample extends Activity implements View.OnClickLi
public void onClick(View v) {
if (v == mSkipButton) {
// Canceling, so finish all
setResult(ChooseLockPattern.RESULT_FINISHED);
finish();
} else if (v == mNextButton) {
stopAnimation(mAnimation);
Intent intent = new Intent(this, ChooseLockPattern.class);
startActivity(intent);
startActivityForResult(intent, REQUESTCODE_CHOOSE);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUESTCODE_CHOOSE && resultCode == ChooseLockPattern.RESULT_FINISHED) {
setResult(resultCode);
finish();
}
}
private void initViews() {
mNextButton = findViewById(R.id.next_button);
mNextButton.setOnClickListener(this);

View File

@@ -24,8 +24,10 @@ import android.os.Bundle;
import android.view.View;
public class ChooseLockPatternTutorial extends Activity implements View.OnClickListener {
protected View mNextButton;
protected View mSkipButton;
private static final int REQUESTCODE_EXAMPLE = 1;
private View mNextButton;
private View mSkipButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -52,11 +54,22 @@ public class ChooseLockPatternTutorial extends Activity implements View.OnClickL
public void onClick(View v) {
if (v == mSkipButton) {
// Canceling, so finish all
setResult(ChooseLockPattern.RESULT_FINISHED);
finish();
} else if (v == mNextButton) {
startActivity(new Intent(this, ChooseLockPatternExample.class));
startActivityForResult(new Intent(this, ChooseLockPatternExample.class),
REQUESTCODE_EXAMPLE);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUESTCODE_EXAMPLE && resultCode == ChooseLockPattern.RESULT_FINISHED) {
setResult(resultCode);
finish();
}
}
}

View File

@@ -27,7 +27,6 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.os.SystemClock;
import android.pim.DateFormat;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
@@ -35,6 +34,7 @@ import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.text.format.DateFormat;
import android.widget.DatePicker;
import android.widget.TimePicker;
@@ -281,9 +281,7 @@ public class DateTimeSettings
/* Get & Set values from the system settings */
private boolean is24Hour() {
String setting = Settings.System.getString(getContentResolver(),
Settings.System.TIME_12_24);
return HOURS_24.equals(setting);
return DateFormat.is24HourFormat(this);
}
private void set24Hour(boolean is24Hour) {

View File

@@ -16,6 +16,7 @@
package com.android.settings;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.SystemProperties;
import android.preference.Preference;
@@ -32,9 +33,11 @@ public class DevelopmentSettings extends PreferenceActivity {
private static final String ENABLE_ADB = "enable_adb";
private static final String KEEP_SCREEN_ON = "keep_screen_on";
private static final String ALLOW_MOCK_LOCATION = "allow_mock_location";
private CheckBoxPreference mEnableAdb;
private CheckBoxPreference mKeepScreenOn;
private CheckBoxPreference mAllowMockLocation;
@Override
protected void onCreate(Bundle icicle) {
@@ -44,16 +47,19 @@ public class DevelopmentSettings extends PreferenceActivity {
mEnableAdb = (CheckBoxPreference) findPreference(ENABLE_ADB);
mKeepScreenOn = (CheckBoxPreference) findPreference(KEEP_SCREEN_ON);
mAllowMockLocation = (CheckBoxPreference) findPreference(ALLOW_MOCK_LOCATION);
}
@Override
protected void onResume() {
super.onResume();
mEnableAdb.setChecked(Settings.System.getInt(getContentResolver(),
Settings.System.ADB_ENABLED, 0) != 0);
mEnableAdb.setChecked(Settings.Secure.getInt(getContentResolver(),
Settings.Secure.ADB_ENABLED, 0) != 0);
mKeepScreenOn.setChecked(Settings.System.getInt(getContentResolver(),
Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0) != 0);
mAllowMockLocation.setChecked(Settings.Secure.getInt(getContentResolver(),
Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0);
}
@Override
@@ -66,11 +72,15 @@ public class DevelopmentSettings extends PreferenceActivity {
}
if (preference == mEnableAdb) {
Settings.System.putInt(getContentResolver(), Settings.System.ADB_ENABLED,
Settings.Secure.putInt(getContentResolver(), Settings.Secure.ADB_ENABLED,
mEnableAdb.isChecked() ? 1 : 0);
} else if (preference == mKeepScreenOn) {
Settings.System.putInt(getContentResolver(), Settings.System.STAY_ON_WHILE_PLUGGED_IN,
mKeepScreenOn.isChecked() ? 1 : 0);
mKeepScreenOn.isChecked() ?
(BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB) : 0);
} else if (preference == mAllowMockLocation) {
Settings.Secure.putInt(getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION,
mAllowMockLocation.isChecked() ? 1 : 0);
}
return false;

View File

@@ -46,6 +46,7 @@ public class DeviceInfoSettings extends PreferenceActivity {
private static final String KEY_TERMS = "terms";
private static final String KEY_LICENSE = "license";
private static final String KEY_COPYRIGHT = "copyright";
private static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings";
@Override
protected void onCreate(Bundle icicle) {
@@ -56,7 +57,7 @@ public class DeviceInfoSettings extends PreferenceActivity {
setSummary("firmware_version", "ro.build.version.release");
setSummary("baseband_version", "gsm.version.baseband");
setSummary("device_model", "ro.product.model");
setSummary("build_number", "ro.build.description");
setSummary("build_number", "ro.build.version.incremental");
findPreference("kernel_version").setSummary(getFormattedKernelVersion());
/*
@@ -74,6 +75,8 @@ public class DeviceInfoSettings extends PreferenceActivity {
Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
Utils.updatePreferenceToSpecificActivityOrRemove(this, parentPreference, KEY_TEAM,
Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
Utils.updatePreferenceToSpecificActivityOrRemove(this, parentPreference, KEY_SYSTEM_UPDATE_SETTINGS,
Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
}
private void setSummary(String preference, String property) {

View File

@@ -0,0 +1,191 @@
/*
* 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 java.util.HashSet;
import java.util.List;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.preference.CheckBoxPreference;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
/*
* Displays preferences for input methods.
*/
public class InputMethodsSettings extends PreferenceActivity {
private List<InputMethodInfo> mInputMethodProperties;
final TextUtils.SimpleStringSplitter mStringColonSplitter
= new TextUtils.SimpleStringSplitter(':');
private String mLastInputMethodId;
private String mLastTickedInputMethodId;
static public String getInputMethodIdFromKey(String key) {
return key;
}
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.input_methods_prefs);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
mInputMethodProperties = imm.getInputMethodList();
mLastInputMethodId = Settings.Secure.getString(getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD);
int N = (mInputMethodProperties == null ? 0 : mInputMethodProperties
.size());
for (int i = 0; i < N; ++i) {
InputMethodInfo property = mInputMethodProperties.get(i);
String prefKey = property.getId();
CharSequence label = property.loadLabel(getPackageManager());
// Add a check box.
CheckBoxPreference chkbxPref = new CheckBoxPreference(this);
chkbxPref.setKey(prefKey);
chkbxPref.setTitle(label);
getPreferenceScreen().addPreference(chkbxPref);
// If setting activity is available, add a setting screen entry.
if (null != property.getSettingsActivity()) {
PreferenceScreen prefScreen = new PreferenceScreen(this, null);
prefScreen.setKey(property.getSettingsActivity());
// XXX TODO: handle localization properly.
prefScreen.setTitle(label + " settings");
getPreferenceScreen().addPreference(prefScreen);
}
}
}
@Override
protected void onResume() {
super.onResume();
final HashSet<String> enabled = new HashSet<String>();
String enabledStr = Settings.Secure.getString(getContentResolver(),
Settings.Secure.ENABLED_INPUT_METHODS);
if (enabledStr != null) {
final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
splitter.setString(enabledStr);
while (splitter.hasNext()) {
enabled.add(splitter.next());
}
}
// Update the statuses of the Check Boxes.
int N = mInputMethodProperties.size();
for (int i = 0; i < N; ++i) {
final String id = mInputMethodProperties.get(i).getId();
CheckBoxPreference pref = (CheckBoxPreference) findPreference(mInputMethodProperties
.get(i).getId());
pref.setChecked(enabled.contains(id));
}
mLastTickedInputMethodId = null;
}
@Override
protected void onPause() {
super.onPause();
StringBuilder builder = new StringBuilder(256);
boolean haveLastInputMethod = false;
int firstEnabled = -1;
int N = mInputMethodProperties.size();
for (int i = 0; i < N; ++i) {
final String id = mInputMethodProperties.get(i).getId();
CheckBoxPreference pref = (CheckBoxPreference) findPreference(id);
boolean hasIt = id.equals(mLastInputMethodId);
if (pref.isChecked()) {
if (builder.length() > 0) builder.append(':');
builder.append(id);
if (firstEnabled < 0) {
firstEnabled = i;
}
if (hasIt) haveLastInputMethod = true;
} else if (hasIt) {
mLastInputMethodId = mLastTickedInputMethodId;
}
}
// If the last input method is unset, set it as the first enabled one.
if (null == mLastInputMethodId || "".equals(mLastInputMethodId)) {
if (firstEnabled >= 0) {
mLastInputMethodId = mInputMethodProperties.get(firstEnabled).getId();
} else {
mLastInputMethodId = null;
}
}
Settings.Secure.putString(getContentResolver(),
Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
Settings.Secure.putString(getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD, mLastInputMethodId);
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
// Those monkeys kept committing suicide, so we add this property
// to disable this functionality
if (!TextUtils.isEmpty(SystemProperties.get("ro.monkey"))) {
return false;
}
if (preference instanceof CheckBoxPreference) {
CheckBoxPreference chkPref = (CheckBoxPreference) preference;
String id = getInputMethodIdFromKey(chkPref.getKey());
if (chkPref.isChecked()) {
mLastTickedInputMethodId = id;
} else if (id.equals(mLastTickedInputMethodId)) {
mLastTickedInputMethodId = null;
}
} else if (preference instanceof PreferenceScreen) {
if (preference.getIntent() == null) {
PreferenceScreen pref = (PreferenceScreen) preference;
String activityName = pref.getKey();
String packageName = activityName.substring(0, activityName
.lastIndexOf("."));
if (activityName.length() > 0) {
Intent i = new Intent(Intent.ACTION_MAIN);
i.setClassName(packageName, activityName);
startActivity(i);
}
}
}
return false;
}
}

View File

@@ -29,7 +29,6 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -37,6 +36,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.format.Formatter;
import android.util.Config;
import android.util.Log;
import java.util.ArrayList;
@@ -50,33 +50,62 @@ import android.widget.LinearLayout;
import android.widget.TextView;
/**
* Activity to display application information from Settings
*
* Activity to display application information from Settings. This activity presents
* extended information associated with a package like code, data, total size, permissions
* used by the application and also the set of default launchable activities.
* For system applications, an option to clear user data is displayed only if data size is > 0.
* System applications that do not want clear user data do not have this option.
* For non-system applications, there is no option to clear data. Instead there is an option to
* uninstall the application.
*/
public class InstalledAppDetails extends Activity implements View.OnClickListener, DialogInterface.OnClickListener {
private static final String TAG="InstalledAppDetails";
private static final int _UNKNOWN_APP=R.string.unknown;
//wait times used for the async package manager api
private ApplicationInfo mAppInfo;
private Button mUninstallButton;
private Button mAppButton;
private Button mActivitiesButton;
private boolean mSysPackage;
private boolean localLOGV=Config.LOGV || true;
private boolean mCanUninstall;
private boolean localLOGV=Config.LOGV || false;
private TextView mTotalSize;
private TextView mAppSize;
private TextView mDataSize;
private PkgSizeObserver mSizeObserver;
private ClearUserDataObserver mClearDataObserver;
// Views related to cache info
private View mCachePanel;
private TextView mCacheSize;
private Button mClearCacheButton;
private ClearCacheObserver mClearCacheObserver;
PackageStats mSizeInfo;
private Button mManageSpaceButton;
private PackageManager mPm;
private String mBStr, mKbStr, mMbStr;
//internal constants used in Handler
private static final int CLEAR_USER_DATA = 1;
private static final int OP_SUCCESSFUL = 1;
private static final int OP_FAILED = 2;
private static final int CLEAR_USER_DATA = 1;
private static final int GET_PKG_SIZE = 2;
private static final int CLEAR_CACHE = 3;
private static final String ATTR_PACKAGE_STATS="PackageStats";
// invalid size value used initially and also when size retrieval through PackageManager
// fails for whatever reason
private static final int SIZE_INVALID = -1;
// Resource strings
private CharSequence mInvalidSizeStr;
private CharSequence mComputingStr;
private CharSequence mAppButtonText;
// Possible btn states
private enum AppButtonStates {
CLEAR_DATA,
UNINSTALL,
NONE
}
private AppButtonStates mAppButtonState;
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -86,17 +115,22 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
case GET_PKG_SIZE:
refreshSizeInfo(msg);
break;
case CLEAR_CACHE:
// Refresh size info
mPm.getPackageSizeInfo(mAppInfo.packageName, mSizeObserver);
break;
default:
break;
}
}
};
private boolean isSystemPackage() {
if ((mAppInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
return true;
private boolean isUninstallable() {
if (((mAppInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) &&
((mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0)) {
return false;
}
return false;
return true;
}
class ClearUserDataObserver extends IPackageDataObserver.Stub {
@@ -119,28 +153,46 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
}
}
class ClearCacheObserver extends IPackageDataObserver.Stub {
public void onRemoveCompleted(final String packageName, final boolean succeeded) {
final Message msg = mHandler.obtainMessage(CLEAR_CACHE);
msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
mHandler.sendMessage(msg);
}
}
private String getSizeStr(long size) {
String retStr = "";
if(size < 1024) {
return String.valueOf(size)+mBStr;
if (size == SIZE_INVALID) {
return mInvalidSizeStr.toString();
}
long kb, mb, rem;
kb = size >> 10;
rem = size - (kb << 10);
if(kb < 1024) {
if(rem > 512) {
kb++;
return Formatter.formatFileSize(this, size);
}
private void setAppBtnState() {
boolean visible = false;
if(mCanUninstall) {
//app can clear user data
if((mAppInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
== ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) {
mAppButtonText = getText(R.string.clear_user_data_text);
mAppButtonState = AppButtonStates.CLEAR_DATA;
visible = true;
} else {
//hide button if diableClearUserData is set
visible = false;
mAppButtonState = AppButtonStates.NONE;
}
retStr += String.valueOf(kb)+mKbStr;
return retStr;
} else {
visible = true;
mAppButtonState = AppButtonStates.UNINSTALL;
mAppButtonText = getText(R.string.uninstall_text);
}
if(visible) {
mAppButton.setText(mAppButtonText);
mAppButton.setVisibility(View.VISIBLE);
} else {
mAppButton.setVisibility(View.GONE);
}
mb = kb >> 10;
if(kb >= 512) {
//round off
mb++;
}
retStr += String.valueOf(mb)+ mMbStr;
return retStr;
}
/** Called when the activity is first created. */
@@ -152,45 +204,25 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
//get application's name from intent
Intent intent = getIntent();
final String packageName = intent.getStringExtra(ManageApplications.APP_PKG_NAME);
mSizeInfo = intent.getParcelableExtra(ManageApplications.APP_PKG_SIZE);
long total = -1;
long code = -1;
long data = -1;
if(mSizeInfo != null) {
total = mSizeInfo.cacheSize+mSizeInfo.codeSize+mSizeInfo.dataSize;
code = mSizeInfo.codeSize;
data = mSizeInfo.dataSize+mSizeInfo.cacheSize;
}
String unknownStr = getString(_UNKNOWN_APP);
mBStr = getString(R.string.b_text);
mKbStr = getString(R.string.kb_text);
mMbStr = getString(R.string.mb_text);
String totalSizeStr = unknownStr;
if(total != -1) {
totalSizeStr = getSizeStr(total);
}
String appSizeStr = unknownStr;
if(code != -1) {
appSizeStr = getSizeStr(code);
}
String dataSizeStr = unknownStr;
if(data != -1) {
dataSizeStr = getSizeStr(data);
}
if(localLOGV) Log.i(TAG, "packageName:"+packageName+", total="+total+
"code="+code+", data="+data);
mComputingStr = getText(R.string.computing_size);
// Try retrieving package stats again
CharSequence totalSizeStr, appSizeStr, dataSizeStr;
totalSizeStr = appSizeStr = dataSizeStr = mComputingStr;
if(localLOGV) Log.i(TAG, "Have to compute package sizes");
mSizeObserver = new PkgSizeObserver();
mPm.getPackageSizeInfo(packageName, mSizeObserver);
try {
mAppInfo = mPm.getApplicationInfo(packageName, 0);
mAppInfo = mPm.getApplicationInfo(packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
} catch (NameNotFoundException e) {
Throwable th = e.fillInStackTrace();
Log.e(TAG, "Exception when retrieving package:"+packageName, e);
displayErrorDialog(R.string.app_not_found_dlg_text, true, true);
}
setContentView(R.layout.installed_app_details);
((ImageView)findViewById(R.id.app_icon)).setImageDrawable(mPm.
getApplicationIcon(mAppInfo));
setContentView(R.layout.installed_app_details);
((ImageView)findViewById(R.id.app_icon)).setImageDrawable(mAppInfo.loadIcon(mPm));
//set application name TODO version
CharSequence appName = mPm.getApplicationLabel(mAppInfo);
CharSequence appName = mAppInfo.loadLabel(mPm);
if(appName == null) {
appName = getString(_UNKNOWN_APP);
}
@@ -208,33 +240,22 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
mDataSize = (TextView)findViewById(R.id.data_size_text);
mDataSize.setText(dataSizeStr);
mUninstallButton = ((Button)findViewById(R.id.uninstall_button));
mAppButton = ((Button)findViewById(R.id.uninstall_button));
//determine if app is a system app
mSysPackage = isSystemPackage();
if(localLOGV) Log.i(TAG, "Is systemPackage "+mSysPackage);
int btnText;
boolean btnClickable = true;
if(mSysPackage) {
//app can clear user data
if((mAppInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
== ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) {
mUninstallButton.setText(R.string.clear_user_data_text);
//disable button if data is 0
if(data == 0) {
mUninstallButton.setEnabled(false);
} else {
//enable button
mUninstallButton.setOnClickListener(this);
}
} else {
//hide button if diableClearUserData is set
mUninstallButton.setVisibility(View.GONE);
}
} else {
mUninstallButton.setText(R.string.uninstall_text);
mUninstallButton.setOnClickListener(this);
mCanUninstall = !isUninstallable();
if(localLOGV) Log.i(TAG, "Is systemPackage "+mCanUninstall);
setAppBtnState();
mManageSpaceButton = (Button)findViewById(R.id.manage_space_button);
if(mAppInfo.manageSpaceActivityName != null) {
mManageSpaceButton.setVisibility(View.VISIBLE);
mManageSpaceButton.setOnClickListener(this);
}
// Cache section
mCachePanel = findViewById(R.id.cache_panel);
mCacheSize = (TextView) findViewById(R.id.cache_size_text);
mClearCacheButton = (Button) findViewById(R.id.clear_cache_button);
//clear activities
mActivitiesButton = (Button)findViewById(R.id.clear_activities_button);
List<ComponentName> prefActList = new ArrayList<ComponentName>();
@@ -251,23 +272,19 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
autoLaunchView.setText(R.string.auto_launch_enable_text);
mActivitiesButton.setOnClickListener(this);
}
mManageSpaceButton = (Button)findViewById(R.id.manage_space_button);
if(mAppInfo.manageSpaceActivityName != null) {
mManageSpaceButton.setVisibility(View.VISIBLE);
mManageSpaceButton.setOnClickListener(this);
// security permissions section
LinearLayout permsView = (LinearLayout) findViewById(R.id.permissions_section);
AppSecurityPermissions asp = new AppSecurityPermissions(this, packageName);
if(asp.getPermissionCount() > 0) {
permsView.setVisibility(View.VISIBLE);
// Make the security sections header visible
LinearLayout securityList = (LinearLayout) permsView.findViewById(
R.id.security_settings_list);
securityList.addView(asp.getPermissionsView());
} else {
permsView.setVisibility(View.GONE);
}
//security permissions section
AppSecurityPermissions asp = new AppSecurityPermissions(this);
PackageInfo pkgInfo;
try {
pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
} catch (NameNotFoundException e) {
Log.w(TAG, "Couldnt retrieve permissions for package:"+packageName);
return;
}
asp.setSecurityPermissionsView(pkgInfo);
LinearLayout securityList = (LinearLayout) findViewById(R.id.security_settings_list);
securityList.addView(asp.getPermissionsView());
}
private void displayErrorDialog(int msgId, final boolean finish, final boolean changed) {
@@ -292,7 +309,7 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
Intent intent = new Intent();
intent.putExtra(ManageApplications.APP_CHG, appChanged);
setResult(ManageApplications.RESULT_OK, intent);
mUninstallButton.setEnabled(false);
mAppButton.setEnabled(false);
if(finish) {
finish();
}
@@ -305,29 +322,53 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
*/
private void refreshSizeInfo(Message msg) {
boolean changed = false;
Intent intent = new Intent();
PackageStats newPs = msg.getData().getParcelable(ATTR_PACKAGE_STATS);
long newTot = newPs.cacheSize+newPs.codeSize+newPs.dataSize;
long oldTot = mSizeInfo.cacheSize+mSizeInfo.codeSize+mSizeInfo.dataSize;
if(newTot != oldTot) {
mTotalSize.setText(getSizeStr(newTot));
changed = true;
}
if(newPs.codeSize != mSizeInfo.codeSize) {
mAppSize.setText(getSizeStr(newPs.codeSize));
changed = true;
}
if((newPs.dataSize != mSizeInfo.dataSize) || (newPs.cacheSize != mSizeInfo.cacheSize)) {
mDataSize.setText(getSizeStr(newPs.dataSize+newPs.cacheSize));
changed = true;
}
if(changed) {
mUninstallButton.setText(R.string.clear_user_data_text);
if(mSizeInfo == null) {
mSizeInfo = newPs;
intent.putExtra(ManageApplications.APP_PKG_SIZE, mSizeInfo);
mTotalSize.setText(getSizeStr(newTot));
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));
changed = true;
}
if(newPs.codeSize != mSizeInfo.codeSize) {
mAppSize.setText(getSizeStr(newPs.codeSize));
changed = true;
}
if((newPs.dataSize != mSizeInfo.dataSize) || (newPs.cacheSize != mSizeInfo.cacheSize)) {
mDataSize.setText(getSizeStr(newPs.dataSize+newPs.cacheSize));
}
if(changed) {
mSizeInfo = newPs;
}
}
long data = mSizeInfo.dataSize+mSizeInfo.cacheSize;
// Disable button if data is 0
if(mAppButtonState != AppButtonStates.NONE){
mAppButton.setText(mAppButtonText);
if((mAppButtonState == AppButtonStates.CLEAR_DATA) && (data == 0)) {
mAppButton.setEnabled(false);
} else {
mAppButton.setEnabled(true);
mAppButton.setOnClickListener(this);
}
}
refreshCacheInfo(newPs.cacheSize);
}
private void refreshCacheInfo(long cacheSize) {
// Set cache info
mCacheSize.setText(getSizeStr(cacheSize));
if (cacheSize <= 0) {
mClearCacheButton.setEnabled(false);
} else {
mClearCacheButton.setOnClickListener(this);
}
intent.putExtra(ManageApplications.APP_CHG, changed);
setResult(ManageApplications.RESULT_OK, intent);
}
/*
@@ -339,11 +380,10 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
String packageName = mAppInfo.packageName;
if(result == OP_SUCCESSFUL) {
Log.i(TAG, "Cleared user data for system package:"+packageName);
PkgSizeObserver observer = new PkgSizeObserver();
mPm.getPackageSizeInfo(packageName, observer);
mPm.getPackageSizeInfo(packageName, mSizeObserver);
} else {
mUninstallButton.setText(R.string.clear_user_data_text);
mUninstallButton.setEnabled(true);
mAppButton.setText(R.string.clear_user_data_text);
mAppButton.setEnabled(true);
}
}
@@ -352,20 +392,21 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
* button for a system package
*/
private void initiateClearUserDataForSysPkg() {
mUninstallButton.setEnabled(false);
mAppButton.setEnabled(false);
//invoke uninstall or clear user data based on sysPackage
boolean recomputeSizes = false;
String packageName = mAppInfo.packageName;
Log.i(TAG, "Clearing user data for system package");
ClearUserDataObserver observer = new ClearUserDataObserver();
if(mClearDataObserver == null) {
mClearDataObserver = new ClearUserDataObserver();
}
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
boolean res = am.clearApplicationUserData(packageName, observer);
boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
if(!res) {
//doesnt initiate clear. some error. should not happen but just log error for now
Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
displayErrorDialog(R.string.clear_data_failed, false, false);
} else {
mUninstallButton.setText(R.string.recompute_size);
mAppButton.setText(R.string.recompute_size);
}
}
@@ -375,8 +416,8 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
*/
public void onClick(View v) {
String packageName = mAppInfo.packageName;
if(v == mUninstallButton) {
if(mSysPackage) {
if(v == mAppButton) {
if(mCanUninstall) {
//display confirmation dialog
new AlertDialog.Builder(this)
.setTitle(getString(R.string.clear_data_dlg_title))
@@ -399,11 +440,17 @@ public class InstalledAppDetails extends Activity implements View.OnClickListene
Intent intent = new Intent(Intent.ACTION_DEFAULT);
intent.setClassName(mAppInfo.packageName, mAppInfo.manageSpaceActivityName);
startActivityForResult(intent, -1);
} else if (v == mClearCacheButton) {
// Lazy initialization of observer
if (mClearCacheObserver == null) {
mClearCacheObserver = new ClearCacheObserver();
}
mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver);
}
}
public void onClick(DialogInterface dialog, int which) {
if(which == AlertDialog.BUTTON1) {
if(which == AlertDialog.BUTTON_POSITIVE) {
//invoke uninstall or clear user data based on sysPackage
initiateClearUserDataForSysPkg();
} else {

View File

@@ -63,30 +63,55 @@ public class LocalePicker extends ListActivity {
setContentView(getContentView());
String[] locales = getAssets().getLocales();
final int N = locales.length;
mLocales = new Loc[N];
for (int i = 0; i < N; i++) {
Locale locale = null;
Arrays.sort(locales);
final int origSize = locales.length;
Loc[] preprocess = new Loc[origSize];
int finalSize = 0;
for (int i = 0 ; i < origSize; i++ ) {
String s = locales[i];
int len = s.length();
if (len == 0) {
locale = new Locale("en", "US");
} else if (len == 2) {
locale = new Locale(s);
if (len == 2) {
Locale l = new Locale(s);
preprocess[finalSize++] = new Loc(l.getDisplayLanguage(), l);
} else if (len == 5) {
locale = new Locale(s.substring(0, 2), s.substring(3, 5));
}
String displayName = "";
if (locale != null) {
displayName = locale.getDisplayName();
}
if ("zz_ZZ".equals(s)) {
displayName = "Pseudo...";
}
String language = s.substring(0, 2);
String country = s.substring(3, 5);
Locale l = new Locale(language, country);
mLocales[i] = new Loc(displayName, locale);
if (finalSize == 0) {
preprocess[finalSize++] = new Loc(l.getDisplayLanguage(), l);
} else {
// check previous entry:
// same lang and no country -> overwrite it with a lang-only name
// same lang and a country -> upgrade to full name and
// insert ours with full name
// diff lang -> insert ours with lang-only name
if (preprocess[finalSize-1].locale.getLanguage().equals(language)) {
String prevCountry = preprocess[finalSize-1].locale.getCountry();
if (prevCountry.length() == 0) {
preprocess[finalSize-1].locale = l;
preprocess[finalSize-1].label = l.getDisplayLanguage();
} else {
preprocess[finalSize-1].label = preprocess[finalSize-1].locale.getDisplayName();
preprocess[finalSize++] = new Loc(l.getDisplayName(), l);
}
} else {
String displayName;
if (s.equals("zz_ZZ")) {
displayName = "Pseudo...";
} else {
displayName = l.getDisplayLanguage();
}
preprocess[finalSize++] = new Loc(displayName, l);
}
}
}
}
mLocales = new Loc[finalSize];
for (int i = 0; i < finalSize ; i++) {
mLocales[i] = preprocess[i];
}
int layoutId = R.layout.locale_picker_item;
int fieldId = R.id.locale;
ArrayAdapter<Loc> adapter = new ArrayAdapter<Loc>(this, layoutId, fieldId, mLocales);
@@ -107,25 +132,11 @@ public class LocalePicker extends ListActivity {
Loc loc = mLocales[position];
config.locale = loc.locale;
final String language = loc.locale.getLanguage();
final String region = loc.locale.getCountry();
// indicate this isn't some passing default - the user wants this remembered
config.userSetLocale = true;
am.updateConfiguration(config);
// Update the System properties
SystemProperties.set("user.language", language);
SystemProperties.set("user.region", region);
// Write to file for persistence across reboots
try {
BufferedWriter bw = new BufferedWriter(new java.io.FileWriter(
System.getenv("ANDROID_DATA") + "/locale"));
bw.write(language + "_" + region);
bw.close();
} catch (java.io.IOException ioe) {
Log.e(TAG,
"Unable to persist locale. Error writing to locale file."
+ ioe);
}
} catch (RemoteException e) {
// Intentionally left blank
}

File diff suppressed because it is too large Load Diff

View File

@@ -222,7 +222,7 @@ public class ProxySelector extends Activity
if (!TextUtils.isEmpty(hostname)) {
hostname += ':' + portStr;
}
Settings.System.putString(res, Settings.System.HTTP_PROXY, hostname);
Settings.Secure.putString(res, Settings.Secure.HTTP_PROXY, hostname);
sendBroadcast(new Intent(Proxy.PROXY_CHANGE_ACTION));
return true;

View File

@@ -31,13 +31,14 @@ import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.pim.DateUtils;
import android.preference.PreferenceManager;
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.telephony.NeighboringCellInfo;
import android.telephony.gsm.GsmCellLocation;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -66,6 +67,7 @@ import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
public class RadioInfo extends Activity {
@@ -210,7 +212,7 @@ public class RadioInfo extends Activity {
case EVENT_QUERY_NEIGHBORING_CIDS_DONE:
ar= (AsyncResult) msg.obj;
if (ar.exception == null) {
updateNeighboringCids((String[])ar.result);
updateNeighboringCids((ArrayList<NeighboringCellInfo>)ar.result);
} else {
mNeighboringCids.setText("unknown");
}
@@ -651,23 +653,21 @@ public class RadioInfo extends Activity {
+ ((cid == -1) ? "unknown" : Integer.toHexString(cid)));
}
private final void updateNeighboringCids(String[] cids) {
if (cids != null && cids.length > 0 && cids[0] != null) {
int size = Integer.parseInt(cids[0]);
String neiborings;
if (size > 0) {
neiborings = "{";
for (int i=1; i<=size; i++) {
neiborings += cids[i] + ", ";
}
neiborings += "}";
private final void updateNeighboringCids(ArrayList<NeighboringCellInfo> cids) {
String neighborings = "";
if (cids != null) {
if ( cids.isEmpty() ) {
neighborings = "no neighboring cells";
} else {
neiborings = "none";
for (NeighboringCellInfo cell : cids) {
neighborings += "{" + Integer.toHexString(cell.getCid())
+ "@" + cell.getRssi() + "} ";
}
}
mNeighboringCids.setText(neiborings);
} else {
mNeighboringCids.setText("unknown");
neighborings = "unknown";
}
mNeighboringCids.setText(neighborings);
}
private final void
@@ -952,13 +952,15 @@ public class RadioInfo extends Activity {
.append("\n to ")
.append(pdp.getApn().toString())
.append("\ninterface: ")
.append(phone.getInterfaceName(phone.getActiveApn()))
.append(phone.getInterfaceName(phone.getActiveApnTypes()[0]))
.append("\naddress: ")
.append(phone.getIpAddress(phone.getActiveApn()))
.append(phone.getIpAddress(phone.getActiveApnTypes()[0]))
.append("\ngateway: ")
.append(phone.getGateway(phone.getActiveApn()));
String[] dns = phone.getDnsServers(phone.getActiveApn());
sb.append("\ndns: ").append(dns[0]).append(", ").append(dns[1]);
.append(phone.getGateway(phone.getActiveApnTypes()[0]));
String[] dns = phone.getDnsServers(phone.getActiveApnTypes()[0]);
if (dns != null) {
sb.append("\ndns: ").append(dns[0]).append(", ").append(dns[1]);
}
} else if (pdp.getState().isInactive()) {
sb.append(" disconnected with last try at ")
.append(DateUtils.timeString(pdp.getLastFailTime()))

View File

@@ -0,0 +1,129 @@
/*
* 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.content.Context;
import android.media.AudioManager;
import android.preference.VolumePreference;
import android.preference.VolumePreference.SeekBarVolumizer;
import android.provider.Settings;
import android.util.AttributeSet;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.SeekBar;
import android.widget.TextView;
/**
* Special preference type that allows configuration of both the ring volume and
* notification volume.
*/
public class RingerVolumePreference extends VolumePreference implements
CheckBox.OnCheckedChangeListener {
private static final String TAG = "RingerVolumePreference";
private CheckBox mNotificationsUseRingVolumeCheckbox;
private SeekBarVolumizer mNotificationSeekBarVolumizer;
private TextView mNotificationVolumeTitle;
public RingerVolumePreference(Context context, AttributeSet attrs) {
super(context, attrs);
// The always visible seekbar is for ring volume
setStreamType(AudioManager.STREAM_RING);
setDialogLayoutResource(R.layout.preference_dialog_ringervolume);
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
mNotificationsUseRingVolumeCheckbox =
(CheckBox) view.findViewById(R.id.same_notification_volume);
mNotificationsUseRingVolumeCheckbox.setOnCheckedChangeListener(this);
mNotificationsUseRingVolumeCheckbox.setChecked(Settings.System.getInt(
getContext().getContentResolver(),
Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1);
final SeekBar seekBar = (SeekBar) view.findViewById(R.id.notification_volume_seekbar);
mNotificationSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar,
AudioManager.STREAM_NOTIFICATION);
mNotificationVolumeTitle = (TextView) view.findViewById(R.id.notification_volume_title);
setNotificationVolumeVisibility(!mNotificationsUseRingVolumeCheckbox.isChecked());
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (!positiveResult && mNotificationSeekBarVolumizer != null) {
mNotificationSeekBarVolumizer.revertVolume();
}
cleanup();
}
@Override
public void onActivityStop() {
super.onActivityStop();
cleanup();
}
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
setNotificationVolumeVisibility(!isChecked);
Settings.System.putInt(getContext().getContentResolver(),
Settings.System.NOTIFICATIONS_USE_RING_VOLUME, isChecked ? 1 : 0);
if (isChecked) {
// The user wants the notification to be same as ring, so do a
// one-time sync right now
AudioManager audioManager = (AudioManager) getContext()
.getSystemService(Context.AUDIO_SERVICE);
audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION,
audioManager.getStreamVolume(AudioManager.STREAM_RING), 0);
}
}
@Override
protected void onSampleStarting(SeekBarVolumizer volumizer) {
super.onSampleStarting(volumizer);
if (mNotificationSeekBarVolumizer != null && volumizer != mNotificationSeekBarVolumizer) {
mNotificationSeekBarVolumizer.stopSample();
}
}
private void setNotificationVolumeVisibility(boolean visible) {
if (mNotificationSeekBarVolumizer != null) {
mNotificationSeekBarVolumizer.getSeekBar().setVisibility(
visible ? View.VISIBLE : View.GONE);
mNotificationVolumeTitle.setVisibility(visible ? View.VISIBLE : View.GONE);
}
}
private void cleanup() {
if (mNotificationSeekBarVolumizer != null) {
mNotificationSeekBarVolumizer.stop();
mNotificationSeekBarVolumizer = null;
}
}
}

View File

@@ -44,11 +44,13 @@ public class SecuritySettings extends PreferenceActivity
private static final String KEY_LOCK_ENABLED = "lockenabled";
private static final String KEY_VISIBLE_PATTERN = "visiblepattern";
private static final String KEY_TACTILE_FEEDBACK_ENABLED = "tactilefeedback";
private static final int CONFIRM_PATTERN_REQUEST_CODE = 55;
private LockPatternUtils mLockPatternUtils;
private CheckBoxPreference mLockEnabled;
private CheckBoxPreference mVisiblePattern;
private CheckBoxPreference mTactileFeedback;
private Preference mChoosePattern;
private CheckBoxPreference mShowPassword;
@@ -103,6 +105,12 @@ public class SecuritySettings extends PreferenceActivity
mVisiblePattern.setTitle(R.string.lockpattern_settings_enable_visible_pattern_title);
inlinePrefCat.addPreference(mVisiblePattern);
// tactile feedback
mTactileFeedback = new CheckBoxPreference(this);
mTactileFeedback.setKey(KEY_TACTILE_FEEDBACK_ENABLED);
mTactileFeedback.setTitle(R.string.lockpattern_settings_enable_tactile_feedback_title);
inlinePrefCat.addPreference(mTactileFeedback);
// change pattern lock
Intent intent = new Intent();
intent.setClassName("com.android.settings",
@@ -146,9 +154,11 @@ public class SecuritySettings extends PreferenceActivity
boolean patternExists = mLockPatternUtils.savedPatternExists();
mLockEnabled.setEnabled(patternExists);
mVisiblePattern.setEnabled(patternExists);
mTactileFeedback.setEnabled(patternExists);
mLockEnabled.setChecked(mLockPatternUtils.isLockPatternEnabled());
mVisiblePattern.setChecked(mLockPatternUtils.isVisiblePatternEnabled());
mTactileFeedback.setChecked(mLockPatternUtils.isTactileFeedbackEnabled());
int chooseStringRes = mLockPatternUtils.savedPatternExists() ?
R.string.lockpattern_settings_change_lock_pattern :
@@ -169,6 +179,8 @@ public class SecuritySettings extends PreferenceActivity
mLockPatternUtils.setLockPatternEnabled(isToggled(preference));
} else if (KEY_VISIBLE_PATTERN.equals(key)) {
mLockPatternUtils.setVisiblePatternEnabled(isToggled(preference));
} else if (KEY_TACTILE_FEEDBACK_ENABLED.equals(key)) {
mLockPatternUtils.setTactileFeedbackEnabled(isToggled(preference));
} else if (preference == mShowPassword) {
Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD,
mShowPassword.isChecked() ? 1 : 0);
@@ -198,9 +210,9 @@ public class SecuritySettings extends PreferenceActivity
}
private void setProviders(String providers) {
// Update the system setting LOCATION_PROVIDERS_ALLOWED
Settings.System.putString(getContentResolver(),
Settings.System.LOCATION_PROVIDERS_ALLOWED, providers);
// Update the secure setting LOCATION_PROVIDERS_ALLOWED
Settings.Secure.putString(getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED, providers);
if (Config.LOGV) {
Log.v("Location Accuracy", "Setting LOCATION_PROVIDERS_ALLOWED = " + providers);
}
@@ -213,8 +225,8 @@ public class SecuritySettings extends PreferenceActivity
*/
private String getAllowedProviders() {
String allowedProviders =
Settings.System.getString(getContentResolver(),
Settings.System.LOCATION_PROVIDERS_ALLOWED);
Settings.Secure.getString(getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if (allowedProviders == null) {
allowedProviders = "";
}

View File

@@ -28,13 +28,10 @@ import android.widget.Toast;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import org.apache.commons.codec.binary.Base64;
/**
* The "dialog" that shows from "License" in the Settings app.
*/
@@ -92,27 +89,8 @@ public class SettingsLicenseActivity extends AlertActivity {
WebView webView = new WebView(this);
if (LOGV) Log.v(TAG, "Started encode at " + System.currentTimeMillis());
// Need to encode to base64 for WebView to load the contents properly
String dataStr;
try {
byte[] base64Bytes = Base64.encodeBase64(data.toString().getBytes("ISO8859_1"));
dataStr = new String(base64Bytes);
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Could not convert to base64", e);
showErrorAndFinish();
return;
}
if (LOGV) Log.v(TAG, "Ended encode at " + System.currentTimeMillis());
if (LOGV) {
Log.v(TAG, "Started test decode at " + System.currentTimeMillis());
Base64.decodeBase64(dataStr.getBytes());
Log.v(TAG, "Ended decode at " + System.currentTimeMillis());
}
// Begin the loading. This will be done in a separate thread in WebView.
webView.loadData(dataStr, "text/html", "base64");
webView.loadDataWithBaseURL(null, data.toString(), "text/html", "utf-8", null);
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {

View File

@@ -25,6 +25,8 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
@@ -32,6 +34,7 @@ import android.preference.PreferenceScreen;
import android.preference.CheckBoxPreference;
import android.provider.Settings;
import android.util.Log;
import android.view.IWindowManager;
public class SoundAndDisplaySettings extends PreferenceActivity implements
Preference.OnPreferenceChangeListener {
@@ -45,14 +48,19 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
private static final String KEY_SCREEN_TIMEOUT = "screen_timeout";
private static final String KEY_DTMF_TONE = "dtmf_tone";
private static final String KEY_SOUND_EFFECTS = "sound_effects";
private static final String KEY_ANIMATIONS = "animations";
private CheckBoxPreference mSilent;
private CheckBoxPreference mVibrate;
private CheckBoxPreference mDtmfTone;
private CheckBoxPreference mSoundEffects;
private CheckBoxPreference mAnimations;
private float[] mAnimationScales;
private AudioManager mAudioManager;
private IWindowManager mWindowManager;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -73,6 +81,7 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
ContentResolver resolver = getContentResolver();
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
addPreferencesFromResource(R.xml.sound_and_display_settings);
@@ -86,11 +95,13 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
mSoundEffects.setPersistent(false);
mSoundEffects.setChecked(Settings.System.getInt(resolver,
Settings.System.SOUND_EFFECTS_ENABLED, 0) != 0);
mAnimations = (CheckBoxPreference) findPreference(KEY_ANIMATIONS);
mAnimations.setPersistent(false);
ListPreference screenTimeoutPreference =
(ListPreference) findPreference(KEY_SCREEN_TIMEOUT);
screenTimeoutPreference.setValue(String.valueOf(Settings.System.getInt(
getContentResolver(), SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE)));
resolver, SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE)));
screenTimeoutPreference.setOnPreferenceChangeListener(this);
}
@@ -124,6 +135,23 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
if (phoneVibrate != mVibrate.isChecked() || force) {
mVibrate.setChecked(phoneVibrate);
}
boolean animations = true;
try {
mAnimationScales = mWindowManager.getAnimationScales();
} catch (RemoteException e) {
}
if (mAnimationScales != null) {
for (int i=0; i<mAnimationScales.length; i++) {
if (mAnimationScales[i] == 0) {
animations = false;
break;
}
}
}
if (animations != mAnimations.isChecked() || force) {
mAnimations.setChecked(animations);
}
}
@Override
@@ -151,6 +179,15 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
}
Settings.System.putInt(getContentResolver(), Settings.System.SOUND_EFFECTS_ENABLED,
mSoundEffects.isChecked() ? 1 : 0);
} else if (preference == mAnimations) {
for (int i=0; i<mAnimationScales.length; i++) {
mAnimationScales[i] = mAnimations.isChecked() ? 1 : 0;
}
try {
mWindowManager.setAnimationScales(mAnimationScales);
} catch (RemoteException e) {
}
}
return true;
}

View File

@@ -16,25 +16,13 @@
package com.android.settings;
import com.android.settings.bluetooth.BluetoothEnabler;
import com.android.settings.wifi.WifiEnabler;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothIntent;
import android.bluetooth.IBluetoothDeviceCallback;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.preference.CheckBoxPreference;
import android.provider.Settings;
import android.widget.Toast;
public class WirelessSettings extends PreferenceActivity {
@@ -44,13 +32,7 @@ public class WirelessSettings extends PreferenceActivity {
private WifiEnabler mWifiEnabler;
private AirplaneModeEnabler mAirplaneModeEnabler;
private CheckBoxPreference mToggleBluetooth;
private IntentFilter mIntentFilter;
private static final int EVENT_FAILED_BT_ENABLE = 1;
private static final int EVENT_PASSED_BT_ENABLE = 2;
private BluetoothEnabler mBtEnabler;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -58,30 +40,25 @@ public class WirelessSettings extends PreferenceActivity {
addPreferencesFromResource(R.xml.wireless_settings);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(BluetoothIntent.ENABLED_ACTION);
mIntentFilter.addAction(BluetoothIntent.DISABLED_ACTION);
initToggles();
}
@Override
protected void onResume() {
super.onResume();
refreshToggles();
registerReceiver(mReceiver, mIntentFilter);
mWifiEnabler.resume();
mAirplaneModeEnabler.resume();
mBtEnabler.resume();
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
mWifiEnabler.pause();
mAirplaneModeEnabler.pause();
mBtEnabler.pause();
}
private void initToggles() {
@@ -95,116 +72,9 @@ public class WirelessSettings extends PreferenceActivity {
this,
(CheckBoxPreference) findPreference(KEY_TOGGLE_AIRPLANE));
mToggleBluetooth = (CheckBoxPreference) findPreference(KEY_TOGGLE_BLUETOOTH);
mToggleBluetooth.setPersistent(false);
mBtEnabler = new BluetoothEnabler(
this,
(CheckBoxPreference) findPreference(KEY_TOGGLE_BLUETOOTH));
}
private void refreshToggles() {
mToggleBluetooth.setChecked(isBluetoothEnabled());
mToggleBluetooth.setEnabled(true);
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference == mToggleBluetooth) {
setBluetoothEnabled(mToggleBluetooth.isChecked());
return true;
}
return false;
}
private boolean isBluetoothEnabled() {
BluetoothDevice device = (BluetoothDevice)getSystemService(BLUETOOTH_SERVICE);
if (device != null) {
return device.isEnabled();
} else {
return false;
}
}
private void setBluetoothEnabled(boolean enabled) {
try {
BluetoothDevice device = (BluetoothDevice)getSystemService(BLUETOOTH_SERVICE);
if (enabled) {
// Turn it off until intent or callback is delivered
mToggleBluetooth.setChecked(false);
if (device.enable(mBtCallback)) {
mToggleBluetooth.setSummary(R.string.bluetooth_enabling);
mToggleBluetooth.setEnabled(false);
}
} else {
if (device.disable()) {
Settings.System.putInt(getContentResolver(),
Settings.System.BLUETOOTH_ON, 0);
} else {
// Unusual situation, that you can't turn off bluetooth
mToggleBluetooth.setChecked(true);
}
}
} catch (NullPointerException e) {
// TODO: 1071858
mToggleBluetooth.setChecked(false);
mToggleBluetooth.setEnabled(false);
}
}
private IBluetoothDeviceCallback mBtCallback = new IBluetoothDeviceCallback.Stub() {
public void onEnableResult(int res) {
switch (res) {
case BluetoothDevice.RESULT_FAILURE:
mHandler.sendMessage(mHandler.obtainMessage(EVENT_FAILED_BT_ENABLE, 0));
break;
case BluetoothDevice.RESULT_SUCCESS:
mHandler.sendMessage(mHandler.obtainMessage(EVENT_PASSED_BT_ENABLE, 0));
break;
}
}
public void onCreateBondingResult(String device, int res) {
// Don't care
}
public void onGetRemoteServiceChannelResult(String address, int channel) { }
};
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BluetoothIntent.ENABLED_ACTION)) {
updateBtStatus(true);
} else if (action.equals(BluetoothIntent.DISABLED_ACTION)) {
mToggleBluetooth.setChecked(false);
}
}
};
private void updateBtStatus(boolean enabled) {
mToggleBluetooth.setChecked(enabled);
mToggleBluetooth.setEnabled(true);
mToggleBluetooth.setSummary(R.string.bluetooth_quick_toggle_summary);
if (enabled) {
Settings.System.putInt(getContentResolver(),
Settings.System.BLUETOOTH_ON, 1);
}
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_PASSED_BT_ENABLE:
updateBtStatus(true);
break;
case EVENT_FAILED_BT_ENABLE:
updateBtStatus(false);
Toast.makeText(WirelessSettings.this,
getResources().getString(R.string.bluetooth_failed_to_enable),
Toast.LENGTH_SHORT).show();
break;
}
}
};
}

View File

@@ -0,0 +1,122 @@
/*
* 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.bluetooth;
import com.android.settings.R;
import android.content.Context;
import android.preference.Preference;
import android.util.TypedValue;
import android.view.View;
import android.widget.ImageView;
/**
* BluetoothDevicePreference is the preference type used to display each remote
* Bluetooth device in the Bluetooth Settings screen.
*/
public class BluetoothDevicePreference extends Preference implements LocalBluetoothDevice.Callback {
private static final String TAG = "BluetoothDevicePreference";
private static int sDimAlpha = Integer.MIN_VALUE;
private LocalBluetoothDevice mLocalDevice;
/**
* Cached local copy of whether the device is busy. This is only updated
* from {@link #onDeviceAttributesChanged(LocalBluetoothDevice)}.
*/
private boolean mIsBusy;
public BluetoothDevicePreference(Context context, LocalBluetoothDevice localDevice) {
super(context);
if (sDimAlpha == Integer.MIN_VALUE) {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
sDimAlpha = (int) (outValue.getFloat() * 255);
}
mLocalDevice = localDevice;
setLayoutResource(R.layout.preference_bluetooth);
localDevice.registerCallback(this);
onDeviceAttributesChanged(localDevice);
}
public LocalBluetoothDevice getDevice() {
return mLocalDevice;
}
@Override
protected void onPrepareForRemoval() {
super.onPrepareForRemoval();
mLocalDevice.unregisterCallback(this);
}
public void onDeviceAttributesChanged(LocalBluetoothDevice device) {
/*
* The preference framework takes care of making sure the value has
* changed before proceeding.
*/
setTitle(mLocalDevice.getName());
/*
* TODO: Showed "Paired" even though it was "Connected". This may be
* related to BluetoothHeadset not bound to the actual
* BluetoothHeadsetService when we got here.
*/
setSummary(mLocalDevice.getSummary());
// Used to gray out the item
mIsBusy = mLocalDevice.isBusy();
// Data has changed
notifyChanged();
// This could affect ordering, so notify that also
notifyHierarchyChanged();
}
@Override
public boolean isEnabled() {
return super.isEnabled() && !mIsBusy;
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
ImageView btClass = (ImageView) view.findViewById(R.id.btClass);
btClass.setImageResource(mLocalDevice.getBtClassDrawable());
btClass.setAlpha(isEnabled() ? 255 : sDimAlpha);
}
@Override
public int compareTo(Preference another) {
if (!(another instanceof BluetoothDevicePreference)) {
// Put other preference types above us
return 1;
}
return mLocalDevice.compareTo(((BluetoothDevicePreference) another).mLocalDevice);
}
}

View File

@@ -0,0 +1,192 @@
/*
* 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.bluetooth;
import com.android.settings.R;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.SystemProperties;
import android.preference.Preference;
import android.preference.CheckBoxPreference;
import android.util.Log;
/**
* BluetoothDiscoverableEnabler is a helper to manage the "Discoverable"
* checkbox. It sets/unsets discoverability and keeps track of how much time
* until the the discoverability is automatically turned off.
*/
public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChangeListener {
private static final String TAG = "BluetoothDiscoverableEnabler";
private static final boolean V = LocalBluetoothManager.V;
private static final String SYSTEM_PROPERTY_DISCOVERABLE_TIMEOUT =
"debug.bt.discoverable_time";
private static final int DISCOVERABLE_TIMEOUT = 120;
private static final String SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP =
"discoverable_end_timestamp";
private final Context mContext;
private final Handler mUiHandler;
private final CheckBoxPreference mCheckBoxPreference;
private final LocalBluetoothManager mLocalManager;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
handleModeChanged(intent.getIntExtra(BluetoothIntent.MODE,
BluetoothDevice.MODE_UNKNOWN));
}
};
private final Runnable mUpdateCountdownSummaryRunnable = new Runnable() {
public void run() {
updateCountdownSummary();
}
};
public BluetoothDiscoverableEnabler(Context context, CheckBoxPreference checkBoxPreference) {
mContext = context;
mUiHandler = new Handler();
mCheckBoxPreference = checkBoxPreference;
checkBoxPreference.setPersistent(false);
mLocalManager = LocalBluetoothManager.getInstance(context);
if (mLocalManager == null) {
// Bluetooth not supported
checkBoxPreference.setEnabled(false);
}
}
public void resume() {
if (mLocalManager == null) {
return;
}
mContext.registerReceiver(mReceiver,
new IntentFilter(BluetoothIntent.MODE_CHANGED_ACTION));
mCheckBoxPreference.setOnPreferenceChangeListener(this);
handleModeChanged(mLocalManager.getBluetoothManager().getMode());
}
public void pause() {
if (mLocalManager == null) {
return;
}
mUiHandler.removeCallbacks(mUpdateCountdownSummaryRunnable);
mCheckBoxPreference.setOnPreferenceChangeListener(null);
mContext.unregisterReceiver(mReceiver);
}
public boolean onPreferenceChange(Preference preference, Object value) {
if (V) {
Log.v(TAG, "Preference changed to " + value);
}
// Turn on/off BT discoverability
setEnabled((Boolean) value);
return true;
}
private void setEnabled(final boolean enable) {
BluetoothDevice manager = mLocalManager.getBluetoothManager();
if (enable) {
int timeout = getDiscoverableTimeout();
manager.setDiscoverableTimeout(timeout);
long endTimestamp = System.currentTimeMillis() + timeout * 1000;
persistDiscoverableEndTimestamp(endTimestamp);
manager.setMode(BluetoothDevice.MODE_DISCOVERABLE);
handleModeChanged(BluetoothDevice.MODE_DISCOVERABLE);
} else {
manager.setMode(BluetoothDevice.MODE_CONNECTABLE);
}
}
private int getDiscoverableTimeout() {
int timeout = SystemProperties.getInt(SYSTEM_PROPERTY_DISCOVERABLE_TIMEOUT, -1);
if (timeout <= 0) {
timeout = DISCOVERABLE_TIMEOUT;
}
return timeout;
}
private void persistDiscoverableEndTimestamp(long endTimestamp) {
SharedPreferences.Editor editor = mLocalManager.getSharedPreferences().edit();
editor.putLong(SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP, endTimestamp);
editor.commit();
}
private void handleModeChanged(int mode) {
if (V) {
Log.v(TAG, "Got mode changed: " + mode);
}
if (mode == BluetoothDevice.MODE_DISCOVERABLE) {
mCheckBoxPreference.setChecked(true);
updateCountdownSummary();
} else {
mCheckBoxPreference.setChecked(false);
}
}
private void updateCountdownSummary() {
int mode = mLocalManager.getBluetoothManager().getMode();
if (mode != BluetoothDevice.MODE_DISCOVERABLE) return;
long currentTimestamp = System.currentTimeMillis();
long endTimestamp = mLocalManager.getSharedPreferences().getLong(
SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP, 0);
if (currentTimestamp > endTimestamp) {
// We're still in discoverable mode, but maybe there isn't a timeout.
mCheckBoxPreference.setSummaryOn(null);
return;
}
String formattedTimeLeft = String.valueOf((endTimestamp - currentTimestamp) / 1000);
mCheckBoxPreference.setSummaryOn(
mContext.getResources().getString(R.string.bluetooth_is_discoverable,
formattedTimeLeft));
synchronized (this) {
mUiHandler.removeCallbacks(mUpdateCountdownSummaryRunnable);
mUiHandler.postDelayed(mUpdateCountdownSummaryRunnable, 1000);
}
}
}

View File

@@ -0,0 +1,149 @@
/*
* 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.bluetooth;
import com.android.settings.R;
import com.android.settings.bluetooth.LocalBluetoothManager.ExtendedBluetoothState;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.preference.Preference;
import android.preference.CheckBoxPreference;
import android.text.TextUtils;
import android.util.Config;
/**
* BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox
* preference. It is turns on/off Bluetooth and ensures the summary of the
* preference reflects the current state.
*/
public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
private static final boolean LOCAL_LOGD = Config.LOGD || false;
private static final String TAG = "BluetoothEnabler";
private final Context mContext;
private final CheckBoxPreference mCheckBoxPreference;
private final CharSequence mOriginalSummary;
private final LocalBluetoothManager mLocalManager;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
handleStateChanged(mLocalManager.getBluetoothState());
}
};
public BluetoothEnabler(Context context, CheckBoxPreference checkBoxPreference) {
mContext = context;
mCheckBoxPreference = checkBoxPreference;
mOriginalSummary = checkBoxPreference.getSummary();
checkBoxPreference.setPersistent(false);
mLocalManager = LocalBluetoothManager.getInstance(context);
if (mLocalManager == null) {
// Bluetooth not supported
checkBoxPreference.setEnabled(false);
}
}
public void resume() {
if (mLocalManager == null) {
return;
}
ExtendedBluetoothState state = mLocalManager.getBluetoothState();
// This is the widget enabled state, not the preference toggled state
mCheckBoxPreference.setEnabled(state == ExtendedBluetoothState.ENABLED ||
state == ExtendedBluetoothState.DISABLED);
// BT state is not a sticky broadcast, so set it manually
handleStateChanged(state);
mContext.registerReceiver(mReceiver,
new IntentFilter(LocalBluetoothManager.EXTENDED_BLUETOOTH_STATE_CHANGED_ACTION));
mCheckBoxPreference.setOnPreferenceChangeListener(this);
}
public void pause() {
if (mLocalManager == null) {
return;
}
mContext.unregisterReceiver(mReceiver);
mCheckBoxPreference.setOnPreferenceChangeListener(null);
}
public boolean onPreferenceChange(Preference preference, Object value) {
// Turn on/off BT
setEnabled((Boolean) value);
// Don't update UI to opposite state until we're sure
return false;
}
private void setEnabled(final boolean enable) {
// Disable preference
mCheckBoxPreference.setEnabled(false);
mLocalManager.setBluetoothEnabled(enable);
}
private void handleStateChanged(ExtendedBluetoothState state) {
if (state == ExtendedBluetoothState.DISABLED || state == ExtendedBluetoothState.ENABLED) {
mCheckBoxPreference.setChecked(state == ExtendedBluetoothState.ENABLED);
mCheckBoxPreference
.setSummary(state == ExtendedBluetoothState.DISABLED ? mOriginalSummary : null);
mCheckBoxPreference.setEnabled(isEnabledByDependency());
} else if (state == ExtendedBluetoothState.ENABLING ||
state == ExtendedBluetoothState.DISABLING) {
mCheckBoxPreference.setSummary(state == ExtendedBluetoothState.ENABLING
? R.string.wifi_starting
: R.string.wifi_stopping);
} else if (state == ExtendedBluetoothState.UNKNOWN) {
mCheckBoxPreference.setChecked(false);
mCheckBoxPreference.setSummary(R.string.wifi_error);
mCheckBoxPreference.setEnabled(true);
}
}
private boolean isEnabledByDependency() {
Preference dep = getDependencyPreference();
if (dep == null) {
return true;
}
return !dep.shouldDisableDependents();
}
private Preference getDependencyPreference() {
String depKey = mCheckBoxPreference.getDependency();
if (TextUtils.isEmpty(depKey)) {
return null;
}
return mCheckBoxPreference.getPreferenceManager().findPreference(depKey);
}
}

View File

@@ -0,0 +1,159 @@
/*
* 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.bluetooth;
import com.android.settings.bluetooth.LocalBluetoothManager.ExtendedBluetoothState;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothIntent;
import android.bluetooth.IBluetoothDeviceCallback;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.util.Log;
/**
* BluetoothEventRedirector receives broadcasts and callbacks from the Bluetooth
* API and dispatches the event on the UI thread to the right class in the
* Settings.
*/
public class BluetoothEventRedirector {
private static final String TAG = "BluetoothEventRedirector";
private static final boolean V = LocalBluetoothManager.V;
private LocalBluetoothManager mManager;
private Handler mUiHandler = new Handler();
private IBluetoothDeviceCallback mBtDevCallback = new IBluetoothDeviceCallback.Stub() {
public void onCreateBondingResult(final String address, final int result) {
if (V) {
Log.v(TAG, "onCreateBondingResult(" + address + ", " + result + ")");
}
mUiHandler.post(new Runnable() {
public void run() {
boolean wasSuccess = result == BluetoothDevice.RESULT_SUCCESS;
LocalBluetoothDeviceManager deviceManager = mManager.getLocalDeviceManager();
deviceManager.onBondingStateChanged(address, wasSuccess);
if (!wasSuccess) {
deviceManager.onBondingError(address);
}
}
});
}
public void onEnableResult(int result) { }
public void onGetRemoteServiceChannelResult(String address, int channel) { }
};
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (V) {
Log.v(TAG, "Received " + intent.getAction());
}
String action = intent.getAction();
String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
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.BONDING_CREATED_ACTION)) {
mManager.getLocalDeviceManager().onBondingStateChanged(address, true);
} else if (action.equals(BluetoothIntent.BONDING_REMOVED_ACTION)) {
mManager.getLocalDeviceManager().onBondingStateChanged(address, false);
} else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
mManager.getLocalDeviceManager().onProfileStateChanged(address);
int newState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, 0);
int oldState = intent.getIntExtra(BluetoothIntent.HEADSET_PREVIOUS_STATE, 0);
if (newState == BluetoothHeadset.STATE_DISCONNECTED &&
oldState == BluetoothHeadset.STATE_CONNECTING) {
mManager.getLocalDeviceManager().onConnectingError(address);
}
} else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
mManager.getLocalDeviceManager().onProfileStateChanged(address);
int newState = intent.getIntExtra(BluetoothA2dp.SINK_STATE, 0);
int oldState = intent.getIntExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, 0);
if (newState == BluetoothA2dp.STATE_DISCONNECTED &&
oldState == BluetoothA2dp.STATE_CONNECTING) {
mManager.getLocalDeviceManager().onConnectingError(address);
}
}
}
};
public BluetoothEventRedirector(LocalBluetoothManager localBluetoothManager) {
mManager = localBluetoothManager;
}
public void start() {
IntentFilter filter = new IntentFilter();
// Bluetooth on/off broadcasts
filter.addAction(BluetoothIntent.ENABLED_ACTION);
filter.addAction(BluetoothIntent.DISABLED_ACTION);
// Discovery broadcasts
filter.addAction(BluetoothIntent.DISCOVERY_STARTED_ACTION);
filter.addAction(BluetoothIntent.DISCOVERY_COMPLETED_ACTION);
filter.addAction(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION);
filter.addAction(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
filter.addAction(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
// Pairing broadcasts
filter.addAction(BluetoothIntent.BONDING_CREATED_ACTION);
filter.addAction(BluetoothIntent.BONDING_REMOVED_ACTION);
// Fine-grained state broadcasts
filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
mManager.getContext().registerReceiver(mBroadcastReceiver, filter);
}
public void stop() {
mManager.getContext().unregisterReceiver(mBroadcastReceiver);
}
public IBluetoothDeviceCallback getBluetoothDeviceCallback() {
return mBtDevCallback;
}
}

View File

@@ -0,0 +1,79 @@
/*
* 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.bluetooth;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.preference.EditTextPreference;
import android.preference.PreferenceManager;
import android.util.AttributeSet;
/**
* BluetoothNamePreference is the preference type for editing the device's
* Bluetooth name. It asks the user for a name, and persists it via the
* Bluetooth API.
*/
public class BluetoothNamePreference extends EditTextPreference {
private static final String TAG = "BluetoothNamePreference";
private LocalBluetoothManager mLocalManager;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
setSummaryToName();
}
};
public BluetoothNamePreference(Context context, AttributeSet attrs) {
super(context, attrs);
mLocalManager = LocalBluetoothManager.getInstance(context);
setSummaryToName();
}
public void resume() {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothIntent.ENABLED_ACTION);
filter.addAction(BluetoothIntent.NAME_CHANGED_ACTION);
getContext().registerReceiver(mReceiver, filter);
}
public void pause() {
getContext().unregisterReceiver(mReceiver);
}
private void setSummaryToName() {
BluetoothDevice manager = mLocalManager.getBluetoothManager();
if (manager.isEnabled()) {
setSummary(manager.getName());
}
}
@Override
protected boolean persistString(String value) {
BluetoothDevice manager = mLocalManager.getBluetoothManager();
manager.setName(value);
return true;
}
}

View File

@@ -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.bluetooth;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothIntent;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.text.InputFilter;
import android.text.method.DigitsKeyListener;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
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 {
private static final String TAG = "BluetoothPinDialog";
private LocalBluetoothManager mLocalManager;
private String mAddress;
private EditText mPinView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
if (!intent.getAction().equals(BluetoothIntent.PAIRING_REQUEST_ACTION))
{
Log.e(TAG,
"Error: this activity may be started only with intent " +
BluetoothIntent.PAIRING_REQUEST_ACTION);
finish();
}
mLocalManager = LocalBluetoothManager.getInstance(this);
mAddress = intent.getStringExtra(BluetoothIntent.ADDRESS);
// Set up the "dialog"
final AlertController.AlertParams p = mAlertParams;
p.mIconId = android.R.drawable.ic_dialog_info;
p.mTitle = getString(R.string.bluetooth_pin_entry);
p.mView = createView();
p.mPositiveButtonText = getString(android.R.string.ok);
p.mPositiveButtonListener = this;
p.mNegativeButtonText = getString(android.R.string.cancel);
p.mNegativeButtonListener = this;
setupAlert();
}
private View createView() {
View view = getLayoutInflater().inflate(R.layout.bluetooth_pin_entry, null);
String name = mLocalManager.getLocalDeviceManager().getName(mAddress);
TextView messageView = (TextView) view.findViewById(R.id.message);
messageView.setText(getString(R.string.bluetooth_enter_pin_msg, name));
mPinView = (EditText) view.findViewById(R.id.text);
return view;
}
private void onPair(String pin) {
byte[] pinBytes = BluetoothDevice.convertPinToBytes(pin);
if (pinBytes == null) {
return;
}
mLocalManager.getBluetoothManager().setPin(mAddress, pinBytes);
}
private void onCancel() {
mLocalManager.getBluetoothManager().cancelPin(mAddress);
}
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
onPair(mPinView.getText().toString());
break;
case DialogInterface.BUTTON_NEGATIVE:
onCancel();
break;
}
}
}

View File

@@ -0,0 +1,96 @@
/*
* 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.bluetooth;
import com.android.settings.R;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.text.TextUtils;
/**
* BluetoothPinRequest is a receiver for any Bluetooth pairing PIN request. It
* checks if the Bluetooth Settings is currently visible and brings up the PIN
* entry dialog. Otherwise it puts a Notification in the status bar, which can
* be clicked to bring up the PIN entry dialog.
*/
public class BluetoothPinRequest extends BroadcastReceiver {
public static final int NOTIFICATION_ID = android.R.drawable.stat_sys_data_bluetooth;
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BluetoothIntent.PAIRING_REQUEST_ACTION)) {
LocalBluetoothManager localManager = LocalBluetoothManager.getInstance(context);
String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
Intent pinIntent = new Intent();
pinIntent.setClass(context, BluetoothPinDialog.class);
pinIntent.putExtra(BluetoothIntent.ADDRESS, address);
pinIntent.setAction(BluetoothIntent.PAIRING_REQUEST_ACTION);
pinIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (localManager.getForegroundActivity() != null) {
// Since the BT-related activity is in the foreground, just open the dialog
context.startActivity(pinIntent);
} else {
// Put up a notification that leads to the dialog
Resources res = context.getResources();
Notification notification = new Notification(
android.R.drawable.stat_sys_data_bluetooth,
res.getString(R.string.bluetooth_notif_ticker),
System.currentTimeMillis());
PendingIntent pending = PendingIntent.getActivity(context, 0,
pinIntent, PendingIntent.FLAG_ONE_SHOT);
String name = intent.getStringExtra(BluetoothIntent.NAME);
if (TextUtils.isEmpty(name)) {
name = localManager.getLocalDeviceManager().getName(address);
}
notification.setLatestEventInfo(context,
res.getString(R.string.bluetooth_notif_title),
res.getString(R.string.bluetooth_notif_message) + name,
pending);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
NotificationManager manager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(NOTIFICATION_ID, notification);
}
} else if (action.equals(BluetoothIntent.PAIRING_CANCEL_ACTION)) {
// Remove the notification
NotificationManager manager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(NOTIFICATION_ID);
}
}
}

View File

@@ -0,0 +1,258 @@
/*
* 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.bluetooth;
import com.android.settings.ProgressCategory;
import com.android.settings.R;
import com.android.settings.bluetooth.LocalBluetoothManager.ExtendedBluetoothState;
import java.util.List;
import java.util.WeakHashMap;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView.AdapterContextMenuInfo;
/**
* BluetoothSettings is the Settings screen for Bluetooth configuration and
* connection management.
*/
public class BluetoothSettings extends PreferenceActivity
implements LocalBluetoothManager.Callback {
private static final String TAG = "BluetoothSettings";
private static final int MENU_SCAN = Menu.FIRST;
private static final String KEY_BT_CHECKBOX = "bt_checkbox";
private static final String KEY_BT_DISCOVERABLE = "bt_discoverable";
private static final String KEY_BT_DEVICE_LIST = "bt_device_list";
private static final String KEY_BT_NAME = "bt_name";
private static final String KEY_BT_SCAN = "bt_scan";
private LocalBluetoothManager mLocalManager;
private BluetoothEnabler mEnabler;
private BluetoothDiscoverableEnabler mDiscoverableEnabler;
private BluetoothNamePreference mNamePreference;
private ProgressCategory mDeviceList;
private WeakHashMap<LocalBluetoothDevice, BluetoothDevicePreference> mDevicePreferenceMap =
new WeakHashMap<LocalBluetoothDevice, BluetoothDevicePreference>();
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO: put this in callback instead of receiving
onBluetoothStateChanged(mLocalManager.getBluetoothState());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLocalManager = LocalBluetoothManager.getInstance(this);
if (mLocalManager == null) finish();
addPreferencesFromResource(R.xml.bluetooth_settings);
mEnabler = new BluetoothEnabler(
this,
(CheckBoxPreference) findPreference(KEY_BT_CHECKBOX));
mDiscoverableEnabler = new BluetoothDiscoverableEnabler(
this,
(CheckBoxPreference) findPreference(KEY_BT_DISCOVERABLE));
mNamePreference = (BluetoothNamePreference) findPreference(KEY_BT_NAME);
mDeviceList = (ProgressCategory) findPreference(KEY_BT_DEVICE_LIST);
registerForContextMenu(getListView());
}
@Override
protected void onResume() {
super.onResume();
// Repopulate (which isn't too bad since it's cached in the settings
// bluetooth manager
mDevicePreferenceMap.clear();
mDeviceList.removeAll();
addDevices();
mEnabler.resume();
mDiscoverableEnabler.resume();
mNamePreference.resume();
mLocalManager.registerCallback(this);
mLocalManager.startScanning(false);
registerReceiver(mReceiver,
new IntentFilter(LocalBluetoothManager.EXTENDED_BLUETOOTH_STATE_CHANGED_ACTION));
mLocalManager.setForegroundActivity(this);
}
@Override
protected void onPause() {
super.onPause();
mLocalManager.setForegroundActivity(null);
unregisterReceiver(mReceiver);
mLocalManager.unregisterCallback(this);
mNamePreference.pause();
mDiscoverableEnabler.pause();
mEnabler.pause();
}
private void addDevices() {
List<LocalBluetoothDevice> devices = mLocalManager.getLocalDeviceManager().getDevicesCopy();
for (LocalBluetoothDevice device : devices) {
onDeviceAdded(device);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, MENU_SCAN, 0, R.string.bluetooth_scan_for_devices)
.setIcon(R.drawable.ic_menu_refresh)
.setAlphabeticShortcut('r');
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.findItem(MENU_SCAN).setEnabled(mLocalManager.getBluetoothManager().isEnabled());
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_SCAN:
mLocalManager.startScanning(true);
return true;
default:
return false;
}
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
if (KEY_BT_SCAN.equals(preference.getKey())) {
mLocalManager.startScanning(true);
return true;
}
if (preference instanceof BluetoothDevicePreference) {
BluetoothDevicePreference btPreference = (BluetoothDevicePreference) preference;
btPreference.getDevice().onClicked();
return true;
}
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
LocalBluetoothDevice device = getDeviceFromMenuInfo(menuInfo);
if (device == null) return;
device.onCreateContextMenu(menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
LocalBluetoothDevice device = getDeviceFromMenuInfo(item.getMenuInfo());
if (device == null) return false;
device.onContextItemSelected(item);
return true;
}
private LocalBluetoothDevice getDeviceFromMenuInfo(ContextMenuInfo menuInfo) {
if ((menuInfo == null) || !(menuInfo instanceof AdapterContextMenuInfo)) {
return null;
}
AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo;
Preference pref = (Preference) getPreferenceScreen().getRootAdapter().getItem(
adapterMenuInfo.position);
if (pref == null || !(pref instanceof BluetoothDevicePreference)) {
return null;
}
return ((BluetoothDevicePreference) pref).getDevice();
}
public void onDeviceAdded(LocalBluetoothDevice device) {
if (mDevicePreferenceMap.get(device) != null) {
throw new IllegalStateException("Got onDeviceAdded, but device already exists");
}
createDevicePreference(device);
}
private void createDevicePreference(LocalBluetoothDevice device) {
BluetoothDevicePreference preference = new BluetoothDevicePreference(this, device);
mDeviceList.addPreference(preference);
mDevicePreferenceMap.put(device, preference);
}
public void onDeviceDeleted(LocalBluetoothDevice device) {
BluetoothDevicePreference preference = mDevicePreferenceMap.remove(device);
if (preference != null) {
mDeviceList.removePreference(preference);
}
}
public void onScanningStateChanged(boolean started) {
mDeviceList.setProgress(started);
}
private void onBluetoothStateChanged(ExtendedBluetoothState bluetoothState) {
// When bluetooth is enabled (and we are in the activity, which we are),
// we should start a scan
if (bluetoothState == ExtendedBluetoothState.ENABLED) {
mLocalManager.startScanning(false);
}
}
}

View File

@@ -0,0 +1,297 @@
/*
* 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.bluetooth;
import com.android.settings.R;
import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
import android.content.Intent;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.text.TextUtils;
import android.widget.ImageView;
import android.widget.TextView;
import android.util.Log;
/**
* ConnectSpecificProfilesActivity presents the user with all of the profiles
* for a particular device, and allows him to choose which should be connected
* (or disconnected).
*/
public class ConnectSpecificProfilesActivity extends PreferenceActivity
implements LocalBluetoothDevice.Callback, Preference.OnPreferenceChangeListener {
private static final String TAG = "ConnectSpecificProfilesActivity";
private static final String KEY_ONLINE_MODE = "online_mode";
private static final String KEY_TITLE = "title";
private static final String KEY_PROFILE_CONTAINER = "profile_container";
public static final String EXTRA_ADDRESS = "address";
private LocalBluetoothManager mManager;
private LocalBluetoothDevice mDevice;
private PreferenceGroup mProfileContainer;
private CheckBoxPreference mOnlineModePreference;
/**
* The current mode of this activity and its checkboxes (either online mode
* or offline mode). In online mode, user interactions with the profile
* checkboxes will also toggle the profile's connectivity. In offline mode,
* they will not, and only the preferred state will be saved for the
* profile.
*/
private boolean mOnlineMode;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String address;
if (savedInstanceState != null) {
address = savedInstanceState.getString(EXTRA_ADDRESS);
} else {
Intent intent = getIntent();
address = intent.getStringExtra(EXTRA_ADDRESS);
}
if (TextUtils.isEmpty(address)) {
Log.w(TAG, "Activity started without address");
finish();
}
mManager = LocalBluetoothManager.getInstance(this);
mDevice = mManager.getLocalDeviceManager().findDevice(address);
if (mDevice == null) {
Log.w(TAG, "Device not found, cannot connect to it");
finish();
}
addPreferencesFromResource(R.xml.bluetooth_device_advanced);
mProfileContainer = (PreferenceGroup) findPreference(KEY_PROFILE_CONTAINER);
// Set the title of the screen
findPreference(KEY_TITLE).setTitle(
getString(R.string.bluetooth_device_advanced_title, mDevice.getName()));
// Listen for check/uncheck of the online mode checkbox
mOnlineModePreference = (CheckBoxPreference) findPreference(KEY_ONLINE_MODE);
mOnlineModePreference.setOnPreferenceChangeListener(this);
// Add a preference for each profile
addPreferencesForProfiles();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(EXTRA_ADDRESS, mDevice.getAddress());
}
@Override
protected void onResume() {
super.onResume();
mManager.setForegroundActivity(this);
mDevice.registerCallback(this);
refresh(true);
}
@Override
protected void onPause() {
super.onPause();
mDevice.unregisterCallback(this);
mManager.setForegroundActivity(null);
}
private void addPreferencesForProfiles() {
for (Profile profile : mDevice.getProfiles()) {
Preference pref = createProfilePreference(profile);
mProfileContainer.addPreference(pref);
}
}
/**
* Creates a checkbox preference for the particular profile. The key will be
* the profile's name.
*
* @param profile The profile for which the preference controls.
* @return A preference that allows the user to choose whether this profile
* will be connected to.
*/
private CheckBoxPreference createProfilePreference(Profile profile) {
CheckBoxPreference pref = new CheckBoxPreference(this);
pref.setKey(profile.toString());
pref.setTitle(profile.localizedString);
pref.setPersistent(false);
pref.setOnPreferenceChangeListener(this);
refreshProfilePreference(pref, profile);
return pref;
}
public boolean onPreferenceChange(Preference preference, Object newValue) {
String key = preference.getKey();
if (TextUtils.isEmpty(key) || newValue == null) return true;
if (key.equals(KEY_ONLINE_MODE)) {
onOnlineModeCheckedStateChanged((Boolean) newValue);
} else {
Profile profile = getProfileOf(preference);
if (profile == null) return false;
onProfileCheckedStateChanged(profile, (Boolean) newValue);
}
return true;
}
private void onOnlineModeCheckedStateChanged(boolean checked) {
switchModes(checked, false);
}
private void onProfileCheckedStateChanged(Profile profile, boolean checked) {
if (mOnlineMode) {
if (checked) {
mDevice.connect(profile);
} else {
mDevice.disconnect(profile);
}
}
LocalBluetoothProfileManager.setPreferredProfile(this, mDevice.getAddress(), profile,
checked);
}
public void onDeviceAttributesChanged(LocalBluetoothDevice device) {
refresh(false);
}
private void refresh(boolean forceRefresh) {
// The online mode could have changed
updateOnlineMode(forceRefresh);
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.
*/
private void switchModes(boolean onlineMode, boolean force) {
if (mOnlineMode != onlineMode || force) {
mOnlineMode = onlineMode;
if (onlineMode) {
mDevice.connect();
} else {
mDevice.disconnect();
}
refreshOnlineModePreference();
}
}
private void refreshOnlineModePreference() {
mOnlineModePreference.setChecked(mOnlineMode);
/**
* If the device is online, show status. Otherwise, show a summary that
* describes what the checkbox does.
*/
mOnlineModePreference.setSummary(mOnlineMode ? mDevice.getSummary()
: R.string.bluetooth_device_advanced_online_mode_summary);
}
private void refreshProfiles() {
for (Profile profile : mDevice.getProfiles()) {
CheckBoxPreference profilePref =
(CheckBoxPreference) findPreference(profile.toString());
if (profilePref == null) continue;
refreshProfilePreference(profilePref, profile);
}
}
private void refreshProfilePreference(CheckBoxPreference profilePref, Profile profile) {
String address = mDevice.getAddress();
LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
.getProfileManager(mManager, profile);
int connectionStatus = profileManager.getConnectionStatus(address);
profilePref.setSummary(getProfileSummary(profileManager, profile, address,
connectionStatus, mOnlineMode));
profilePref.setChecked(
LocalBluetoothProfileManager.isPreferredProfile(this, address, profile));
}
private Profile getProfileOf(Preference pref) {
if (!(pref instanceof CheckBoxPreference)) return null;
String key = pref.getKey();
if (TextUtils.isEmpty(key)) return null;
try {
return Profile.valueOf(pref.getKey());
} catch (IllegalArgumentException e) {
return null;
}
}
private static int getProfileSummary(LocalBluetoothProfileManager profileManager,
Profile profile, String address, int connectionStatus, boolean onlineMode) {
if (!onlineMode || connectionStatus == SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED) {
return getProfileSummaryForSettingPreference(profile);
} else {
return profileManager.getSummary(address);
}
}
/**
* Gets the summary that describes when checked, it will become a preferred profile.
*
* @param profile The profile to get the summary for.
* @return The summary.
*/
private static final int getProfileSummaryForSettingPreference(Profile profile) {
switch (profile) {
case A2DP:
return R.string.bluetooth_a2dp_profile_summary_use_for;
case HEADSET:
return R.string.bluetooth_headset_profile_summary_use_for;
default:
return 0;
}
}
}

View File

@@ -0,0 +1,558 @@
/*
* 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.bluetooth;
import com.android.settings.R;
import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
import android.app.AlertDialog;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothClass;
import android.bluetooth.IBluetoothDeviceCallback;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.os.IBinder;
import android.os.RemoteException;
import android.text.TextUtils;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import java.util.ArrayList;
import java.util.List;
/**
* LocalBluetoothDevice represents a remote Bluetooth device. It contains
* attributes of the device (such as the address, name, RSSI, etc.) and
* functionality that can be performed on the device (connect, pair, disconnect,
* etc.).
*/
public class LocalBluetoothDevice implements Comparable<LocalBluetoothDevice> {
private static final String TAG = "LocalBluetoothDevice";
private static final int CONTEXT_ITEM_CONNECT = Menu.FIRST + 1;
private static final int CONTEXT_ITEM_DISCONNECT = Menu.FIRST + 2;
private static final int CONTEXT_ITEM_UNPAIR = Menu.FIRST + 3;
private static final int CONTEXT_ITEM_CONNECT_ADVANCED = Menu.FIRST + 4;
private final String mAddress;
private String mName;
private short mRssi;
private int mBtClass = BluetoothClass.ERROR;
private List<Profile> mProfiles = new ArrayList<Profile>();
private boolean mVisible;
private int mPairingStatus;
private final LocalBluetoothManager mLocalManager;
private List<Callback> mCallbacks = new ArrayList<Callback>();
/**
* When we connect to multiple profiles, we only want to display a single
* error even if they all fail. This tracks that state.
*/
private boolean mIsConnectingErrorPossible;
LocalBluetoothDevice(Context context, String address) {
mLocalManager = LocalBluetoothManager.getInstance(context);
if (mLocalManager == null) {
throw new IllegalStateException(
"Cannot use LocalBluetoothDevice without Bluetooth hardware");
}
mAddress = address;
fillData();
}
public void onClicked() {
int pairingStatus = getPairingStatus();
if (isConnected()) {
askDisconnect();
} else if (pairingStatus == SettingsBtStatus.PAIRING_STATUS_PAIRED) {
connect();
} else if (pairingStatus == SettingsBtStatus.PAIRING_STATUS_UNPAIRED) {
pair();
}
}
public void disconnect() {
for (Profile profile : mProfiles) {
disconnect(profile);
}
}
public void disconnect(Profile profile) {
LocalBluetoothProfileManager profileManager =
LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile);
int status = profileManager.getConnectionStatus(mAddress);
if (SettingsBtStatus.isConnectionStatusConnected(status)) {
profileManager.disconnect(mAddress);
}
}
public void askDisconnect() {
Context context = mLocalManager.getForegroundActivity();
if (context == null) {
// Cannot ask, since we need an activity context
disconnect();
return;
}
Resources res = context.getResources();
String name = getName();
if (TextUtils.isEmpty(name)) {
name = res.getString(R.string.bluetooth_device);
}
String message = res.getString(R.string.bluetooth_disconnect_blank, name);
DialogInterface.OnClickListener disconnectListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
disconnect();
}
};
AlertDialog ad = new AlertDialog.Builder(context)
.setTitle(getName())
.setMessage(message)
.setPositiveButton(android.R.string.ok, disconnectListener)
.setNegativeButton(android.R.string.cancel, null)
.show();
}
public void connect() {
if (!ensurePaired()) return;
Context context = mLocalManager.getContext();
boolean hasAtLeastOnePreferredProfile = false;
for (Profile profile : mProfiles) {
if (LocalBluetoothProfileManager.isPreferredProfile(context, mAddress, profile)) {
hasAtLeastOnePreferredProfile = true;
connect(profile);
}
}
if (!hasAtLeastOnePreferredProfile) {
connectAndPreferAllProfiles();
}
}
private void connectAndPreferAllProfiles() {
if (!ensurePaired()) return;
Context context = mLocalManager.getContext();
for (Profile profile : mProfiles) {
LocalBluetoothProfileManager.setPreferredProfile(context, mAddress, profile, true);
connect(profile);
}
}
public void connect(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();
}
}
}
public void showConnectingError() {
if (!mIsConnectingErrorPossible) return;
mIsConnectingErrorPossible = false;
mLocalManager.showError(mAddress, R.string.bluetooth_error_title,
R.string.bluetooth_connecting_error_message);
}
private boolean ensurePaired() {
if (getPairingStatus() == SettingsBtStatus.PAIRING_STATUS_UNPAIRED) {
pair();
return false;
} else {
return true;
}
}
public void pair() {
BluetoothDevice manager = mLocalManager.getBluetoothManager();
// Pairing doesn't work if scanning, so cancel
if (manager.isDiscovering()) {
manager.cancelDiscovery();
}
if (mLocalManager.createBonding(mAddress)) {
setPairingStatus(SettingsBtStatus.PAIRING_STATUS_PAIRING);
}
}
public void unpair() {
BluetoothDevice manager = mLocalManager.getBluetoothManager();
switch (getPairingStatus()) {
case SettingsBtStatus.PAIRING_STATUS_PAIRED:
manager.removeBonding(mAddress);
break;
case SettingsBtStatus.PAIRING_STATUS_PAIRING:
manager.cancelBondingProcess(mAddress);
break;
}
}
private void fillData() {
BluetoothDevice manager = mLocalManager.getBluetoothManager();
fetchName();
mBtClass = manager.getRemoteClass(mAddress);
LocalBluetoothProfileManager.fill(mBtClass, mProfiles);
mPairingStatus = manager.hasBonding(mAddress)
? SettingsBtStatus.PAIRING_STATUS_PAIRED
: SettingsBtStatus.PAIRING_STATUS_UNPAIRED;
mVisible = false;
dispatchAttributesChanged();
}
public String getAddress() {
return mAddress;
}
public String getName() {
return mName;
}
public void refreshName() {
fetchName();
dispatchAttributesChanged();
}
private void fetchName() {
mName = mLocalManager.getBluetoothManager().getRemoteName(mAddress);
if (TextUtils.isEmpty(mName)) {
mName = mAddress;
}
}
public void refresh() {
dispatchAttributesChanged();
}
public boolean isVisible() {
return mVisible;
}
void setVisible(boolean visible) {
if (mVisible != visible) {
mVisible = visible;
dispatchAttributesChanged();
}
}
public int getPairingStatus() {
return mPairingStatus;
}
void setPairingStatus(int pairingStatus) {
if (mPairingStatus != pairingStatus) {
mPairingStatus = pairingStatus;
dispatchAttributesChanged();
}
}
void setRssi(short rssi) {
if (mRssi != rssi) {
mRssi = rssi;
dispatchAttributesChanged();
}
}
/**
* Checks whether we are connected to this device (any profile counts).
*
* @return Whether it is connected.
*/
public boolean isConnected() {
for (Profile profile : mProfiles) {
int status = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile)
.getConnectionStatus(mAddress);
if (SettingsBtStatus.isConnectionStatusConnected(status)) {
return true;
}
}
return false;
}
public boolean isBusy() {
for (Profile profile : mProfiles) {
int status = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile)
.getConnectionStatus(mAddress);
if (SettingsBtStatus.isConnectionStatusBusy(status)) {
return true;
}
}
if (getPairingStatus() == SettingsBtStatus.PAIRING_STATUS_PAIRING) {
return true;
}
return false;
}
public int getBtClassDrawable() {
// First try looking at profiles
if (mProfiles.contains(Profile.A2DP)) {
return R.drawable.ic_bt_headphones_a2dp;
} else if (mProfiles.contains(Profile.HEADSET)) {
return R.drawable.ic_bt_headset_hfp;
}
// Fallback on class
switch (BluetoothClass.Device.Major.getDeviceMajor(mBtClass)) {
case BluetoothClass.Device.Major.COMPUTER:
return R.drawable.ic_bt_laptop;
case BluetoothClass.Device.Major.PHONE:
return R.drawable.ic_bt_cellphone;
default:
return 0;
}
}
public int getSummary() {
// TODO: clean up
int oneOffSummary = getOneOffSummary();
if (oneOffSummary != 0) {
return oneOffSummary;
}
for (Profile profile : mProfiles) {
LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
.getProfileManager(mLocalManager, profile);
int connectionStatus = profileManager.getConnectionStatus(mAddress);
if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus) ||
connectionStatus == SettingsBtStatus.CONNECTION_STATUS_CONNECTING ||
connectionStatus == SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING) {
return SettingsBtStatus.getConnectionStatusSummary(connectionStatus);
}
}
int pairingStatus = getPairingStatus();
return SettingsBtStatus.getPairingStatusSummary(pairingStatus);
}
/**
* We have special summaries when particular profiles are connected. This
* checks for those states and returns an applicable summary.
*
* @return A one-off summary that is applicable for the current state, or 0.
*/
private int getOneOffSummary() {
boolean isA2dpConnected = false, isHeadsetConnected = false, isConnecting = false;
if (mProfiles.contains(Profile.A2DP)) {
LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
.getProfileManager(mLocalManager, Profile.A2DP);
isConnecting = profileManager.getConnectionStatus(mAddress) ==
SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
isA2dpConnected = profileManager.isConnected(mAddress);
}
if (mProfiles.contains(Profile.HEADSET)) {
LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
.getProfileManager(mLocalManager, Profile.HEADSET);
isConnecting |= profileManager.getConnectionStatus(mAddress) ==
SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
isHeadsetConnected = profileManager.isConnected(mAddress);
}
if (isConnecting) {
// If any of these important profiles is connecting, prefer that
return SettingsBtStatus.getConnectionStatusSummary(
SettingsBtStatus.CONNECTION_STATUS_CONNECTING);
} else if (isA2dpConnected && isHeadsetConnected) {
return R.string.bluetooth_summary_connected_to_a2dp_headset;
} else if (isA2dpConnected) {
return R.string.bluetooth_summary_connected_to_a2dp;
} else if (isHeadsetConnected) {
return R.string.bluetooth_summary_connected_to_headset;
} else {
return 0;
}
}
public List<Profile> getProfiles() {
return new ArrayList<Profile>(mProfiles);
}
public void onCreateContextMenu(ContextMenu menu) {
// 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 pairingStatus = getPairingStatus();
boolean isConnected = isConnected();
menu.setHeaderTitle(getName());
if (isConnected) {
menu.add(0, CONTEXT_ITEM_DISCONNECT, 0, R.string.bluetooth_device_context_disconnect);
} else {
// For connection action, show either "Connect" or "Pair & connect"
int connectString = pairingStatus == SettingsBtStatus.PAIRING_STATUS_UNPAIRED
? R.string.bluetooth_device_context_pair_connect
: R.string.bluetooth_device_context_connect;
menu.add(0, CONTEXT_ITEM_CONNECT, 0, connectString);
}
if (pairingStatus == SettingsBtStatus.PAIRING_STATUS_PAIRED) {
// For unpair action, show either "Unpair" or "Disconnect & unpair"
int unpairString = isConnected
? R.string.bluetooth_device_context_disconnect_unpair
: R.string.bluetooth_device_context_unpair;
menu.add(0, CONTEXT_ITEM_UNPAIR, 0, unpairString);
// Show the connection options item
menu.add(0, CONTEXT_ITEM_CONNECT_ADVANCED, 0,
R.string.bluetooth_device_context_connect_advanced);
}
}
/**
* Called when a context menu item is clicked.
*
* @param item The item that was clicked.
*/
public void onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case CONTEXT_ITEM_DISCONNECT:
disconnect();
break;
case CONTEXT_ITEM_CONNECT:
connect();
break;
case CONTEXT_ITEM_UNPAIR:
unpair();
break;
case CONTEXT_ITEM_CONNECT_ADVANCED:
Intent intent = new Intent();
// Need an activity context to open this in our task
Context context = mLocalManager.getForegroundActivity();
if (context == null) {
// Fallback on application context, and open in a new task
context = mLocalManager.getContext();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
intent.setClass(context, ConnectSpecificProfilesActivity.class);
intent.putExtra(ConnectSpecificProfilesActivity.EXTRA_ADDRESS, mAddress);
context.startActivity(intent);
break;
}
}
public void registerCallback(Callback callback) {
synchronized (mCallbacks) {
mCallbacks.add(callback);
}
}
public void unregisterCallback(Callback callback) {
synchronized (mCallbacks) {
mCallbacks.remove(callback);
}
}
private void dispatchAttributesChanged() {
synchronized (mCallbacks) {
for (Callback callback : mCallbacks) {
callback.onDeviceAttributesChanged(this);
}
}
}
@Override
public String toString() {
return mAddress;
}
@Override
public boolean equals(Object o) {
if ((o == null) || !(o instanceof LocalBluetoothDevice)) {
throw new ClassCastException();
}
return mAddress.equals(((LocalBluetoothDevice) o).mAddress);
}
@Override
public int hashCode() {
return mAddress.hashCode();
}
public int compareTo(LocalBluetoothDevice another) {
int comparison;
// Connected above not connected
comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0);
if (comparison != 0) return comparison;
// Paired above not paired
comparison = (another.mPairingStatus == SettingsBtStatus.PAIRING_STATUS_PAIRED ? 1 : 0) -
(mPairingStatus == SettingsBtStatus.PAIRING_STATUS_PAIRED ? 1 : 0);
if (comparison != 0) return comparison;
// Visible above not visible
comparison = (another.mVisible ? 1 : 0) - (mVisible ? 1 : 0);
if (comparison != 0) return comparison;
// Stronger signal above weaker signal
comparison = another.mRssi - mRssi;
if (comparison != 0) return comparison;
// Fallback on name
return getName().compareTo(another.getName());
}
public interface Callback {
void onDeviceAttributesChanged(LocalBluetoothDevice device);
}
}

View File

@@ -0,0 +1,209 @@
/*
* 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.bluetooth;
import android.app.AlertDialog;
import android.bluetooth.BluetoothDevice;
import android.util.Log;
import android.widget.Toast;
import android.content.Context;
import com.android.settings.R;
import com.android.settings.bluetooth.LocalBluetoothManager.Callback;
import java.util.ArrayList;
import java.util.List;
/**
* LocalBluetoothDeviceManager manages the set of remote Bluetooth devices.
*/
public class LocalBluetoothDeviceManager {
private static final String TAG = "LocalBluetoothDeviceManager";
final LocalBluetoothManager mLocalManager;
final List<Callback> mCallbacks;
final List<LocalBluetoothDevice> mDevices = new ArrayList<LocalBluetoothDevice>();
public LocalBluetoothDeviceManager(LocalBluetoothManager localManager) {
mLocalManager = localManager;
mCallbacks = localManager.getCallbacks();
readPairedDevices();
}
private synchronized void readPairedDevices() {
BluetoothDevice manager = mLocalManager.getBluetoothManager();
String[] bondedAddresses = manager.listBondings();
if (bondedAddresses == null) return;
for (String address : bondedAddresses) {
LocalBluetoothDevice device = findDevice(address);
if (device == null) {
device = new LocalBluetoothDevice(mLocalManager.getContext(), address);
mDevices.add(device);
dispatchDeviceAdded(device);
}
}
}
public synchronized List<LocalBluetoothDevice> getDevicesCopy() {
return new ArrayList<LocalBluetoothDevice>(mDevices);
}
void onBluetoothStateChanged(boolean enabled) {
if (enabled) {
readPairedDevices();
}
}
public synchronized void onDeviceAppeared(String address, short rssi) {
boolean deviceAdded = false;
LocalBluetoothDevice device = findDevice(address);
if (device == null) {
device = new LocalBluetoothDevice(mLocalManager.getContext(), address);
mDevices.add(device);
deviceAdded = true;
}
device.setRssi(rssi);
device.setVisible(true);
if (deviceAdded) {
dispatchDeviceAdded(device);
}
}
public synchronized void onDeviceDisappeared(String address) {
LocalBluetoothDevice device = findDevice(address);
if (device == null) return;
device.setVisible(false);
checkForDeviceRemoval(device);
}
private void checkForDeviceRemoval(LocalBluetoothDevice device) {
if (device.getPairingStatus() == SettingsBtStatus.PAIRING_STATUS_UNPAIRED &&
!device.isVisible()) {
// If device isn't paired, remove it altogether
mDevices.remove(device);
dispatchDeviceDeleted(device);
}
}
public synchronized void onDeviceNameUpdated(String address) {
LocalBluetoothDevice device = findDevice(address);
if (device != null) {
device.refreshName();
}
}
public synchronized LocalBluetoothDevice findDevice(String address) {
for (int i = mDevices.size() - 1; i >= 0; i--) {
LocalBluetoothDevice device = mDevices.get(i);
if (device.getAddress().equals(address)) {
return device;
}
}
return null;
}
/**
* Attempts to get the name of a remote device, otherwise returns the address.
*
* @param address The address.
* @return The name, or if unavailable, the address.
*/
public String getName(String address) {
LocalBluetoothDevice device = findDevice(address);
return device != null ? device.getName() : address;
}
private void dispatchDeviceAdded(LocalBluetoothDevice device) {
synchronized (mCallbacks) {
for (Callback callback : mCallbacks) {
callback.onDeviceAdded(device);
}
}
// TODO: divider between prev paired/connected and scanned
}
private void dispatchDeviceDeleted(LocalBluetoothDevice device) {
synchronized (mCallbacks) {
for (Callback callback : mCallbacks) {
callback.onDeviceDeleted(device);
}
}
}
public synchronized void onBondingStateChanged(String address, boolean created) {
LocalBluetoothDevice device = findDevice(address);
if (device == null) {
Log.e(TAG, "Got bonding state changed for " + address +
", but we have no record of that device.");
return;
}
device.setPairingStatus(created ? SettingsBtStatus.PAIRING_STATUS_PAIRED
: SettingsBtStatus.PAIRING_STATUS_UNPAIRED);
checkForDeviceRemoval(device);
if (created) {
// Auto-connect after pairing
device.connect();
}
}
public synchronized void onBondingError(String address) {
mLocalManager.showError(address, R.string.bluetooth_error_title,
R.string.bluetooth_pairing_error_message);
}
public synchronized void onProfileStateChanged(String address) {
LocalBluetoothDevice device = findDevice(address);
if (device == null) return;
device.refresh();
}
public synchronized void onConnectingError(String address) {
LocalBluetoothDevice device = findDevice(address);
if (device == null) return;
/*
* Go through the device's delegate so we don't spam the user with
* errors connecting to different profiles, and instead make sure the
* user sees a single error for his single 'connect' action.
*/
device.showConnectingError();
}
public synchronized void onScanningStateChanged(boolean started) {
if (!started) return;
// If starting a new scan, clear old visibility
for (int i = mDevices.size() - 1; i >= 0; i--) {
LocalBluetoothDevice device = mDevices.get(i);
device.setVisible(false);
checkForDeviceRemoval(device);
}
}
}

View File

@@ -0,0 +1,260 @@
/*
* 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.bluetooth;
import com.android.settings.R;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;
import android.widget.Toast;
// TODO: have some notion of shutting down. Maybe a minute after they leave BT settings?
/**
* LocalBluetoothManager provides a simplified interface on top of a subset of
* the Bluetooth API.
*/
public class LocalBluetoothManager {
private static final String TAG = "LocalBluetoothManager";
static final boolean V = true;
public static final String EXTENDED_BLUETOOTH_STATE_CHANGED_ACTION =
"com.android.settings.bluetooth.intent.action.EXTENDED_BLUETOOTH_STATE_CHANGED";
private static final String SHARED_PREFERENCES_NAME = "bluetooth_settings";
private static LocalBluetoothManager INSTANCE;
/** Used when obtaining a reference to the singleton instance. */
private static Object INSTANCE_LOCK = new Object();
private boolean mInitialized;
private Context mContext;
/** If a BT-related activity is in the foreground, this will be it. */
private Activity mForegroundActivity;
private BluetoothDevice mManager;
private LocalBluetoothDeviceManager mLocalDeviceManager;
private BluetoothEventRedirector mEventRedirector;
public static enum ExtendedBluetoothState { ENABLED, ENABLING, DISABLED, DISABLING, UNKNOWN }
private ExtendedBluetoothState mState = ExtendedBluetoothState.UNKNOWN;
private List<Callback> mCallbacks = new ArrayList<Callback>();
private static final int SCAN_EXPIRATION_MS = 5 * 60 * 1000; // 5 mins
private long mLastScan;
public static LocalBluetoothManager getInstance(Context context) {
synchronized (INSTANCE_LOCK) {
if (INSTANCE == null) {
INSTANCE = new LocalBluetoothManager();
}
if (!INSTANCE.init(context)) {
return null;
}
return INSTANCE;
}
}
private boolean init(Context context) {
if (mInitialized) return true;
mInitialized = true;
// This will be around as long as this process is
mContext = context.getApplicationContext();
mManager = (BluetoothDevice) context.getSystemService(Context.BLUETOOTH_SERVICE);
if (mManager == null) {
return false;
}
mLocalDeviceManager = new LocalBluetoothDeviceManager(this);
mEventRedirector = new BluetoothEventRedirector(this);
mEventRedirector.start();
return true;
}
public BluetoothDevice getBluetoothManager() {
return mManager;
}
public Context getContext() {
return mContext;
}
public Activity getForegroundActivity() {
return mForegroundActivity;
}
public void setForegroundActivity(Activity activity) {
mForegroundActivity = activity;
}
public SharedPreferences getSharedPreferences() {
return mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
public LocalBluetoothDeviceManager getLocalDeviceManager() {
return mLocalDeviceManager;
}
List<Callback> getCallbacks() {
return mCallbacks;
}
public void registerCallback(Callback callback) {
synchronized (mCallbacks) {
mCallbacks.add(callback);
}
}
public void unregisterCallback(Callback callback) {
synchronized (mCallbacks) {
mCallbacks.remove(callback);
}
}
public void startScanning(boolean force) {
if (mManager.isDiscovering()) {
/*
* Already discovering, but give the callback that information.
* Note: we only call the callbacks, not the same path as if the
* scanning state had really changed (in that case the device
* manager would clear its list of unpaired scanned devices).
*/
dispatchScanningStateChanged(true);
} else {
// Don't scan more than frequently than SCAN_EXPIRATION_MS, unless forced
if (!force && mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) return;
if (mManager.startDiscovery(true)) {
mLastScan = System.currentTimeMillis();
}
}
}
public ExtendedBluetoothState getBluetoothState() {
if (mState == ExtendedBluetoothState.UNKNOWN) {
syncBluetoothState();
}
return mState;
}
void setBluetoothStateInt(ExtendedBluetoothState state) {
mState = state;
/*
* TODO: change to callback method. originally it was broadcast to
* parallel the framework's method, but it just complicates things here.
*/
// If this were a real API, I'd add as an extra
mContext.sendBroadcast(new Intent(EXTENDED_BLUETOOTH_STATE_CHANGED_ACTION));
if (state == ExtendedBluetoothState.ENABLED || state == ExtendedBluetoothState.DISABLED) {
mLocalDeviceManager.onBluetoothStateChanged(state == ExtendedBluetoothState.ENABLED);
}
}
private void syncBluetoothState() {
setBluetoothStateInt(mManager.isEnabled()
? ExtendedBluetoothState.ENABLED
: ExtendedBluetoothState.DISABLED);
}
public void setBluetoothEnabled(boolean enabled) {
boolean wasSetStateSuccessful = enabled
? mManager.enable()
: mManager.disable();
if (wasSetStateSuccessful) {
setBluetoothStateInt(enabled
? ExtendedBluetoothState.ENABLING
: ExtendedBluetoothState.DISABLING);
} else {
if (V) {
Log.v(TAG,
"setBluetoothEnabled call, manager didn't return success for enabled: "
+ enabled);
}
syncBluetoothState();
}
}
/**
* @param started True if scanning started, false if scanning finished.
*/
void onScanningStateChanged(boolean started) {
// TODO: have it be a callback (once we switch bluetooth state changed to callback)
mLocalDeviceManager.onScanningStateChanged(started);
dispatchScanningStateChanged(started);
}
private void dispatchScanningStateChanged(boolean started) {
synchronized (mCallbacks) {
for (Callback callback : mCallbacks) {
callback.onScanningStateChanged(started);
}
}
}
public boolean createBonding(String address) {
return mManager.createBonding(address, mEventRedirector.getBluetoothDeviceCallback());
}
public void showError(String address, int titleResId, int messageResId) {
LocalBluetoothDevice device = mLocalDeviceManager.findDevice(address);
if (device == null) return;
String name = device.getName();
String message = mContext.getString(messageResId, name);
if (mForegroundActivity != null) {
// Need an activity context to show a dialog
AlertDialog ad = new AlertDialog.Builder(mForegroundActivity)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(titleResId)
.setMessage(message)
.setPositiveButton(android.R.string.ok, null)
.show();
} else {
// Fallback on a toast
Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
}
}
public interface Callback {
void onScanningStateChanged(boolean started);
void onDeviceAdded(LocalBluetoothDevice device);
void onDeviceDeleted(LocalBluetoothDevice device);
}
}

View File

@@ -0,0 +1,312 @@
/*
* 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.bluetooth;
import com.android.settings.R;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothClass;
import android.content.Context;
import android.content.SharedPreferences;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* LocalBluetoothProfileManager is an abstract class defining the basic
* functionality related to a profile.
*/
public abstract class LocalBluetoothProfileManager {
// TODO: close profiles when we're shutting down
private static Map<Profile, LocalBluetoothProfileManager> sProfileMap =
new HashMap<Profile, LocalBluetoothProfileManager>();
protected LocalBluetoothManager mLocalManager;
public static LocalBluetoothProfileManager getProfileManager(LocalBluetoothManager localManager,
Profile profile) {
LocalBluetoothProfileManager profileManager;
synchronized (sProfileMap) {
profileManager = sProfileMap.get(profile);
if (profileManager == null) {
switch (profile) {
case A2DP:
profileManager = new A2dpProfileManager(localManager);
break;
case HEADSET:
profileManager = new HeadsetProfileManager(localManager);
break;
}
sProfileMap.put(profile, profileManager);
}
}
return profileManager;
}
// TODO: remove once the framework has this API
public static boolean isPreferredProfile(Context context, String address, Profile profile) {
return getPreferredProfileSharedPreferences(context).getBoolean(
getPreferredProfileKey(address, profile), true);
}
public static void setPreferredProfile(Context context, String address, Profile profile,
boolean preferred) {
getPreferredProfileSharedPreferences(context).edit().putBoolean(
getPreferredProfileKey(address, profile), preferred).commit();
}
private static SharedPreferences getPreferredProfileSharedPreferences(Context context) {
return context.getSharedPreferences("bluetooth_preferred_profiles", Context.MODE_PRIVATE);
}
private static String getPreferredProfileKey(String address, Profile profile) {
return address + "_" + profile.toString();
}
/**
* Temporary method to fill profiles based on a device's class.
*
* @param btClass The class
* @param profiles The list of profiles to fill
*/
public static void fill(int btClass, List<Profile> profiles) {
profiles.clear();
if (A2dpProfileManager.doesClassMatch(btClass)) {
profiles.add(Profile.A2DP);
}
if (HeadsetProfileManager.doesClassMatch(btClass)) {
profiles.add(Profile.HEADSET);
}
}
protected LocalBluetoothProfileManager(LocalBluetoothManager localManager) {
mLocalManager = localManager;
}
public abstract int connect(String address);
public abstract int disconnect(String address);
public abstract int getConnectionStatus(String address);
public abstract int getSummary(String address);
public boolean isConnected(String address) {
return SettingsBtStatus.isConnectionStatusConnected(getConnectionStatus(address));
}
// TODO: int instead of enum
public enum Profile {
HEADSET(R.string.bluetooth_profile_headset),
A2DP(R.string.bluetooth_profile_a2dp);
public final int localizedString;
private Profile(int localizedString) {
this.localizedString = localizedString;
}
}
/**
* A2dpProfileManager is an abstraction for the {@link BluetoothA2dp} service.
*/
private static class A2dpProfileManager extends LocalBluetoothProfileManager {
private BluetoothA2dp mService;
public A2dpProfileManager(LocalBluetoothManager localManager) {
super(localManager);
mService = new BluetoothA2dp(localManager.getContext());
// TODO: block until connection?
}
@Override
public int connect(String address) {
return mService.connectSink(address);
}
@Override
public int disconnect(String address) {
return mService.disconnectSink(address);
}
static boolean doesClassMatch(int btClass) {
if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
return true;
}
// By the specification A2DP sinks must indicate the RENDER service
// class, but some do not (Chordette). So match on a few more to be
// safe
switch (BluetoothClass.Device.getDevice(btClass)) {
case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
case BluetoothClass.Device.AUDIO_VIDEO_LOUDSPEAKER:
case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
return true;
default:
return false;
}
}
@Override
public int getConnectionStatus(String address) {
return convertState(mService.getSinkState(address));
}
@Override
public int getSummary(String address) {
int connectionStatus = getConnectionStatus(address);
if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
return R.string.bluetooth_a2dp_profile_summary_connected;
} else {
return SettingsBtStatus.getConnectionStatusSummary(connectionStatus);
}
}
private static int convertState(int a2dpState) {
switch (a2dpState) {
case BluetoothA2dp.STATE_CONNECTED:
return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
case BluetoothA2dp.STATE_CONNECTING:
return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
case BluetoothA2dp.STATE_DISCONNECTED:
return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
case BluetoothA2dp.STATE_DISCONNECTING:
return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING;
case BluetoothA2dp.STATE_PLAYING:
return SettingsBtStatus.CONNECTION_STATUS_ACTIVE;
default:
return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
}
}
}
/**
* HeadsetProfileManager is an abstraction for the {@link BluetoothHeadset} service.
*/
private static class HeadsetProfileManager extends LocalBluetoothProfileManager {
private BluetoothHeadset mService;
public HeadsetProfileManager(LocalBluetoothManager localManager) {
super(localManager);
// final boolean[] isServiceConnected = new boolean[1];
// BluetoothHeadset.ServiceListener l = new BluetoothHeadset.ServiceListener() {
// public void onServiceConnected() {
// synchronized (this) {
// isServiceConnected[0] = true;
// notifyAll();
// }
// }
// public void onServiceDisconnected() {
// mService = null;
// }
// };
// TODO: block, but can't on UI thread
mService = new BluetoothHeadset(localManager.getContext(), null);
// synchronized (l) {
// while (!isServiceConnected[0]) {
// try {
// l.wait(100);
// } catch (InterruptedException e) {
// throw new IllegalStateException(e);
// }
// }
// }
}
@Override
public int connect(String address) {
// Since connectHeadset fails if already connected to a headset, we
// disconnect from any headset first
mService.disconnectHeadset();
return mService.connectHeadset(address, null)
? BluetoothError.SUCCESS : BluetoothError.ERROR;
}
@Override
public int disconnect(String address) {
if (mService.getHeadsetAddress().equals(address)) {
return mService.disconnectHeadset() ? BluetoothError.SUCCESS : BluetoothError.ERROR;
} else {
return BluetoothError.SUCCESS;
}
}
static boolean doesClassMatch(int btClass) {
switch (BluetoothClass.Device.getDevice(btClass)) {
case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
return true;
default:
return false;
}
}
@Override
public int getConnectionStatus(String address) {
String headsetAddress = mService.getHeadsetAddress();
return headsetAddress != null && headsetAddress.equals(address)
? convertState(mService.getState())
: SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
}
@Override
public int getSummary(String address) {
int connectionStatus = getConnectionStatus(address);
if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
return R.string.bluetooth_headset_profile_summary_connected;
} else {
return SettingsBtStatus.getConnectionStatusSummary(connectionStatus);
}
}
private static int convertState(int headsetState) {
switch (headsetState) {
case BluetoothHeadset.STATE_CONNECTED:
return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
case BluetoothHeadset.STATE_CONNECTING:
return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
case BluetoothHeadset.STATE_DISCONNECTED:
return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
default:
return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
}
}
}
}

View File

@@ -0,0 +1,85 @@
/*
* 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.bluetooth;
import com.android.settings.R;
/**
* SettingsBtStatus is a helper class that contains constants for various status
* codes.
*/
public class SettingsBtStatus {
private static final String TAG = "SettingsBtStatus";
// Connection status
public static final int CONNECTION_STATUS_UNKNOWN = 0;
public static final int CONNECTION_STATUS_ACTIVE = 1;
/** Use {@link #isConnected} to check for the connected state */
public static final int CONNECTION_STATUS_CONNECTED = 2;
public static final int CONNECTION_STATUS_CONNECTING = 3;
public static final int CONNECTION_STATUS_DISCONNECTED = 4;
public static final int CONNECTION_STATUS_DISCONNECTING = 5;
public static final int getConnectionStatusSummary(int connectionStatus) {
switch (connectionStatus) {
case CONNECTION_STATUS_ACTIVE:
return R.string.bluetooth_connected;
case CONNECTION_STATUS_CONNECTED:
return R.string.bluetooth_connected;
case CONNECTION_STATUS_CONNECTING:
return R.string.bluetooth_connecting;
case CONNECTION_STATUS_DISCONNECTED:
return R.string.bluetooth_disconnected;
case CONNECTION_STATUS_DISCONNECTING:
return R.string.bluetooth_disconnecting;
case CONNECTION_STATUS_UNKNOWN:
return R.string.bluetooth_unknown;
default:
return 0;
}
}
public static final boolean isConnectionStatusConnected(int connectionStatus) {
return connectionStatus == CONNECTION_STATUS_ACTIVE
|| connectionStatus == CONNECTION_STATUS_CONNECTED;
}
public static final boolean isConnectionStatusBusy(int connectionStatus) {
return connectionStatus == CONNECTION_STATUS_CONNECTING
|| connectionStatus == CONNECTION_STATUS_DISCONNECTING;
}
// Pairing status
public static final int PAIRING_STATUS_UNPAIRED = 0;
public static final int PAIRING_STATUS_PAIRED = 1;
public static final int PAIRING_STATUS_PAIRING = 2;
public static final int getPairingStatusSummary(int pairingStatus) {
switch (pairingStatus) {
case PAIRING_STATUS_PAIRED:
return R.string.bluetooth_paired;
case PAIRING_STATUS_PAIRING:
return R.string.bluetooth_pairing;
case PAIRING_STATUS_UNPAIRED:
return R.string.bluetooth_not_connected;
default:
return 0;
}
}
}

View File

@@ -22,6 +22,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Environment;
import android.os.IMountService;
@@ -30,6 +31,7 @@ import android.os.StatFs;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.util.Log;
import com.android.settings.R;
@@ -37,6 +39,8 @@ import java.io.File;
import java.text.DecimalFormat;
public class Memory extends PreferenceActivity {
private static final String TAG = "Memory";
private static final String MEMORY_SD_SIZE = "memory_sd_size";
@@ -50,15 +54,14 @@ public class Memory extends PreferenceActivity {
private Preference mSdAvail;
private Preference mSdUnmount;
private IMountService mMountService;
// Access using getMountService()
private IMountService mMountService = null;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.device_info_memory);
mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
mRes = getResources();
mSdSize = findPreference(MEMORY_SD_SIZE);
@@ -89,6 +92,18 @@ public class Memory extends PreferenceActivity {
unregisterReceiver(mReceiver);
}
private synchronized IMountService getMountService() {
if (mMountService == null) {
IBinder service = ServiceManager.getService("mount");
if (service != null) {
mMountService = IMountService.Stub.asInterface(service);
} else {
Log.e(TAG, "Can't get mount service");
}
}
return mMountService;
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference == mSdUnmount) {
@@ -107,8 +122,13 @@ public class Memory extends PreferenceActivity {
};
private void unmount() {
IMountService mountService = getMountService();
try {
mMountService.unmountMedia(Environment.getExternalStorageDirectory().toString());
if (mountService != null) {
mountService.unmountMedia(Environment.getExternalStorageDirectory().toString());
} else {
Log.e(TAG, "Mount service is null, can't unmount");
}
} catch (RemoteException ex) {
// Failed for some reason, try to update UI to actual state
updateMemoryStatus();

View File

@@ -240,9 +240,11 @@ public class Status extends PreferenceActivity {
}
private void setSummaryText(String preference, String text) {
if (text != null) {
findPreference(preference).setSummary(text);
if (TextUtils.isEmpty(text)) {
text = sUnknown;
}
findPreference(preference).setSummary(text);
}
private void updateNetworkType() {

View File

@@ -263,7 +263,7 @@ public class QuickLaunchSettings extends PreferenceActivity implements
KeyCharacterMap keyMap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
// Go through all the key codes and create a preference for the appropriate keys
for (int keyCode = KeyEvent.MAX_KEYCODE - 1; keyCode >= 0; keyCode--) {
for (int keyCode = KeyEvent.getMaxKeyCode() - 1; keyCode >= 0; keyCode--) {
// Get the label for the primary char on the key that produces this key code
char shortcut = (char) Character.toLowerCase(keyMap.getDisplayLabel(keyCode));
if (shortcut == 0 || shortcutSeen.get(shortcut, false)) continue;

View File

@@ -25,6 +25,7 @@ import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.text.method.PasswordTransformationMethod;
import android.text.method.TransformationMethod;
import android.util.Log;
@@ -303,7 +304,7 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
}
if (mState.primary && mState.ipAddress != 0) {
addInfoRow(R.string.ip_address, ipAddressToString(mState.ipAddress));
addInfoRow(R.string.ip_address, Formatter.formatIpAddress(mState.ipAddress));
}
} else if (mMode == MODE_CONFIGURE) {
@@ -579,14 +580,6 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
return 0;
}
private static String ipAddressToString(int addr) {
StringBuffer buf = new StringBuffer();
buf.append(addr & 0xff).append('.').
append((addr >>>= 8) & 0xff).append('.').
append((addr >>>= 8) & 0xff).append('.').
append((addr >>>= 8) & 0xff);
return buf.toString();
}
public void onClick(View v) {
if (v == mShowPasswordCheckBox) {

View File

@@ -538,7 +538,13 @@ public final class AccessPointState implements Comparable<AccessPointState>, Par
// If password is empty, it should be left untouched
if (!TextUtils.isEmpty(mPassword)) {
config.preSharedKey = convertToQuotedString(mPassword);
if (mPassword.length() == 64 && isHex(mPassword)) {
// Goes unquoted as hex
config.preSharedKey = mPassword;
} else {
// Goes quoted as ASCII
config.preSharedKey = convertToQuotedString(mPassword);
}
}
} else if (security.equals(OPEN)) {
@@ -554,8 +560,12 @@ public final class AccessPointState implements Comparable<AccessPointState>, Par
return false;
}
for (int i = len - 1; i >= 0; i--) {
final char c = wepKey.charAt(i);
return isHex(wepKey);
}
private static boolean isHex(String key) {
for (int i = key.length() - 1; i >= 0; i--) {
final char c = key.charAt(i);
if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f')) {
return false;
}

View File

@@ -19,12 +19,16 @@ package com.android.settings.wifi;
import com.android.settings.R;
import android.content.ContentResolver;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.provider.Settings.System;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
@@ -32,8 +36,10 @@ import android.widget.Toast;
public class IpSettings extends PreferenceActivity implements Preference.OnPreferenceChangeListener {
private static final String KEY_MAC_ADDRESS = "mac_address";
private static final String KEY_USE_STATIC_IP = "use_static_ip";
private static final String KEY_NUM_CHANNELS = "num_channels";
private String[] mSettingNames = {
System.WIFI_STATIC_IP, System.WIFI_STATIC_GATEWAY, System.WIFI_STATIC_NETMASK,
System.WIFI_STATIC_DNS1, System.WIFI_STATIC_DNS2
@@ -61,12 +67,46 @@ public class IpSettings extends PreferenceActivity implements Preference.OnPrefe
preference.setOnPreferenceChangeListener(this);
}
}
@Override
protected void onResume() {
super.onResume();
updateUi();
initNumChannelsPreference();
refreshMacAddress();
}
private void initNumChannelsPreference() {
ListPreference pref = (ListPreference) findPreference(KEY_NUM_CHANNELS);
pref.setOnPreferenceChangeListener(this);
WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
/*
* Generate the list of valid channel counts to show in the ListPreference.
* The values are numerical, so the only text to be localized is the
* "channel_word" resource.
*/
int[] validChannelCounts = wifiManager.getValidChannelCounts();
if (validChannelCounts == null) {
Toast.makeText(this, R.string.wifi_setting_num_channels_error,
Toast.LENGTH_SHORT).show();
return;
}
String[] entries = new String[validChannelCounts.length];
String[] entryValues = new String[validChannelCounts.length];
for (int i = 0; i < validChannelCounts.length; i++) {
entryValues[i] = String.valueOf(validChannelCounts[i]);
entries[i] = getString(R.string.wifi_setting_num_channels_channel_phrase,
validChannelCounts[i]);
}
pref.setEntries(entries);
pref.setEntryValues(entryValues);
int numChannels = wifiManager.getNumAllowedChannels();
if (numChannels >= 0) {
pref.setValue(String.valueOf(numChannels));
}
}
@Override
@@ -80,14 +120,34 @@ public class IpSettings extends PreferenceActivity implements Preference.OnPrefe
}
public boolean onPreferenceChange(Preference preference, Object newValue) {
String value = (String) newValue;
if (!isIpAddress(value)) {
Toast.makeText(this, R.string.wifi_ip_settings_invalid_ip, Toast.LENGTH_LONG).show();
return false;
String key = preference.getKey();
if (key == null) return true;
if (key.equals(KEY_NUM_CHANNELS)) {
try {
int numChannels = Integer.parseInt((String) newValue);
WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
if (!wifiManager.setNumAllowedChannels(numChannels)) {
Toast.makeText(this, R.string.wifi_setting_num_channels_error,
Toast.LENGTH_SHORT).show();
}
} catch (NumberFormatException e) {
Toast.makeText(this, R.string.wifi_setting_num_channels_error,
Toast.LENGTH_SHORT).show();
return false;
}
} else {
String value = (String) newValue;
if (!isIpAddress(value)) {
Toast.makeText(this, R.string.wifi_ip_settings_invalid_ip, Toast.LENGTH_LONG).show();
return false;
}
preference.setSummary(value);
}
preference.setSummary(value);
return true;
}
@@ -177,4 +237,14 @@ public class IpSettings extends PreferenceActivity implements Preference.OnPrefe
}
}
private void refreshMacAddress() {
WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
Preference wifiMacAddressPref = findPreference(KEY_MAC_ADDRESS);
String macAddress = wifiInfo == null ? null : wifiInfo.getMacAddress();
wifiMacAddressPref.setSummary(!TextUtils.isEmpty(macAddress) ? macAddress
: getString(R.string.status_unavailable));
}
}

View File

@@ -94,7 +94,7 @@ public class WifiLayer {
private boolean mIsObtainingAddress;
/**
* See {@link Settings.System#WIFI_NUM_OPEN_NETWORKS_KEPT}.
* See {@link android.provider.Settings.Secure#WIFI_NUM_OPEN_NETWORKS_KEPT}.
*/
private int WIFI_NUM_OPEN_NETWORKS_KEPT;
/**
@@ -229,8 +229,8 @@ public class WifiLayer {
mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
WIFI_NUM_OPEN_NETWORKS_KEPT = Settings.System.getInt(mContext.getContentResolver(),
Settings.System.WIFI_NUM_OPEN_NETWORKS_KEPT, 10);
WIFI_NUM_OPEN_NETWORKS_KEPT = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT, 10);
}
/**

View File

@@ -134,8 +134,8 @@ public class WifiSettings extends PreferenceActivity implements WifiLayer.Callba
mOpenNetworkNotificationsEnabled = (CheckBoxPreference) preferenceScreen
.findPreference(KEY_OPEN_NETWORK_NOTIFICATIONS_ENABLED);
mOpenNetworkNotificationsEnabled.setChecked(Settings.System.getInt(getContentResolver(),
Settings.System.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
mOpenNetworkNotificationsEnabled.setChecked(Settings.Secure.getInt(getContentResolver(),
Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
mAddOtherNetwork = preferenceScreen.findPreference(KEY_ADD_OTHER_NETWORK);
@@ -323,9 +323,9 @@ public class WifiSettings extends PreferenceActivity implements WifiLayer.Callba
if (preference == mAddOtherNetwork) {
showAddOtherNetworkDialog();
} else if (preference == mOpenNetworkNotificationsEnabled) {
Settings.System.putInt(getContentResolver(),
Settings.System.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
mOpenNetworkNotificationsEnabled.isChecked() ? 1 : 0);
Settings.Secure.putInt(getContentResolver(),
Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
mOpenNetworkNotificationsEnabled.isChecked() ? 1 : 0);
} else if (preference instanceof AccessPointPreference) {
AccessPointState state = ((AccessPointPreference) preference).getAccessPointState();
showAccessPointDialog(state, AccessPointDialog.MODE_INFO);