Code drop from //branches/cupcake/...@124589
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
@@ -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() {
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
|
@@ -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) {
|
||||
|
191
src/com/android/settings/InputMethodsSettings.java
Normal file
191
src/com/android/settings/InputMethodsSettings.java
Normal 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;
|
||||
}
|
||||
}
|
@@ -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 {
|
||||
|
@@ -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
@@ -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;
|
||||
|
@@ -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()))
|
||||
|
129
src/com/android/settings/RingerVolumePreference.java
Normal file
129
src/com/android/settings/RingerVolumePreference.java
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -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 = "";
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
149
src/com/android/settings/bluetooth/BluetoothEnabler.java
Normal file
149
src/com/android/settings/bluetooth/BluetoothEnabler.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
159
src/com/android/settings/bluetooth/BluetoothEventRedirector.java
Normal file
159
src/com/android/settings/bluetooth/BluetoothEventRedirector.java
Normal 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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
112
src/com/android/settings/bluetooth/BluetoothPinDialog.java
Normal file
112
src/com/android/settings/bluetooth/BluetoothPinDialog.java
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
96
src/com/android/settings/bluetooth/BluetoothPinRequest.java
Normal file
96
src/com/android/settings/bluetooth/BluetoothPinRequest.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
258
src/com/android/settings/bluetooth/BluetoothSettings.java
Normal file
258
src/com/android/settings/bluetooth/BluetoothSettings.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
558
src/com/android/settings/bluetooth/LocalBluetoothDevice.java
Normal file
558
src/com/android/settings/bluetooth/LocalBluetoothDevice.java
Normal 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);
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
260
src/com/android/settings/bluetooth/LocalBluetoothManager.java
Normal file
260
src/com/android/settings/bluetooth/LocalBluetoothManager.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
85
src/com/android/settings/bluetooth/SettingsBtStatus.java
Normal file
85
src/com/android/settings/bluetooth/SettingsBtStatus.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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();
|
||||
|
@@ -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() {
|
||||
|
@@ -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;
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user