Change DeviceProfilesSettings to DialogFragment

This makes the lifecycle simpler to fix a crash after rotation.
Also do some adjusting of alignment while here.

Bug: 21444336
Bug: 21205689
Change-Id: I67eccf4833f53b5e5088ae5e6038d041e8653565
This commit is contained in:
Jason Monk
2015-06-02 14:05:55 -04:00
parent 1b7bff11af
commit 0d7d927216
3 changed files with 170 additions and 159 deletions

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="25dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/bluetooth_preference_paired_dialog_name_label"
android:textAppearance="@android:style/TextAppearance.Material.Body1"
android:textColor="?android:attr/textColorSecondary"
android:textDirection="locale"
android:paddingTop="16dp"
style="@style/bt_item_label" />
<EditText
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions"
android:maxLength="@integer/bluetooth_name_length"
android:singleLine="true"
android:paddingBottom="@dimen/bluetooth_dialog_padding"
style="@style/bt_item_edit_content" />
<TextView
android:id="@+id/profiles_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="4dp"
android:text="@string/bluetooth_device_advanced_profile_header_title"
android:textAppearance="@android:style/TextAppearance.Material.Body1"
android:textColor="?android:attr/textColorSecondary" />
<LinearLayout
android:id="@+id/profiles_section"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -18,13 +18,10 @@ package com.android.settings.bluetooth;
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
@@ -37,14 +34,10 @@ import android.text.Spannable;
import android.text.style.TextAppearanceSpan;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
@@ -423,6 +416,7 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment implem
}
}
@Override
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
setDeviceListGroup(getPreferenceScreen());
removeAllDevices();
@@ -430,6 +424,7 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment implem
}
private final View.OnClickListener mDeviceProfilesListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
// User clicked on advanced options icon for a device in the list
if (!(v.getTag() instanceof CachedBluetoothDevice)) {
@@ -438,77 +433,13 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment implem
}
final CachedBluetoothDevice device = (CachedBluetoothDevice) v.getTag();
final Activity activity = getActivity();
DeviceProfilesSettings profileFragment = (DeviceProfilesSettings)activity.
getFragmentManager().findFragmentById(R.id.bluetooth_fragment_settings);
if (mSettingsDialogView != null){
ViewGroup parent = (ViewGroup) mSettingsDialogView.getParent();
if (parent != null) {
parent.removeView(mSettingsDialogView);
}
}
if (profileFragment == null) {
LayoutInflater inflater = getActivity().getLayoutInflater();
mSettingsDialogView = inflater.inflate(R.layout.bluetooth_device_settings, null);
profileFragment = (DeviceProfilesSettings)activity.getFragmentManager()
.findFragmentById(R.id.bluetooth_fragment_settings);
// To enable scrolling we store the name field in a seperate header and add to
// the ListView of the profileFragment.
View header = inflater.inflate(R.layout.bluetooth_device_settings_header, null);
profileFragment.getListView().addHeaderView(header);
}
final View dialogLayout = mSettingsDialogView;
AlertDialog.Builder settingsDialog = new AlertDialog.Builder(activity);
profileFragment.setDevice(device);
final EditText deviceName = (EditText)dialogLayout.findViewById(R.id.name);
deviceName.setText(device.getName(), TextView.BufferType.EDITABLE);
final DeviceProfilesSettings dpsFragment = profileFragment;
final Context context = v.getContext();
settingsDialog.setView(dialogLayout);
settingsDialog.setTitle(R.string.bluetooth_preference_paired_devices);
settingsDialog.setPositiveButton(R.string.okay,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
EditText deviceName = (EditText)dialogLayout.findViewById(R.id.name);
device.setName(deviceName.getText().toString());
}
});
settingsDialog.setNegativeButton(R.string.forget,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
device.unpair();
com.android.settings.bluetooth.Utils.updateSearchIndex(activity,
BluetoothSettings.class.getName(), device.getName(),
context.getResources().getString(R.string.bluetooth_settings),
R.drawable.ic_settings_bluetooth, false);
}
});
// We must ensure that the fragment gets destroyed to avoid duplicate fragments.
settingsDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
public void onDismiss(final DialogInterface dialog) {
if (!activity.isDestroyed()) {
activity.getFragmentManager().beginTransaction().remove(dpsFragment)
.commitAllowingStateLoss();
}
}
});
AlertDialog dialog = settingsDialog.create();
dialog.create();
dialog.show();
// We must ensure that clicking on the EditText will bring up the keyboard.
dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
Bundle args = new Bundle();
args.putString(DeviceProfilesSettings.ARG_DEVICE_ADDRESS,
device.getDevice().getAddress());
DeviceProfilesSettings profileSettings = new DeviceProfilesSettings();
profileSettings.setArguments(args);
profileSettings.show(getFragmentManager(),
DeviceProfilesSettings.class.getSimpleName());
}
};

