Add a new Bluetooth device details page
Bug: 35877479 Test: make RunSettingsRoboTests The existing behavior is to bring up a dialog with Bluetooth device details with checkboxes for each supported profile. This adds a new page that serves the same purpose with a switch for each profile and a footer containing the MAC address. Whether to use the new page or old dialog is controlled by a flag accessible via BluetoothFeatureProvider. Change-Id: I026c363d4cd33932a84017a67cbef51c258bad10
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.content.Context;
|
||||
import android.support.v14.preference.PreferenceFragment;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Button;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.applications.LayoutPreference;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
/**
|
||||
* This class adds two buttons: one to connect/disconnect from a device (depending on the current
|
||||
* connected state), and one to "forget" (ie unpair) the device.
|
||||
*/
|
||||
public class BluetoothDetailsButtonsController extends BluetoothDetailsController {
|
||||
private static final String KEY_ACTION_BUTTONS = "action_buttons";
|
||||
private boolean mIsConnected;
|
||||
|
||||
private LayoutPreference mActionButtons;
|
||||
|
||||
public BluetoothDetailsButtonsController(Context context, PreferenceFragment fragment,
|
||||
CachedBluetoothDevice device, Lifecycle lifecycle) {
|
||||
super(context, fragment, device, lifecycle);
|
||||
mIsConnected = device.isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(PreferenceScreen screen) {
|
||||
mActionButtons = (LayoutPreference) screen.findPreference(getPreferenceKey());
|
||||
Button rightButton = (Button) mActionButtons.findViewById(R.id.right_button);
|
||||
rightButton.setText(R.string.forget);
|
||||
rightButton.setOnClickListener((view) -> {
|
||||
mCachedDevice.unpair();
|
||||
mFragment.getActivity().finish();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refresh() {
|
||||
Button leftButton = (Button) mActionButtons.findViewById(R.id.left_button);
|
||||
leftButton.setEnabled(!mCachedDevice.isBusy());
|
||||
boolean notInitialized = TextUtils.isEmpty(leftButton.getText());
|
||||
|
||||
boolean previouslyConnected = mIsConnected;
|
||||
mIsConnected = mCachedDevice.isConnected();
|
||||
if (mIsConnected) {
|
||||
if (notInitialized || !previouslyConnected) {
|
||||
leftButton.setText(R.string.bluetooth_device_context_disconnect);
|
||||
leftButton.setOnClickListener((view) -> {
|
||||
mCachedDevice.disconnect();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (notInitialized || previouslyConnected) {
|
||||
leftButton.setText(R.string.bluetooth_device_context_connect);
|
||||
leftButton.setOnClickListener((view) -> {
|
||||
mCachedDevice.connect(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return KEY_ACTION_BUTTONS;
|
||||
}
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.content.Context;
|
||||
import android.support.v14.preference.PreferenceFragment;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.core.PreferenceController;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnPause;
|
||||
import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||
|
||||
/**
|
||||
* This class provides common lifecycle and bluetooth device event registration for Bluetooth device
|
||||
* details controllers.
|
||||
*/
|
||||
public abstract class BluetoothDetailsController extends PreferenceController
|
||||
implements CachedBluetoothDevice.Callback, LifecycleObserver, OnPause, OnResume {
|
||||
|
||||
protected final Context mContext;
|
||||
protected final PreferenceFragment mFragment;
|
||||
protected final CachedBluetoothDevice mCachedDevice;
|
||||
|
||||
public BluetoothDetailsController(Context context, PreferenceFragment fragment,
|
||||
CachedBluetoothDevice device, Lifecycle lifecycle) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
mFragment = fragment;
|
||||
mCachedDevice = device;
|
||||
lifecycle.addObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
mCachedDevice.unregisterCallback(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
mCachedDevice.registerCallback(this);
|
||||
refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceAttributesChanged() {
|
||||
refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
init(screen);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a method to do one-time initialization when the screen is first created, such as
|
||||
* adding preferences.
|
||||
* @param screen the screen where this controller's preferences should be added
|
||||
*/
|
||||
protected abstract void init(PreferenceScreen screen);
|
||||
|
||||
/**
|
||||
* This method is called when something about the bluetooth device has changed, and this object
|
||||
* should update the preferences it manages based on the new state.
|
||||
*/
|
||||
protected abstract void refresh();
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.content.Context;
|
||||
import android.support.v14.preference.PreferenceFragment;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.settings.applications.LayoutPreference;
|
||||
import com.android.settings.widget.EntityHeaderController;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
/**
|
||||
* This class adds a header with device name and status (connected/disconnected, etc.).
|
||||
*/
|
||||
public class BluetoothDetailsHeaderController extends BluetoothDetailsController {
|
||||
|
||||
private EntityHeaderController mHeaderController;
|
||||
|
||||
public BluetoothDetailsHeaderController(Context context, PreferenceFragment fragment,
|
||||
CachedBluetoothDevice device, Lifecycle lifecycle) {
|
||||
super(context, fragment, device, lifecycle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(PreferenceScreen screen) {
|
||||
mHeaderController = EntityHeaderController.newInstance(mFragment.getActivity(), mFragment,
|
||||
null);
|
||||
LayoutPreference pref = mHeaderController.done(mFragment.getActivity(), mContext);
|
||||
screen.addPreference(pref);
|
||||
}
|
||||
|
||||
protected void setHeaderProperties() {
|
||||
Pair<Integer, String> pair = Utils.getBtClassDrawableWithDescription
|
||||
(mContext.getResources(), mCachedDevice);
|
||||
int summaryResourceId = mCachedDevice.getConnectionSummary();
|
||||
mHeaderController.setLabel(mCachedDevice.getName());
|
||||
mHeaderController.setIcon(mContext.getDrawable(pair.first));
|
||||
mHeaderController.setIconContentDescription(pair.second);
|
||||
mHeaderController.setSummary(
|
||||
summaryResourceId > 0 ? mContext.getString(summaryResourceId) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refresh() {
|
||||
setHeaderProperties();
|
||||
mHeaderController.done(mFragment.getActivity(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return EntityHeaderController.PREF_KEY_APP_HEADER;
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.content.Context;
|
||||
import android.support.v14.preference.PreferenceFragment;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.widget.FooterPreference;
|
||||
import com.android.settingslib.widget.FooterPreferenceMixin;
|
||||
|
||||
/**
|
||||
* This class adds the device MAC address to a footer.
|
||||
*/
|
||||
public class BluetoothDetailsMacAddressController extends BluetoothDetailsController {
|
||||
FooterPreferenceMixin mFooterPreferenceMixin;
|
||||
FooterPreference mFooterPreference;
|
||||
|
||||
public BluetoothDetailsMacAddressController(Context context,
|
||||
PreferenceFragment fragment,
|
||||
CachedBluetoothDevice device,
|
||||
Lifecycle lifecycle) {
|
||||
super(context, fragment, device, lifecycle);
|
||||
mFooterPreferenceMixin = new FooterPreferenceMixin(fragment, lifecycle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(PreferenceScreen screen) {
|
||||
mFooterPreference = mFooterPreferenceMixin.createFooterPreference();
|
||||
mFooterPreference.setTitle(mContext.getString(
|
||||
R.string.bluetooth_device_mac_address, mCachedDevice.getDevice().getAddress()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refresh() {}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return mFooterPreference.getKey();
|
||||
}
|
||||
}
|
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.BluetoothProfile;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v14.preference.PreferenceFragment;
|
||||
import android.support.v14.preference.SwitchPreference;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceCategory;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.settingslib.bluetooth.A2dpProfile;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
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 com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class adds switches for toggling the individual profiles that a Bluetooth device
|
||||
* supports, such as "Phone audio", "Media audio", "Contact sharing", etc.
|
||||
*/
|
||||
public class BluetoothDetailsProfilesController extends BluetoothDetailsController
|
||||
implements Preference.OnPreferenceClickListener {
|
||||
private static final String KEY_PROFILES_GROUP = "bluetooth_profiles";
|
||||
|
||||
@VisibleForTesting
|
||||
static final String HIGH_QUALITY_AUDIO_PREF_TAG = "A2dpProfileHighQualityAudio";
|
||||
|
||||
private LocalBluetoothManager mManager;
|
||||
private LocalBluetoothProfileManager mProfileManager;
|
||||
private CachedBluetoothDevice mCachedDevice;
|
||||
private PreferenceCategory mProfilesContainer;
|
||||
|
||||
public BluetoothDetailsProfilesController(Context context, PreferenceFragment fragment,
|
||||
LocalBluetoothManager manager, CachedBluetoothDevice device, Lifecycle lifecycle) {
|
||||
super(context, fragment, device, lifecycle);
|
||||
mManager = manager;
|
||||
mProfileManager = mManager.getProfileManager();
|
||||
mCachedDevice = device;
|
||||
lifecycle.addObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(PreferenceScreen screen) {
|
||||
mProfilesContainer = (PreferenceCategory)screen.findPreference(getPreferenceKey());
|
||||
// Call refresh here even though it will get called later in onResume, to avoid the
|
||||
// list of switches appearing to "pop" into the page.
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a switch preference for the particular profile.
|
||||
*
|
||||
* @param context The context to use when creating the SwitchPreference
|
||||
* @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 SwitchPreference createProfilePreference(Context context,
|
||||
LocalBluetoothProfile profile) {
|
||||
SwitchPreference pref = new SwitchPreference(context);
|
||||
pref.setKey(profile.toString());
|
||||
pref.setTitle(profile.getNameResource(mCachedDevice.getDevice()));
|
||||
pref.setOnPreferenceClickListener(this);
|
||||
return pref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the state for an existing SwitchPreference for a profile.
|
||||
*/
|
||||
private void refreshProfilePreference(SwitchPreference profilePref,
|
||||
LocalBluetoothProfile profile) {
|
||||
BluetoothDevice device = mCachedDevice.getDevice();
|
||||
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));
|
||||
}
|
||||
|
||||
if (profile instanceof A2dpProfile) {
|
||||
A2dpProfile a2dp = (A2dpProfile) profile;
|
||||
SwitchPreference highQualityPref = (SwitchPreference) mProfilesContainer.findPreference(
|
||||
HIGH_QUALITY_AUDIO_PREF_TAG);
|
||||
if (highQualityPref != null) {
|
||||
if (a2dp.isPreferred(device) && a2dp.supportsHighQualityAudio(device)) {
|
||||
highQualityPref.setVisible(true);
|
||||
highQualityPref.setTitle(a2dp.getHighQualityAudioOptionLabel(device));
|
||||
highQualityPref.setChecked(a2dp.isHighQualityAudioEnabled(device));
|
||||
highQualityPref.setEnabled(!mCachedDevice.isBusy());
|
||||
} else {
|
||||
highQualityPref.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to enable a profile for a device.
|
||||
*/
|
||||
private void enableProfile(LocalBluetoothProfile profile, BluetoothDevice device,
|
||||
SwitchPreference profilePref) {
|
||||
if (profile instanceof PbapServerProfile) {
|
||||
mCachedDevice.setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_ALLOWED);
|
||||
// We don't need to do the additional steps below for this profile.
|
||||
return;
|
||||
}
|
||||
if (profile instanceof MapProfile) {
|
||||
mCachedDevice.setMessagePermissionChoice(BluetoothDevice.ACCESS_ALLOWED);
|
||||
}
|
||||
profile.setPreferred(device, true);
|
||||
mCachedDevice.connectProfile(profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to disable a profile for a device
|
||||
*/
|
||||
private void disableProfile(LocalBluetoothProfile profile, BluetoothDevice device,
|
||||
SwitchPreference profilePref) {
|
||||
if (profile instanceof PbapServerProfile) {
|
||||
mCachedDevice.setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_REJECTED);
|
||||
// We don't need to do the additional steps below for this profile.
|
||||
return;
|
||||
}
|
||||
mCachedDevice.disconnect(profile);
|
||||
profile.setPreferred(device, false);
|
||||
if (profile instanceof MapProfile) {
|
||||
mCachedDevice.setMessagePermissionChoice(BluetoothDevice.ACCESS_REJECTED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When the pref for a bluetooth profile is clicked on, we want to toggle the enabled/disabled
|
||||
* state for that profile.
|
||||
*/
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
LocalBluetoothProfile profile = mProfileManager.getProfileByName(preference.getKey());
|
||||
if (profile == null) {
|
||||
// It might be the PbapServerProfile, which is not stored by name.
|
||||
PbapServerProfile psp = mManager.getProfileManager().getPbapProfile();
|
||||
if (TextUtils.equals(preference.getKey(), psp.toString())) {
|
||||
profile = psp;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
SwitchPreference profilePref = (SwitchPreference) preference;
|
||||
BluetoothDevice device = mCachedDevice.getDevice();
|
||||
if (profilePref.isChecked()) {
|
||||
enableProfile(profile, device, profilePref);
|
||||
} else {
|
||||
disableProfile(profile, device, profilePref);
|
||||
}
|
||||
refreshProfilePreference(profilePref, profile);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper to get the list of connectable and special profiles.
|
||||
*/
|
||||
private List<LocalBluetoothProfile> getProfiles() {
|
||||
List<LocalBluetoothProfile> result = mCachedDevice.getConnectableProfiles();
|
||||
|
||||
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();
|
||||
result.add(psp);
|
||||
}
|
||||
|
||||
final MapProfile mapProfile = mManager.getProfileManager().getMapProfile();
|
||||
final int mapPermission = mCachedDevice.getMessagePermissionChoice();
|
||||
if (mapPermission != CachedBluetoothDevice.ACCESS_UNKNOWN) {
|
||||
result.add(mapProfile);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper method to be called after adding a Preference for a profile. If that
|
||||
* profile happened to be A2dp and the device supports high quality audio, it will add a
|
||||
* separate preference for controlling whether to actually use high quality audio.
|
||||
*
|
||||
* @param profile the profile just added
|
||||
*/
|
||||
private void maybeAddHighQualityAudioPref(LocalBluetoothProfile profile) {
|
||||
if (!(profile instanceof A2dpProfile)) {
|
||||
return;
|
||||
}
|
||||
BluetoothDevice device = mCachedDevice.getDevice();
|
||||
A2dpProfile a2dp = (A2dpProfile) profile;
|
||||
if (a2dp.supportsHighQualityAudio(device)) {
|
||||
SwitchPreference highQualityAudioPref = new SwitchPreference(
|
||||
mProfilesContainer.getContext());
|
||||
highQualityAudioPref.setKey(HIGH_QUALITY_AUDIO_PREF_TAG);
|
||||
highQualityAudioPref.setVisible(false);
|
||||
highQualityAudioPref.setOnPreferenceClickListener(clickedPref -> {
|
||||
boolean enable = ((SwitchPreference) clickedPref).isChecked();
|
||||
a2dp.setHighQualityAudioEnabled(mCachedDevice.getDevice(), enable);
|
||||
return true;
|
||||
});
|
||||
mProfilesContainer.addPreference(highQualityAudioPref);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the state of the switches for all profiles, possibly adding or removing switches as
|
||||
* needed.
|
||||
*/
|
||||
@Override
|
||||
protected void refresh() {
|
||||
for (LocalBluetoothProfile profile : getProfiles()) {
|
||||
SwitchPreference pref = (SwitchPreference) mProfilesContainer.findPreference(
|
||||
profile.toString());
|
||||
if (pref == null) {
|
||||
pref = createProfilePreference(mProfilesContainer.getContext(), profile);
|
||||
mProfilesContainer.addPreference(pref);
|
||||
maybeAddHighQualityAudioPref(profile);
|
||||
}
|
||||
refreshProfilePreference(pref, profile);
|
||||
}
|
||||
for (LocalBluetoothProfile removedProfile : mCachedDevice.getRemovedProfiles()) {
|
||||
SwitchPreference pref = (SwitchPreference) mProfilesContainer.findPreference(
|
||||
removedProfile.toString());
|
||||
if (pref != null) {
|
||||
mProfilesContainer.removePreference(pref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return KEY_PROFILES_GROUP;
|
||||
}
|
||||
}
|
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.PreferenceController;
|
||||
import com.android.settings.dashboard.RestrictedDashboardFragment;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment {
|
||||
public static final String KEY_DEVICE_ADDRESS = "device_address";
|
||||
private static final String TAG = "BTDeviceDetailsFrg";
|
||||
|
||||
private String mDeviceAddress;
|
||||
|
||||
public BluetoothDeviceDetailsFragment() {
|
||||
super(DISALLOW_CONFIG_BLUETOOTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
mDeviceAddress = getArguments().getString(KEY_DEVICE_ADDRESS);
|
||||
super.onAttach(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return MetricsProto.MetricsEvent.BLUETOOTH_DEVICE_DETAILS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.bluetooth_device_details_fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<PreferenceController> getPreferenceControllers(Context context) {
|
||||
ArrayList<PreferenceController> controllers = new ArrayList<>();
|
||||
LocalBluetoothManager manager = Utils.getLocalBtManager(context);
|
||||
BluetoothDevice remoteDevice = manager.getBluetoothAdapter().getRemoteDevice(
|
||||
mDeviceAddress);
|
||||
CachedBluetoothDevice device = manager.getCachedDeviceManager().findDevice(remoteDevice);
|
||||
if (device != null) {
|
||||
Lifecycle lifecycle = getLifecycle();
|
||||
controllers.add(new BluetoothDetailsHeaderController(context, this, device, lifecycle));
|
||||
controllers.add(new BluetoothDetailsButtonsController(context, this, device,
|
||||
lifecycle));
|
||||
controllers.add(new BluetoothDetailsProfilesController(context, this, manager, device,
|
||||
lifecycle));
|
||||
controllers.add(new BluetoothDetailsMacAddressController(context, this, device,
|
||||
lifecycle));
|
||||
}
|
||||
return controllers;
|
||||
}
|
||||
}
|
@@ -17,7 +17,6 @@
|
||||
package com.android.settings.bluetooth;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
@@ -27,7 +26,6 @@ import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceViewHolder;
|
||||
import android.text.Html;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.TypedValue;
|
||||
import android.widget.ImageView;
|
||||
@@ -38,10 +36,6 @@ import com.android.settings.core.instrumentation.MetricsFeatureProvider;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.widget.GearPreference;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.HidProfile;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
|
||||
@@ -63,18 +57,11 @@ public final class BluetoothDevicePreference extends GearPreference implements
|
||||
private String contentDescription = null;
|
||||
|
||||
/* Talk-back descriptions for various BT icons */
|
||||
Resources r = getContext().getResources();
|
||||
public final String COMPUTER = r.getString(R.string.bluetooth_talkback_computer);
|
||||
public final String INPUT_PERIPHERAL = r.getString(
|
||||
R.string.bluetooth_talkback_input_peripheral);
|
||||
public final String HEADSET = r.getString(R.string.bluetooth_talkback_headset);
|
||||
public final String PHONE = r.getString(R.string.bluetooth_talkback_phone);
|
||||
public final String IMAGING = r.getString(R.string.bluetooth_talkback_imaging);
|
||||
public final String HEADPHONE = r.getString(R.string.bluetooth_talkback_headphone);
|
||||
public final String BLUETOOTH = r.getString(R.string.bluetooth_talkback_bluetooth);
|
||||
Resources mResources;
|
||||
|
||||
public BluetoothDevicePreference(Context context, CachedBluetoothDevice cachedDevice) {
|
||||
super(context, null);
|
||||
mResources = getContext().getResources();
|
||||
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||
|
||||
if (sDimAlpha == Integer.MIN_VALUE) {
|
||||
@@ -139,7 +126,8 @@ public final class BluetoothDevicePreference extends GearPreference implements
|
||||
}
|
||||
|
||||
|
||||
Pair<Integer, String> pair = getBtClassDrawableWithDescription();
|
||||
Pair<Integer, String> pair = Utils.getBtClassDrawableWithDescription(mResources,
|
||||
mCachedDevice);
|
||||
if (pair.first != 0) {
|
||||
setIcon(pair.first);
|
||||
contentDescription = pair.second;
|
||||
@@ -246,45 +234,4 @@ public final class BluetoothDevicePreference extends GearPreference implements
|
||||
}
|
||||
}
|
||||
|
||||
private Pair<Integer, String> getBtClassDrawableWithDescription() {
|
||||
BluetoothClass btClass = mCachedDevice.getBtClass();
|
||||
if (btClass != null) {
|
||||
switch (btClass.getMajorDeviceClass()) {
|
||||
case BluetoothClass.Device.Major.COMPUTER:
|
||||
return new Pair<Integer, String>(R.drawable.ic_bt_laptop, COMPUTER);
|
||||
|
||||
case BluetoothClass.Device.Major.PHONE:
|
||||
return new Pair<Integer, String>(R.drawable.ic_bt_cellphone, PHONE);
|
||||
|
||||
case BluetoothClass.Device.Major.PERIPHERAL:
|
||||
return new Pair<Integer, String>(HidProfile.getHidClassDrawable(btClass),
|
||||
INPUT_PERIPHERAL);
|
||||
|
||||
case BluetoothClass.Device.Major.IMAGING:
|
||||
return new Pair<Integer, String>(R.drawable.ic_bt_imaging, IMAGING);
|
||||
|
||||
default:
|
||||
// unrecognized device class; continue
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "mBtClass is null");
|
||||
}
|
||||
|
||||
List<LocalBluetoothProfile> profiles = mCachedDevice.getProfiles();
|
||||
for (LocalBluetoothProfile profile : profiles) {
|
||||
int resId = profile.getDrawableResource(btClass);
|
||||
if (resId != 0) {
|
||||
return new Pair<Integer, String>(resId, null);
|
||||
}
|
||||
}
|
||||
if (btClass != null) {
|
||||
if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
|
||||
return new Pair<Integer, String>(R.drawable.ic_bt_headset_hfp, HEADSET);
|
||||
}
|
||||
if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
|
||||
return new Pair<Integer, String>(R.drawable.ic_bt_headphones_a2dp, HEADPHONE);
|
||||
}
|
||||
}
|
||||
return new Pair<Integer, String>(R.drawable.ic_settings_bluetooth, BLUETOOTH);
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@
|
||||
package com.android.settings.bluetooth;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.ContentResolver;
|
||||
@@ -25,6 +26,7 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemProperties;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v7.preference.Preference;
|
||||
@@ -352,12 +354,28 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
|
||||
return;
|
||||
}
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(DeviceProfilesSettings.ARG_DEVICE_ADDRESS,
|
||||
device.getDevice().getAddress());
|
||||
final DeviceProfilesSettings profileSettings = new DeviceProfilesSettings();
|
||||
profileSettings.setArguments(args);
|
||||
profileSettings.show(getFragmentManager(),
|
||||
DeviceProfilesSettings.class.getSimpleName());
|
||||
Context context = getActivity();
|
||||
boolean useDetailPage = FeatureFactory.getFactory(context).getBluetoothFeatureProvider(
|
||||
context).isDeviceDetailPageEnabled();
|
||||
if (!useDetailPage) {
|
||||
// Old version - uses a dialog.
|
||||
args.putString(DeviceProfilesSettings.ARG_DEVICE_ADDRESS,
|
||||
device.getDevice().getAddress());
|
||||
final DeviceProfilesSettings profileSettings = new DeviceProfilesSettings();
|
||||
profileSettings.setArguments(args);
|
||||
profileSettings.show(getFragmentManager(),
|
||||
DeviceProfilesSettings.class.getSimpleName());
|
||||
} else {
|
||||
// New version - uses a separate screen.
|
||||
args.putString(BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS,
|
||||
device.getDevice().getAddress());
|
||||
BluetoothDeviceDetailsFragment fragment = new BluetoothDeviceDetailsFragment();
|
||||
final SettingsActivity activity =
|
||||
(SettingsActivity) BluetoothSettings.this.getActivity();
|
||||
activity.startPreferencePanel(this,
|
||||
BluetoothDeviceDetailsFragment.class.getName(), args,
|
||||
R.string.device_details_title, null, null, 0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -17,20 +17,28 @@
|
||||
package com.android.settings.bluetooth;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.res.Resources;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.util.Pair;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.HidProfile;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
||||
import com.android.settingslib.bluetooth.Utils.ErrorListener;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utils is a helper class that contains constants for various
|
||||
* Android resource IDs, debug logging flags, and static methods
|
||||
@@ -141,4 +149,52 @@ public final class Utils {
|
||||
com.android.settingslib.bluetooth.Utils.setErrorListener(mErrorListener);
|
||||
}
|
||||
};
|
||||
|
||||
static Pair<Integer, String> getBtClassDrawableWithDescription(Resources r,
|
||||
CachedBluetoothDevice cachedDevice) {
|
||||
BluetoothClass btClass = cachedDevice.getBtClass();
|
||||
if (btClass != null) {
|
||||
switch (btClass.getMajorDeviceClass()) {
|
||||
case BluetoothClass.Device.Major.COMPUTER:
|
||||
return new Pair<Integer, String>(R.drawable.ic_bt_laptop,
|
||||
r.getString(R.string.bluetooth_talkback_computer));
|
||||
|
||||
case BluetoothClass.Device.Major.PHONE:
|
||||
return new Pair<Integer, String>(R.drawable.ic_bt_cellphone,
|
||||
r.getString(R.string.bluetooth_talkback_phone));
|
||||
|
||||
case BluetoothClass.Device.Major.PERIPHERAL:
|
||||
return new Pair<Integer, String>(HidProfile.getHidClassDrawable(btClass),
|
||||
r.getString(
|
||||
R.string.bluetooth_talkback_input_peripheral));
|
||||
|
||||
case BluetoothClass.Device.Major.IMAGING:
|
||||
return new Pair<Integer, String>(R.drawable.ic_bt_imaging,
|
||||
r.getString(R.string.bluetooth_talkback_imaging));
|
||||
|
||||
default:
|
||||
// unrecognized device class; continue
|
||||
}
|
||||
}
|
||||
|
||||
List<LocalBluetoothProfile> profiles = cachedDevice.getProfiles();
|
||||
for (LocalBluetoothProfile profile : profiles) {
|
||||
int resId = profile.getDrawableResource(btClass);
|
||||
if (resId != 0) {
|
||||
return new Pair<Integer, String>(resId, null);
|
||||
}
|
||||
}
|
||||
if (btClass != null) {
|
||||
if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
|
||||
return new Pair<Integer, String>(R.drawable.ic_bt_headset_hfp,
|
||||
r.getString(R.string.bluetooth_talkback_headset));
|
||||
}
|
||||
if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
|
||||
return new Pair<Integer, String>(R.drawable.ic_bt_headphones_a2dp,
|
||||
r.getString(R.string.bluetooth_talkback_headphone));
|
||||
}
|
||||
}
|
||||
return new Pair<Integer, String>(R.drawable.ic_settings_bluetooth,
|
||||
r.getString(R.string.bluetooth_talkback_bluetooth));
|
||||
}
|
||||
}
|
||||
|
@@ -57,6 +57,7 @@ import com.android.settings.applications.UsageAccessDetails;
|
||||
import com.android.settings.applications.VrListenerSettings;
|
||||
import com.android.settings.applications.WriteSettingsDetails;
|
||||
import com.android.settings.applications.assist.ManageAssist;
|
||||
import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
|
||||
import com.android.settings.bluetooth.BluetoothSettings;
|
||||
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
|
||||
import com.android.settings.dashboard.SupportFragment;
|
||||
@@ -247,6 +248,7 @@ public class SettingsGateway {
|
||||
EnterprisePrivacySettings.class.getName(),
|
||||
WebViewAppPicker.class.getName(),
|
||||
LockscreenDashboardFragment.class.getName(),
|
||||
BluetoothDeviceDetailsFragment.class.getName(),
|
||||
};
|
||||
|
||||
public static final String[] SETTINGS_FOR_RESTRICTED = {
|
||||
|
Reference in New Issue
Block a user