Add Wifi Setup screen for Setup Wizard with XL size screen.

* Add WifiSettingsForSetupWizardXL as a new Activity
The activity has WifiSettings fragment in it. It also contains
several buttons, texts around the fragment.

* Making configuration UI part of Preference list.
In Wifi Setup for Setup Wizard XL, WifiSettings fragment lets
a UI for configuring access points shown inside a
PregerenceCategory object, while it has been shown as Dialog.

To achieve this action, WifiDialog is decomposed into two parts:
- WifiConfigUiBase (Mainly UI part)
- WifiConfigController (Mainly Wifi controller part)

All codes for wifi configuration in WifiDialog is now in
WifiConfigController, which is reused from
WifiConfigPreference.

* Misc stuff
- Remove AccessPoint#compareTo(). Instead,
  AccessPoint.AccessPointComparater should be used when needed.

Change-Id: I520d690d3301837d32f91dad54a973a379ce1989
This commit is contained in:
Daisuke Miyakawa
2010-08-27 10:04:08 -07:00
parent 0b4dc9fd6f
commit d36699282c
18 changed files with 1537 additions and 426 deletions

View File

@@ -99,6 +99,11 @@
</intent-filter> </intent-filter>
</activity-alias> </activity-alias>
<activity android:name=".wifi.WifiSettingsForSetupWizardXL"
android:clearTaskOnLaunch="true"
android:screenOrientation="landscape"
android:exported="true" />
<activity android:name=".wifi.AdvancedSettings" <activity android:name=".wifi.AdvancedSettings"
android:label="@string/wifi_ip_settings_titlebar" android:label="@string/wifi_ip_settings_titlebar"
> >

View File

@@ -3,4 +3,4 @@
-keep class com.android.settings.*Picker -keep class com.android.settings.*Picker
-keep class com.android.settings.*Settings -keep class com.android.settings.*Settings
-keep class com.android.settings.wifi.*Settings -keep class com.android.settings.wifi.*Settings
-keep class com.android.settings.deviceinfo.* -keep class com.android.settings.deviceinfo.*

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2006 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
<LinearLayout android:id="@+android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical" />
</LinearLayout>

View File

@@ -0,0 +1,149 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingTop="70dip"
android:paddingBottom="80dip"
android:paddingLeft="60dip"
android:paddingRight="60dip">
<!-- Left: almost empty with one title at the top -->
<RelativeLayout
android:orientation="vertical"
android:layout_width="0px"
android:layout_weight=".3"
android:layout_height="fill_parent"
android:paddingRight="10dip"
android:paddingBottom="10dip">
<TextView
android:id="@+id/wifi_setup_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center|top"
android:textSize="48dip"
android:textColor="#FF30FF30"
android:text="@string/wifi_setup_title"/>
<Button
android:id="@+id/wifi_setup_cancel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:textSize="24dip"
android:text="@string/wifi_cancel"
android:visibility="gone" />
</RelativeLayout>
<!-- Center: Full of fragment -->
<LinearLayout
android:orientation="vertical"
android:layout_width="0px"
android:layout_weight=".4"
android:layout_height="fill_parent"
android:paddingTop="20dip"
android:paddingLeft="10dip"
android:paddingRight="30dip"
android:paddingBottom="15dip">
<!-- Assume the text size of this text should be same as Preference's
texts. See also preference.xml -->
<TextView
android:id="@+id/wifi_setup_status"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#ff113344"
android:paddingLeft="5dip"
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:layout_marginBottom="20dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/wifi_setup_status_select_network"/>
<fragment
class="com.android.settings.wifi.WifiSettings"
android:id="@+id/wifi_setup_fragment"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- Right: various information -->
<RelativeLayout
android:orientation="vertical"
android:layout_width="0px"
android:layout_weight=".3"
android:layout_height="fill_parent"
android:paddingTop="22dip"
android:paddingLeft="30dip"
android:paddingBottom="10dip">
<TextView
android:id="@+id/scanning_progress_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:textSize="24dip"
android:text="@string/progress_scanning"/>
<ProgressBar
android:id="@+id/scanning_progress_bar"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_below="@id/scanning_progress_text"
style="?android:attr/progressBarStyleHorizontal" />
<Button
android:id="@+id/wifi_setup_connect"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:textSize="24dip"
android:text="@string/wifi_connect"
android:visibility="gone" />
<Button
android:id="@+id/wifi_setup_forget"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:textSize="24dip"
android:text="@string/wifi_forget"
android:visibility="gone" />
<Button
android:id="@+id/wifi_setup_skip_or_next"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dip"
android:layout_alignParentBottom="true"
android:textSize="24dip"
android:text="@string/wifi_setup_skip" />
<Button
android:id="@+id/wifi_setup_refresh_list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@id/wifi_setup_skip_or_next"
android:textSize="24dip"
android:text="@string/wifi_setup_refresh_list" />
<Button
android:id="@+id/wifi_setup_add_network"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@id/wifi_setup_refresh_list"
android:textSize="24dip"
android:text="@string/wifi_setup_add_network" />
</RelativeLayout>
</LinearLayout>

View File

@@ -0,0 +1,151 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- All ids in this layout must be in wifi_dialog.xml -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- <TextView android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/title" /> -->
<LinearLayout android:id="@+id/info"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<LinearLayout android:id="@+id/type"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/wifi_ssid" />
<EditText android:id="@+id/ssid"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:inputType="textNoSuggestions" />
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/wifi_security" />
<Spinner android:id="@+id/security"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:prompt="@string/wifi_security"
android:entries="@array/wifi_security" />
</LinearLayout> <!-- android:id="@+id/type" -->
<LinearLayout android:id="@+id/fields"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<LinearLayout android:id="@+id/eap"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/wifi_eap_method" />
<Spinner android:id="@+id/method"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:prompt="@string/wifi_eap_method"
android:entries="@array/wifi_eap_method" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/please_select_phase2" />
<Spinner android:id="@+id/phase2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:prompt="@string/please_select_phase2"
android:entries="@array/wifi_phase2_entries" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/wifi_eap_ca_cert" />
<Spinner android:id="@+id/ca_cert"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:prompt="@string/wifi_eap_ca_cert" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/wifi_eap_user_cert" />
<Spinner android:id="@+id/user_cert"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:prompt="@string/wifi_eap_user_cert" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/wifi_eap_identity" />
<EditText android:id="@+id/identity"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:inputType="textNoSuggestions" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/wifi_eap_anonymous" />
<EditText android:id="@+id/anonymous"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:inputType="textNoSuggestions" />
</LinearLayout> <!-- android:id="@+id/eap" -->
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/wifi_password" />
<EditText android:id="@+id/password"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:password="true" />
<CheckBox android:id="@+id/show_password"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/wifi_show_password" />
</LinearLayout> <!-- android:id="@+id/fields" -->
</LinearLayout>

View File

@@ -2644,4 +2644,42 @@ found in the list of installed applications.</string>
<string name="sound_category_calls_title">Incoming calls</string> <string name="sound_category_calls_title">Incoming calls</string>
<string name="sound_category_notification_title">Notifications</string> <string name="sound_category_notification_title">Notifications</string>
<string name="sound_category_feedback_title">Feedback</string> <string name="sound_category_feedback_title">Feedback</string>
<!-- Wifi Setup For Setup Wizard with XL screen -->
<!-- Title shown in Wifi Setup For Setup Wizard with XL screen -->
<string name="wifi_setup_title">WiFi setup</string>
<!-- Text message shown when Wifi is not connected.
Used in Wifi Setup For Setup Wizard with XL screen. -->
<string name="wifi_setup_not_connected">Not connected</string>
<!-- Button message shown on the button adding manual setting.
Used in Wifi Setup For Setup Wizard with XL screen. -->
<string name="wifi_setup_add_network">Add network</string>
<!-- Button message shown on the button refreshing a list of network.
Used in Wifi Setup For Setup Wizard with XL screen. -->
<string name="wifi_setup_refresh_list">Refresh list</string>
<!-- Button message shown on the button enabling users skip Wifi Setup.
Used in Wifi Setup For Setup Wizard with XL screen. -->
<string name="wifi_setup_skip">Skip</string>
<!-- Button message shown on the button enabling users go the next step.
Used in Wifi Setup For Setup Wizard with XL screen. -->
<string name="wifi_setup_next">Next</string>
<!-- Message shown above available network when there's no connected network.
Used in Wifi Setup For Setup Wizard with XL screen. -->
<string name="wifi_setup_status_select_network">Touch to select network</string>
<!-- Message shown above available networks when a user clicked one of available
networks and the UI is showing one possible existing network.
Used in Wifi Setup For Setup Wizard with XL screen. -->
<string name="wifi_setup_status_existing_network">Connect to existing network</string>
<!-- The message shown above available networks when a user clicked "Add network"
button. Used in Wifi Setup For Setup Wizard with XL screen. -->
<string name="wifi_setup_status_new_network">Connect to new network</string>
<!-- The message shown above available networks when a user clicked one of available
networks or created another profile and he/she is waiting for the connection
is established.
Used in Wifi Setup For Setup Wizard with XL screen. -->
<string name="wifi_setup_status_connecting">Connecting...</string>
<!-- The message show above available networks when connection is established.
Used in Wifi Setup For Setup Wizard with XL screen. -->
<string name="wifi_setup_status_connected">Connected</string>
</resources> </resources>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<com.android.settings.wifi.AccessPointCategoryForSetupWizardXL
android:key="access_points"
android:persistent="false" />
</PreferenceScreen>

