Home | History | Annotate | Download | only in tiles
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.systemui.qs.tiles;
     18 
     19 import android.bluetooth.BluetoothAdapter;
     20 import android.bluetooth.BluetoothDevice;
     21 import android.bluetooth.BluetoothProfile;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.provider.Settings;
     25 import android.text.TextUtils;
     26 import android.view.View;
     27 import android.view.ViewGroup;
     28 import android.widget.Button;
     29 import android.widget.Switch;
     30 
     31 import com.android.internal.logging.MetricsLogger;
     32 import com.android.internal.logging.MetricsProto.MetricsEvent;
     33 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
     34 import com.android.systemui.R;
     35 import com.android.systemui.qs.QSDetailItems;
     36 import com.android.systemui.qs.QSDetailItems.Item;
     37 import com.android.systemui.qs.QSTile;
     38 import com.android.systemui.statusbar.policy.BluetoothController;
     39 
     40 import java.util.ArrayList;
     41 import java.util.Collection;
     42 
     43 /** Quick settings tile: Bluetooth **/
     44 public class BluetoothTile extends QSTile<QSTile.BooleanState>  {
     45     private static final Intent BLUETOOTH_SETTINGS = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
     46 
     47     private final BluetoothController mController;
     48     private final BluetoothDetailAdapter mDetailAdapter;
     49 
     50     public BluetoothTile(Host host) {
     51         super(host);
     52         mController = host.getBluetoothController();
     53         mDetailAdapter = new BluetoothDetailAdapter();
     54     }
     55 
     56     @Override
     57     public DetailAdapter getDetailAdapter() {
     58         return mDetailAdapter;
     59     }
     60 
     61     @Override
     62     public BooleanState newTileState() {
     63         return new BooleanState();
     64     }
     65 
     66     @Override
     67     public void setListening(boolean listening) {
     68         if (listening) {
     69             mController.addStateChangedCallback(mCallback);
     70         } else {
     71             mController.removeStateChangedCallback(mCallback);
     72         }
     73     }
     74 
     75     @Override
     76     protected void handleSecondaryClick() {
     77         // Secondary clicks are header clicks, just toggle.
     78         final boolean isEnabled = (Boolean)mState.value;
     79         MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
     80         mController.setBluetoothEnabled(!isEnabled);
     81     }
     82 
     83     @Override
     84     public Intent getLongClickIntent() {
     85         return new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
     86     }
     87 
     88     @Override
     89     protected void handleClick() {
     90         if (!mController.canConfigBluetooth()) {
     91             mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
     92             return;
     93         }
     94         showDetail(true);
     95         if (!mState.value) {
     96             mState.value = true;
     97             mController.setBluetoothEnabled(true);
     98         }
     99     }
    100 
    101     @Override
    102     public CharSequence getTileLabel() {
    103         return mContext.getString(R.string.quick_settings_bluetooth_label);
    104     }
    105 
    106     @Override
    107     protected void handleUpdateState(BooleanState state, Object arg) {
    108         final boolean enabled = mController.isBluetoothEnabled();
    109         final boolean connected = mController.isBluetoothConnected();
    110         final boolean connecting = mController.isBluetoothConnecting();
    111         state.value = enabled;
    112         state.autoMirrorDrawable = false;
    113         state.minimalContentDescription =
    114                 mContext.getString(R.string.accessibility_quick_settings_bluetooth);
    115         if (enabled) {
    116             state.label = null;
    117             if (connected) {
    118                 state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connected);
    119                 state.label = mController.getLastDeviceName();
    120                 state.contentDescription = mContext.getString(
    121                         R.string.accessibility_bluetooth_name, state.label);
    122                 state.minimalContentDescription = state.minimalContentDescription + ","
    123                         + state.contentDescription;
    124             } else if (connecting) {
    125                 state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connecting);
    126                 state.contentDescription = mContext.getString(
    127                         R.string.accessibility_quick_settings_bluetooth_connecting);
    128                 state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
    129                 state.minimalContentDescription = state.minimalContentDescription + ","
    130                         + state.contentDescription;
    131             } else {
    132                 state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_on);
    133                 state.contentDescription = mContext.getString(
    134                         R.string.accessibility_quick_settings_bluetooth_on) + ","
    135                         + mContext.getString(R.string.accessibility_not_connected);
    136                 state.minimalContentDescription = state.minimalContentDescription + ","
    137                         + mContext.getString(R.string.accessibility_not_connected);
    138             }
    139             if (TextUtils.isEmpty(state.label)) {
    140                 state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
    141             }
    142         } else {
    143             state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_off);
    144             state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
    145             state.contentDescription = mContext.getString(
    146                     R.string.accessibility_quick_settings_bluetooth_off);
    147         }
    148 
    149         CharSequence bluetoothName = state.label;
    150         if (connected) {
    151             bluetoothName = state.dualLabelContentDescription = mContext.getString(
    152                     R.string.accessibility_bluetooth_name, state.label);
    153         }
    154         state.dualLabelContentDescription = bluetoothName;
    155         state.contentDescription = state.contentDescription + "," + mContext.getString(
    156                 R.string.accessibility_quick_settings_open_settings, getTileLabel());
    157         state.expandedAccessibilityClassName = Button.class.getName();
    158         state.minimalAccessibilityClassName = Switch.class.getName();
    159     }
    160 
    161     @Override
    162     public int getMetricsCategory() {
    163         return MetricsEvent.QS_BLUETOOTH;
    164     }
    165 
    166     @Override
    167     protected String composeChangeAnnouncement() {
    168         if (mState.value) {
    169             return mContext.getString(R.string.accessibility_quick_settings_bluetooth_changed_on);
    170         } else {
    171             return mContext.getString(R.string.accessibility_quick_settings_bluetooth_changed_off);
    172         }
    173     }
    174 
    175     @Override
    176     public boolean isAvailable() {
    177         return mController.isBluetoothSupported();
    178     }
    179 
    180     private final BluetoothController.Callback mCallback = new BluetoothController.Callback() {
    181         @Override
    182         public void onBluetoothStateChange(boolean enabled) {
    183             refreshState();
    184         }
    185 
    186         @Override
    187         public void onBluetoothDevicesChanged() {
    188             mUiHandler.post(new Runnable() {
    189                 @Override
    190                 public void run() {
    191                     mDetailAdapter.updateItems();
    192                 }
    193             });
    194             refreshState();
    195         }
    196     };
    197 
    198     private final class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
    199         private QSDetailItems mItems;
    200 
    201         @Override
    202         public CharSequence getTitle() {
    203             return mContext.getString(R.string.quick_settings_bluetooth_label);
    204         }
    205 
    206         @Override
    207         public Boolean getToggleState() {
    208             return mState.value;
    209         }
    210 
    211         @Override
    212         public boolean getToggleEnabled() {
    213             return mController.getBluetoothState() == BluetoothAdapter.STATE_OFF
    214                     || mController.getBluetoothState() == BluetoothAdapter.STATE_ON;
    215         }
    216 
    217         @Override
    218         public Intent getSettingsIntent() {
    219             return BLUETOOTH_SETTINGS;
    220         }
    221 
    222         @Override
    223         public void setToggleState(boolean state) {
    224             MetricsLogger.action(mContext, MetricsEvent.QS_BLUETOOTH_TOGGLE, state);
    225             mController.setBluetoothEnabled(state);
    226             showDetail(false);
    227         }
    228 
    229         @Override
    230         public int getMetricsCategory() {
    231             return MetricsEvent.QS_BLUETOOTH_DETAILS;
    232         }
    233 
    234         @Override
    235         public View createDetailView(Context context, View convertView, ViewGroup parent) {
    236             mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
    237             mItems.setTagSuffix("Bluetooth");
    238             mItems.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty,
    239                     R.string.quick_settings_bluetooth_detail_empty_text);
    240             mItems.setCallback(this);
    241             updateItems();
    242             setItemsVisible(mState.value);
    243             return mItems;
    244         }
    245 
    246         public void setItemsVisible(boolean visible) {
    247             if (mItems == null) return;
    248             mItems.setItemsVisible(visible);
    249         }
    250 
    251         private void updateItems() {
    252             if (mItems == null) return;
    253             ArrayList<Item> items = new ArrayList<Item>();
    254             final Collection<CachedBluetoothDevice> devices = mController.getDevices();
    255             if (devices != null) {
    256                 for (CachedBluetoothDevice device : devices) {
    257                     if (device.getBondState() == BluetoothDevice.BOND_NONE) continue;
    258                     final Item item = new Item();
    259                     item.icon = R.drawable.ic_qs_bluetooth_on;
    260                     item.line1 = device.getName();
    261                     int state = device.getMaxConnectionState();
    262                     if (state == BluetoothProfile.STATE_CONNECTED) {
    263                         item.icon = R.drawable.ic_qs_bluetooth_connected;
    264                         item.line2 = mContext.getString(R.string.quick_settings_connected);
    265                         item.canDisconnect = true;
    266                     } else if (state == BluetoothProfile.STATE_CONNECTING) {
    267                         item.icon = R.drawable.ic_qs_bluetooth_connecting;
    268                         item.line2 = mContext.getString(R.string.quick_settings_connecting);
    269                     }
    270                     item.tag = device;
    271                     items.add(item);
    272                 }
    273             }
    274             mItems.setItems(items.toArray(new Item[items.size()]));
    275         }
    276 
    277         @Override
    278         public void onDetailItemClick(Item item) {
    279             if (item == null || item.tag == null) return;
    280             final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
    281             if (device != null && device.getMaxConnectionState()
    282                     == BluetoothProfile.STATE_DISCONNECTED) {
    283                 mController.connect(device);
    284             }
    285         }
    286 
    287         @Override
    288         public void onDetailItemDisconnect(Item item) {
    289             if (item == null || item.tag == null) return;
    290             final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
    291             if (device != null) {
    292                 mController.disconnect(device);
    293             }
    294         }
    295     }
    296 }
    297