Home | History | Annotate | Download | only in setup
      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.tv.settings.connectivity.setup;
     18 
     19 import android.arch.lifecycle.ViewModelProviders;
     20 import android.content.Context;
     21 import android.net.wifi.WifiConfiguration;
     22 import android.os.Bundle;
     23 import android.support.annotation.NonNull;
     24 import android.support.v17.leanback.widget.GuidanceStylist;
     25 import android.support.v17.leanback.widget.GuidedAction;
     26 import android.support.v17.leanback.widget.GuidedActionsStylist;
     27 import android.support.v4.app.Fragment;
     28 import android.support.v4.app.FragmentActivity;
     29 import android.text.InputType;
     30 import android.view.LayoutInflater;
     31 import android.view.View;
     32 import android.view.ViewGroup;
     33 import android.widget.CheckBox;
     34 import android.widget.EditText;
     35 
     36 import com.android.settingslib.wifi.AccessPoint;
     37 import com.android.tv.settings.R;
     38 import com.android.tv.settings.connectivity.util.GuidedActionsAlignUtil;
     39 import com.android.tv.settings.connectivity.util.State;
     40 import com.android.tv.settings.connectivity.util.StateMachine;
     41 
     42 import java.util.List;
     43 
     44 /**
     45  * State responsible for entering the password.
     46  */
     47 public class EnterPasswordState implements State {
     48     private final FragmentActivity mActivity;
     49     private Fragment mFragment;
     50 
     51     public EnterPasswordState(FragmentActivity activity) {
     52         mActivity = activity;
     53     }
     54 
     55     @Override
     56     public void processForward() {
     57         mFragment = new EnterPasswordFragment();
     58         FragmentChangeListener listener = (FragmentChangeListener) mActivity;
     59         listener.onFragmentChange(mFragment, true);
     60     }
     61 
     62     @Override
     63     public void processBackward() {
     64         mFragment = new EnterPasswordFragment();
     65         FragmentChangeListener listener = (FragmentChangeListener) mActivity;
     66         listener.onFragmentChange(mFragment, false);
     67     }
     68 
     69     @Override
     70     public Fragment getFragment() {
     71         return mFragment;
     72     }
     73 
     74     /**
     75      * Fragment that enters password of the Wi-Fi.
     76      */
     77     public static class EnterPasswordFragment extends WifiConnectivityGuidedStepFragment {
     78         private static final int PSK_MIN_LENGTH = 8;
     79         private static final int WEP_MIN_LENGTH = 5;
     80         private UserChoiceInfo mUserChoiceInfo;
     81         private StateMachine mStateMachine;
     82         private EditText mTextInput;
     83         private CheckBox mCheckBox;
     84 
     85         @NonNull
     86         @Override
     87         public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
     88             String title = getString(
     89                     R.string.wifi_setup_input_password,
     90                     mUserChoiceInfo.getWifiConfiguration().getPrintableSsid());
     91             return new GuidanceStylist.Guidance(
     92                     title,
     93                     null,
     94                     null,
     95                     null);
     96         }
     97 
     98         @Override
     99         public GuidedActionsStylist onCreateActionsStylist() {
    100             return new GuidedActionsStylist() {
    101                 @Override
    102                 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    103                     LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    104                     View v = inflater.inflate(onProvideItemLayoutId(viewType), parent, false);
    105                     return new PasswordViewHolder(v);
    106                 }
    107 
    108                 @Override
    109                 public void onBindViewHolder(ViewHolder vh, GuidedAction action) {
    110                     super.onBindViewHolder(vh, action);
    111                     if (action.getId() == GuidedAction.ACTION_ID_CONTINUE) {
    112                         PasswordViewHolder viewHolder = (PasswordViewHolder) vh;
    113                         mTextInput = (EditText) viewHolder.getTitleView();
    114                         mCheckBox = viewHolder.mCheckbox;
    115                         mCheckBox.setOnClickListener(view -> {
    116                             updatePasswordInputObfuscation();
    117                             EnterPasswordFragment.this.openInEditMode(action);
    118                         });
    119                         mCheckBox.setChecked(mUserChoiceInfo.isPasswordHidden());
    120                         updatePasswordInputObfuscation();
    121                         openInEditMode(action);
    122                     }
    123                 }
    124 
    125                 @Override
    126                 public int onProvideItemLayoutId() {
    127                     return R.layout.setup_password_item;
    128                 }
    129             };
    130         }
    131 
    132         @Override
    133         public void onCreate(Bundle savedInstanceState) {
    134             mUserChoiceInfo = ViewModelProviders
    135                     .of(getActivity())
    136                     .get(UserChoiceInfo.class);
    137             mStateMachine = ViewModelProviders
    138                     .of(getActivity())
    139                     .get(StateMachine.class);
    140             super.onCreate(savedInstanceState);
    141         }
    142 
    143         @Override
    144         public void onCreateActions(@NonNull List<GuidedAction> actions,
    145                 Bundle savedInstanceState) {
    146             Context context = getActivity();
    147             CharSequence prevPassword = mUserChoiceInfo.getPageSummary(UserChoiceInfo.PASSWORD);
    148             boolean isPasswordHidden = mUserChoiceInfo.isPasswordHidden();
    149             actions.add(new GuidedAction.Builder(context)
    150                     .title(prevPassword == null ? "" : prevPassword)
    151                     .editInputType(InputType.TYPE_CLASS_TEXT
    152                             | (isPasswordHidden
    153                             ? InputType.TYPE_TEXT_VARIATION_PASSWORD
    154                             : InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD))
    155                     .id(GuidedAction.ACTION_ID_CONTINUE)
    156                     .editable(true)
    157                     .build());
    158         }
    159 
    160         @Override
    161         public long onGuidedActionEditedAndProceed(GuidedAction action) {
    162             if (action.getId() == GuidedAction.ACTION_ID_CONTINUE) {
    163                 String password = action.getTitle().toString();
    164                 if (password.length() >= WEP_MIN_LENGTH) {
    165                     mUserChoiceInfo.put(UserChoiceInfo.PASSWORD, action.getTitle().toString());
    166                     mUserChoiceInfo.setPasswordHidden(mCheckBox.isChecked());
    167                     setWifiConfigurationPassword(password);
    168                     mStateMachine.getListener().onComplete(StateMachine.OPTIONS_OR_CONNECT);
    169                 }
    170             }
    171             return action.getId();
    172         }
    173 
    174         private void updatePasswordInputObfuscation() {
    175             mTextInput.setInputType(InputType.TYPE_CLASS_TEXT
    176                     | (mCheckBox.isChecked()
    177                     ? InputType.TYPE_TEXT_VARIATION_PASSWORD
    178                     : InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD));
    179         }
    180 
    181         private void setWifiConfigurationPassword(String password) {
    182             int wifiSecurity = mUserChoiceInfo.getWifiSecurity();
    183             WifiConfiguration wifiConfiguration = mUserChoiceInfo.getWifiConfiguration();
    184             if (wifiSecurity == AccessPoint.SECURITY_WEP) {
    185                 int length = password.length();
    186                 // WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
    187                 if ((length == 10 || length == 26 || length == 32 || length == 58)
    188                         && password.matches("[0-9A-Fa-f]*")) {
    189                     wifiConfiguration.wepKeys[0] = password;
    190                 } else if (length == 5 || length == 13 || length == 16 || length == 29) {
    191                     wifiConfiguration.wepKeys[0] = '"' + password + '"';
    192                 }
    193             } else {
    194                 if (wifiSecurity == AccessPoint.SECURITY_PSK
    195                         && password.length() < PSK_MIN_LENGTH) {
    196                     return;
    197                 }
    198                 if (password.matches("[0-9A-Fa-f]{64}")) {
    199                     wifiConfiguration.preSharedKey = password;
    200                 } else {
    201                     wifiConfiguration.preSharedKey = '"' + password + '"';
    202                 }
    203             }
    204         }
    205 
    206         private static class PasswordViewHolder extends GuidedActionsAlignUtil.SetupViewHolder {
    207             CheckBox mCheckbox;
    208 
    209             PasswordViewHolder(View v) {
    210                 super(v);
    211                 mCheckbox = v.findViewById(R.id.password_checkbox);
    212             }
    213         }
    214     }
    215 }
    216