Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2018 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 package com.android.settings.widget;
     17 
     18 import android.app.AlertDialog;
     19 import android.content.Context;
     20 import android.content.DialogInterface;
     21 import android.net.wifi.WifiConfiguration;
     22 import android.os.Bundle;
     23 import android.os.Parcel;
     24 import android.os.Parcelable;
     25 import android.support.annotation.VisibleForTesting;
     26 import android.util.AttributeSet;
     27 import android.view.View;
     28 import android.widget.Button;
     29 import android.widget.CheckBox;
     30 import android.widget.CompoundButton;
     31 import android.widget.LinearLayout;
     32 
     33 import com.android.settings.R;
     34 import com.android.settingslib.CustomDialogPreference;
     35 
     36 import java.util.ArrayList;
     37 
     38 public class HotspotApBandSelectionPreference extends CustomDialogPreference implements
     39         CompoundButton.OnCheckedChangeListener, DialogInterface.OnShowListener {
     40     private static final int UNSET = Integer.MIN_VALUE;
     41 
     42     @VisibleForTesting
     43     static final String KEY_CHECKED_BANDS = "checked_bands";
     44     @VisibleForTesting
     45     static final String KEY_HOTSPOT_SUPER_STATE = "hotspot_super_state";
     46 
     47     @VisibleForTesting
     48     CheckBox mBox2G;
     49     @VisibleForTesting
     50     CheckBox mBox5G;
     51     @VisibleForTesting
     52     ArrayList<Integer> mRestoredBands;
     53     @VisibleForTesting
     54     boolean mShouldRestore;
     55 
     56     private String[] mBandEntries;
     57     private int mExistingConfigValue = UNSET;
     58 
     59     public HotspotApBandSelectionPreference(Context context) {
     60         super(context);
     61     }
     62 
     63     public HotspotApBandSelectionPreference(Context context, AttributeSet attrs) {
     64         super(context, attrs);
     65     }
     66 
     67     public HotspotApBandSelectionPreference(Context context, AttributeSet attrs, int defStyleAttr) {
     68         super(context, attrs, defStyleAttr);
     69     }
     70 
     71     public HotspotApBandSelectionPreference(Context context, AttributeSet attrs, int defStyleAttr,
     72             int defStyleRes) {
     73         super(context, attrs, defStyleAttr, defStyleRes);
     74     }
     75 
     76     @Override
     77     protected void onRestoreInstanceState(Parcelable state) {
     78         SavedState myState = (SavedState) state;
     79 
     80         super.onRestoreInstanceState(myState.getSuperState());
     81 
     82         mShouldRestore = myState.shouldRestore;
     83         if (mShouldRestore) {
     84             mRestoredBands = new ArrayList<>();
     85             if (myState.enabled2G) {
     86                 mRestoredBands.add(WifiConfiguration.AP_BAND_2GHZ);
     87             }
     88             if (myState.enabled5G) {
     89                 mRestoredBands.add(WifiConfiguration.AP_BAND_5GHZ);
     90             }
     91         } else {
     92             mRestoredBands = null;
     93         }
     94         updatePositiveButton();
     95     }
     96 
     97     @Override
     98     protected void onBindDialogView(View view) {
     99         super.onBindDialogView(view);
    100         final Context context = getContext();
    101 
    102         // Register so we can adjust the buttons if needed once the dialog is available.
    103         setOnShowListener(this);
    104 
    105         mBandEntries = context.getResources().getStringArray(R.array.wifi_ap_band_config_full);
    106         // add a checkbox for every band entry.
    107         addApBandViews((LinearLayout) view);
    108         // try to update the button just in case we already missed the onShow call.
    109         updatePositiveButton();
    110         // clear any saved state so it doesn't leak across multiple rotations/dialog closings
    111         mRestoredBands = null;
    112         mShouldRestore = false;
    113     }
    114 
    115     @Override
    116     protected Parcelable onSaveInstanceState() {
    117         final Parcelable superState = super.onSaveInstanceState();
    118 
    119         SavedState myState = new SavedState(superState);
    120         myState.shouldRestore = getDialog() != null;
    121         myState.enabled2G = mBox2G != null && mBox2G.isChecked();
    122         myState.enabled5G = mBox5G != null && mBox5G.isChecked();
    123         return myState;
    124     }
    125 
    126     @Override
    127     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    128         if (!(buttonView instanceof CheckBox)) {
    129             return;
    130         }
    131         updatePositiveButton();
    132     }
    133 
    134     @Override
    135     protected void onClick(DialogInterface dialog, int which) {
    136         // we only want to persist our enabled bands if apply is clicked
    137         if (which == DialogInterface.BUTTON_POSITIVE) {
    138             if (mBox2G.isChecked() || mBox5G.isChecked()) {
    139                 int wifiBand = getWifiBand();
    140                 mExistingConfigValue = wifiBand;
    141                 callChangeListener(wifiBand);
    142             }
    143         }
    144     }
    145 
    146     /**
    147      * Used to set the band selection for the preference if one already exists
    148      * @param band the band to set it to from {@link WifiConfiguration}
    149      */
    150     public void setExistingConfigValue(int band) {
    151         mExistingConfigValue = band;
    152     }
    153 
    154     private void addApBandViews(LinearLayout view) {
    155         mBox2G = view.findViewById(R.id.box_2g);
    156         mBox2G.setText(mBandEntries[WifiConfiguration.AP_BAND_2GHZ]);
    157         mBox2G.setChecked(restoreBandIfNeeded(WifiConfiguration.AP_BAND_2GHZ));
    158         mBox2G.setOnCheckedChangeListener(this);
    159 
    160         mBox5G = view.findViewById(R.id.box_5g);
    161         mBox5G.setText(mBandEntries[WifiConfiguration.AP_BAND_5GHZ]);
    162         mBox5G.setChecked(restoreBandIfNeeded(WifiConfiguration.AP_BAND_5GHZ));
    163         mBox5G.setOnCheckedChangeListener(this);
    164     }
    165 
    166     private boolean restoreBandIfNeeded(int band) {
    167         // Only use the provided config if we aren't restoring, restore if state available
    168         return (isBandPreviouslySelected(band) && !mShouldRestore)
    169                 || (mShouldRestore && mRestoredBands.contains(band));
    170     }
    171 
    172     private void updatePositiveButton() {
    173         AlertDialog dialog = (AlertDialog) getDialog();
    174         Button button = dialog == null ? null : dialog.getButton(DialogInterface.BUTTON_POSITIVE);
    175         if (button != null && mBox5G != null && mBox2G != null) {
    176             button.setEnabled(mBox2G.isChecked() || mBox5G.isChecked());
    177         }
    178     }
    179 
    180     @VisibleForTesting
    181     int getWifiBand() {
    182         final boolean checked_2g = mBox2G.isChecked();
    183         final boolean checked_5g = mBox5G.isChecked();
    184         if (checked_2g && checked_5g) {
    185             return WifiConfiguration.AP_BAND_ANY;
    186         } else if (checked_2g && !checked_5g) {
    187             return WifiConfiguration.AP_BAND_2GHZ;
    188         } else if (checked_5g && !checked_2g) {
    189             return WifiConfiguration.AP_BAND_5GHZ;
    190         } else {
    191             throw new IllegalStateException("Wifi Config only supports selecting one or all bands");
    192         }
    193     }
    194 
    195     private boolean isBandPreviouslySelected(int bandIndex) {
    196         switch(mExistingConfigValue) {
    197             case WifiConfiguration.AP_BAND_ANY:
    198                 return true;
    199             case WifiConfiguration.AP_BAND_2GHZ:
    200                 return bandIndex == 0;
    201             case WifiConfiguration.AP_BAND_5GHZ:
    202                 return bandIndex == 1;
    203             case UNSET:
    204             default:
    205                 return false;
    206         }
    207     }
    208 
    209     @Override
    210     public void onShow(DialogInterface dialog) {
    211         updatePositiveButton();
    212     }
    213 
    214     private static class SavedState extends BaseSavedState {
    215         boolean shouldRestore;
    216         boolean enabled2G;
    217         boolean enabled5G;
    218 
    219         public SavedState(Parcelable source) {
    220             super(source);
    221         }
    222 
    223         private SavedState(Parcel in) {
    224             super(in);
    225             shouldRestore =  in.readByte() == 1;
    226             enabled2G = in.readByte() == 1;
    227             enabled5G = in.readByte() == 1;
    228         }
    229 
    230         @Override
    231         public void writeToParcel(Parcel dest, int flags) {
    232             super.writeToParcel(dest, flags);
    233             dest.writeByte((byte) (shouldRestore ? 1 : 0));
    234             dest.writeByte((byte) (enabled2G ? 1: 0));
    235             dest.writeByte((byte) (enabled5G ? 1 : 0));
    236         }
    237 
    238         @Override
    239         public String toString() {
    240             return "HotspotApBandSelectionPreference.SavedState{"
    241                     + Integer.toHexString(System.identityHashCode(this))
    242                     + " shouldRestore=" + shouldRestore
    243                     + " enabled2G=" + enabled2G
    244                     + " enabled5G=" + enabled5G + "}";
    245         }
    246 
    247         public static final Parcelable.Creator<SavedState> CREATOR
    248                 = new Parcelable.Creator<SavedState>() {
    249             public SavedState createFromParcel(Parcel in) {
    250                 return new SavedState(in);
    251             }
    252 
    253             public SavedState[] newArray(int size) {
    254                 return new SavedState[size];
    255             }
    256         };
    257     }
    258 }
    259