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  */
16 package com.android.settings.wifi;
17 
18 import android.app.Activity;
19 import android.app.AlertDialog;
20 import android.app.Dialog;
21 import android.app.DialogFragment;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.res.Resources;
28 import android.net.ConnectivityManager;
29 import android.net.NetworkInfo;
30 import android.net.wifi.WifiManager;
31 import android.os.Bundle;
32 import android.preference.PreferenceFragment;
33 import android.util.Log;
34 
35 import com.android.settings.ButtonBarHandler;
36 import com.android.settings.R;
37 import com.android.settings.SetupWizardUtils;
38 import com.android.setupwizard.navigationbar.SetupWizardNavBar;
39 import com.android.setupwizard.navigationbar.SetupWizardNavBar.NavigationBarListener;
40 
41 public 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
onCreate(Bundle savedInstanceState)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
onSaveInstanceState(Bundle outState)104     protected void onSaveInstanceState(Bundle outState) {
105         super.onSaveInstanceState(outState);
106         outState.putBoolean(PARAM_USER_SELECTED_NETWORK, mUserSelectedNetwork);
107     }
108 
109     @Override
onRestoreInstanceState(Bundle savedInstanceState)110     protected void onRestoreInstanceState(Bundle savedInstanceState) {
111         super.onRestoreInstanceState(savedInstanceState);
112         mUserSelectedNetwork = savedInstanceState.getBoolean(PARAM_USER_SELECTED_NETWORK, true);
113     }
114 
isWifiConnected()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 
refreshConnectionState()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 
setNextButtonEnabled(boolean enabled)151     private void setNextButtonEnabled(boolean enabled) {
152         if (mNavigationBar != null) {
153             mNavigationBar.getNextButton().setEnabled(enabled);
154         }
155     }
156 
setNextButtonText(int resId)157     private void setNextButtonText(int resId) {
158         if (mNavigationBar != null) {
159             mNavigationBar.getNextButton().setText(resId);
160         }
161     }
162 
networkSelected()163     /* package */ void networkSelected() {
164         Log.d(TAG, "Network selected by user");
165         mUserSelectedNetwork = true;
166     }
167 
168     @Override
onResume()169     public void onResume() {
170         super.onResume();
171         registerReceiver(mReceiver, mFilter);
172         refreshConnectionState();
173     }
174 
175     @Override
onPause()176     public void onPause() {
177         unregisterReceiver(mReceiver);
178         super.onPause();
179     }
180 
181     @Override
onApplyThemeResource(Resources.Theme theme, int resid, boolean first)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
isValidFragment(String fragmentName)188     protected boolean isValidFragment(String fragmentName) {
189         return WifiSettingsForSetupWizard.class.getName().equals(fragmentName);
190     }
191 
192     @Override
getWifiSettingsClass()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      */
finishOrNext(int resultCode)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
onNavigationBarCreated(final SetupWizardNavBar bar)213     public void onNavigationBarCreated(final SetupWizardNavBar bar) {
214         mNavigationBar = bar;
215         SetupWizardUtils.setImmersiveMode(this, bar);
216     }
217 
218     @Override
onNavigateBack()219     public void onNavigateBack() {
220         onBackPressed();
221     }
222 
223     @Override
onNavigateNext()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      */
isNetworkConnected()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 {
newInstance(int messageRes)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 
WifiSkipDialog()259         public WifiSkipDialog() {
260             // no-arg constructor for fragment
261         }
262 
263         @Override
onCreateDialog(Bundle savedInstanceState)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