blob: 335d88835d40b11324a04f6528e0b8555b073f5e [file] [log] [blame]
/*
* Copyright (C) 2011 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.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.text.TextWatcher;
import android.app.Dialog;
import android.widget.Button;
import android.text.Editable;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import java.util.HashMap;
/**
* This preference fragment presents the user with all of the profiles
* for a particular device, and allows them to be individually connected
* (or disconnected).
*/
public final class DeviceProfilesSettings extends SettingsPreferenceFragment
implements CachedBluetoothDevice.Callback, Preference.OnPreferenceChangeListener {
private static final String TAG = "DeviceProfilesSettings";
private static final String KEY_RENAME_DEVICE = "rename_device";
private static final String KEY_PROFILE_CONTAINER = "profile_container";
private static final String KEY_UNPAIR = "unpair";
public static final String EXTRA_DEVICE = "device";
private RenameEditTextPreference mRenameDeviceNamePref;
private LocalBluetoothManager mManager;
private CachedBluetoothDevice mCachedDevice;
private LocalBluetoothProfileManager mProfileManager;
private PreferenceGroup mProfileContainer;
private EditTextPreference mDeviceNamePref;
private final HashMap<LocalBluetoothProfile, CheckBoxPreference> mAutoConnectPrefs
= new HashMap<LocalBluetoothProfile, CheckBoxPreference>();
private AlertDialog mDisconnectDialog;
private boolean mProfileGroupIsRemoved;
private class RenameEditTextPreference implements TextWatcher{
public void afterTextChanged(Editable s) {
Dialog d = mDeviceNamePref.getDialog();
if (d instanceof AlertDialog) {
((AlertDialog) d).getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(s.length() > 0);
}
}
// TextWatcher interface
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// not used
}
// TextWatcher interface
public void onTextChanged(CharSequence s, int start, int before, int count) {
// not used
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BluetoothDevice device;
if (savedInstanceState != null) {
device = savedInstanceState.getParcelable(EXTRA_DEVICE);
} else {
Bundle args = getArguments();
device = args.getParcelable(EXTRA_DEVICE);
}
addPreferencesFromResource(R.xml.bluetooth_device_advanced);
getPreferenceScreen().setOrderingAsAdded(false);
mProfileContainer = (PreferenceGroup) findPreference(KEY_PROFILE_CONTAINER);
mDeviceNamePref = (EditTextPreference) findPreference(KEY_RENAME_DEVICE);
if (device == null) {
Log.w(TAG, "Activity started without a remote Bluetooth device");
finish();
return; // TODO: test this failure path
}
mRenameDeviceNamePref = new RenameEditTextPreference();
mManager = LocalBluetoothManager.getInstance(getActivity());
CachedBluetoothDeviceManager deviceManager =
mManager.getCachedDeviceManager();
mProfileManager = mManager.getProfileManager();
mCachedDevice = deviceManager.findDevice(device);
if (mCachedDevice == null) {
Log.w(TAG, "Device not found, cannot connect to it");
finish();
return; // TODO: test this failure path
}
String deviceName = mCachedDevice.getName();
mDeviceNamePref.setSummary(deviceName);
mDeviceNamePref.setText(deviceName);
mDeviceNamePref.setOnPreferenceChangeListener(this);
// Add a preference for each profile
addPreferencesForProfiles();
}
@Override
public void onDestroy() {
super.onDestroy();
if (mDisconnectDialog != null) {
mDisconnectDialog.dismiss();
mDisconnectDialog = null;
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(EXTRA_DEVICE, mCachedDevice.getDevice());
}
@Override
public void onResume() {
super.onResume();
mManager.setForegroundActivity(getActivity());
mCachedDevice.registerCallback(this);
if(mCachedDevice.getBondState() == BluetoothDevice.BOND_NONE)
finish();
refresh();
EditText et = mDeviceNamePref.getEditText();
if (et != null) {
et.addTextChangedListener(mRenameDeviceNamePref);
Dialog d = mDeviceNamePref.getDialog();
if (d instanceof AlertDialog) {
Button b = ((AlertDialog) d).getButton(AlertDialog.BUTTON_POSITIVE);
b.setEnabled(et.getText().length() > 0);
}
}
}
@Override
public void onPause() {
super.onPause();
mCachedDevice.unregisterCallback(this);
mManager.setForegroundActivity(null);
}
private void addPreferencesForProfiles() {
for (LocalBluetoothProfile profile : mCachedDevice.getConnectableProfiles()) {
Preference pref = createProfilePreference(profile);
mProfileContainer.addPreference(pref);
}
showOrHideProfileGroup();
}
private void showOrHideProfileGroup() {
int numProfiles = mProfileContainer.getPreferenceCount();
if (!mProfileGroupIsRemoved && numProfiles == 0) {
getPreferenceScreen().removePreference(mProfileContainer);
mProfileGroupIsRemoved = true;
} else if (mProfileGroupIsRemoved && numProfiles != 0) {
getPreferenceScreen().addPreference(mProfileContainer);
mProfileGroupIsRemoved = false;
}
}
/**
* 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(LocalBluetoothProfile profile) {
CheckBoxPreference pref = new CheckBoxPreference(getActivity());
pref.setKey(profile.toString());
pref.setTitle(profile.getNameResource(mCachedDevice.getDevice()));
pref.setPersistent(false);
pref.setOrder(getProfilePreferenceIndex(profile.getOrdinal()));
pref.setOnPreferenceChangeListener(this);
int iconResource = profile.getDrawableResource(mCachedDevice.getBtClass());
if (iconResource != 0) {
pref.setIcon(getResources().getDrawable(iconResource));
}
/**
* Gray out profile while connecting and disconnecting
*/
pref.setEnabled(!mCachedDevice.isBusy());
refreshProfilePreference(pref, profile);
return pref;
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
String key = preference.getKey();
if (key.equals(KEY_UNPAIR)) {
unpairDevice();
finish();
return true;
}
return super.onPreferenceTreeClick(screen, preference);
}
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == mDeviceNamePref) {
mCachedDevice.setName((String) newValue);
} else if (preference instanceof CheckBoxPreference) {
LocalBluetoothProfile prof = getProfileOf(preference);
onProfileClicked(prof, (CheckBoxPreference) preference);
return false; // checkbox will update from onDeviceAttributesChanged() callback
} else {
return false;
}
return true;
}
private void onProfileClicked(LocalBluetoothProfile profile, CheckBoxPreference profilePref) {
BluetoothDevice device = mCachedDevice.getDevice();
int status = profile.getConnectionStatus(device);
boolean isConnected =
status == BluetoothProfile.STATE_CONNECTED;
if (isConnected) {
askDisconnect(getActivity(), profile);
} else {
if (profile.isPreferred(device)) {
// profile is preferred but not connected: disable auto-connect
profile.setPreferred(device, false);
refreshProfilePreference(profilePref, profile);
} else {
profile.setPreferred(device, true);
mCachedDevice.connectProfile(profile);
}
}
}
private void askDisconnect(Context context,
final LocalBluetoothProfile profile) {
// local reference for callback
final CachedBluetoothDevice device = mCachedDevice;
String name = device.getName();
if (TextUtils.isEmpty(name)) {
name = context.getString(R.string.bluetooth_device);
}
String profileName = context.getString(profile.getNameResource(device.getDevice()));
String title = context.getString(R.string.bluetooth_disable_profile_title);
String message = context.getString(R.string.bluetooth_disable_profile_message,
profileName, name);
DialogInterface.OnClickListener disconnectListener =
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
device.disconnect(profile);
profile.setPreferred(device.getDevice(), false);
}
};
mDisconnectDialog = Utils.showDisconnectDialog(context,
mDisconnectDialog, disconnectListener, title, Html.fromHtml(message));
}
public void onDeviceAttributesChanged() {
refresh();
}
private void refresh() {
String deviceName = mCachedDevice.getName();
mDeviceNamePref.setSummary(deviceName);
mDeviceNamePref.setText(deviceName);
refreshProfiles();
}
private void refreshProfiles() {
for (LocalBluetoothProfile profile : mCachedDevice.getConnectableProfiles()) {
CheckBoxPreference profilePref = (CheckBoxPreference)findPreference(profile.toString());
if (profilePref == null) {
profilePref = createProfilePreference(profile);
mProfileContainer.addPreference(profilePref);
} else {
refreshProfilePreference(profilePref, profile);
}
}
for (LocalBluetoothProfile profile : mCachedDevice.getRemovedProfiles()) {
Preference profilePref = findPreference(profile.toString());
if (profilePref != null) {
Log.d(TAG, "Removing " + profile.toString() + " from profile list");
mProfileContainer.removePreference(profilePref);
}
}
showOrHideProfileGroup();
}
private void refreshProfilePreference(CheckBoxPreference profilePref,
LocalBluetoothProfile profile) {
BluetoothDevice device = mCachedDevice.getDevice();
/*
* Gray out checkbox while connecting and disconnecting
*/
profilePref.setEnabled(!mCachedDevice.isBusy());
profilePref.setChecked(profile.isPreferred(device));
profilePref.setSummary(profile.getSummaryResourceForDevice(device));
}
private LocalBluetoothProfile getProfileOf(Preference pref) {
if (!(pref instanceof CheckBoxPreference)) {
return null;
}
String key = pref.getKey();
if (TextUtils.isEmpty(key)) return null;
try {
return mProfileManager.getProfileByName(pref.getKey());
} catch (IllegalArgumentException ignored) {
return null;
}
}
private int getProfilePreferenceIndex(int profIndex) {
return mProfileContainer.getOrder() + profIndex * 10;
}
private void unpairDevice() {
mCachedDevice.unpair();
}
}