| /* |
| * 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.support.v7.preference.CheckBoxPreference; |
| import android.support.v7.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; |
| } |
| } |
| } |