View File

@@ -21,9 +21,7 @@ import android.preference.PreferenceCategory;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import java.util.Map; public class ProgressCategory extends ProgressCategoryBase {
public class ProgressCategory extends PreferenceCategory {
private boolean mProgress = false; private boolean mProgress = false;
private View oldView = null; private View oldView = null;
@@ -36,10 +34,10 @@ public class ProgressCategory extends PreferenceCategory {
@Override @Override
public void onBindView(View view) { public void onBindView(View view) {
super.onBindView(view); super.onBindView(view);
View textView = view.findViewById(R.id.scanning_text); final View textView = view.findViewById(R.id.scanning_text);
View progressBar = view.findViewById(R.id.scanning_progress); final View progressBar = view.findViewById(R.id.scanning_progress);
int visibility = mProgress ? View.VISIBLE : View.INVISIBLE; final int visibility = mProgress ? View.VISIBLE : View.INVISIBLE;
textView.setVisibility(visibility); textView.setVisibility(visibility);
progressBar.setVisibility(visibility); progressBar.setVisibility(visibility);
@@ -50,11 +48,8 @@ public class ProgressCategory extends PreferenceCategory {
} }
oldView = view; oldView = view;
} }
/** @Override
* Turn on/off the progress indicator and text on the right.
* @param progressOn whether or not the progress should be displayed
*/
public void setProgress(boolean progressOn) { public void setProgress(boolean progressOn) {
mProgress = progressOn; mProgress = progressOn;
notifyChanged(); notifyChanged();

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings;
import android.content.Context;
import android.preference.PreferenceCategory;
import android.util.AttributeSet;
public abstract class ProgressCategoryBase extends PreferenceCategory {
public ProgressCategoryBase(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* Turn on/off the progress indicator and text on the right.
* @param progressOn whether or not the progress should be displayed
*/
public abstract void setProgress(boolean progressOn);
}

View File

@@ -16,24 +16,53 @@
package com.android.settings.wifi; package com.android.settings.wifi;
import com.android.settings.R;
import android.content.Context; import android.content.Context;
import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.DetailedState;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiInfo; import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.net.wifi.ScanResult;
import android.preference.Preference; import android.preference.Preference;
import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import com.android.settings.R;
import java.util.Comparator;
class AccessPoint extends Preference { class AccessPoint extends Preference {
private static final int[] STATE_SECURED = {R.attr.state_encrypted}; private static final int[] STATE_SECURED = {R.attr.state_encrypted};
private static final int[] STATE_NONE = {}; private static final int[] STATE_NONE = {};
public static final class Comparater
implements Comparator<AccessPoint> {
@Override
public int compare(AccessPoint accessPoint1, AccessPoint accessPoint2) {
// Active one goes first.
if (accessPoint1.mInfo != accessPoint2.mInfo) {
return (accessPoint1.mInfo != null) ? -1 : 1;
}
// Reachable one goes before unreachable one.
if ((accessPoint1.mRssi ^ accessPoint2.mRssi) < 0) {
return (accessPoint1.mRssi != Integer.MAX_VALUE) ? -1 : 1;
}
// Configured one goes before unconfigured one.
if ((accessPoint1.networkId ^ accessPoint2.networkId) < 0) {
return (accessPoint1.networkId != -1) ? -1 : 1;
}
// Sort by signal strength.
int difference = WifiManager.compareSignalLevel(
accessPoint2.mRssi, accessPoint1.mRssi);
if (difference != 0) {
return difference;
}
// Sort by ssid.
return accessPoint1.ssid.compareToIgnoreCase(accessPoint2.ssid);
}
}
static final int SECURITY_NONE = 0; static final int SECURITY_NONE = 0;
static final int SECURITY_WEP = 1; static final int SECURITY_WEP = 1;
static final int SECURITY_PSK = 2; static final int SECURITY_PSK = 2;
@@ -105,32 +134,6 @@ class AccessPoint extends Preference {
super.onBindView(view); super.onBindView(view);
} }
@Override
public int compareTo(Preference preference) {
if (!(preference instanceof AccessPoint)) {
return 1;
}
AccessPoint other = (AccessPoint) preference;
// Active one goes first.
if (mInfo != other.mInfo) {
return (mInfo != null) ? -1 : 1;
}
// Reachable one goes before unreachable one.
if ((mRssi ^ other.mRssi) < 0) {
return (mRssi != Integer.MAX_VALUE) ? -1 : 1;
}
// Configured one goes before unconfigured one.
if ((networkId ^ other.networkId) < 0) {
return (networkId != -1) ? -1 : 1;
}
// Sort by signal strength.
int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi);
if (difference != 0) {
return difference;
}
// Sort by ssid.
return ssid.compareToIgnoreCase(other.ssid);
}
boolean update(ScanResult result) { boolean update(ScanResult result) {
// We do not call refresh() since this is called before onBindView(). // We do not call refresh() since this is called before onBindView().

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.wifi;
import android.content.Context;
import android.util.AttributeSet;
import com.android.settings.ProgressCategoryBase;
import com.android.settings.R;
public class AccessPointCategoryForSetupWizardXL extends ProgressCategoryBase {
public AccessPointCategoryForSetupWizardXL(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.access_point_category_for_setup_wizard_xl);
}
@Override
public void setProgress(boolean progressOn) {
notifyChanged();
}
}

View File

@@ -16,11 +16,10 @@
package com.android.settings.wifi; package com.android.settings.wifi;
import com.android.settings.R;
import android.content.Context; import android.content.Context;
import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.DetailedState;
import android.text.TextUtils;
import com.android.settings.R;
class Summary { class Summary {
static String get(Context context, String ssid, DetailedState state) { static String get(Context context, String ssid, DetailedState state) {

View File

@@ -0,0 +1,369 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.wifi;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.net.NetworkInfo.DetailedState;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.AuthAlgorithm;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiInfo;
import android.security.Credentials;
import android.security.KeyStore;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.text.format.Formatter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.Spinner;
import android.widget.TextView;
import com.android.settings.R;
/**
* The class for allowing UIs like {@link WifiDialog} and {@link WifiConfigPreference} to
* share the logic for controlling buttons, text fields, etc.
*/
public class WifiConfigController implements TextWatcher,
View.OnClickListener, AdapterView.OnItemSelectedListener {
private static final String KEYSTORE_SPACE = "keystore://";
private final WifiConfigUiBase mConfigUi;
private final View mView;
private final AccessPoint mAccessPoint;
private boolean mEdit;
private TextView mSsid;
// e.g. AccessPoint.SECURITY_NONE
private int mSecurityType;
private TextView mPasswordView;
private Spinner mEapMethod;
private Spinner mEapCaCert;
private Spinner mPhase2;
private Spinner mEapUserCert;
private TextView mEapIdentity;
private TextView mEapAnonymous;
static boolean requireKeyStore(WifiConfiguration config) {
String values[] = {config.ca_cert.value(), config.client_cert.value(),
config.private_key.value()};
for (String value : values) {
if (value != null && value.startsWith(KEYSTORE_SPACE)) {
return true;
}
}
return false;
}
public WifiConfigController(WifiConfigUiBase parent, View view, AccessPoint accessPoint,
boolean edit, DialogInterface.OnClickListener listener) {
mConfigUi = parent;
mView = view;
mAccessPoint = accessPoint;
mSecurityType = (accessPoint == null) ? AccessPoint.SECURITY_NONE : accessPoint.security;
mEdit = edit;
final Context context = mConfigUi.getContext();
final Resources resources = context.getResources();
if (mAccessPoint == null) {
mConfigUi.setTitle(R.string.wifi_add_network);
mView.findViewById(R.id.type).setVisibility(View.VISIBLE);
mSsid = (TextView) mView.findViewById(R.id.ssid);
mSsid.addTextChangedListener(this);
((Spinner) mView.findViewById(R.id.security)).setOnItemSelectedListener(this);
mConfigUi.setSubmitButton(context.getString(R.string.wifi_save));
} else {
mConfigUi.setTitle(mAccessPoint.ssid);
ViewGroup group = (ViewGroup) mView.findViewById(R.id.info);
DetailedState state = mAccessPoint.getState();
if (state != null) {
addRow(group, R.string.wifi_status, Summary.get(mConfigUi.getContext(), state));
}
String[] type = resources.getStringArray(R.array.wifi_security);
addRow(group, R.string.wifi_security, type[mAccessPoint.security]);
int level = mAccessPoint.getLevel();
if (level != -1) {
String[] signal = resources.getStringArray(R.array.wifi_signal);
addRow(group, R.string.wifi_signal, signal[level]);
}
WifiInfo info = mAccessPoint.getInfo();
if (info != null) {
addRow(group, R.string.wifi_speed, info.getLinkSpeed() + WifiInfo.LINK_SPEED_UNITS);
// TODO: fix the ip address for IPv6.
int address = info.getIpAddress();
if (address != 0) {
addRow(group, R.string.wifi_ip_address, Formatter.formatIpAddress(address));
}
}
if (mAccessPoint.networkId == -1 || mEdit) {
showSecurityFields();
}
if (mEdit) {
mConfigUi.setSubmitButton(context.getString(R.string.wifi_save));
} else {
if (state == null && level != -1) {
mConfigUi.setSubmitButton(context.getString(R.string.wifi_connect));
}
if (mAccessPoint.networkId != -1) {
mConfigUi.setForgetButton(context.getString(R.string.wifi_forget));
}
}
}
mConfigUi.setCancelButton(context.getString(R.string.wifi_cancel));
if (mConfigUi.getSubmitButton() != null) {
enableSubmitIfAppropriate();
}
}
private void addRow(ViewGroup group, int name, String value) {
View row = mConfigUi.getLayoutInflater().inflate(R.layout.wifi_dialog_row, group, false);
((TextView) row.findViewById(R.id.name)).setText(name);
((TextView) row.findViewById(R.id.value)).setText(value);
group.addView(row);
}
private void enableSubmitIfAppropriate() {
// TODO: make sure this is complete.
if ((mSsid != null && mSsid.length() == 0) ||
((mAccessPoint == null || mAccessPoint.networkId == -1) &&
((mSecurityType == AccessPoint.SECURITY_WEP && mPasswordView.length() == 0) ||
(mSecurityType == AccessPoint.SECURITY_PSK && mPasswordView.length() < 8)))) {
mConfigUi.getSubmitButton().setEnabled(false);
} else {
mConfigUi.getSubmitButton().setEnabled(true);
}
}
/* package */ WifiConfiguration getConfig() {
if (mAccessPoint != null && mAccessPoint.networkId != -1 && !mEdit) {
return null;
}
WifiConfiguration config = new WifiConfiguration();
if (mAccessPoint == null) {
config.SSID = AccessPoint.convertToQuotedString(
mSsid.getText().toString());
// If the user adds a network manually, assume that it is hidden.
config.hiddenSSID = true;
} else if (mAccessPoint.networkId == -1) {
config.SSID = AccessPoint.convertToQuotedString(
mAccessPoint.ssid);
} else {
config.networkId = mAccessPoint.networkId;
}
switch (mSecurityType) {
case AccessPoint.SECURITY_NONE:
config.allowedKeyManagement.set(KeyMgmt.NONE);
return config;
case AccessPoint.SECURITY_WEP:
config.allowedKeyManagement.set(KeyMgmt.NONE);
config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
if (mPasswordView.length() != 0) {
int length = mPasswordView.length();
String password = mPasswordView.getText().toString();
// WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
if ((length == 10 || length == 26 || length == 58) &&
password.matches("[0-9A-Fa-f]*")) {
config.wepKeys[0] = password;
} else {
config.wepKeys[0] = '"' + password + '"';
}
}
return config;
case AccessPoint.SECURITY_PSK:
config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
if (mPasswordView.length() != 0) {
String password = mPasswordView.getText().toString();
if (password.matches("[0-9A-Fa-f]{64}")) {
config.preSharedKey = password;
} else {
config.preSharedKey = '"' + password + '"';
}
}
return config;
case AccessPoint.SECURITY_EAP:
config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
config.eap.setValue((String) mEapMethod.getSelectedItem());
config.phase2.setValue((mPhase2.getSelectedItemPosition() == 0) ? "" :
"auth=" + mPhase2.getSelectedItem());
config.ca_cert.setValue((mEapCaCert.getSelectedItemPosition() == 0) ? "" :
KEYSTORE_SPACE + Credentials.CA_CERTIFICATE +
(String) mEapCaCert.getSelectedItem());
config.client_cert.setValue((mEapUserCert.getSelectedItemPosition() == 0) ? "" :
KEYSTORE_SPACE + Credentials.USER_CERTIFICATE +
(String) mEapUserCert.getSelectedItem());
config.private_key.setValue((mEapUserCert.getSelectedItemPosition() == 0) ? "" :
KEYSTORE_SPACE + Credentials.USER_PRIVATE_KEY +
(String) mEapUserCert.getSelectedItem());
config.identity.setValue((mEapIdentity.length() == 0) ? "" :
mEapIdentity.getText().toString());
config.anonymous_identity.setValue((mEapAnonymous.length() == 0) ? "" :
mEapAnonymous.getText().toString());
if (mPasswordView.length() != 0) {
config.password.setValue(mPasswordView.getText().toString());
}
return config;
}
return null;
}
private void showSecurityFields() {
if (mSecurityType == AccessPoint.SECURITY_NONE) {
mView.findViewById(R.id.fields).setVisibility(View.GONE);
return;
}
mView.findViewById(R.id.fields).setVisibility(View.VISIBLE);
if (mPasswordView == null) {
mPasswordView = (TextView) mView.findViewById(R.id.password);
mPasswordView.addTextChangedListener(this);
((CheckBox) mView.findViewById(R.id.show_password)).setOnClickListener(this);
if (mAccessPoint != null && mAccessPoint.networkId != -1) {
mPasswordView.setHint(R.string.wifi_unchanged);
}
}
if (mSecurityType != AccessPoint.SECURITY_EAP) {
mView.findViewById(R.id.eap).setVisibility(View.GONE);
return;
}
mView.findViewById(R.id.eap).setVisibility(View.VISIBLE);
if (mEapMethod == null) {
mEapMethod = (Spinner) mView.findViewById(R.id.method);
mPhase2 = (Spinner) mView.findViewById(R.id.phase2);
mEapCaCert = (Spinner) mView.findViewById(R.id.ca_cert);
mEapUserCert = (Spinner) mView.findViewById(R.id.user_cert);
mEapIdentity = (TextView) mView.findViewById(R.id.identity);
mEapAnonymous = (TextView) mView.findViewById(R.id.anonymous);
loadCertificates(mEapCaCert, Credentials.CA_CERTIFICATE);
loadCertificates(mEapUserCert, Credentials.USER_PRIVATE_KEY);
if (mAccessPoint != null && mAccessPoint.networkId != -1) {
WifiConfiguration config = mAccessPoint.getConfig();
setSelection(mEapMethod, config.eap.value());
setSelection(mPhase2, config.phase2.value());
setCertificate(mEapCaCert, Credentials.CA_CERTIFICATE,
config.ca_cert.value());
setCertificate(mEapUserCert, Credentials.USER_PRIVATE_KEY,
config.private_key.value());
mEapIdentity.setText(config.identity.value());
mEapAnonymous.setText(config.anonymous_identity.value());
}
}
}
private void loadCertificates(Spinner spinner, String prefix) {
final Context context = mConfigUi.getContext();
final String unspecified = context.getString(R.string.wifi_unspecified);
String[] certs = KeyStore.getInstance().saw(prefix);
if (certs == null || certs.length == 0) {
certs = new String[] {unspecified};
} else {
final String[] array = new String[certs.length + 1];
array[0] = unspecified;
System.arraycopy(certs, 0, array, 1, certs.length);
certs = array;
}
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
context, android.R.layout.simple_spinner_item, certs);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
}
private void setCertificate(Spinner spinner, String prefix, String cert) {
prefix = KEYSTORE_SPACE + prefix;
if (cert != null && cert.startsWith(prefix)) {
setSelection(spinner, cert.substring(prefix.length()));
}
}
private void setSelection(Spinner spinner, String value) {
if (value != null) {
ArrayAdapter<String> adapter = (ArrayAdapter<String>) spinner.getAdapter();
for (int i = adapter.getCount() - 1; i >= 0; --i) {
if (value.equals(adapter.getItem(i))) {
spinner.setSelection(i);
break;
}
}
}
}
@Override
public void afterTextChanged(Editable s) {
enableSubmitIfAppropriate();
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void onClick(View view) {
mPasswordView.setInputType(
InputType.TYPE_CLASS_TEXT | (((CheckBox) view).isChecked() ?
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD :
InputType.TYPE_TEXT_VARIATION_PASSWORD));
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
mSecurityType = position;
showSecurityFields();
enableSubmitIfAppropriate();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
}

View File

@@ -0,0 +1,129 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.wifi;
import android.content.Context;
import android.content.DialogInterface;
import android.preference.Preference;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.android.settings.R;
/**
* Preference letting users modify a setting for Wifi network. This work as an alternative UI
* for {@link WifiDialog} without shouwing popup Dialog.
*/
public class WifiConfigPreference extends Preference implements WifiConfigUiBase {
private WifiSettings mWifiSettings;
private View mView;
private final DialogInterface.OnClickListener mListener;
private WifiConfigController mController;
private AccessPoint mAccessPoint;
private boolean mEdit;
private LayoutInflater mInflater;
public WifiConfigPreference(WifiSettings wifiSettings,
DialogInterface.OnClickListener listener,
AccessPoint accessPoint, boolean edit) {
super(wifiSettings.getActivity());
mWifiSettings = wifiSettings;
setLayoutResource(R.layout.wifi_config_preference);
mListener = listener;
mAccessPoint = accessPoint;
mEdit = edit;
mInflater = (LayoutInflater)
wifiSettings.getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
protected View onCreateView(ViewGroup parent) {
// Called every time the list is created.
if (mView != null) {
// TODO: we need to re-forcus something.
return mView;
}
mView = mInflater.inflate(getLayoutResource(), parent, false);
mController = new WifiConfigController(this, mView, mAccessPoint, mEdit, mListener);
return mView;
}
@Override
public WifiConfigController getController() {
return mController;
}
public View findViewById(int id) {
return mView.findViewById(id);
}
public AccessPoint getAccessPoint() {
return mAccessPoint;
}
@Override
public boolean isEdit() {
return mEdit;
}
@Override
public LayoutInflater getLayoutInflater() {
return mInflater;
}
@Override
public Button getSubmitButton() {
return (Button)mWifiSettings.getActivity().findViewById(R.id.wifi_setup_connect);
}
@Override
public Button getForgetButton() {
return (Button)mWifiSettings.getActivity().findViewById(R.id.wifi_setup_forget);
}
@Override
public Button getCancelButton() {
return (Button)mWifiSettings.getActivity().findViewById(R.id.wifi_setup_cancel);
}
@Override
public void setSubmitButton(CharSequence text) {
final Button button = (Button)
mWifiSettings.getActivity().findViewById(R.id.wifi_setup_connect);
button.setVisibility(View.VISIBLE);
// test
mWifiSettings.getActivity().findViewById(R.id.wifi_setup_forget).setVisibility(View.GONE);
}
@Override
public void setForgetButton(CharSequence text) {
final Button button = (Button)
mWifiSettings.getActivity().findViewById(R.id.wifi_setup_forget);
button.setVisibility(View.VISIBLE);
}
@Override
public void setCancelButton(CharSequence text) {
final Button button = (Button)
mWifiSettings.getActivity().findViewById(R.id.wifi_setup_cancel);
button.setVisibility(View.VISIBLE);
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.wifi;
import android.content.Context;
import android.view.LayoutInflater;
import android.widget.Button;
/**
* Foundation interface glues between Activities and UIs like
* {@link WifiDialog} or {@link WifiConfigController}.
*/
public interface WifiConfigUiBase {
public Context getContext();
public WifiConfigController getController();
public LayoutInflater getLayoutInflater();
public boolean isEdit();
public void setTitle(int id);
public void setTitle(CharSequence title);
public void setSubmitButton(CharSequence text);
public void setForgetButton(CharSequence text);
public void setCancelButton(CharSequence text);
public Button getSubmitButton();
public Button getForgetButton();
public Button getCancelButton();
}

View File

@@ -16,154 +16,37 @@
package com.android.settings.wifi; package com.android.settings.wifi;
import com.android.settings.R;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.res.Resources;
import android.net.NetworkInfo.DetailedState;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.AuthAlgorithm;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiInfo;
import android.os.Bundle; import android.os.Bundle;
import android.security.Credentials;
import android.security.KeyStore;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.text.format.Formatter;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.widget.Button;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.Spinner;
import android.widget.TextView;
class WifiDialog extends AlertDialog implements View.OnClickListener, import com.android.settings.R;
TextWatcher, AdapterView.OnItemSelectedListener {
private static final String KEYSTORE_SPACE = "keystore://";
class WifiDialog extends AlertDialog implements WifiConfigUiBase {
static final int BUTTON_SUBMIT = DialogInterface.BUTTON_POSITIVE; static final int BUTTON_SUBMIT = DialogInterface.BUTTON_POSITIVE;
static final int BUTTON_FORGET = DialogInterface.BUTTON_NEUTRAL; static final int BUTTON_FORGET = DialogInterface.BUTTON_NEUTRAL;
final boolean edit; private final boolean mEdit;
private final DialogInterface.OnClickListener mListener; private final DialogInterface.OnClickListener mListener;
private final AccessPoint mAccessPoint; private final AccessPoint mAccessPoint;
private View mView; private View mView;
private TextView mSsid; private WifiConfigController mController;
private int mSecurity;
private TextView mPassword;
private Spinner mEapMethod; public WifiDialog(Context context, DialogInterface.OnClickListener listener,
private Spinner mEapCaCert;
private Spinner mPhase2;
private Spinner mEapUserCert;
private TextView mEapIdentity;
private TextView mEapAnonymous;
static boolean requireKeyStore(WifiConfiguration config) {
String values[] = {config.ca_cert.value(), config.client_cert.value(),
config.private_key.value()};
for (String value : values) {
if (value != null && value.startsWith(KEYSTORE_SPACE)) {
return true;
}
}
return false;
}
WifiDialog(Context context, DialogInterface.OnClickListener listener,
AccessPoint accessPoint, boolean edit) { AccessPoint accessPoint, boolean edit) {
super(context); super(context);
this.edit = edit; mEdit = edit;
mListener = listener; mListener = listener;
mAccessPoint = accessPoint; mAccessPoint = accessPoint;
mSecurity = (accessPoint == null) ? AccessPoint.SECURITY_NONE : accessPoint.security;
} }
WifiConfiguration getConfig() { @Override
if (mAccessPoint != null && mAccessPoint.networkId != -1 && !edit) { public WifiConfigController getController() {
return null; return mController;
}
WifiConfiguration config = new WifiConfiguration();
if (mAccessPoint == null) {
config.SSID = AccessPoint.convertToQuotedString(
mSsid.getText().toString());
// If the user adds a network manually, assume that it is hidden.
config.hiddenSSID = true;
} else if (mAccessPoint.networkId == -1) {
config.SSID = AccessPoint.convertToQuotedString(
mAccessPoint.ssid);
} else {
config.networkId = mAccessPoint.networkId;
}
switch (mSecurity) {
case AccessPoint.SECURITY_NONE:
config.allowedKeyManagement.set(KeyMgmt.NONE);
return config;
case AccessPoint.SECURITY_WEP:
config.allowedKeyManagement.set(KeyMgmt.NONE);
config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
if (mPassword.length() != 0) {
int length = mPassword.length();
String password = mPassword.getText().toString();
// WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
if ((length == 10 || length == 26 || length == 58) &&
password.matches("[0-9A-Fa-f]*")) {
config.wepKeys[0] = password;
} else {
config.wepKeys[0] = '"' + password + '"';
}
}
return config;
case AccessPoint.SECURITY_PSK:
config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
if (mPassword.length() != 0) {
String password = mPassword.getText().toString();
if (password.matches("[0-9A-Fa-f]{64}")) {
config.preSharedKey = password;
} else {
config.preSharedKey = '"' + password + '"';
}
}
return config;
case AccessPoint.SECURITY_EAP:
config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
config.eap.setValue((String) mEapMethod.getSelectedItem());
config.phase2.setValue((mPhase2.getSelectedItemPosition() == 0) ? "" :
"auth=" + mPhase2.getSelectedItem());
config.ca_cert.setValue((mEapCaCert.getSelectedItemPosition() == 0) ? "" :
KEYSTORE_SPACE + Credentials.CA_CERTIFICATE +
(String) mEapCaCert.getSelectedItem());
config.client_cert.setValue((mEapUserCert.getSelectedItemPosition() == 0) ? "" :
KEYSTORE_SPACE + Credentials.USER_CERTIFICATE +
(String) mEapUserCert.getSelectedItem());
config.private_key.setValue((mEapUserCert.getSelectedItemPosition() == 0) ? "" :
KEYSTORE_SPACE + Credentials.USER_PRIVATE_KEY +
(String) mEapUserCert.getSelectedItem());
config.identity.setValue((mEapIdentity.length() == 0) ? "" :
mEapIdentity.getText().toString());
config.anonymous_identity.setValue((mEapAnonymous.length() == 0) ? "" :
mEapAnonymous.getText().toString());
if (mPassword.length() != 0) {
config.password.setValue(mPassword.getText().toString());
}
return config;
}
return null;
} }
@Override @Override
@@ -171,200 +54,42 @@ class WifiDialog extends AlertDialog implements View.OnClickListener,
mView = getLayoutInflater().inflate(R.layout.wifi_dialog, null); mView = getLayoutInflater().inflate(R.layout.wifi_dialog, null);
setView(mView); setView(mView);
setInverseBackgroundForced(true); setInverseBackgroundForced(true);
mController = new WifiConfigController(this, mView, mAccessPoint, mEdit, mListener);
Context context = getContext();
Resources resources = context.getResources();
if (mAccessPoint == null) {
setTitle(R.string.wifi_add_network);
mView.findViewById(R.id.type).setVisibility(View.VISIBLE);
mSsid = (TextView) mView.findViewById(R.id.ssid);
mSsid.addTextChangedListener(this);
((Spinner) mView.findViewById(R.id.security)).setOnItemSelectedListener(this);
setButton(BUTTON_SUBMIT, context.getString(R.string.wifi_save), mListener);
} else {
setTitle(mAccessPoint.ssid);
ViewGroup group = (ViewGroup) mView.findViewById(R.id.info);
DetailedState state = mAccessPoint.getState();
if (state != null) {
addRow(group, R.string.wifi_status, Summary.get(getContext(), state));
}
String[] type = resources.getStringArray(R.array.wifi_security);
addRow(group, R.string.wifi_security, type[mAccessPoint.security]);
int level = mAccessPoint.getLevel();
if (level != -1) {
String[] signal = resources.getStringArray(R.array.wifi_signal);
addRow(group, R.string.wifi_signal, signal[level]);
}
WifiInfo info = mAccessPoint.getInfo();
if (info != null) {
addRow(group, R.string.wifi_speed, info.getLinkSpeed() + WifiInfo.LINK_SPEED_UNITS);
// TODO: fix the ip address for IPv6.
int address = info.getIpAddress();
if (address != 0) {
addRow(group, R.string.wifi_ip_address, Formatter.formatIpAddress(address));
}
}
if (mAccessPoint.networkId == -1 || edit) {
showSecurityFields();
}
if (edit) {
setButton(BUTTON_SUBMIT, context.getString(R.string.wifi_save), mListener);
} else {
if (state == null && level != -1) {
setButton(BUTTON_SUBMIT, context.getString(R.string.wifi_connect), mListener);
}
if (mAccessPoint.networkId != -1) {
setButton(BUTTON_FORGET, context.getString(R.string.wifi_forget), mListener);
}
}
}
setButton(DialogInterface.BUTTON_NEGATIVE,
context.getString(R.string.wifi_cancel), mListener);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (getButton(BUTTON_SUBMIT) != null) {
validate();
}
} }
private void addRow(ViewGroup group, int name, String value) { @Override
View row = getLayoutInflater().inflate(R.layout.wifi_dialog_row, group, false); public boolean isEdit() {
((TextView) row.findViewById(R.id.name)).setText(name); return mEdit;
((TextView) row.findViewById(R.id.value)).setText(value);
group.addView(row);
} }
private void validate() { @Override
// TODO: make sure this is complete. public Button getSubmitButton() {
if ((mSsid != null && mSsid.length() == 0) || return getButton(BUTTON_SUBMIT);
((mAccessPoint == null || mAccessPoint.networkId == -1) &&
((mSecurity == AccessPoint.SECURITY_WEP && mPassword.length() == 0) ||
(mSecurity == AccessPoint.SECURITY_PSK && mPassword.length() < 8)))) {
getButton(BUTTON_SUBMIT).setEnabled(false);
} else {
getButton(BUTTON_SUBMIT).setEnabled(true);
}
} }
public void onClick(View view) { @Override
mPassword.setInputType( public Button getForgetButton() {
InputType.TYPE_CLASS_TEXT | (((CheckBox) view).isChecked() ? return getButton(BUTTON_FORGET);
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD :
InputType.TYPE_TEXT_VARIATION_PASSWORD));
} }
public void onTextChanged(CharSequence s, int start, int before, int count) { @Override
public Button getCancelButton() {
return getButton(BUTTON_NEGATIVE);
} }
public void beforeTextChanged(CharSequence s, int start, int count, int after) { @Override
} public void setSubmitButton(CharSequence text) {
setButton(BUTTON_SUBMIT, text, mListener);
public void afterTextChanged(Editable editable) {
validate();
} }
public void onItemSelected(AdapterView parent, View view, int position, long id) { @Override
mSecurity = position; public void setForgetButton(CharSequence text) {
showSecurityFields(); setButton(BUTTON_FORGET, text, mListener);
validate();
} }
public void onNothingSelected(AdapterView parent) { @Override
} public void setCancelButton(CharSequence text) {
setButton(BUTTON_NEGATIVE, text, mListener);
private void showSecurityFields() {
if (mSecurity == AccessPoint.SECURITY_NONE) {
mView.findViewById(R.id.fields).setVisibility(View.GONE);
return;
}
mView.findViewById(R.id.fields).setVisibility(View.VISIBLE);
if (mPassword == null) {
mPassword = (TextView) mView.findViewById(R.id.password);
mPassword.addTextChangedListener(this);
((CheckBox) mView.findViewById(R.id.show_password)).setOnClickListener(this);
if (mAccessPoint != null && mAccessPoint.networkId != -1) {
mPassword.setHint(R.string.wifi_unchanged);
}
}
if (mSecurity != AccessPoint.SECURITY_EAP) {
mView.findViewById(R.id.eap).setVisibility(View.GONE);
return;
}
mView.findViewById(R.id.eap).setVisibility(View.VISIBLE);
if (mEapMethod == null) {
mEapMethod = (Spinner) mView.findViewById(R.id.method);
mPhase2 = (Spinner) mView.findViewById(R.id.phase2);
mEapCaCert = (Spinner) mView.findViewById(R.id.ca_cert);
mEapUserCert = (Spinner) mView.findViewById(R.id.user_cert);
mEapIdentity = (TextView) mView.findViewById(R.id.identity);
mEapAnonymous = (TextView) mView.findViewById(R.id.anonymous);
loadCertificates(mEapCaCert, Credentials.CA_CERTIFICATE);
loadCertificates(mEapUserCert, Credentials.USER_PRIVATE_KEY);
if (mAccessPoint != null && mAccessPoint.networkId != -1) {
WifiConfiguration config = mAccessPoint.getConfig();
setSelection(mEapMethod, config.eap.value());
setSelection(mPhase2, config.phase2.value());
setCertificate(mEapCaCert, Credentials.CA_CERTIFICATE,
config.ca_cert.value());
setCertificate(mEapUserCert, Credentials.USER_PRIVATE_KEY,
config.private_key.value());
mEapIdentity.setText(config.identity.value());
mEapAnonymous.setText(config.anonymous_identity.value());
}
}
}
private void loadCertificates(Spinner spinner, String prefix) {
String[] certs = KeyStore.getInstance().saw(prefix);
Context context = getContext();
String unspecified = context.getString(R.string.wifi_unspecified);
if (certs == null || certs.length == 0) {
certs = new String[] {unspecified};
} else {
String[] array = new String[certs.length + 1];
array[0] = unspecified;
System.arraycopy(certs, 0, array, 1, certs.length);
certs = array;
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
context, android.R.layout.simple_spinner_item, certs);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
}
private void setCertificate(Spinner spinner, String prefix, String cert) {
prefix = KEYSTORE_SPACE + prefix;
if (cert != null && cert.startsWith(prefix)) {
setSelection(spinner, cert.substring(prefix.length()));
}
}
private void setSelection(Spinner spinner, String value) {
if (value != null) {
ArrayAdapter<String> adapter = (ArrayAdapter<String>) spinner.getAdapter();
for (int i = adapter.getCount() - 1; i >= 0; --i) {
if (value.equals(adapter.getItem(i))) {
spinner.setSelection(i);
break;
}
}
}
} }
} }

View File

@@ -47,16 +47,32 @@ import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.android.settings.ProgressCategory; import com.android.settings.ProgressCategoryBase;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment; import com.android.settings.SettingsPreferenceFragment;
import java.util.ArrayList; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.TreeSet;
/**
* This currently provides three types of UI.
*
* Two are for phones with relatively small screens: "for SetupWizard" and "for usual Settings".
* Users just need to launch WifiSettings Activity as usual. The request will be appropriately
* handled by ActivityManager, and they will have appropriate look-and-feel with this fragment.
*
* Third type is for Setup Wizard with X-Large, landscape UI. Users need to launch
* {@link WifiSettingsForSetupWizardXL} Activity, which contains this fragment but also has
* other decorations specific to that screen.
*/
public class WifiSettings extends SettingsPreferenceFragment public class WifiSettings extends SettingsPreferenceFragment
implements DialogInterface.OnClickListener { implements DialogInterface.OnClickListener {
private static final int MENU_ID_SCAN = Menu.FIRST; private static final int MENU_ID_SCAN = Menu.FIRST;
@@ -65,7 +81,13 @@ public class WifiSettings extends SettingsPreferenceFragment
private static final int MENU_ID_FORGET = Menu.FIRST + 3; private static final int MENU_ID_FORGET = Menu.FIRST + 3;
private static final int MENU_ID_MODIFY = Menu.FIRST + 4; private static final int MENU_ID_MODIFY = Menu.FIRST + 4;
// Indicates that this fragment is used as a part of Setup Wizard with XL screen settings.
// This fragment should show information which has been shown as Dialog in combined UI
// inside this fragment.
/* package */ static final String IN_XL_SETUP_WIZARD = "in_setup_wizard";
// this boolean extra specifies whether to disable the Next button when not connected // this boolean extra specifies whether to disable the Next button when not connected
// Note: this is only effective in Setup Wizard with XL screen size.
private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect"; private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect";
private final IntentFilter mFilter; private final IntentFilter mFilter;
@@ -75,19 +97,26 @@ public class WifiSettings extends SettingsPreferenceFragment
private WifiManager mWifiManager; private WifiManager mWifiManager;
private WifiEnabler mWifiEnabler; private WifiEnabler mWifiEnabler;
private CheckBoxPreference mNotifyOpenNetworks; private CheckBoxPreference mNotifyOpenNetworks;
private ProgressCategory mAccessPoints; private ProgressCategoryBase mAccessPoints;
private Preference mAddNetwork; private Preference mAddNetwork;
// An access point being editted is stored here.
private AccessPoint mSelectedAccessPoint;
private DetailedState mLastState; private DetailedState mLastState;
private WifiInfo mLastInfo; private WifiInfo mLastInfo;
private int mKeyStoreNetworkId = -1; private int mKeyStoreNetworkId = -1;
private AccessPoint mSelected;
private WifiDialog mDialog;
// should Next button only be enabled when we have a connection? // should Next button only be enabled when we have a connection?
private boolean mEnableNextOnConnection; private boolean mEnableNextOnConnection;
private boolean mInXlSetupWizard;
// TODO: merge into one
private WifiConfigPreference mConfigPreference;
private WifiDialog mDialog;
private boolean mRefrainListUpdate;
public WifiSettings() { public WifiSettings() {
mFilter = new IntentFilter(); mFilter = new IntentFilter();
@@ -120,19 +149,26 @@ public class WifiSettings extends SettingsPreferenceFragment
final Activity activity = getActivity(); final Activity activity = getActivity();
final Intent intent = activity.getIntent(); final Intent intent = activity.getIntent();
mInXlSetupWizard = intent.getBooleanExtra(IN_XL_SETUP_WIZARD, false);
// if we're supposed to enable/disable the Next button based on our current connection // if we're supposed to enable/disable the Next button based on our current connection
// state, start it off in the right state // state, start it off in the right state
mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false); mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false);
if (mEnableNextOnConnection && hasNextButton()) {
ConnectivityManager connectivity = (ConnectivityManager) if (mEnableNextOnConnection) {
getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); if (mEnableNextOnConnection && hasNextButton()) {
if (connectivity != null) { final ConnectivityManager connectivity = (ConnectivityManager)
NetworkInfo info = connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI); getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
getNextButton().setEnabled(info.isConnected()); if (connectivity != null) {
NetworkInfo info = connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
changeNextButtonState(info.isConnected());
}
} }
} }
if (intent.getBooleanExtra("only_access_points", false)) { if (mInXlSetupWizard) {
addPreferencesFromResource(R.xml.wifi_access_points_for_wifi_setup_xl);
} else if (intent.getBooleanExtra("only_access_points", false)) {
addPreferencesFromResource(R.xml.wifi_access_points); addPreferencesFromResource(R.xml.wifi_access_points);
} else { } else {
addPreferencesFromResource(R.xml.wifi_settings); addPreferencesFromResource(R.xml.wifi_settings);
@@ -147,8 +183,11 @@ public class WifiSettings extends SettingsPreferenceFragment
// After confirming PreferenceScreen is available, we call super. // After confirming PreferenceScreen is available, we call super.
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
mAccessPoints = (ProgressCategory) findPreference("access_points"); // This may be either ProgressCategory or AccessPointCategoryForXL.
mAccessPoints.setOrderingAsAdded(false); final ProgressCategoryBase preference =
(ProgressCategoryBase) findPreference("access_points");
mAccessPoints = preference;
mAccessPoints.setOrderingAsAdded(true);
mAddNetwork = findPreference("add_network"); mAddNetwork = findPreference("add_network");
registerForContextMenu(getListView()); registerForContextMenu(getListView());
@@ -167,7 +206,34 @@ public class WifiSettings extends SettingsPreferenceFragment
mWifiManager.connectNetwork(mKeyStoreNetworkId); mWifiManager.connectNetwork(mKeyStoreNetworkId);
} }
mKeyStoreNetworkId = -1; mKeyStoreNetworkId = -1;
updateAccessPoints(); if (mInXlSetupWizard) {
// We show "Now scanning"
final int wifiState = mWifiManager.getWifiState();
switch (wifiState) {
case WifiManager.WIFI_STATE_ENABLED: {
updateAccessPoints();
break;
}
case WifiManager.WIFI_STATE_DISABLED:
case WifiManager.WIFI_STATE_DISABLING:
case WifiManager.WIFI_STATE_UNKNOWN: {
mWifiManager.setWifiEnabled(true);
} // $FALL-THROUGH$
default: {
mAccessPoints.removeAll();
Preference preference = new Preference(getActivity());
preference.setLayoutResource(R.layout.preference_widget_shortcut);
preference.setSelectable(false);
preference.setTitle("Connecting");
preference.setSummary("COONNECTING");
mAccessPoints.addPreference(preference);
break;
}
}
} else {
Log.d("@@@", "updateAccessPoints");
updateAccessPoints();
}
} }
@Override @Override
@@ -186,10 +252,13 @@ public class WifiSettings extends SettingsPreferenceFragment
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan) // We don't want menus in Setup Wizard XL.
.setIcon(R.drawable.ic_menu_scan_network); if (!mInXlSetupWizard) {
menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced) menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan)
.setIcon(android.R.drawable.ic_menu_manage); .setIcon(R.drawable.ic_menu_scan_network);
menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)
.setIcon(android.R.drawable.ic_menu_manage);
}
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
} }
@@ -215,14 +284,15 @@ public class WifiSettings extends SettingsPreferenceFragment
((AdapterContextMenuInfo) info).position); ((AdapterContextMenuInfo) info).position);
if (preference instanceof AccessPoint) { if (preference instanceof AccessPoint) {
mSelected = (AccessPoint) preference; mSelectedAccessPoint = (AccessPoint) preference;
menu.setHeaderTitle(mSelected.ssid); menu.setHeaderTitle(mSelectedAccessPoint.ssid);
if (mSelected.getLevel() != -1 && mSelected.getState() == null) { if (mSelectedAccessPoint.getLevel() != -1
&& mSelectedAccessPoint.getState() == null) {
menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect); menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
} }
if (mSelected.networkId != -1) { if (mSelectedAccessPoint.networkId != -1) {
menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget); menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget);
if (mSelected.security != AccessPoint.SECURITY_NONE) { if (mSelectedAccessPoint.security != AccessPoint.SECURITY_NONE) {
menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify); menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify);
} }
} }
@@ -232,31 +302,34 @@ public class WifiSettings extends SettingsPreferenceFragment
@Override @Override
public boolean onContextItemSelected(MenuItem item) { public boolean onContextItemSelected(MenuItem item) {
if (mSelected == null) { if (mSelectedAccessPoint == null) {
return super.onContextItemSelected(item); return super.onContextItemSelected(item);
} }
switch (item.getItemId()) { switch (item.getItemId()) {
case MENU_ID_CONNECT: case MENU_ID_CONNECT: {
if (mSelected.networkId != -1) { if (mSelectedAccessPoint.networkId != -1) {
if (!requireKeyStore(mSelected.getConfig())) { if (!requireKeyStore(mSelectedAccessPoint.getConfig())) {
mWifiManager.connectNetwork(mSelected.networkId); mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);
} }
} else if (mSelected.security == AccessPoint.SECURITY_NONE) { } else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) {
// Shortcut for open networks. // Shortcut for open networks.
WifiConfiguration config = new WifiConfiguration(); WifiConfiguration config = new WifiConfiguration();
config.SSID = AccessPoint.convertToQuotedString(mSelected.ssid); config.SSID = AccessPoint.convertToQuotedString(mSelectedAccessPoint.ssid);
config.allowedKeyManagement.set(KeyMgmt.NONE); config.allowedKeyManagement.set(KeyMgmt.NONE);
mWifiManager.connectNetwork(config); mWifiManager.connectNetwork(config);
} else { } else {
showDialog(mSelected, false); showConfigUi(mSelectedAccessPoint, true);
} }
return true; return true;
case MENU_ID_FORGET: }
mWifiManager.forgetNetwork(mSelected.networkId); case MENU_ID_FORGET: {
mWifiManager.forgetNetwork(mSelectedAccessPoint.networkId);
return true; return true;
case MENU_ID_MODIFY: }
showDialog(mSelected, true); case MENU_ID_MODIFY: {
showConfigUi(mSelectedAccessPoint, true);
return true; return true;
}
} }
return super.onContextItemSelected(item); return super.onContextItemSelected(item);
} }
@@ -264,11 +337,10 @@ public class WifiSettings extends SettingsPreferenceFragment
@Override @Override
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) { public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
if (preference instanceof AccessPoint) { if (preference instanceof AccessPoint) {
mSelected = (AccessPoint) preference; mSelectedAccessPoint = (AccessPoint) preference;
showDialog(mSelected, false); showConfigUi(mSelectedAccessPoint, false);
} else if (preference == mAddNetwork) { } else if (preference == mAddNetwork) {
mSelected = null; onAddNetworkPressed();
showDialog(null, true);
} else if (preference == mNotifyOpenNetworks) { } else if (preference == mNotifyOpenNetworks) {
Secure.putInt(getContentResolver(), Secure.putInt(getContentResolver(),
Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
@@ -279,27 +351,51 @@ public class WifiSettings extends SettingsPreferenceFragment
return true; return true;
} }
public void onClick(DialogInterface dialogInterface, int button) { /**
if (button == WifiDialog.BUTTON_FORGET && mSelected != null) { * Called when a user clicks "Add network" preference or relevant button.
mWifiManager.forgetNetwork(mSelected.networkId); */
} else if (button == WifiDialog.BUTTON_SUBMIT && mDialog != null) { private void showConfigUi(AccessPoint accessPoint, boolean edit) {
WifiConfiguration config = mDialog.getConfig(); synchronized (this) {
mRefrainListUpdate = false;
}
if (mInXlSetupWizard) {
final Activity activity = getActivity();
activity.findViewById(R.id.wifi_setup_connect).setVisibility(View.VISIBLE);
activity.findViewById(R.id.wifi_setup_cancel).setVisibility(View.VISIBLE);
showConfigPreference(accessPoint, edit);
} else {
showDialog(accessPoint, edit);
}
}
if (config == null) { private void showConfigPreference(AccessPoint accessPoint, boolean edit) {
if (mSelected != null && !requireKeyStore(mSelected.getConfig())) { // We don't want to show more than one WifiConfigPreference
mWifiManager.connectNetwork(mSelected.networkId); if (mConfigPreference != null) {
} mAccessPoints.removePreference(mConfigPreference);
} else if (config.networkId != -1) { }
if (mSelected != null) {
mWifiManager.saveNetwork(config); mConfigPreference = new WifiConfigPreference(this, this, accessPoint, edit);
} toggleButtonsVisibility(false);
} else {
if (mDialog.edit || requireKeyStore(config)) { updateAccessPoints();
mWifiManager.saveNetwork(config); mScanner.pause();
} else { }
mWifiManager.connectNetwork(config);
} private void toggleButtonsVisibility(boolean firstLayout) {
} final Activity activity = getActivity();
if (firstLayout) {
activity.findViewById(R.id.wifi_setup_add_network).setVisibility(View.VISIBLE);
activity.findViewById(R.id.wifi_setup_refresh_list).setVisibility(View.VISIBLE);
activity.findViewById(R.id.wifi_setup_skip_or_next).setVisibility(View.VISIBLE);
activity.findViewById(R.id.wifi_setup_connect).setVisibility(View.GONE);
activity.findViewById(R.id.wifi_setup_forget).setVisibility(View.GONE);
activity.findViewById(R.id.wifi_setup_cancel).setVisibility(View.GONE);
} else {
activity.findViewById(R.id.wifi_setup_add_network).setVisibility(View.GONE);
activity.findViewById(R.id.wifi_setup_refresh_list).setVisibility(View.GONE);
activity.findViewById(R.id.wifi_setup_skip_or_next).setVisibility(View.GONE);
// made visible from controller.
} }
} }
@@ -312,7 +408,7 @@ public class WifiSettings extends SettingsPreferenceFragment
} }
private boolean requireKeyStore(WifiConfiguration config) { private boolean requireKeyStore(WifiConfiguration config) {
if (WifiDialog.requireKeyStore(config) && if (WifiConfigController.requireKeyStore(config) &&
KeyStore.getInstance().test() != KeyStore.NO_ERROR) { KeyStore.getInstance().test() != KeyStore.NO_ERROR) {
mKeyStoreNetworkId = config.networkId; mKeyStoreNetworkId = config.networkId;
Credentials.getInstance().unlock(getActivity()); Credentials.getInstance().unlock(getActivity());
@@ -321,10 +417,40 @@ public class WifiSettings extends SettingsPreferenceFragment
return false; return false;
} }
/**
* Shows the latest access points available with supplimental information like
* the strength of network and the security for it.
*/
private void updateAccessPoints() { private void updateAccessPoints() {
List<AccessPoint> accessPoints = new ArrayList<AccessPoint>(); synchronized (this) {
if (mRefrainListUpdate) {
return;
}
}
List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks(); if (mConfigPreference != null) {
mAccessPoints.removeAll();
final AccessPoint parent = mConfigPreference.getAccessPoint();
if (parent != null) {
parent.setSelectable(false);
mAccessPoints.addPreference(parent);
}
mAccessPoints.addPreference(mConfigPreference);
} else {
// AccessPoints are automatically sorted with TreeSet.
final Collection<AccessPoint> accessPoints = constructAccessPoints();
mAccessPoints.removeAll();
for (AccessPoint accessPoint : accessPoints) {
mAccessPoints.addPreference(accessPoint);
}
}
}
private Collection<AccessPoint> constructAccessPoints() {
Collection<AccessPoint> accessPoints =
new TreeSet<AccessPoint>(new AccessPoint.Comparater());
final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
if (configs != null) { if (configs != null) {
for (WifiConfiguration config : configs) { for (WifiConfiguration config : configs) {
AccessPoint accessPoint = new AccessPoint(getActivity(), config); AccessPoint accessPoint = new AccessPoint(getActivity(), config);
@@ -333,7 +459,7 @@ public class WifiSettings extends SettingsPreferenceFragment
} }
} }
List<ScanResult> results = mWifiManager.getScanResults(); final List<ScanResult> results = mWifiManager.getScanResults();
if (results != null) { if (results != null) {
for (ScanResult result : results) { for (ScanResult result : results) {
// Ignore hidden and ad-hoc networks. // Ignore hidden and ad-hoc networks.
@@ -354,10 +480,7 @@ public class WifiSettings extends SettingsPreferenceFragment
} }
} }
mAccessPoints.removeAll(); return accessPoints;
for (AccessPoint accessPoint : accessPoints) {
mAccessPoints.addPreference(accessPoint);
}
} }
private void handleEvent(Intent intent) { private void handleEvent(Intent intent) {
@@ -367,16 +490,14 @@ public class WifiSettings extends SettingsPreferenceFragment
WifiManager.WIFI_STATE_UNKNOWN)); WifiManager.WIFI_STATE_UNKNOWN));
} else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) || } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) ||
WifiManager.SUPPLICANT_CONFIG_CHANGED_ACTION.equals(action)) { WifiManager.SUPPLICANT_CONFIG_CHANGED_ACTION.equals(action)) {
updateAccessPoints(); updateAccessPoints();
} else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) { } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
updateConnectionState(WifiInfo.getDetailedStateOf((SupplicantState) updateConnectionState(WifiInfo.getDetailedStateOf((SupplicantState)
intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE))); intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
} else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
NetworkInfo info = (NetworkInfo) intent.getParcelableExtra( NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
WifiManager.EXTRA_NETWORK_INFO); WifiManager.EXTRA_NETWORK_INFO);
if (mEnableNextOnConnection && hasNextButton()) { changeNextButtonState(info.isConnected());
getNextButton().setEnabled(info.isConnected());
}
updateConnectionState(info.getDetailedState()); updateConnectionState(info.getDetailedState());
} else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) { } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
updateConnectionState(null); updateConnectionState(null);
@@ -402,7 +523,16 @@ public class WifiSettings extends SettingsPreferenceFragment
} }
for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) { for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) {
((AccessPoint) mAccessPoints.getPreference(i)).update(mLastInfo, mLastState); // Maybe there's a WifiConfigPreference
Preference preference = mAccessPoints.getPreference(i);
if (preference instanceof AccessPoint) {
((AccessPoint) preference).update(mLastInfo, mLastState);
}
}
final Activity activity = getActivity();
if (activity instanceof WifiSettingsForSetupWizardXL) {
((WifiSettingsForSetupWizardXL)activity).updateConnectionState(mLastState);
} }
} }
@@ -419,6 +549,9 @@ public class WifiSettings extends SettingsPreferenceFragment
private int mRetry = 0; private int mRetry = 0;
void resume() { void resume() {
synchronized (WifiSettings.this) {
mRefrainListUpdate = false;
}
if (!hasMessages(0)) { if (!hasMessages(0)) {
sendEmptyMessage(0); sendEmptyMessage(0);
} }
@@ -427,6 +560,9 @@ public class WifiSettings extends SettingsPreferenceFragment
void pause() { void pause() {
mRetry = 0; mRetry = 0;
mAccessPoints.setProgress(false); mAccessPoints.setProgress(false);
synchronized (WifiSettings.this) {
mRefrainListUpdate = true;
}
removeMessages(0); removeMessages(0);
} }
@@ -445,4 +581,96 @@ public class WifiSettings extends SettingsPreferenceFragment
sendEmptyMessageDelayed(0, 10000); sendEmptyMessageDelayed(0, 10000);
} }
} }
private void changeNextButtonState(boolean wifiAvailable) {
if (mInXlSetupWizard) {
final Button button =
(Button)getActivity().findViewById(R.id.wifi_setup_skip_or_next);
button.setEnabled(true);
if (wifiAvailable) {
button.setText(R.string.wifi_setup_next);
} else {
button.setText(R.string.wifi_setup_skip);
}
} else if (mEnableNextOnConnection && hasNextButton()) {
// Assumes layout for phones has next button inside it.
getNextButton().setEnabled(wifiAvailable);
}
}
public void onClick(DialogInterface dialogInterface, int button) {
if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {
forget();
} else if (button == WifiDialog.BUTTON_SUBMIT) {
submit();
}
}
/* package */ void submit() {
final WifiConfigUiBase uiBase = (mDialog != null ? mDialog : mConfigPreference);
final WifiConfiguration config = uiBase.getController().getConfig();
if (config == null) {
if (mSelectedAccessPoint != null
&& !requireKeyStore(mSelectedAccessPoint.getConfig())) {
mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);
}
} else if (config.networkId != -1) {
if (mSelectedAccessPoint != null) {
mWifiManager.saveNetwork(config);
}
} else {
if (uiBase.isEdit() || requireKeyStore(config)) {
mWifiManager.saveNetwork(config);
} else {
mWifiManager.connectNetwork(config);
}
}
detachConfigPreference();
}
/* package */ void forget() {
mWifiManager.forgetNetwork(mSelectedAccessPoint.networkId);
detachConfigPreference();
changeNextButtonState(false);
final Activity activity = getActivity();
if (activity instanceof WifiSettingsForSetupWizardXL) {
((WifiSettingsForSetupWizardXL)activity).onForget();
}
}
/* package */ void refreshAccessPoints() {
if (mWifiManager.isWifiEnabled()) {
mScanner.resume();
}
mConfigPreference = null;
mAccessPoints.removeAll();
final Activity activity = getActivity();
if (activity instanceof WifiSettingsForSetupWizardXL) {
((WifiSettingsForSetupWizardXL)activity).onRefreshAccessPoints();
}
}
/* package */ void detachConfigPreference() {
if (mConfigPreference != null) {
if (mWifiManager.isWifiEnabled()) {
mScanner.resume();
}
mAccessPoints.removePreference(mConfigPreference);
mConfigPreference = null;
updateAccessPoints();
toggleButtonsVisibility(true);
}
}
/* package */ void onAddNetworkPressed() {
mSelectedAccessPoint = null;
showConfigUi(null, true);
}
} }

