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.content.Context;
     20 import android.content.Intent;
     21 import android.content.pm.PackageManager;
     22 import android.content.res.Resources;
     23 import android.provider.Settings;
     24 import android.util.Log;
     25 import android.view.View;
     26 import android.view.ViewGroup;
     27 import android.widget.Button;
     28 import android.widget.Switch;
     29 
     30 import com.android.internal.logging.MetricsLogger;
     31 import com.android.internal.logging.MetricsProto.MetricsEvent;
     32 import com.android.settingslib.wifi.AccessPoint;
     33 import com.android.systemui.R;
     34 import com.android.systemui.qs.QSDetailItems;
     35 import com.android.systemui.qs.QSDetailItems.Item;
     36 import com.android.systemui.qs.QSIconView;
     37 import com.android.systemui.qs.QSTile;
     38 import com.android.systemui.qs.SignalTileView;
     39 import com.android.systemui.statusbar.policy.NetworkController;
     40 import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
     41 import com.android.systemui.statusbar.policy.NetworkController.IconState;
     42 import com.android.systemui.statusbar.policy.SignalCallbackAdapter;
     43 
     44 import java.util.List;
     45 
     46 /** Quick settings tile: Wifi **/
     47 public class WifiTile extends QSTile<QSTile.SignalState> {
     48     private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
     49 
     50     private final NetworkController mController;
     51     private final AccessPointController mWifiController;
     52     private final WifiDetailAdapter mDetailAdapter;
     53     private final QSTile.SignalState mStateBeforeClick = newTileState();
     54 
     55     protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback();
     56 
     57     public WifiTile(Host host) {
     58         super(host);
     59         mController = host.getNetworkController();
     60         mWifiController = mController.getAccessPointController();
     61         mDetailAdapter = new WifiDetailAdapter();
     62     }
     63 
     64     @Override
     65     public SignalState newTileState() {
     66         return new SignalState();
     67     }
     68 
     69     @Override
     70     public void setListening(boolean listening) {
     71         if (listening) {
     72             mController.addSignalCallback(mSignalCallback);
     73         } else {
     74             mController.removeSignalCallback(mSignalCallback);
     75         }
     76     }
     77 
     78     @Override
     79     public void setDetailListening(boolean listening) {
     80         if (listening) {
     81             mWifiController.addAccessPointCallback(mDetailAdapter);
     82         } else {
     83             mWifiController.removeAccessPointCallback(mDetailAdapter);
     84         }
     85     }
     86 
     87     @Override
     88     public DetailAdapter getDetailAdapter() {
     89         return mDetailAdapter;
     90     }
     91 
     92     @Override
     93     public QSIconView createTileView(Context context) {
     94         return new SignalTileView(context);
     95     }
     96 
     97     @Override
     98     public Intent getLongClickIntent() {
     99         return WIFI_SETTINGS;
    100     }
    101 
    102     @Override
    103     protected void handleSecondaryClick() {
    104         // Secondary clicks are header clicks, just toggle.
    105         mState.copyTo(mStateBeforeClick);
    106         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
    107         mController.setWifiEnabled(!mState.value);
    108     }
    109 
    110     @Override
    111     protected void handleClick() {
    112         if (!mWifiController.canConfigWifi()) {
    113             mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_WIFI_SETTINGS));
    114             return;
    115         }
    116         showDetail(true);
    117         if (!mState.value) {
    118             mController.setWifiEnabled(true);
    119             mState.value = true;
    120         }
    121     }
    122 
    123     @Override
    124     public CharSequence getTileLabel() {
    125         return mContext.getString(R.string.quick_settings_wifi_label);
    126     }
    127 
    128     @Override
    129     protected void handleUpdateState(SignalState state, Object arg) {
    130         if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg);
    131         CallbackInfo cb = (CallbackInfo) arg;
    132         if (cb == null) {
    133             cb = mSignalCallback.mInfo;
    134         }
    135 
    136         boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null);
    137         boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.enabledDesc == null);
    138         boolean enabledChanging = state.value != cb.enabled;
    139         if (enabledChanging) {
    140             mDetailAdapter.setItemsVisible(cb.enabled);
    141             fireToggleStateChanged(cb.enabled);
    142         }
    143         state.value = cb.enabled;
    144         state.connected = wifiConnected;
    145         state.activityIn = cb.enabled && cb.activityIn;
    146         state.activityOut = cb.enabled && cb.activityOut;
    147         state.filter = true;
    148         final StringBuffer minimalContentDescription = new StringBuffer();
    149         final StringBuffer expandedContentDescription = new StringBuffer();
    150         final Resources r = mContext.getResources();
    151         if (!state.value) {
    152             state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disabled);
    153             state.label = r.getString(R.string.quick_settings_wifi_label);
    154         } else if (wifiConnected) {
    155             state.icon = ResourceIcon.get(cb.wifiSignalIconId);
    156             state.label = removeDoubleQuotes(cb.enabledDesc);
    157         } else if (wifiNotConnected) {
    158             state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disconnected);
    159             state.label = r.getString(R.string.quick_settings_wifi_label);
    160         } else {
    161             state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_no_network);
    162             state.label = r.getString(R.string.quick_settings_wifi_label);
    163         }
    164         minimalContentDescription.append(
    165                 mContext.getString(R.string.quick_settings_wifi_label)).append(",");
    166         if (state.value) {
    167             expandedContentDescription.append(
    168                     r.getString(R.string.quick_settings_wifi_on_label)).append(",");
    169             if (wifiConnected) {
    170                 minimalContentDescription.append(cb.wifiSignalContentDescription).append(",");
    171                 minimalContentDescription.append(removeDoubleQuotes(cb.enabledDesc));
    172                 expandedContentDescription.append(cb.wifiSignalContentDescription).append(",");
    173                 expandedContentDescription.append(removeDoubleQuotes(cb.enabledDesc));
    174             }
    175         } else {
    176             expandedContentDescription.append(
    177                     r.getString(R.string.quick_settings_wifi_off_label));
    178         }
    179         state.minimalContentDescription =  minimalContentDescription;
    180         expandedContentDescription.append(",").append(
    181                 r.getString(R.string.accessibility_quick_settings_open_settings, getTileLabel()));
    182         state.contentDescription = expandedContentDescription;
    183         CharSequence wifiName = state.label;
    184         if (state.connected) {
    185             wifiName = r.getString(R.string.accessibility_wifi_name, state.label);
    186         }
    187         state.dualLabelContentDescription = wifiName;
    188         state.expandedAccessibilityClassName = Button.class.getName();
    189         state.minimalAccessibilityClassName = Switch.class.getName();
    190     }
    191 
    192     @Override
    193     public int getMetricsCategory() {
    194         return MetricsEvent.QS_WIFI;
    195     }
    196 
    197     @Override
    198     protected boolean shouldAnnouncementBeDelayed() {
    199         return mStateBeforeClick.value == mState.value;
    200     }
    201 
    202     @Override
    203     protected String composeChangeAnnouncement() {
    204         if (mState.value) {
    205             return mContext.getString(R.string.accessibility_quick_settings_wifi_changed_on);
    206         } else {
    207             return mContext.getString(R.string.accessibility_quick_settings_wifi_changed_off);
    208         }
    209     }
    210 
    211     @Override
    212     public boolean isAvailable() {
    213         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
    214     }
    215 
    216     private static String removeDoubleQuotes(String string) {
    217         if (string == null) return null;
    218         final int length = string.length();
    219         if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
    220             return string.substring(1, length - 1);
    221         }
    222         return string;
    223     }
    224 
    225     protected static final class CallbackInfo {
    226         boolean enabled;
    227         boolean connected;
    228         int wifiSignalIconId;
    229         String enabledDesc;
    230         boolean activityIn;
    231         boolean activityOut;
    232         String wifiSignalContentDescription;
    233 
    234         @Override
    235         public String toString() {
    236             return new StringBuilder("CallbackInfo[")
    237                 .append("enabled=").append(enabled)
    238                 .append(",connected=").append(connected)
    239                 .append(",wifiSignalIconId=").append(wifiSignalIconId)
    240                 .append(",enabledDesc=").append(enabledDesc)
    241                 .append(",activityIn=").append(activityIn)
    242                 .append(",activityOut=").append(activityOut)
    243                 .append(",wifiSignalContentDescription=").append(wifiSignalContentDescription)
    244                 .append(']').toString();
    245         }
    246     }
    247 
    248     protected final class WifiSignalCallback extends SignalCallbackAdapter {
    249         final CallbackInfo mInfo = new CallbackInfo();
    250 
    251         @Override
    252         public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
    253                 boolean activityIn, boolean activityOut, String description) {
    254             if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled);
    255             mInfo.enabled = enabled;
    256             mInfo.connected = qsIcon.visible;
    257             mInfo.wifiSignalIconId = qsIcon.icon;
    258             mInfo.enabledDesc = description;
    259             mInfo.activityIn = activityIn;
    260             mInfo.activityOut = activityOut;
    261             mInfo.wifiSignalContentDescription = qsIcon.contentDescription;
    262             refreshState(mInfo);
    263         }
    264     };
    265 
    266     private final class WifiDetailAdapter implements DetailAdapter,
    267             NetworkController.AccessPointController.AccessPointCallback, QSDetailItems.Callback {
    268 
    269         private QSDetailItems mItems;
    270         private AccessPoint[] mAccessPoints;
    271 
    272         @Override
    273         public CharSequence getTitle() {
    274             return mContext.getString(R.string.quick_settings_wifi_label);
    275         }
    276 
    277         public Intent getSettingsIntent() {
    278             return WIFI_SETTINGS;
    279         }
    280 
    281         @Override
    282         public Boolean getToggleState() {
    283             return mState.value;
    284         }
    285 
    286         @Override
    287         public void setToggleState(boolean state) {
    288             if (DEBUG) Log.d(TAG, "setToggleState " + state);
    289             MetricsLogger.action(mContext, MetricsEvent.QS_WIFI_TOGGLE, state);
    290             mController.setWifiEnabled(state);
    291             showDetail(false);
    292         }
    293 
    294         @Override
    295         public int getMetricsCategory() {
    296             return MetricsEvent.QS_WIFI_DETAILS;
    297         }
    298 
    299         @Override
    300         public View createDetailView(Context context, View convertView, ViewGroup parent) {
    301             if (DEBUG) Log.d(TAG, "createDetailView convertView=" + (convertView != null));
    302             mAccessPoints = null;
    303             mWifiController.scanForAccessPoints();
    304             fireScanStateChanged(true);
    305             mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
    306             mItems.setTagSuffix("Wifi");
    307             mItems.setCallback(this);
    308             mItems.setEmptyState(R.drawable.ic_qs_wifi_detail_empty,
    309                     R.string.quick_settings_wifi_detail_empty_text);
    310             updateItems();
    311             setItemsVisible(mState.value);
    312             return mItems;
    313         }
    314 
    315         @Override
    316         public void onAccessPointsChanged(final List<AccessPoint> accessPoints) {
    317             mAccessPoints = accessPoints.toArray(new AccessPoint[accessPoints.size()]);
    318             updateItems();
    319             if (accessPoints != null && accessPoints.size() > 0) {
    320                 fireScanStateChanged(false);
    321             }
    322         }
    323 
    324         @Override
    325         public void onSettingsActivityTriggered(Intent settingsIntent) {
    326             mHost.startActivityDismissingKeyguard(settingsIntent);
    327         }
    328 
    329         @Override
    330         public void onDetailItemClick(Item item) {
    331             if (item == null || item.tag == null) return;
    332             final AccessPoint ap = (AccessPoint) item.tag;
    333             if (!ap.isActive()) {
    334                 if (mWifiController.connect(ap)) {
    335                     mHost.collapsePanels();
    336                 }
    337             }
    338             showDetail(false);
    339         }
    340 
    341         @Override
    342         public void onDetailItemDisconnect(Item item) {
    343             // noop
    344         }
    345 
    346         public void setItemsVisible(boolean visible) {
    347             if (mItems == null) return;
    348             mItems.setItemsVisible(visible);
    349         }
    350 
    351         private void updateItems() {
    352             if (mItems == null) return;
    353             Item[] items = null;
    354             if (mAccessPoints != null) {
    355                 items = new Item[mAccessPoints.length];
    356                 for (int i = 0; i < mAccessPoints.length; i++) {
    357                     final AccessPoint ap = mAccessPoints[i];
    358                     final Item item = new Item();
    359                     item.tag = ap;
    360                     item.icon = mWifiController.getIcon(ap);
    361                     item.line1 = ap.getSsid();
    362                     item.line2 = ap.isActive() ? ap.getSummary() : null;
    363                     item.overlay = ap.getSecurity() != AccessPoint.SECURITY_NONE
    364                             ? mContext.getDrawable(R.drawable.qs_ic_wifi_lock)
    365                             : null;
    366                     items[i] = item;
    367                 }
    368             }
    369             mItems.setItems(items);
    370         }
    371     }
    372 }
    373