1/*
2 * Copyright (C) 2012 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 */
16package com.android.settings.wifi;
17
18import android.app.AlertDialog;
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.net.NetworkInfo;
24import android.net.NetworkInfo.DetailedState;
25import android.net.wifi.WifiInfo;
26import android.net.wifi.WifiManager;
27import android.net.wifi.WpsInfo;
28import android.os.Bundle;
29import android.os.Handler;
30import android.view.View;
31import android.widget.Button;
32import android.widget.ProgressBar;
33import android.widget.TextView;
34
35import com.android.settings.R;
36
37import java.util.Timer;
38import java.util.TimerTask;
39
40
41/**
42 * Dialog to show WPS progress.
43 */
44public class WpsDialog extends AlertDialog {
45
46    private final static String TAG = "WpsDialog";
47    private static final String DIALOG_STATE = "android:dialogState";
48    private static final String DIALOG_MSG_STRING = "android:dialogMsg";
49
50    private View mView;
51    private TextView mTextView;
52    private ProgressBar mTimeoutBar;
53    private ProgressBar mProgressBar;
54    private Button mButton;
55    private Timer mTimer;
56
57    private static final int WPS_TIMEOUT_S = 120;
58
59    private WifiManager mWifiManager;
60    private WifiManager.WpsCallback mWpsListener;
61    private int mWpsSetup;
62
63    private final IntentFilter mFilter;
64    private BroadcastReceiver mReceiver;
65
66    private Context mContext;
67    private Handler mHandler = new Handler();
68    private String mMsgString = "";
69
70    private enum DialogState {
71        WPS_INIT,
72        WPS_START,
73        WPS_COMPLETE,
74        CONNECTED, //WPS + IP config is done
75        WPS_FAILED
76    }
77    DialogState mDialogState = DialogState.WPS_INIT;
78
79    public WpsDialog(Context context, int wpsSetup) {
80        super(context);
81        mContext = context;
82        mWpsSetup = wpsSetup;
83
84        class WpsListener extends WifiManager.WpsCallback {
85
86            public void onStarted(String pin) {
87                if (pin != null) {
88                    updateDialog(DialogState.WPS_START, String.format(
89                            mContext.getString(R.string.wifi_wps_onstart_pin), pin));
90                } else {
91                    updateDialog(DialogState.WPS_START, mContext.getString(
92                            R.string.wifi_wps_onstart_pbc));
93                }
94            }
95
96            public void onSucceeded() {
97                updateDialog(DialogState.WPS_COMPLETE,
98                        mContext.getString(R.string.wifi_wps_complete));
99            }
100
101            public void onFailed(int reason) {
102                String msg;
103                switch (reason) {
104                    case WifiManager.WPS_OVERLAP_ERROR:
105                        msg = mContext.getString(R.string.wifi_wps_failed_overlap);
106                        break;
107                    case WifiManager.WPS_WEP_PROHIBITED:
108                        msg = mContext.getString(R.string.wifi_wps_failed_wep);
109                        break;
110                    case WifiManager.WPS_TKIP_ONLY_PROHIBITED:
111                        msg = mContext.getString(R.string.wifi_wps_failed_tkip);
112                        break;
113                    case WifiManager.IN_PROGRESS:
114                        msg = mContext.getString(R.string.wifi_wps_in_progress);
115                        break;
116                    default:
117                        msg = mContext.getString(R.string.wifi_wps_failed_generic);
118                        break;
119                }
120                updateDialog(DialogState.WPS_FAILED, msg);
121            }
122        }
123
124        mWpsListener = new WpsListener();
125
126
127        mFilter = new IntentFilter();
128        mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
129        mReceiver = new BroadcastReceiver() {
130            @Override
131            public void onReceive(Context context, Intent intent) {
132                handleEvent(context, intent);
133            }
134        };
135        setCanceledOnTouchOutside(false);
136    }
137
138    @Override
139    public Bundle onSaveInstanceState () {
140        Bundle bundle  = super.onSaveInstanceState();
141        bundle.putString(DIALOG_STATE, mDialogState.toString());
142        bundle.putString(DIALOG_MSG_STRING, mMsgString.toString());
143        return bundle;
144    }
145
146    @Override
147    public void onRestoreInstanceState(Bundle savedInstanceState) {
148        if (savedInstanceState != null) {
149            super.onRestoreInstanceState(savedInstanceState);
150            DialogState dialogState = mDialogState.valueOf(savedInstanceState.getString(DIALOG_STATE));
151            String msg = savedInstanceState.getString(DIALOG_MSG_STRING);
152            updateDialog(dialogState, msg);
153        }
154    }
155
156    @Override
157    protected void onCreate(Bundle savedInstanceState) {
158        mView = getLayoutInflater().inflate(R.layout.wifi_wps_dialog, null);
159
160        mTextView = (TextView) mView.findViewById(R.id.wps_dialog_txt);
161        mTextView.setText(R.string.wifi_wps_setup_msg);
162
163        mTimeoutBar = ((ProgressBar) mView.findViewById(R.id.wps_timeout_bar));
164        mTimeoutBar.setMax(WPS_TIMEOUT_S);
165        mTimeoutBar.setProgress(0);
166
167        mProgressBar = ((ProgressBar) mView.findViewById(R.id.wps_progress_bar));
168        mProgressBar.setVisibility(View.GONE);
169
170        mButton = ((Button) mView.findViewById(R.id.wps_dialog_btn));
171        mButton.setText(R.string.wifi_cancel);
172        mButton.setOnClickListener(new View.OnClickListener() {
173            @Override
174            public void onClick(View v) {
175                dismiss();
176            }
177        });
178
179        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
180
181        setView(mView);
182        if (savedInstanceState == null) {
183            WpsInfo wpsConfig = new WpsInfo();
184            wpsConfig.setup = mWpsSetup;
185            mWifiManager.startWps(wpsConfig, mWpsListener);
186        }
187        super.onCreate(savedInstanceState);
188    }
189
190    @Override
191    protected void onStart() {
192        /*
193         * increment timeout bar per second.
194         */
195        mTimer = new Timer(false);
196        mTimer.schedule(new TimerTask() {
197            @Override
198            public void run() {
199                mHandler.post(new Runnable() {
200
201                    @Override
202                    public void run() {
203                        mTimeoutBar.incrementProgressBy(1);
204                    }
205                });
206            }
207        }, 1000, 1000);
208
209        mContext.registerReceiver(mReceiver, mFilter);
210
211    }
212
213    @Override
214    protected void onStop() {
215        if (mDialogState != DialogState.WPS_COMPLETE) {
216            mWifiManager.cancelWps(null);
217        }
218
219        if (mReceiver != null) {
220            mContext.unregisterReceiver(mReceiver);
221            mReceiver = null;
222        }
223
224        if (mTimer != null) {
225            mTimer.cancel();
226        }
227    }
228
229    private void updateDialog(final DialogState state, final String msg) {
230        if (mDialogState.ordinal() >= state.ordinal()) {
231            //ignore.
232            return;
233        }
234        mDialogState = state;
235        mMsgString = msg;
236
237        mHandler.post(new Runnable() {
238                @Override
239                public void run() {
240                    switch(state) {
241                        case WPS_COMPLETE:
242                            mTimeoutBar.setVisibility(View.GONE);
243                            mProgressBar.setVisibility(View.VISIBLE);
244                            break;
245                        case CONNECTED:
246                        case WPS_FAILED:
247                            mButton.setText(mContext.getString(R.string.dlg_ok));
248                            mTimeoutBar.setVisibility(View.GONE);
249                            mProgressBar.setVisibility(View.GONE);
250                            if (mReceiver != null) {
251                                mContext.unregisterReceiver(mReceiver);
252                                mReceiver = null;
253                            }
254                            break;
255                    }
256                    mTextView.setText(msg);
257                }
258            });
259   }
260
261    private void handleEvent(Context context, Intent intent) {
262        String action = intent.getAction();
263        if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
264            NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
265                    WifiManager.EXTRA_NETWORK_INFO);
266            final NetworkInfo.DetailedState state = info.getDetailedState();
267            if (state == DetailedState.CONNECTED &&
268                    mDialogState == DialogState.WPS_COMPLETE) {
269                WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
270                if (wifiInfo != null) {
271                    String msg = String.format(mContext.getString(
272                            R.string.wifi_wps_connected), wifiInfo.getSSID());
273                    updateDialog(DialogState.CONNECTED, msg);
274                }
275            }
276        }
277    }
278
279}
280