View File

@@ -0,0 +1,157 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.wifi;
import android.app.Activity;
import android.net.NetworkInfo.DetailedState;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.settings.R;
import java.util.EnumMap;
/**
* WifiSetings Activity specific for SetupWizard with X-Large screen size.
*/
public class WifiSettingsForSetupWizardXL extends Activity implements OnClickListener {
private static final EnumMap<DetailedState, DetailedState> stateMap =
new EnumMap<DetailedState, DetailedState>(DetailedState.class);
static {
stateMap.put(DetailedState.IDLE, DetailedState.DISCONNECTED);
stateMap.put(DetailedState.SCANNING, DetailedState.DISCONNECTED);
stateMap.put(DetailedState.CONNECTING, DetailedState.CONNECTING);
stateMap.put(DetailedState.AUTHENTICATING, DetailedState.CONNECTING);
stateMap.put(DetailedState.OBTAINING_IPADDR, DetailedState.CONNECTING);
stateMap.put(DetailedState.CONNECTED, DetailedState.CONNECTED);
stateMap.put(DetailedState.SUSPENDED, DetailedState.SUSPENDED); // ?
stateMap.put(DetailedState.DISCONNECTING, DetailedState.DISCONNECTED);
stateMap.put(DetailedState.DISCONNECTED, DetailedState.DISCONNECTED);
stateMap.put(DetailedState.FAILED, DetailedState.DISCONNECTED);
}
private TextView mProgressText;
private ProgressBar mProgressBar;
private WifiSettings mWifiSettings;
private TextView mStatusText;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.wifi_settings_for_setup_wizard_xl);
mWifiSettings =
(WifiSettings)getFragmentManager().findFragmentById(R.id.wifi_setup_fragment);
setup();
// XXX: should we use method?
getIntent().putExtra(WifiSettings.IN_XL_SETUP_WIZARD, true);
}
public void setup() {
mProgressText = (TextView)findViewById(R.id.scanning_progress_text);
mProgressBar = (ProgressBar)findViewById(R.id.scanning_progress_bar);
mProgressBar.setMax(2);
mProgressBar.setIndeterminate(true);
mStatusText = (TextView)findViewById(R.id.wifi_setup_status);
((Button)findViewById(R.id.wifi_setup_refresh_list)).setOnClickListener(this);
((Button)findViewById(R.id.wifi_setup_add_network)).setOnClickListener(this);
((Button)findViewById(R.id.wifi_setup_skip_or_next)).setOnClickListener(this);
((Button)findViewById(R.id.wifi_setup_connect)).setOnClickListener(this);
((Button)findViewById(R.id.wifi_setup_forget)).setOnClickListener(this);
((Button)findViewById(R.id.wifi_setup_cancel)).setOnClickListener(this);
}
@Override
public void onClick(View view) {
final int id = view.getId();
switch (id) {
case R.id.wifi_setup_refresh_list:
mWifiSettings.refreshAccessPoints();
break;
case R.id.wifi_setup_add_network:
mWifiSettings.onAddNetworkPressed();
break;
case R.id.wifi_setup_skip_or_next:
setResult(Activity.RESULT_OK);
finish();
break;
case R.id.wifi_setup_connect:
mWifiSettings.submit();
break;
case R.id.wifi_setup_forget:
mWifiSettings.forget();
break;
case R.id.wifi_setup_cancel:
mWifiSettings.detachConfigPreference();
break;
}
}
public void updateConnectionState(DetailedState originalState) {
final DetailedState state = stateMap.get(originalState);
final String message;
mProgressBar.setIndeterminate(false);
switch (state) {
case CONNECTING: {
message = Summary.get(this, state);
mProgressBar.setProgress(1);
mStatusText.setText(R.string.wifi_setup_status_connecting);
break;
}
case CONNECTED: {
message = Summary.get(this, state);
mProgressBar.setProgress(2);
mStatusText.setText(R.string.wifi_setup_status_connected);
break;
}
default: // Not connected.
message = getString(R.string.wifi_setup_not_connected);
mProgressBar.setProgress(0);
mStatusText.setText(R.string.wifi_setup_status_select_network);
break;
}
mProgressText.setText(message);
}
public void onWifiConfigPreferenceAttached(boolean isNewNetwork) {
if (isNewNetwork) {
mStatusText.setText(R.string.wifi_setup_status_new_network);
} else {
mStatusText.setText(R.string.wifi_setup_status_existing_network);
}
}
public void onForget() {
mProgressBar.setIndeterminate(false);
mProgressBar.setProgress(0);
mProgressText.setText(getString(R.string.wifi_setup_not_connected));
}
public void onRefreshAccessPoints() {
mProgressBar.setIndeterminate(true);
mProgressText.setText(Summary.get(this, DetailedState.SCANNING));
}
}