Home | History | Annotate | Download | only in tether
      1 /*
      2  * Copyright (C) 2017 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.settings.wifi.tether;
     18 
     19 import android.content.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IntentFilter;
     23 import android.net.ConnectivityManager;
     24 import android.net.wifi.WifiConfiguration;
     25 import android.net.wifi.WifiManager;
     26 import android.provider.Settings;
     27 import android.support.annotation.VisibleForTesting;
     28 import android.support.v7.preference.Preference;
     29 import android.support.v7.preference.PreferenceScreen;
     30 import android.text.BidiFormatter;
     31 
     32 import com.android.settings.R;
     33 import com.android.settings.Utils;
     34 import com.android.settings.core.PreferenceControllerMixin;
     35 import com.android.settingslib.core.AbstractPreferenceController;
     36 import com.android.settingslib.core.lifecycle.Lifecycle;
     37 import com.android.settingslib.core.lifecycle.LifecycleObserver;
     38 import com.android.settingslib.core.lifecycle.events.OnStart;
     39 import com.android.settingslib.core.lifecycle.events.OnStop;
     40 
     41 public class WifiTetherPreferenceController extends AbstractPreferenceController
     42         implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop {
     43 
     44     private static final String WIFI_TETHER_SETTINGS = "wifi_tether";
     45     private static final IntentFilter AIRPLANE_INTENT_FILTER = new IntentFilter(
     46             Intent.ACTION_AIRPLANE_MODE_CHANGED);
     47     private static final int ID_NULL = -1;
     48 
     49     private final ConnectivityManager mConnectivityManager;
     50     private final String[] mWifiRegexs;
     51     private final WifiManager mWifiManager;
     52     private final Lifecycle mLifecycle;
     53     private int mSoftApState;
     54     @VisibleForTesting
     55     Preference mPreference;
     56     @VisibleForTesting
     57     WifiTetherSoftApManager mWifiTetherSoftApManager;
     58 
     59     public WifiTetherPreferenceController(Context context, Lifecycle lifecycle) {
     60         this(context, lifecycle, true /* initSoftApManager */);
     61     }
     62 
     63     @VisibleForTesting
     64     WifiTetherPreferenceController(Context context, Lifecycle lifecycle,
     65             boolean initSoftApManager) {
     66         super(context);
     67         mConnectivityManager =
     68                 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
     69         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
     70         mWifiRegexs = mConnectivityManager.getTetherableWifiRegexs();
     71         mLifecycle = lifecycle;
     72         if (lifecycle != null) {
     73             lifecycle.addObserver(this);
     74         }
     75         if (initSoftApManager) {
     76             initWifiTetherSoftApManager();
     77         }
     78     }
     79 
     80     @Override
     81     public boolean isAvailable() {
     82         return mWifiRegexs != null
     83                 && mWifiRegexs.length != 0
     84                 && !Utils.isMonkeyRunning();
     85     }
     86 
     87     @Override
     88     public void displayPreference(PreferenceScreen screen) {
     89         super.displayPreference(screen);
     90         mPreference = screen.findPreference(WIFI_TETHER_SETTINGS);
     91         if (mPreference == null) {
     92             // unavailable
     93             return;
     94         }
     95     }
     96 
     97     @Override
     98     public String getPreferenceKey() {
     99         return WIFI_TETHER_SETTINGS;
    100     }
    101 
    102     @Override
    103     public void onStart() {
    104         if (mPreference != null) {
    105             mContext.registerReceiver(mReceiver, AIRPLANE_INTENT_FILTER);
    106             clearSummaryForAirplaneMode();
    107             if (mWifiTetherSoftApManager != null) {
    108                 mWifiTetherSoftApManager.registerSoftApCallback();
    109             }
    110         }
    111     }
    112 
    113     @Override
    114     public void onStop() {
    115         if (mPreference != null) {
    116             mContext.unregisterReceiver(mReceiver);
    117             if (mWifiTetherSoftApManager != null) {
    118                 mWifiTetherSoftApManager.unRegisterSoftApCallback();
    119             }
    120         }
    121     }
    122 
    123     @VisibleForTesting
    124     void initWifiTetherSoftApManager() {
    125         // This manager only handles the number of connected devices, other parts are handled by
    126         // normal BroadcastReceiver in this controller
    127         mWifiTetherSoftApManager = new WifiTetherSoftApManager(mWifiManager,
    128                 new WifiTetherSoftApManager.WifiTetherSoftApCallback() {
    129                     @Override
    130                     public void onStateChanged(int state, int failureReason) {
    131                         mSoftApState = state;
    132                         handleWifiApStateChanged(state, failureReason);
    133                     }
    134 
    135                     @Override
    136                     public void onNumClientsChanged(int numClients) {
    137                         if (mPreference != null
    138                                 && mSoftApState == WifiManager.WIFI_AP_STATE_ENABLED) {
    139                             // Only show the number of clients when state is on
    140                             mPreference.setSummary(mContext.getResources().getQuantityString(
    141                                     R.plurals.wifi_tether_connected_summary, numClients,
    142                                     numClients));
    143                         }
    144                     }
    145                 });
    146     }
    147 
    148     //
    149     // Everything below is copied from WifiApEnabler
    150     //
    151     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    152         @Override
    153         public void onReceive(Context context, Intent intent) {
    154             String action = intent.getAction();
    155             if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
    156                 clearSummaryForAirplaneMode(R.string.wifi_hotspot_off_subtext);
    157             }
    158         }
    159     };
    160 
    161     @VisibleForTesting
    162     void handleWifiApStateChanged(int state, int reason) {
    163         switch (state) {
    164             case WifiManager.WIFI_AP_STATE_ENABLING:
    165                 mPreference.setSummary(R.string.wifi_tether_starting);
    166                 break;
    167             case WifiManager.WIFI_AP_STATE_ENABLED:
    168                 WifiConfiguration wifiConfig = mWifiManager.getWifiApConfiguration();
    169                 updateConfigSummary(wifiConfig);
    170                 break;
    171             case WifiManager.WIFI_AP_STATE_DISABLING:
    172                 mPreference.setSummary(R.string.wifi_tether_stopping);
    173                 break;
    174             case WifiManager.WIFI_AP_STATE_DISABLED:
    175                 mPreference.setSummary(R.string.wifi_hotspot_off_subtext);
    176                 clearSummaryForAirplaneMode();
    177                 break;
    178             default:
    179                 if (reason == WifiManager.SAP_START_FAILURE_NO_CHANNEL) {
    180                     mPreference.setSummary(R.string.wifi_sap_no_channel_error);
    181                 } else {
    182                     mPreference.setSummary(R.string.wifi_error);
    183                 }
    184                 clearSummaryForAirplaneMode();
    185         }
    186     }
    187 
    188     private void updateConfigSummary(WifiConfiguration wifiConfig) {
    189         final String s = mContext.getString(
    190                 com.android.internal.R.string.wifi_tether_configure_ssid_default);
    191 
    192         mPreference.setSummary(mContext.getString(R.string.wifi_tether_enabled_subtext,
    193                 BidiFormatter.getInstance().unicodeWrap(
    194                         (wifiConfig == null) ? s : wifiConfig.SSID)));
    195     }
    196 
    197     private void clearSummaryForAirplaneMode() {
    198         clearSummaryForAirplaneMode(ID_NULL);
    199     }
    200 
    201     private void clearSummaryForAirplaneMode(int defaultId) {
    202         boolean isAirplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
    203                 Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
    204         if (isAirplaneMode) {
    205             mPreference.setSummary(R.string.wifi_tether_disabled_by_airplane);
    206         } else if (defaultId != ID_NULL){
    207             mPreference.setSummary(defaultId);
    208         }
    209     }
    210     //
    211     // Everything above is copied from WifiApEnabler
    212     //
    213 }
    214