381 lines
14 KiB
Java
Executable File
381 lines
14 KiB
Java
Executable File
/*
|
|
* 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.app.Dialog;
|
|
import android.app.DialogFragment;
|
|
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.text.Html;
|
|
import android.text.TextUtils;
|
|
import android.util.Log;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.View.OnClickListener;
|
|
import android.view.ViewGroup;
|
|
import android.widget.CheckBox;
|
|
import android.widget.EditText;
|
|
import android.widget.TextView;
|
|
|
|
import com.android.settings.R;
|
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
|
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
|
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
|
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
|
import com.android.settingslib.bluetooth.MapProfile;
|
|
import com.android.settingslib.bluetooth.PanProfile;
|
|
import com.android.settingslib.bluetooth.PbapServerProfile;
|
|
|
|
import java.util.HashMap;
|
|
|
|
public final class DeviceProfilesSettings extends DialogFragment implements
|
|
CachedBluetoothDevice.Callback, DialogInterface.OnClickListener, OnClickListener {
|
|
private static final String TAG = "DeviceProfilesSettings";
|
|
|
|
public static final String ARG_DEVICE_ADDRESS = "device_address";
|
|
|
|
private static final String KEY_PROFILE_CONTAINER = "profile_container";
|
|
private static final String KEY_UNPAIR = "unpair";
|
|
private static final String KEY_PBAP_SERVER = "PBAP Server";
|
|
|
|
private CachedBluetoothDevice mCachedDevice;
|
|
private LocalBluetoothManager mManager;
|
|
private LocalBluetoothProfileManager mProfileManager;
|
|
|
|
private ViewGroup mProfileContainer;
|
|
private TextView mProfileLabel;
|
|
private EditTextPreference mDeviceNamePref;
|
|
|
|
private final HashMap<LocalBluetoothProfile, CheckBoxPreference> mAutoConnectPrefs
|
|
= new HashMap<LocalBluetoothProfile, CheckBoxPreference>();
|
|
|
|
private AlertDialog mDisconnectDialog;
|
|
private boolean mProfileGroupIsRemoved;
|
|
|
|
private View mRootView;
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
|
|
mManager = Utils.getLocalBtManager(getActivity());
|
|
CachedBluetoothDeviceManager deviceManager = mManager.getCachedDeviceManager();
|
|
|
|
String address = getArguments().getString(ARG_DEVICE_ADDRESS);
|
|
BluetoothDevice remoteDevice = mManager.getBluetoothAdapter().getRemoteDevice(address);
|
|
|
|
mCachedDevice = deviceManager.findDevice(remoteDevice);
|
|
if (mCachedDevice == null) {
|
|
mCachedDevice = deviceManager.addDevice(mManager.getBluetoothAdapter(),
|
|
mManager.getProfileManager(), remoteDevice);
|
|
}
|
|
mProfileManager = mManager.getProfileManager();
|
|
}
|
|
|
|
@Override
|
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
mRootView = LayoutInflater.from(getContext()).inflate(R.layout.device_profiles_settings,
|
|
null);
|
|
mProfileContainer = (ViewGroup) mRootView.findViewById(R.id.profiles_section);
|
|
mProfileLabel = (TextView) mRootView.findViewById(R.id.profiles_label);
|
|
final EditText deviceName = (EditText) mRootView.findViewById(R.id.name);
|
|
deviceName.setText(mCachedDevice.getName(), TextView.BufferType.EDITABLE);
|
|
return new AlertDialog.Builder(getContext())
|
|
.setView(mRootView)
|
|
.setNegativeButton(R.string.forget, this)
|
|
.setPositiveButton(R.string.okay, this)
|
|
.setTitle(R.string.bluetooth_preference_paired_devices)
|
|
.create();
|
|
}
|
|
|
|
@Override
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
switch (which) {
|
|
case DialogInterface.BUTTON_POSITIVE:
|
|
EditText deviceName = (EditText) mRootView.findViewById(R.id.name);
|
|
mCachedDevice.setName(deviceName.getText().toString());
|
|
break;
|
|
case DialogInterface.BUTTON_NEGATIVE:
|
|
mCachedDevice.unpair();
|
|
com.android.settings.bluetooth.Utils.updateSearchIndex(getContext(),
|
|
BluetoothSettings.class.getName(), mCachedDevice.getName(),
|
|
getString(R.string.bluetooth_settings),
|
|
R.drawable.ic_settings_bluetooth, false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onDestroy() {
|
|
super.onDestroy();
|
|
if (mDisconnectDialog != null) {
|
|
mDisconnectDialog.dismiss();
|
|
mDisconnectDialog = null;
|
|
}
|
|
if (mCachedDevice != null) {
|
|
mCachedDevice.unregisterCallback(this);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onSaveInstanceState(Bundle outState) {
|
|
super.onSaveInstanceState(outState);
|
|
}
|
|
|
|
@Override
|
|
public void onResume() {
|
|
super.onResume();
|
|
|
|
mManager.setForegroundActivity(getActivity());
|
|
if (mCachedDevice != null) {
|
|
mCachedDevice.registerCallback(this);
|
|
if (mCachedDevice.getBondState() == BluetoothDevice.BOND_NONE) {
|
|
dismiss();
|
|
return;
|
|
}
|
|
addPreferencesForProfiles();
|
|
refresh();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onPause() {
|
|
super.onPause();
|
|
|
|
if (mCachedDevice != null) {
|
|
mCachedDevice.unregisterCallback(this);
|
|
}
|
|
|
|
mManager.setForegroundActivity(null);
|
|
}
|
|
|
|
private void addPreferencesForProfiles() {
|
|
mProfileContainer.removeAllViews();
|
|
for (LocalBluetoothProfile profile : mCachedDevice.getConnectableProfiles()) {
|
|
CheckBox pref = createProfilePreference(profile);
|
|
mProfileContainer.addView(pref);
|
|
}
|
|
|
|
final int pbapPermission = mCachedDevice.getPhonebookPermissionChoice();
|
|
// Only provide PBAP cabability if the client device has requested PBAP.
|
|
if (pbapPermission != CachedBluetoothDevice.ACCESS_UNKNOWN) {
|
|
final PbapServerProfile psp = mManager.getProfileManager().getPbapProfile();
|
|
CheckBox pbapPref = createProfilePreference(psp);
|
|
mProfileContainer.addView(pbapPref);
|
|
}
|
|
|
|
final MapProfile mapProfile = mManager.getProfileManager().getMapProfile();
|
|
final int mapPermission = mCachedDevice.getMessagePermissionChoice();
|
|
if (mapPermission != CachedBluetoothDevice.ACCESS_UNKNOWN) {
|
|
CheckBox mapPreference = createProfilePreference(mapProfile);
|
|
mProfileContainer.addView(mapPreference);
|
|
}
|
|
|
|
showOrHideProfileGroup();
|
|
}
|
|
|
|
private void showOrHideProfileGroup() {
|
|
int numProfiles = mProfileContainer.getChildCount();
|
|
if (!mProfileGroupIsRemoved && numProfiles == 0) {
|
|
mProfileContainer.setVisibility(View.GONE);
|
|
mProfileLabel.setVisibility(View.GONE);
|
|
mProfileGroupIsRemoved = true;
|
|
} else if (mProfileGroupIsRemoved && numProfiles != 0) {
|
|
mProfileContainer.setVisibility(View.VISIBLE);
|
|
mProfileLabel.setVisibility(View.VISIBLE);
|
|
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 CheckBox createProfilePreference(LocalBluetoothProfile profile) {
|
|
CheckBox pref = new CheckBox(getActivity());
|
|
pref.setTag(profile.toString());
|
|
pref.setText(profile.getNameResource(mCachedDevice.getDevice()));
|
|
pref.setOnClickListener(this);
|
|
|
|
refreshProfilePreference(pref, profile);
|
|
|
|
return pref;
|
|
}
|
|
|
|
@Override
|
|
public void onClick(View v) {
|
|
if (v instanceof CheckBox) {
|
|
LocalBluetoothProfile prof = getProfileOf(v);
|
|
onProfileClicked(prof, (CheckBox) v);
|
|
}
|
|
}
|
|
|
|
private void onProfileClicked(LocalBluetoothProfile profile, CheckBox profilePref) {
|
|
BluetoothDevice device = mCachedDevice.getDevice();
|
|
|
|
if (KEY_PBAP_SERVER.equals(profilePref.getTag())) {
|
|
final int newPermission = mCachedDevice.getPhonebookPermissionChoice()
|
|
== CachedBluetoothDevice.ACCESS_ALLOWED ? CachedBluetoothDevice.ACCESS_REJECTED
|
|
: CachedBluetoothDevice.ACCESS_ALLOWED;
|
|
mCachedDevice.setPhonebookPermissionChoice(newPermission);
|
|
profilePref.setChecked(newPermission == CachedBluetoothDevice.ACCESS_ALLOWED);
|
|
return;
|
|
}
|
|
|
|
if (!profilePref.isChecked()) {
|
|
// Recheck it, until the dialog is done.
|
|
profilePref.setChecked(true);
|
|
askDisconnect(mManager.getForegroundActivity(), profile);
|
|
} else {
|
|
if (profile instanceof MapProfile) {
|
|
mCachedDevice.setMessagePermissionChoice(BluetoothDevice.ACCESS_ALLOWED);
|
|
}
|
|
if (profile.isPreferred(device)) {
|
|
// profile is preferred but not connected: disable auto-connect
|
|
if (profile instanceof PanProfile) {
|
|
mCachedDevice.connectProfile(profile);
|
|
} else {
|
|
profile.setPreferred(device, false);
|
|
}
|
|
} else {
|
|
profile.setPreferred(device, true);
|
|
mCachedDevice.connectProfile(profile);
|
|
}
|
|
refreshProfilePreference(profilePref, 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);
|
|
if (profile instanceof MapProfile) {
|
|
device.setMessagePermissionChoice(BluetoothDevice.ACCESS_REJECTED);
|
|
}
|
|
refreshProfilePreference(findProfile(profile.toString()), profile);
|
|
}
|
|
};
|
|
|
|
mDisconnectDialog = Utils.showDisconnectDialog(context,
|
|
mDisconnectDialog, disconnectListener, title, Html.fromHtml(message));
|
|
}
|
|
|
|
@Override
|
|
public void onDeviceAttributesChanged() {
|
|
refresh();
|
|
}
|
|
|
|
private void refresh() {
|
|
final EditText deviceNameField = (EditText) mRootView.findViewById(R.id.name);
|
|
if (deviceNameField != null) {
|
|
deviceNameField.setText(mCachedDevice.getName());
|
|
}
|
|
|
|
refreshProfiles();
|
|
}
|
|
|
|
private void refreshProfiles() {
|
|
for (LocalBluetoothProfile profile : mCachedDevice.getConnectableProfiles()) {
|
|
CheckBox profilePref = findProfile(profile.toString());
|
|
if (profilePref == null) {
|
|
profilePref = createProfilePreference(profile);
|
|
mProfileContainer.addView(profilePref);
|
|
} else {
|
|
refreshProfilePreference(profilePref, profile);
|
|
}
|
|
}
|
|
for (LocalBluetoothProfile profile : mCachedDevice.getRemovedProfiles()) {
|
|
CheckBox profilePref = findProfile(profile.toString());
|
|
if (profilePref != null) {
|
|
Log.d(TAG, "Removing " + profile.toString() + " from profile list");
|
|
mProfileContainer.removeView(profilePref);
|
|
}
|
|
}
|
|
|
|
showOrHideProfileGroup();
|
|
}
|
|
|
|
private CheckBox findProfile(String profile) {
|
|
return (CheckBox) mProfileContainer.findViewWithTag(profile);
|
|
}
|
|
|
|
private void refreshProfilePreference(CheckBox profilePref,
|
|
LocalBluetoothProfile profile) {
|
|
BluetoothDevice device = mCachedDevice.getDevice();
|
|
|
|
// Gray out checkbox while connecting and disconnecting.
|
|
profilePref.setEnabled(!mCachedDevice.isBusy());
|
|
|
|
if (profile instanceof MapProfile) {
|
|
profilePref.setChecked(mCachedDevice.getMessagePermissionChoice()
|
|
== CachedBluetoothDevice.ACCESS_ALLOWED);
|
|
|
|
} else if (profile instanceof PbapServerProfile) {
|
|
profilePref.setChecked(mCachedDevice.getPhonebookPermissionChoice()
|
|
== CachedBluetoothDevice.ACCESS_ALLOWED);
|
|
|
|
} else if (profile instanceof PanProfile) {
|
|
profilePref.setChecked(profile.getConnectionStatus(device) ==
|
|
BluetoothProfile.STATE_CONNECTED);
|
|
|
|
} else {
|
|
profilePref.setChecked(profile.isPreferred(device));
|
|
}
|
|
}
|
|
|
|
private LocalBluetoothProfile getProfileOf(View v) {
|
|
if (!(v instanceof CheckBox)) {
|
|
return null;
|
|
}
|
|
String key = (String) v.getTag();
|
|
if (TextUtils.isEmpty(key)) return null;
|
|
|
|
try {
|
|
return mProfileManager.getProfileByName(key);
|
|
} catch (IllegalArgumentException ignored) {
|
|
return null;
|
|
}
|
|
}
|
|
}
|