View File

@@ -17,6 +17,8 @@
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;
@@ -24,15 +26,18 @@ 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.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 com.android.internal.logging.MetricsLogger;
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -44,15 +49,12 @@ import com.android.settingslib.bluetooth.PbapServerProfile;
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 {
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";
@@ -61,7 +63,8 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
private LocalBluetoothManager mManager;
private LocalBluetoothProfileManager mProfileManager;
private PreferenceGroup mProfileContainer;
private ViewGroup mProfileContainer;
private TextView mProfileLabel;
private EditTextPreference mDeviceNamePref;
private final HashMap<LocalBluetoothProfile, CheckBoxPreference> mAutoConnectPrefs
@@ -70,26 +73,59 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
private AlertDialog mDisconnectDialog;
private boolean mProfileGroupIsRemoved;
@Override
protected int getMetricsCategory() {
return MetricsLogger.BLUETOOTH_DEVICE_PROFILES;
}
private View mRootView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.bluetooth_device_advanced);
getPreferenceScreen().setOrderingAsAdded(false);
mProfileContainer = (PreferenceGroup) findPreference(KEY_PROFILE_CONTAINER);
mProfileContainer.setLayoutResource(R.layout.bluetooth_preference_category);
mManager = Utils.getLocalBtManager(getActivity());
CachedBluetoothDeviceManager deviceManager =
mManager.getCachedDeviceManager();
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();
@@ -115,7 +151,7 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
if (mCachedDevice != null) {
mCachedDevice.registerCallback(this);
if (mCachedDevice.getBondState() == BluetoothDevice.BOND_NONE) {
finish();
dismiss();
return;
}
refresh();
@@ -144,37 +180,39 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
}
private void addPreferencesForProfiles() {
mProfileContainer.removeAll();
mProfileContainer.removeAllViews();
for (LocalBluetoothProfile profile : mCachedDevice.getConnectableProfiles()) {
Preference pref = createProfilePreference(profile);
mProfileContainer.addPreference(pref);
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();
CheckBoxPreference pbapPref = createProfilePreference(psp);
mProfileContainer.addPreference(pbapPref);
CheckBox pbapPref = createProfilePreference(psp);
mProfileContainer.addView(pbapPref);
}
final MapProfile mapProfile = mManager.getProfileManager().getMapProfile();
final int mapPermission = mCachedDevice.getMessagePermissionChoice();
if (mapPermission != CachedBluetoothDevice.ACCESS_UNKNOWN) {
CheckBoxPreference mapPreference = createProfilePreference(mapProfile);
mProfileContainer.addPreference(mapPreference);
CheckBox mapPreference = createProfilePreference(mapProfile);
mProfileContainer.addView(mapPreference);
}
showOrHideProfileGroup();
}
private void showOrHideProfileGroup() {
int numProfiles = mProfileContainer.getPreferenceCount();
int numProfiles = mProfileContainer.getChildCount();
if (!mProfileGroupIsRemoved && numProfiles == 0) {
getPreferenceScreen().removePreference(mProfileContainer);
mProfileContainer.setVisibility(View.GONE);
mProfileLabel.setVisibility(View.GONE);
mProfileGroupIsRemoved = true;
} else if (mProfileGroupIsRemoved && numProfiles != 0) {
getPreferenceScreen().addPreference(mProfileContainer);
mProfileContainer.setVisibility(View.VISIBLE);
mProfileLabel.setVisibility(View.VISIBLE);
mProfileGroupIsRemoved = false;
}
}
@@ -187,43 +225,29 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
* @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.setLayoutResource(R.layout.preference_start_widget);
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(getActivity().getDrawable(iconResource));
}
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;
}
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;
@Override
public void onClick(View v) {
if (v instanceof CheckBox) {
LocalBluetoothProfile prof = getProfileOf(v);
onProfileClicked(prof, (CheckBox) v);
}
}
return true;
}
private void onProfileClicked(LocalBluetoothProfile profile, CheckBoxPreference profilePref) {
private void onProfileClicked(LocalBluetoothProfile profile, CheckBox profilePref) {
BluetoothDevice device = mCachedDevice.getDevice();
if (profilePref.getKey().equals(KEY_PBAP_SERVER)) {
if (KEY_PBAP_SERVER.equals(profilePref.getTag())) {
final int newPermission = mCachedDevice.getPhonebookPermissionChoice()
== CachedBluetoothDevice.ACCESS_ALLOWED ? CachedBluetoothDevice.ACCESS_REJECTED
: CachedBluetoothDevice.ACCESS_ALLOWED;
@@ -232,11 +256,9 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
return;
}
int status = profile.getConnectionStatus(device);
boolean isConnected =
status == BluetoothProfile.STATE_CONNECTED;
if (profilePref.isChecked()) {
if (!profilePref.isChecked()) {
// Recheck it, until the dialog is done.
profilePref.setChecked(true);
askDisconnect(mManager.getForegroundActivity(), profile);
} else {
if (profile instanceof MapProfile) {
@@ -281,8 +303,7 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
if (profile instanceof MapProfile) {
device.setMessagePermissionChoice(BluetoothDevice.ACCESS_REJECTED);
}
refreshProfilePreference(
(CheckBoxPreference)findPreference(profile.toString()), profile);
refreshProfilePreference(findProfile(profile.toString()), profile);
}
};
@@ -296,7 +317,7 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
}
private void refresh() {
final EditText deviceNameField = (EditText) getView().findViewById(R.id.name);
final EditText deviceNameField = (EditText) mRootView.findViewById(R.id.name);
if (deviceNameField != null) {
deviceNameField.setText(mCachedDevice.getName());
}
@@ -306,26 +327,30 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
private void refreshProfiles() {
for (LocalBluetoothProfile profile : mCachedDevice.getConnectableProfiles()) {
CheckBoxPreference profilePref = (CheckBoxPreference)findPreference(profile.toString());
CheckBox profilePref = findProfile(profile.toString());
if (profilePref == null) {
profilePref = createProfilePreference(profile);
mProfileContainer.addPreference(profilePref);
mProfileContainer.addView(profilePref);
} else {
refreshProfilePreference(profilePref, profile);
}
}
for (LocalBluetoothProfile profile : mCachedDevice.getRemovedProfiles()) {
Preference profilePref = findPreference(profile.toString());
CheckBox profilePref = findProfile(profile.toString());
if (profilePref != null) {
Log.d(TAG, "Removing " + profile.toString() + " from profile list");
mProfileContainer.removePreference(profilePref);
mProfileContainer.removeView(profilePref);
}
}
showOrHideProfileGroup();
}
private void refreshProfilePreference(CheckBoxPreference profilePref,
private CheckBox findProfile(String profile) {
return (CheckBox) mProfileContainer.findViewWithTag(profile);
}
private void refreshProfilePreference(CheckBox profilePref,
LocalBluetoothProfile profile) {
BluetoothDevice device = mCachedDevice.getDevice();
@@ -349,21 +374,17 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
}
}
private LocalBluetoothProfile getProfileOf(Preference pref) {
if (!(pref instanceof CheckBoxPreference)) {
private LocalBluetoothProfile getProfileOf(View v) {
if (!(v instanceof CheckBox)) {
return null;
}
String key = pref.getKey();
String key = (String) v.getTag();
if (TextUtils.isEmpty(key)) return null;
try {
return mProfileManager.getProfileByName(pref.getKey());
return mProfileManager.getProfileByName(key);
} catch (IllegalArgumentException ignored) {
return null;
}
}
private int getProfilePreferenceIndex(int profIndex) {
return mProfileContainer.getOrder() + profIndex * 10;
}
}