/*
* Copyright (C) 2014 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.systemui.qs.tiles;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import com.android.internal.logging.MetricsLogger;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.systemui.R;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.BluetoothController;
import java.util.Collection;
import java.util.Set;
/** Quick settings tile: Bluetooth **/
public class BluetoothTile extends QSTile<QSTile.BooleanState> {
private static final Intent BLUETOOTH_SETTINGS = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
private final BluetoothController mController;
private final BluetoothDetailAdapter mDetailAdapter;
public BluetoothTile(Host host) {
super(host);
mController = host.getBluetoothController();
mDetailAdapter = new BluetoothDetailAdapter();
}
@Override
public boolean supportsDualTargets() {
return true;
}
@Override
public DetailAdapter getDetailAdapter() {
return mDetailAdapter;
}
@Override
protected BooleanState newTileState() {
return new BooleanState();
}
@Override
public void setListening(boolean listening) {
if (listening) {
mController.addStateChangedCallback(mCallback);
} else {
mController.removeStateChangedCallback(mCallback);
}
}
@Override
protected void handleClick() {
final boolean isEnabled = (Boolean)mState.value;
MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
mController.setBluetoothEnabled(!isEnabled);
}
@Override
protected void handleSecondaryClick() {
if (!mState.value) {
mState.value = true;
mController.setBluetoothEnabled(true);
}
showDetail(true);
}
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
final boolean supported = mController.isBluetoothSupported();
final boolean enabled = mController.isBluetoothEnabled();
final boolean connected = mController.isBluetoothConnected();
final boolean connecting = mController.isBluetoothConnecting();
state.visible = supported;
state.value = enabled;
state.autoMirrorDrawable = false;
if (enabled) {
state.label = null;
if (connected) {
state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connected);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_bluetooth_connected);
state.label = mController.getLastDeviceName();
} else if (connecting) {
state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connecting);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_bluetooth_connecting);
state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
} else {
state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_on);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_bluetooth_on);
}
if (TextUtils.isEmpty(state.label)) {
state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
}
} else {
state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_off);
state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_bluetooth_off);
}
String bluetoothName = state.label;
if (connected) {
bluetoothName = state.dualLabelContentDescription = mContext.getString(
R.string.accessibility_bluetooth_name, state.label);
}
state.dualLabelContentDescription = bluetoothName;
}
@Override
public int getMetricsCategory() {
return MetricsLogger.QS_BLUETOOTH;
}
@Override
protected String composeChangeAnnouncement() {
if (mState.value) {
return mContext.getString(R.string.accessibility_quick_settings_bluetooth_changed_on);
} else {
return mContext.getString(R.string.accessibility_quick_settings_bluetooth_changed_off);
}
}
private final BluetoothController.Callback mCallback = new BluetoothController.Callback() {
@Override
public void onBluetoothStateChange(boolean enabled) {
refreshState();
}
@Override
public void onBluetoothDevicesChanged() {
mUiHandler.post(new Runnable() {
@Override
public void run() {
mDetailAdapter.updateItems();
}
});
refreshState();
}
};
private final class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
private QSDetailItems mItems;
@Override
public int getTitle() {
return R.string.quick_settings_bluetooth_label;
}
@Override
public Boolean getToggleState() {
return mState.value;
}
@Override
public Intent getSettingsIntent() {
return BLUETOOTH_SETTINGS;
}
@Override
public void setToggleState(boolean state) {
MetricsLogger.action(mContext, MetricsLogger.QS_BLUETOOTH_TOGGLE, state);
mController.setBluetoothEnabled(state);
showDetail(false);
}
@Override
public int getMetricsCategory() {
return MetricsLogger.QS_BLUETOOTH_DETAILS;
}
@Override
public View createDetailView(Context context, View convertView, ViewGroup parent) {
mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
mItems.setTagSuffix("Bluetooth");
mItems.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty,
R.string.quick_settings_bluetooth_detail_empty_text);
mItems.setCallback(this);
mItems.setMinHeightInItems(0);
updateItems();
setItemsVisible(mState.value);
return mItems;
}
public void setItemsVisible(boolean visible) {
if (mItems == null) return;
mItems.setItemsVisible(visible);
}
private void updateItems() {
if (mItems == null) return;
Item[] items = null;
final Collection<CachedBluetoothDevice> devices = mController.getDevices();
if (devices != null) {
items = new Item[getBondedCount(devices)];
int i = 0;
for (CachedBluetoothDevice device : devices) {
if (device.getBondState() == BluetoothDevice.BOND_NONE) continue;
final Item item = new Item();
item.icon = R.drawable.ic_qs_bluetooth_on;
item.line1 = device.getName();
int state = device.getMaxConnectionState();
if (state == BluetoothProfile.STATE_CONNECTED) {
item.icon = R.drawable.ic_qs_bluetooth_connected;
item.line2 = mContext.getString(R.string.quick_settings_connected);
item.canDisconnect = true;
} else if (state == BluetoothProfile.STATE_CONNECTING) {
item.icon = R.drawable.ic_qs_bluetooth_connecting;
item.line2 = mContext.getString(R.string.quick_settings_connecting);
}
item.tag = device;
items[i++] = item;
}
}
mItems.setItems(items);
}
private int getBondedCount(Collection<CachedBluetoothDevice> devices) {
int ct = 0;
for (CachedBluetoothDevice device : devices) {
if (device.getBondState() != BluetoothDevice.BOND_NONE) {
ct++;
}
}
return ct;
}
@Override
public void onDetailItemClick(Item item) {
if (item == null || item.tag == null) return;
final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
if (device != null && device.getMaxConnectionState()
== BluetoothProfile.STATE_DISCONNECTED) {
mController.connect(device);
}
}
@Override
public void onDetailItemDisconnect(Item item) {
if (item == null || item.tag == null) return;
final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
if (device != null) {
mController.disconnect(device);
}
}
}
}