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.Activity;
19import android.app.AlertDialog;
20import android.app.Dialog;
21import android.app.DialogFragment;
22import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.res.Resources;
28import android.net.ConnectivityManager;
29import android.net.NetworkInfo;
30import android.net.wifi.WifiManager;
31import android.os.Bundle;
32import android.preference.PreferenceFragment;
33import android.util.Log;
34
35import com.android.settings.ButtonBarHandler;
36import com.android.settings.R;
37import com.android.settings.SetupWizardUtils;
38import com.android.setupwizard.navigationbar.SetupWizardNavBar;
39import com.android.setupwizard.navigationbar.SetupWizardNavBar.NavigationBarListener;
40
41public class WifiSetupActivity extends WifiPickerActivity
42        implements ButtonBarHandler, NavigationBarListener {
43    private static final String TAG = "WifiSetupActivity";
44
45    // this boolean extra specifies whether to auto finish when connection is established
46    private static final String EXTRA_AUTO_FINISH_ON_CONNECT = "wifi_auto_finish_on_connect";
47
48    // This boolean extra specifies whether network is required
49    private static final String EXTRA_IS_NETWORK_REQUIRED = "is_network_required";
50
51    // This boolean extra specifies whether wifi is required
52    private static final String EXTRA_IS_WIFI_REQUIRED = "is_wifi_required";
53
54    // Whether auto finish is suspended until user connects to an access point
55    private static final String EXTRA_REQUIRE_USER_NETWORK_SELECTION =
56            "wifi_require_user_network_selection";
57
58    // Key for whether the user selected network in saved instance state bundle
59    private static final String PARAM_USER_SELECTED_NETWORK = "userSelectedNetwork";
60
61    // Activity result when pressing the Skip button
62    private static final int RESULT_SKIP = Activity.RESULT_FIRST_USER;
63
64    // Whether to auto finish when the user selected a network and successfully connected
65    private boolean mAutoFinishOnConnection;
66    // Whether network is required to proceed. This is decided in SUW and passed in as an extra.
67    private boolean mIsNetworkRequired;
68    // Whether wifi is required to proceed. This is decided in SUW and passed in as an extra.
69    private boolean mIsWifiRequired;
70    // Whether the user connected to a network. This excludes the auto-connecting by the system.
71    private boolean mUserSelectedNetwork;
72    // Whether the device is connected to WiFi
73    private boolean mWifiConnected;
74
75    private SetupWizardNavBar mNavigationBar;
76
77    private IntentFilter mFilter = new IntentFilter();
78    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
79        @Override
80        public void onReceive(Context context, Intent intent) {
81            // Refresh the connection state with the latest connection info. Use the connection info
82            // from ConnectivityManager instead of the one attached in the intent to make sure
83            // we have the most up-to-date connection state. b/17511772
84            refreshConnectionState();
85        }
86    };
87
88    @Override
89    protected void onCreate(Bundle savedInstanceState) {
90        super.onCreate(savedInstanceState);
91
92        final Intent intent = getIntent();
93        mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
94        mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
95
96        mAutoFinishOnConnection = intent.getBooleanExtra(EXTRA_AUTO_FINISH_ON_CONNECT, false);
97        mIsNetworkRequired = intent.getBooleanExtra(EXTRA_IS_NETWORK_REQUIRED, false);
98        mIsWifiRequired = intent.getBooleanExtra(EXTRA_IS_WIFI_REQUIRED, false);
99        // Behave like the user already selected a network if we do not require selection
100        mUserSelectedNetwork = !intent.getBooleanExtra(EXTRA_REQUIRE_USER_NETWORK_SELECTION, false);
101    }
102
103    @Override
104    protected void onSaveInstanceState(Bundle outState) {
105        super.onSaveInstanceState(outState);
106        outState.putBoolean(PARAM_USER_SELECTED_NETWORK, mUserSelectedNetwork);
107    }
108
109    @Override
110    protected void onRestoreInstanceState(Bundle savedInstanceState) {
111        super.onRestoreInstanceState(savedInstanceState);
112        mUserSelectedNetwork = savedInstanceState.getBoolean(PARAM_USER_SELECTED_NETWORK, true);
113    }
114
115    private boolean isWifiConnected() {
116        final ConnectivityManager connectivity = (ConnectivityManager)
117                getSystemService(Context.CONNECTIVITY_SERVICE);
118        boolean wifiConnected = connectivity != null &&
119                connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected();
120        mWifiConnected = wifiConnected;
121        return wifiConnected;
122    }
123
124    private void refreshConnectionState() {
125        if (isWifiConnected()) {
126            if (mAutoFinishOnConnection && mUserSelectedNetwork) {
127                Log.d(TAG, "Auto-finishing with connection");
128                finishOrNext(Activity.RESULT_OK);
129                // Require a user selection before auto-finishing next time we are here. The user
130                // can either connect to a different network or press "next" to proceed.
131                mUserSelectedNetwork = false;
132            }
133            setNextButtonText(R.string.setup_wizard_next_button_label);
134            setNextButtonEnabled(true);
135        } else if (mIsWifiRequired || (mIsNetworkRequired && !isNetworkConnected())) {
136            // We do not want the user to skip wifi setting if
137            // - wifi is required, but wifi connection hasn't been established yet;
138            // - or network is required, but no valid connection has been established.
139            setNextButtonText(R.string.skip_label);
140            setNextButtonEnabled(false);
141        } else {
142            // In other cases, user can choose to skip. Specifically these cases are
143            // - wifi is not required;
144            // - and network is not required;
145            // -     or network is required and a valid connection has been established.
146            setNextButtonText(R.string.skip_label);
147            setNextButtonEnabled(true);
148        }
149    }
150
151    private void setNextButtonEnabled(boolean enabled) {
152        if (mNavigationBar != null) {
153            mNavigationBar.getNextButton().setEnabled(enabled);
154        }
155    }
156
157    private void setNextButtonText(int resId) {
158        if (mNavigationBar != null) {
159            mNavigationBar.getNextButton().setText(resId);
160        }
161    }
162
163    /* package */ void networkSelected() {
164        Log.d(TAG, "Network selected by user");
165        mUserSelectedNetwork = true;
166    }
167
168    @Override
169    public void onResume() {
170        super.onResume();
171        registerReceiver(mReceiver, mFilter);
172        refreshConnectionState();
173    }
174
175    @Override
176    public void onPause() {
177        unregisterReceiver(mReceiver);
178        super.onPause();
179    }
180
181    @Override
182    protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
183        resid = SetupWizardUtils.getTheme(getIntent(), resid);
184        super.onApplyThemeResource(theme, resid, first);
185    }
186
187    @Override
188    protected boolean isValidFragment(String fragmentName) {
189        return WifiSettingsForSetupWizard.class.getName().equals(fragmentName);
190    }
191
192    @Override
193    /* package */ Class<? extends PreferenceFragment> getWifiSettingsClass() {
194        return WifiSettingsForSetupWizard.class;
195    }
196
197    /**
198     * Complete this activity and return the results to the caller. If using WizardManager, this
199     * will invoke the next scripted action; otherwise, we simply finish.
200     */
201    public void finishOrNext(int resultCode) {
202        Log.d(TAG, "finishOrNext resultCode=" + resultCode
203                + " isUsingWizardManager=" + SetupWizardUtils.isUsingWizardManager(this));
204        if (SetupWizardUtils.isUsingWizardManager(this)) {
205            SetupWizardUtils.sendResultsToSetupWizard(this, resultCode);
206        } else {
207            setResult(resultCode);
208            finish();
209        }
210    }
211
212    @Override
213    public void onNavigationBarCreated(final SetupWizardNavBar bar) {
214        mNavigationBar = bar;
215        SetupWizardUtils.setImmersiveMode(this, bar);
216    }
217
218    @Override
219    public void onNavigateBack() {
220        onBackPressed();
221    }
222
223    @Override
224    public void onNavigateNext() {
225        if (mWifiConnected) {
226            finishOrNext(RESULT_OK);
227        } else {
228            // Warn of possible data charges if there is a network connection, or lack of updates
229            // if there is none.
230            final int message = isNetworkConnected() ? R.string.wifi_skipped_message :
231                    R.string.wifi_and_mobile_skipped_message;
232            WifiSkipDialog.newInstance(message).show(getFragmentManager(), "dialog");
233        }
234    }
235
236    /**
237     * @return True if there is a valid network connection, whether it is via WiFi, mobile data or
238     *         other means.
239     */
240    private boolean isNetworkConnected() {
241        final ConnectivityManager connectivity = (ConnectivityManager)
242                getSystemService(Context.CONNECTIVITY_SERVICE);
243        if (connectivity == null) {
244            return false;
245        }
246        final NetworkInfo info = connectivity.getActiveNetworkInfo();
247        return info != null && info.isConnected();
248    }
249
250    public static class WifiSkipDialog extends DialogFragment {
251        public static WifiSkipDialog newInstance(int messageRes) {
252            final Bundle args = new Bundle();
253            args.putInt("messageRes", messageRes);
254            final WifiSkipDialog dialog = new WifiSkipDialog();
255            dialog.setArguments(args);
256            return dialog;
257        }
258
259        public WifiSkipDialog() {
260            // no-arg constructor for fragment
261        }
262
263        @Override
264        public Dialog onCreateDialog(Bundle savedInstanceState) {
265            int messageRes = getArguments().getInt("messageRes");
266            return new AlertDialog.Builder(getActivity())
267                    .setMessage(messageRes)
268                    .setCancelable(false)
269                    .setPositiveButton(R.string.wifi_skip_anyway,
270                            new DialogInterface.OnClickListener() {
271                        @Override
272                        public void onClick(DialogInterface dialog, int id) {
273                            WifiSetupActivity activity = (WifiSetupActivity) getActivity();
274                            activity.finishOrNext(RESULT_SKIP);
275                        }
276                    })
277                    .setNegativeButton(R.string.wifi_dont_skip,
278                            new DialogInterface.OnClickListener() {
279                        @Override
280                        public void onClick(DialogInterface dialog, int id) {
281                        }
282                    })
283                    .create();
284        }
285    }
286}
287