diff options
Diffstat (limited to 'src')
23 files changed, 1267 insertions, 484 deletions
diff --git a/src/com/android/settings/AccountPreference.java b/src/com/android/settings/AccountPreference.java index 2cc013c..7547721 100644 --- a/src/com/android/settings/AccountPreference.java +++ b/src/com/android/settings/AccountPreference.java @@ -140,6 +140,8 @@ public class AccountPreference extends Preference { return getContext().getString(R.string.accessibility_sync_disabled); case SYNC_ERROR: return getContext().getString(R.string.accessibility_sync_error); + case SYNC_IN_PROGRESS: + return getContext().getString(R.string.accessibility_sync_in_progress); default: Log.e(TAG, "Unknown sync status: " + status); return getContext().getString(R.string.accessibility_sync_error); diff --git a/src/com/android/settings/TrustAgentSettings.java b/src/com/android/settings/AdvancedSecuritySettings.java index 79cccae..2a8c623 100644 --- a/src/com/android/settings/TrustAgentSettings.java +++ b/src/com/android/settings/AdvancedSecuritySettings.java @@ -18,28 +18,17 @@ package com.android.settings; import com.android.internal.widget.LockPatternUtils; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import android.Manifest; import android.app.ListFragment; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.service.trust.TrustAgentService; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.AttributeSet; -import android.util.Log; -import android.util.Slog; -import android.util.Xml; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -48,17 +37,12 @@ import android.widget.CheckBox; import android.widget.ImageView; import android.widget.TextView; -import java.io.IOException; import java.util.List; -public class TrustAgentSettings extends ListFragment implements View.OnClickListener { - static final String TAG = "TrustAgentSettings"; +public class AdvancedSecuritySettings extends ListFragment implements View.OnClickListener { + static final String TAG = "AdvancedSecuritySettings"; private static final String SERVICE_INTERFACE = TrustAgentService.SERVICE_INTERFACE; - private static final String TRUST_AGENT_META_DATA = TrustAgentService.TRUST_AGENT_META_DATA; - - private static final String PERMISSION_PROVIDE_AGENT = Manifest.permission.PROVIDE_TRUST_AGENT; - private final ArraySet<ComponentName> mActiveAgents = new ArraySet<ComponentName>(); private final ArrayMap<ComponentName, AgentInfo> mAvailableAgents @@ -98,7 +82,7 @@ public class TrustAgentSettings extends ListFragment implements View.OnClickList container.getContext().getApplicationContext()); } setListAdapter(new AgentListAdapter()); - return inflater.inflate(R.layout.trust_agent_settings, container, false); + return inflater.inflate(R.layout.advanced_security_settings, container, false); } @Override @@ -125,79 +109,22 @@ public class TrustAgentSettings extends ListFragment implements View.OnClickList for (ResolveInfo resolveInfo : resolveInfos) { if (resolveInfo.serviceInfo == null) continue; - - String packageName = resolveInfo.serviceInfo.packageName; - if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName) - != PackageManager.PERMISSION_GRANTED) { - Log.w(TAG, "Skipping agent because package " + packageName - + " does not have permission " + PERMISSION_PROVIDE_AGENT + "."); - continue; - } - - ComponentName name = getComponentName(resolveInfo); + if (!TrustAgentUtils.checkProvidePermission(resolveInfo, pm)) continue; + ComponentName name = TrustAgentUtils.getComponentName(resolveInfo); if (!mAvailableAgents.containsKey(name)) { AgentInfo agentInfo = new AgentInfo(); agentInfo.label = resolveInfo.loadLabel(pm); agentInfo.icon = resolveInfo.loadIcon(pm); agentInfo.component = name; - agentInfo.settings = getSettingsComponentName(pm, resolveInfo); + TrustAgentUtils.TrustAgentComponentInfo trustAgentComponentInfo = + TrustAgentUtils.getSettingsComponent(pm, resolveInfo); + agentInfo.settings = trustAgentComponentInfo.componentName; mAvailableAgents.put(name, agentInfo); } } ((BaseAdapter) getListAdapter()).notifyDataSetChanged(); } - private ComponentName getComponentName(ResolveInfo resolveInfo) { - if (resolveInfo == null || resolveInfo.serviceInfo == null) return null; - return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); - } - - private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) { - if (resolveInfo == null || resolveInfo.serviceInfo == null - || resolveInfo.serviceInfo.metaData == null) return null; - String cn = null; - XmlResourceParser parser = null; - Exception caughtException = null; - try { - parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, TRUST_AGENT_META_DATA); - if (parser == null) { - Slog.w(TAG, "Can't find " + TRUST_AGENT_META_DATA + " meta-data"); - return null; - } - Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo); - AttributeSet attrs = Xml.asAttributeSet(parser); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && type != XmlPullParser.START_TAG) { - } - String nodeName = parser.getName(); - if (!"trust-agent".equals(nodeName)) { - Slog.w(TAG, "Meta-data does not start with trust-agent tag"); - return null; - } - TypedArray sa = res - .obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent); - cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity); - sa.recycle(); - } catch (PackageManager.NameNotFoundException e) { - caughtException = e; - } catch (IOException e) { - caughtException = e; - } catch (XmlPullParserException e) { - caughtException = e; - } finally { - if (parser != null) parser.close(); - } - if (caughtException != null) { - Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException); - return null; - } - if (cn != null && cn.indexOf('/') < 0) { - cn = resolveInfo.serviceInfo.packageName + "/" + cn; - } - return cn == null ? null : ComponentName.unflattenFromString(cn); - } - @Override public void onClick(View view) { ViewHolder h = (ViewHolder) view.getTag(); @@ -295,10 +222,10 @@ public class TrustAgentSettings extends ListFragment implements View.OnClickList h.name = (TextView)v.findViewById(R.id.name); h.checkbox = (CheckBox)v.findViewById(R.id.checkbox); h.clickable = v.findViewById(R.id.clickable); - h.clickable.setOnClickListener(TrustAgentSettings.this); + h.clickable.setOnClickListener(AdvancedSecuritySettings.this); h.description = (TextView)v.findViewById(R.id.description); h.settings = v.findViewById(R.id.settings); - h.settings.setOnClickListener(TrustAgentSettings.this); + h.settings.setOnClickListener(AdvancedSecuritySettings.this); v.setTag(h); h.settings.setTag(h); h.clickable.setTag(h); diff --git a/src/com/android/settings/ApnSettings.java b/src/com/android/settings/ApnSettings.java index 3fbb5e3..ef79f2b 100644 --- a/src/com/android/settings/ApnSettings.java +++ b/src/com/android/settings/ApnSettings.java @@ -32,6 +32,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; +import android.os.UserManager; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceGroup; @@ -83,10 +84,14 @@ public class ApnSettings extends PreferenceActivity implements private RestoreApnProcessHandler mRestoreApnProcessHandler; private HandlerThread mRestoreDefaultApnThread; + private UserManager mUm; + private String mSelectedKey; private IntentFilter mMobileStateFilter; + private boolean mUnavailable; + private final BroadcastReceiver mMobileStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -119,6 +124,14 @@ public class ApnSettings extends PreferenceActivity implements protected void onCreate(Bundle icicle) { super.onCreate(icicle); + mUm = (UserManager) getSystemService(Context.USER_SERVICE); + + if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) { + mUnavailable = true; + setContentView(R.layout.apn_disallowed_preference_screen); + return; + } + addPreferencesFromResource(R.xml.apn_settings); getListView().setItemsCanFocus(true); @@ -130,6 +143,10 @@ public class ApnSettings extends PreferenceActivity implements protected void onResume() { super.onResume(); + if (mUnavailable) { + return; + } + registerReceiver(mMobileStateReceiver, mMobileStateFilter); if (!mRestoreDefaultApnMode) { @@ -143,6 +160,10 @@ public class ApnSettings extends PreferenceActivity implements protected void onPause() { super.onPause(); + if (mUnavailable) { + return; + } + unregisterReceiver(mMobileStateReceiver); } diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java index f819755..d24c741 100644 --- a/src/com/android/settings/CryptKeeper.java +++ b/src/com/android/settings/CryptKeeper.java @@ -408,6 +408,7 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList final TextView status = (TextView) findViewById(R.id.owner_info); status.setText(owner_info); + status.setSelected(true); // Required for marquee'ing to work passwordEntryInit(); } }.execute(); diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java index a0a062a..3be2bcc 100644 --- a/src/com/android/settings/DevelopmentSettings.java +++ b/src/com/android/settings/DevelopmentSettings.java @@ -467,6 +467,9 @@ public class DevelopmentSettings extends SettingsPreferenceFragment public void onPause() { super.onPause(); + if (mUnavailable) { + return; + } mSwitchBar.removeOnSwitchChangeListener(this); mSwitchBar.hide(); } diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index 00d1d89..b35a362 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -41,6 +41,7 @@ import android.preference.PreferenceScreen; import android.provider.SearchIndexableResource; import android.provider.Settings; import android.security.KeyStore; +import android.service.trust.TrustAgentService; import android.telephony.TelephonyManager; import android.util.Log; @@ -58,6 +59,8 @@ import java.util.List; public class SecuritySettings extends RestrictedSettingsFragment implements OnPreferenceChangeListener, DialogInterface.OnClickListener, Indexable { static final String TAG = "SecuritySettings"; + private static final Intent TRUST_AGENT_INTENT = + new Intent(TrustAgentService.SERVICE_INTERFACE); // Lock Settings private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change"; @@ -74,6 +77,7 @@ public class SecuritySettings extends RestrictedSettingsFragment private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123; private static final int CONFIRM_EXISTING_FOR_BIOMETRIC_WEAK_IMPROVE_REQUEST = 124; private static final int CONFIRM_EXISTING_FOR_BIOMETRIC_WEAK_LIVELINESS_OFF = 125; + private static final int CHANGE_TRUST_AGENT_SETTINGS = 126; // Misc Settings private static final String KEY_SIM_LOCK = "sim_lock"; @@ -86,6 +90,7 @@ public class SecuritySettings extends RestrictedSettingsFragment private static final String KEY_POWER_INSTANTLY_LOCKS = "power_button_instantly_locks"; private static final String KEY_CREDENTIALS_MANAGER = "credentials_management"; private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; + private static final String KEY_TRUST_AGENT = "trust_agent"; private DevicePolicyManager mDPM; @@ -161,7 +166,7 @@ public class SecuritySettings extends RestrictedSettingsFragment /** * Important! * - * Dont forget to update the SecuritySearchIndexProvider if you are doing any change in the + * Don't forget to update the SecuritySearchIndexProvider if you are doing any change in the * logic or adding/removing preferences here. */ private PreferenceScreen createPreferenceHierarchy() { @@ -270,7 +275,7 @@ public class SecuritySettings extends RestrictedSettingsFragment } // Application install - PreferenceGroup deviceAdminCategory= (PreferenceGroup) + PreferenceGroup deviceAdminCategory = (PreferenceGroup) root.findPreference(KEY_DEVICE_ADMIN_CATEGORY); mToggleAppInstallation = (CheckBoxPreference) findPreference( KEY_TOGGLE_INSTALL_APPLICATIONS); @@ -303,6 +308,37 @@ public class SecuritySettings extends RestrictedSettingsFragment protectByRestrictions(root.findPreference(KEY_CREDENTIALS_INSTALL)); } + // Trust Agent preferences + PreferenceGroup securityCategory = (PreferenceGroup) + root.findPreference(KEY_SECURITY_CATEGORY); + if (securityCategory != null) { + PackageManager pm = getPackageManager(); + List<ResolveInfo> resolveInfos = pm.queryIntentServices(TRUST_AGENT_INTENT, + PackageManager.GET_META_DATA); + for (ResolveInfo resolveInfo : resolveInfos) { + if (resolveInfo.serviceInfo == null) continue; + if (!TrustAgentUtils.checkProvidePermission(resolveInfo, pm)) continue; + TrustAgentUtils.TrustAgentComponentInfo trustAgentComponentInfo = + TrustAgentUtils.getSettingsComponent(pm, resolveInfo); + if (trustAgentComponentInfo.componentName == null || + trustAgentComponentInfo.title == null || + trustAgentComponentInfo.title == "") continue; + Preference trustAgentPreference = + new Preference(securityCategory.getContext()); + trustAgentPreference.setKey(KEY_TRUST_AGENT); + trustAgentPreference.setTitle(trustAgentComponentInfo.title); + trustAgentPreference.setSummary(trustAgentComponentInfo.summary); + // Create intent for this preference. + Intent intent = new Intent(); + intent.setComponent(trustAgentComponentInfo.componentName); + intent.setAction(Intent.ACTION_MAIN); + trustAgentPreference.setIntent(intent); + // Add preference to the settings menu. + securityCategory.addPreference(trustAgentPreference); + break; // Only render the first one. + } + } + return root; } @@ -522,6 +558,13 @@ public class SecuritySettings extends RestrictedSettingsFragment } else if (KEY_TOGGLE_VERIFY_APPLICATIONS.equals(key)) { Settings.Global.putInt(getContentResolver(), Settings.Global.PACKAGE_VERIFIER_ENABLE, mToggleVerifyApps.isChecked() ? 1 : 0); + } else if (KEY_TRUST_AGENT.equals(key)) { + ChooseLockSettingsHelper helper = + new ChooseLockSettingsHelper(this.getActivity(), this); + if (!helper.launchConfirmationActivity(CHANGE_TRUST_AGENT_SETTINGS, null, null)) { + // If this returns false, it means no password confirmation is required. + startActivity(preference.getIntent()); + } } else { // If we didn't handle it, let preferences handle it. return super.onPreferenceTreeClick(preferenceScreen, preference); @@ -552,6 +595,14 @@ public class SecuritySettings extends RestrictedSettingsFragment // is called by grabbing the value from lockPatternUtils. We can't set it here // because mBiometricWeakLiveliness could be null return; + } else if (requestCode == CHANGE_TRUST_AGENT_SETTINGS && resultCode == Activity.RESULT_OK) { + Preference preference = getPreferenceScreen().findPreference(KEY_TRUST_AGENT); + if (preference != null) { + Intent intent = preference.getIntent(); + if (intent != null) { + startActivity(intent); + } + } } createPreferenceHierarchy(); } diff --git a/src/com/android/settings/TetherSettings.java b/src/com/android/settings/TetherSettings.java index 4e0933d..d960ce6 100644 --- a/src/com/android/settings/TetherSettings.java +++ b/src/com/android/settings/TetherSettings.java @@ -47,6 +47,7 @@ import android.text.TextUtils; import android.view.ViewGroup; import android.view.ViewParent; import android.webkit.WebView; +import android.widget.TextView; import java.io.InputStream; import java.util.ArrayList; @@ -92,6 +93,7 @@ public class TetherSettings extends SettingsPreferenceFragment private WifiApDialog mDialog; private WifiManager mWifiManager; private WifiConfiguration mWifiConfig = null; + private UserManager mUm; private boolean mUsbConnected; private boolean mMassStorageActive; @@ -110,11 +112,21 @@ public class TetherSettings extends SettingsPreferenceFragment private String[] mProvisionApp; private static final int PROVISION_REQUEST = 0; + private boolean mUnavailable; + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); addPreferencesFromResource(R.xml.tether_prefs); + mUm = (UserManager) getSystemService(Context.USER_SERVICE); + + if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) { + mUnavailable = true; + setPreferenceScreen(new PreferenceScreen(getActivity(), null)); + return; + } + final Activity activity = getActivity(); BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null) { @@ -264,6 +276,15 @@ public class TetherSettings extends SettingsPreferenceFragment public void onStart() { super.onStart(); + if (mUnavailable) { + TextView emptyView = (TextView) getView().findViewById(android.R.id.empty); + getListView().setEmptyView(emptyView); + if (emptyView != null) { + emptyView.setText(R.string.tethering_settings_not_available); + } + return; + } + final Activity activity = getActivity(); mMassStorageActive = Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState()); @@ -297,6 +318,10 @@ public class TetherSettings extends SettingsPreferenceFragment @Override public void onStop() { super.onStop(); + + if (mUnavailable) { + return; + } getActivity().unregisterReceiver(mTetherChangeReceiver); mTetherChangeReceiver = null; if (mWifiApEnabler != null) { diff --git a/src/com/android/settings/TrustAgentUtils.java b/src/com/android/settings/TrustAgentUtils.java new file mode 100644 index 0000000..31a073c --- /dev/null +++ b/src/com/android/settings/TrustAgentUtils.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2014 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.ComponentName; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.service.trust.TrustAgentService; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Slog; +import android.util.Xml; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +public class TrustAgentUtils { + static final String TAG = "TrustAgentUtils"; + + private static final String TRUST_AGENT_META_DATA = TrustAgentService.TRUST_AGENT_META_DATA; + private static final String PERMISSION_PROVIDE_AGENT = android.Manifest.permission.PROVIDE_TRUST_AGENT; + + /** + * @return true, if the service in resolveInfo has the permission to provide a trust agent. + */ + public static boolean checkProvidePermission(ResolveInfo resolveInfo, PackageManager pm) { + String packageName = resolveInfo.serviceInfo.packageName; + if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName) + != PackageManager.PERMISSION_GRANTED) { + Log.w(TAG, "Skipping agent because package " + packageName + + " does not have permission " + PERMISSION_PROVIDE_AGENT + "."); + return false; + } + return true; + } + + public static class TrustAgentComponentInfo { + ComponentName componentName; + String title; + String summary; + } + + public static ComponentName getComponentName(ResolveInfo resolveInfo) { + if (resolveInfo == null || resolveInfo.serviceInfo == null) return null; + return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); + } + + public static TrustAgentComponentInfo getSettingsComponent( + PackageManager pm, ResolveInfo resolveInfo) { + if (resolveInfo == null || resolveInfo.serviceInfo == null + || resolveInfo.serviceInfo.metaData == null) return null; + String cn = null; + TrustAgentComponentInfo trustAgentComponentInfo = new TrustAgentComponentInfo(); + XmlResourceParser parser = null; + Exception caughtException = null; + try { + parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, TRUST_AGENT_META_DATA); + if (parser == null) { + Slog.w(TAG, "Can't find " + TRUST_AGENT_META_DATA + " meta-data"); + return null; + } + Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo); + AttributeSet attrs = Xml.asAttributeSet(parser); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && type != XmlPullParser.START_TAG) { + } + String nodeName = parser.getName(); + if (!"trust-agent".equals(nodeName)) { + Slog.w(TAG, "Meta-data does not start with trust-agent tag"); + return null; + } + TypedArray sa = + res.obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent); + trustAgentComponentInfo.summary = + sa.getString(com.android.internal.R.styleable.TrustAgent_summary); + trustAgentComponentInfo.title = + sa.getString(com.android.internal.R.styleable.TrustAgent_title); + cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity); + sa.recycle(); + } catch (PackageManager.NameNotFoundException e) { + caughtException = e; + } catch (IOException e) { + caughtException = e; + } catch (XmlPullParserException e) { + caughtException = e; + } finally { + if (parser != null) parser.close(); + } + if (caughtException != null) { + Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException); + return null; + } + if (cn != null && cn.indexOf('/') < 0) { + cn = resolveInfo.serviceInfo.packageName + "/" + cn; + } + trustAgentComponentInfo.componentName = (cn == null) ? null : ComponentName.unflattenFromString(cn); + return trustAgentComponentInfo; + } +} diff --git a/src/com/android/settings/WirelessSettings.java b/src/com/android/settings/WirelessSettings.java index 7aaa0a6..507445f 100644 --- a/src/com/android/settings/WirelessSettings.java +++ b/src/com/android/settings/WirelessSettings.java @@ -34,6 +34,7 @@ import android.nfc.NfcManager; import android.os.Bundle; import android.os.SystemProperties; import android.os.UserHandle; +import android.os.UserManager; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; @@ -86,6 +87,7 @@ public class WirelessSettings extends RestrictedSettingsFragment private ConnectivityManager mCm; private TelephonyManager mTm; private PackageManager mPm; + private UserManager mUm; private static final int MANAGE_MOBILE_PLAN_DIALOG_ID = 1; private static final String SAVED_MANAGE_MOBILE_PLAN_MSG = "mManageMobilePlanMessage"; @@ -251,6 +253,7 @@ public class WirelessSettings extends RestrictedSettingsFragment mCm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); mTm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); mPm = getPackageManager(); + mUm = (UserManager) getSystemService(Context.USER_SERVICE); addPreferencesFromResource(R.xml.wireless_settings); @@ -296,10 +299,11 @@ public class WirelessSettings extends RestrictedSettingsFragment if (toggleable == null || !toggleable.contains(Settings.Global.RADIO_WIFI)) { findPreference(KEY_VPN_SETTINGS).setDependency(KEY_TOGGLE_AIRPLANE); } - if (isSecondaryUser) { // Disable VPN + // Disable VPN. + if (isSecondaryUser || mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) { removePreference(KEY_VPN_SETTINGS); } - protectByRestrictions(KEY_VPN_SETTINGS); + // Manually set dependencies for Bluetooth when not toggleable. if (toggleable == null || !toggleable.contains(Settings.Global.RADIO_BLUETOOTH)) { // No bluetooth-dependent items in the list. Code kept in case one is added later. @@ -319,8 +323,10 @@ public class WirelessSettings extends RestrictedSettingsFragment mNfcEnabler = null; } - // Remove Mobile Network Settings and Manage Mobile Plan if it's a wifi-only device. - if (isSecondaryUser || Utils.isWifiOnly(getActivity())) { + // Remove Mobile Network Settings and Manage Mobile Plan for secondary users, + // if it's a wifi-only device, or if the settings are restricted. + if (isSecondaryUser || Utils.isWifiOnly(getActivity()) + || mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) { removePreference(KEY_MOBILE_NETWORK_SETTINGS); removePreference(KEY_MANAGE_MOBILE_PLAN); } @@ -334,8 +340,6 @@ public class WirelessSettings extends RestrictedSettingsFragment removePreference(KEY_MANAGE_MOBILE_PLAN); } } - protectByRestrictions(KEY_MOBILE_NETWORK_SETTINGS); - protectByRestrictions(KEY_MANAGE_MOBILE_PLAN); // Remove SMS Application if the device does not support SMS if (!isSmsSupported()) { @@ -358,13 +362,13 @@ public class WirelessSettings extends RestrictedSettingsFragment // Disable Tethering if it's not allowed or if it's a wifi-only device final ConnectivityManager cm = (ConnectivityManager) activity.getSystemService(Context.CONNECTIVITY_SERVICE); - if (isSecondaryUser || !cm.isTetheringSupported()) { + if (isSecondaryUser || !cm.isTetheringSupported() + || mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) { getPreferenceScreen().removePreference(findPreference(KEY_TETHER_SETTINGS)); } else { Preference p = findPreference(KEY_TETHER_SETTINGS); p.setTitle(Utils.getTetheringLabel(cm)); } - protectByRestrictions(KEY_TETHER_SETTINGS); // Enable link to CMAS app settings depending on the value in config.xml. boolean isCellBroadcastAppLinkEnabled = this.getResources().getBoolean( @@ -379,12 +383,12 @@ public class WirelessSettings extends RestrictedSettingsFragment } catch (IllegalArgumentException ignored) { isCellBroadcastAppLinkEnabled = false; // CMAS app not installed } - if (isSecondaryUser || !isCellBroadcastAppLinkEnabled) { + if (isSecondaryUser || !isCellBroadcastAppLinkEnabled + || mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS)) { PreferenceScreen root = getPreferenceScreen(); Preference ps = findPreference(KEY_CELL_BROADCAST_SETTINGS); if (ps != null) root.removePreference(ps); } - protectByRestrictions(KEY_CELL_BROADCAST_SETTINGS); } @Override diff --git a/src/com/android/settings/accounts/AccountSettings.java b/src/com/android/settings/accounts/AccountSettings.java new file mode 100644 index 0000000..bb06b2f --- /dev/null +++ b/src/com/android/settings/accounts/AccountSettings.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2014 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.accounts; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.OnAccountsUpdateListener; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.UserManager; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; +import android.preference.PreferenceGroup; + +import com.android.settings.R; +import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.Utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * Settings screen for the account types on the device. + * This shows all account types available for personal and work profiles. + */ +public class AccountSettings extends SettingsPreferenceFragment + implements OnAccountsUpdateListener, OnPreferenceClickListener { + public static final String TAG = "AccountSettings"; + + private static final String KEY_ACCOUNT = "account"; + private static final String KEY_ADD_ACCOUNT = "add_account"; + + private static final String KEY_CATEGORY_PERSONAL = "account_personal"; + private static final String KEY_ADD_ACCOUNT_PERSONAL = "add_account_personal"; + private static final String KEY_CATEGORY_WORK = "account_work"; + + private AuthenticatorHelper mAuthenticatorHelper; + private boolean mListeningToAccountUpdates; + + private PreferenceGroup mAccountTypesForUser; + private Preference mAddAccountForUser; + + private UserManager mUm; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mUm = (UserManager) getSystemService(Context.USER_SERVICE); + + mAuthenticatorHelper = new AuthenticatorHelper(); + mAuthenticatorHelper.updateAuthDescriptions(getActivity()); + mAuthenticatorHelper.onAccountsUpdated(getActivity(), null); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.account_settings); + + if(mUm.isLinkedUser()) { + // Restricted user or similar + // TODO: Do we disallow modifying accounts for restricted profiles? + mAccountTypesForUser = (PreferenceGroup) findPreference(KEY_ACCOUNT); + if (mUm.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) { + removePreference(KEY_ADD_ACCOUNT); + } else { + mAddAccountForUser = findPreference(KEY_ADD_ACCOUNT); + mAddAccountForUser.setOnPreferenceClickListener(this); + } + removePreference(KEY_CATEGORY_PERSONAL); + removePreference(KEY_CATEGORY_WORK); + } else { + mAccountTypesForUser = (PreferenceGroup) findPreference(KEY_CATEGORY_PERSONAL); + mAddAccountForUser = findPreference(KEY_ADD_ACCOUNT_PERSONAL); + mAddAccountForUser.setOnPreferenceClickListener(this); + + // TODO: Show the work accounts also + // TODO: Handle the case where there is only one account + removePreference(KEY_CATEGORY_WORK); + removePreference(KEY_ADD_ACCOUNT); + } + updateAccountTypes(mAccountTypesForUser); + } + + @Override + public void onDestroy() { + super.onDestroy(); + stopListeningToAccountUpdates(); + } + + @Override + public void onAccountsUpdated(Account[] accounts) { + // TODO: watch for package upgrades to invalidate cache; see 7206643 + mAuthenticatorHelper.updateAuthDescriptions(getActivity()); + mAuthenticatorHelper.onAccountsUpdated(getActivity(), accounts); + listenToAccountUpdates(); + updateAccountTypes(mAccountTypesForUser); + } + + @Override + public boolean onPreferenceClick(Preference preference) { + // Check the preference + if (preference == mAddAccountForUser) { + Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); + startActivity(intent); + return true; + } + return false; + } + + private void updateAccountTypes(PreferenceGroup preferenceGroup) { + preferenceGroup.removeAll(); + preferenceGroup.setOrderingAsAdded(true); + for (AccountPreference preference : getAccountTypePreferences()) { + preferenceGroup.addPreference(preference); + } + if (mAddAccountForUser != null) { + preferenceGroup.addPreference(mAddAccountForUser); + } + } + + private List<AccountPreference> getAccountTypePreferences() { + String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes(); + List<AccountPreference> accountTypePreferences = + new ArrayList<AccountPreference>(accountTypes.length); + for (String accountType : accountTypes) { + CharSequence label = mAuthenticatorHelper.getLabelForType(getActivity(), accountType); + if (label == null) { + continue; + } + + Account[] accounts = AccountManager.get(getActivity()).getAccountsByType(accountType); + boolean skipToAccount = accounts.length == 1 + && !mAuthenticatorHelper.hasAccountPreferences(accountType); + + if (skipToAccount) { + Bundle fragmentArguments = new Bundle(); + fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY, + accounts[0]); + + accountTypePreferences.add(new AccountPreference( + getActivity(), + label, + accountType, + AccountSyncSettings.class.getName(), + fragmentArguments)); + } else { + Bundle fragmentArguments = new Bundle(); + fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType); + fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL, + label.toString()); + + accountTypePreferences.add(new AccountPreference( + getActivity(), + label, + accountType, + ManageAccountsSettings.class.getName(), + fragmentArguments)); + } + mAuthenticatorHelper.preloadDrawableForType(getActivity(), accountType); + } + // Sort by label + Collections.sort(accountTypePreferences, new Comparator<AccountPreference>() { + @Override + public int compare(AccountPreference t1, AccountPreference t2) { + return t1.mTitle.toString().compareTo(t2.mTitle.toString()); + } + }); + return accountTypePreferences; + } + + private void listenToAccountUpdates() { + if (!mListeningToAccountUpdates) { + AccountManager.get(getActivity()).addOnAccountsUpdatedListener(this, null, true); + mListeningToAccountUpdates = true; + } + } + + private void stopListeningToAccountUpdates() { + if (mListeningToAccountUpdates) { + AccountManager.get(getActivity()).removeOnAccountsUpdatedListener(this); + mListeningToAccountUpdates = false; + } + } + + private class AccountPreference extends Preference implements OnPreferenceClickListener { + /** + * Title of the tile that is shown to the user. + * @attr ref android.R.styleable#PreferenceHeader_title + */ + private final CharSequence mTitle; + + /** + * Full class name of the fragment to display when this tile is + * selected. + * @attr ref android.R.styleable#PreferenceHeader_fragment + */ + private final String mFragment; + + /** + * Optional arguments to supply to the fragment when it is + * instantiated. + */ + private final Bundle mFragmentArguments; + + + public AccountPreference(Context context, CharSequence title, + String accountType, String fragment, Bundle fragmentArguments) { + super(context); + mTitle = title; + mFragment = fragment; + mFragmentArguments = fragmentArguments; + setWidgetLayoutResource(R.layout.account_type_preference); + + Drawable drawable = mAuthenticatorHelper.getDrawableForType(context, accountType); + setTitle(title); + setIcon(drawable); + + setOnPreferenceClickListener(this); + } + + @Override + public boolean onPreferenceClick(Preference preference) { + if (mFragment != null) { + Utils.startWithFragment( + getContext(), mFragment, mFragmentArguments, null, 0, 0, mTitle); + return true; + } + return false; + } + } + // TODO Implement a {@link SearchIndexProvider} to allow Indexing and Search of account types + // See http://b/15403806 +} diff --git a/src/com/android/settings/inputmethod/UserDictionaryAddWordContents.java b/src/com/android/settings/inputmethod/UserDictionaryAddWordContents.java index d81703e..638818a 100644 --- a/src/com/android/settings/inputmethod/UserDictionaryAddWordContents.java +++ b/src/com/android/settings/inputmethod/UserDictionaryAddWordContents.java @@ -146,7 +146,9 @@ public class UserDictionaryAddWordContents { // should not insert, because either A. the word exists with no shortcut, in which // case the exact same thing we want to insert is already there, or B. the word // exists with at least one shortcut, in which case it has priority on our word. - if (hasWord(newWord, context)) return UserDictionaryAddWordActivity.CODE_ALREADY_PRESENT; + if (TextUtils.isEmpty(newShortcut) && hasWord(newWord, context)) { + return UserDictionaryAddWordActivity.CODE_ALREADY_PRESENT; + } // Disallow duplicates. If the same word with no shortcut is defined, remove it; if // the same word with the same shortcut is defined, remove it; but we don't mind if diff --git a/src/com/android/settings/print/PrintServiceSettingsFragment.java b/src/com/android/settings/print/PrintServiceSettingsFragment.java index 872f7b8..08b1a64 100644 --- a/src/com/android/settings/print/PrintServiceSettingsFragment.java +++ b/src/com/android/settings/print/PrintServiceSettingsFragment.java @@ -739,7 +739,7 @@ public class PrintServiceSettingsFragment extends SettingsPreferenceFragment } }); } - mDiscoverySession.startPrinterDisovery(null); + mDiscoverySession.startPrinterDiscovery(null); } } } diff --git a/src/com/android/settings/search/Index.java b/src/com/android/settings/search/Index.java index bcc6ca4..9723fbf 100644 --- a/src/com/android/settings/search/Index.java +++ b/src/com/android/settings/search/Index.java @@ -45,6 +45,7 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.lang.reflect.Field; +import java.text.Normalizer; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -54,6 +55,7 @@ import java.util.Locale; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Pattern; import static android.provider.SearchIndexablesContract.COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE; import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_RANK; @@ -153,6 +155,10 @@ public class Index { private static final List<String> EMPTY_LIST = Collections.<String>emptyList(); private static Index sInstance; + + private static final Pattern REMOVE_DIACRITICALS_PATTERN + = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); + private final AtomicBoolean mIsAvailable = new AtomicBoolean(false); private final UpdateData mDataToProcess = new UpdateData(); private Context mContext; @@ -924,31 +930,13 @@ public class Index { String intentAction, String intentTargetPackage, String intentTargetClass, boolean enabled, String key) { - String updatedTitle; - if (title != null) { - updatedTitle = title.replaceAll(NON_BREAKING_HYPHEN, HYPHEN); - } - else { - updatedTitle = EMPTY; - } + final String updatedTitle = normalizeHyphen(title); + final String updatedSummaryOn = normalizeHyphen(summaryOn); + final String updatedSummaryOff = normalizeHyphen(summaryOff); - String updatedSummaryOn; - if (summaryOn != null) { - updatedSummaryOn = summaryOn.replaceAll(NON_BREAKING_HYPHEN, HYPHEN); - } else { - updatedSummaryOn = EMPTY; - } - - String updatedSummaryOff; - if (summaryOff != null) { - updatedSummaryOff = summaryOff.replaceAll(NON_BREAKING_HYPHEN, HYPHEN); - } else { - updatedSummaryOff = EMPTY; - } - - String normalizedTitle = updatedTitle.replaceAll(HYPHEN, EMPTY); - String normalizedSummaryOn = updatedSummaryOn.replaceAll(HYPHEN, EMPTY); - String normalizedSummaryOff = updatedSummaryOff.replaceAll(HYPHEN, EMPTY); + final String normalizedTitle = normalizeString(updatedTitle); + final String normalizedSummaryOn = normalizeString(updatedSummaryOn); + final String normalizedSummaryOff = normalizeString(updatedSummaryOff); updateOneRow(database, locale, updatedTitle, normalizedTitle, updatedSummaryOn, normalizedSummaryOn, @@ -957,6 +945,17 @@ public class Index { rank, keywords, intentAction, intentTargetPackage, intentTargetClass, enabled, key); } + private static String normalizeHyphen(String input) { + return (input != null) ? input.replaceAll(NON_BREAKING_HYPHEN, HYPHEN) : EMPTY; + } + + private static String normalizeString(String input) { + final String nohyphen = (input != null) ? input.replaceAll(HYPHEN, EMPTY) : EMPTY; + final String normalized = Normalizer.normalize(nohyphen, Normalizer.Form.NFD); + + return REMOVE_DIACRITICALS_PATTERN.matcher(normalized).replaceAll("").toLowerCase(); + } + private void updateOneRow(SQLiteDatabase database, String locale, String updatedTitle, String normalizedTitle, String updatedSummaryOn, String normalizedSummaryOn, diff --git a/src/com/android/settings/tts/TextToSpeechSettings.java b/src/com/android/settings/tts/TextToSpeechSettings.java index 009b3b7..d3f9c7b 100644 --- a/src/com/android/settings/tts/TextToSpeechSettings.java +++ b/src/com/android/settings/tts/TextToSpeechSettings.java @@ -28,6 +28,7 @@ import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.ContentResolver; import android.content.Intent; +import android.os.AsyncTask; import android.os.Bundle; import android.preference.ListPreference; import android.preference.Preference; @@ -164,6 +165,9 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements setTtsUtteranceProgressListener(); initSettings(); + + // Prevent restarting the TTS connection on rotation + setRetainInstance(true); } @Override diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java index 73aae99..ea6325e 100644 --- a/src/com/android/settings/vpn2/VpnSettings.java +++ b/src/com/android/settings/vpn2/VpnSettings.java @@ -29,8 +29,10 @@ import android.os.Handler; import android.os.Message; import android.os.ServiceManager; import android.os.SystemProperties; +import android.os.UserManager; import android.preference.Preference; import android.preference.PreferenceGroup; +import android.preference.PreferenceScreen; import android.security.Credentials; import android.security.KeyStore; import android.text.TextUtils; @@ -45,6 +47,7 @@ import android.view.View; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.ArrayAdapter; import android.widget.ListView; +import android.widget.TextView; import android.widget.Toast; import com.android.internal.net.LegacyVpnInfo; @@ -80,14 +83,25 @@ public class VpnSettings extends SettingsPreferenceFragment implements private Handler mUpdater; private LegacyVpnInfo mInfo; + private UserManager mUm; // The key of the profile for the current ContextMenu. private String mSelectedKey; + private boolean mUnavailable; + @Override public void onCreate(Bundle savedState) { super.onCreate(savedState); + mUm = (UserManager) getSystemService(Context.USER_SERVICE); + + if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) { + mUnavailable = true; + setPreferenceScreen(new PreferenceScreen(getActivity(), null)); + return; + } + setHasOptionsMenu(true); addPreferencesFromResource(R.xml.vpn_settings2); @@ -156,6 +170,15 @@ public class VpnSettings extends SettingsPreferenceFragment implements public void onResume() { super.onResume(); + if (mUnavailable) { + TextView emptyView = (TextView) getView().findViewById(android.R.id.empty); + getListView().setEmptyView(emptyView); + if (emptyView != null) { + emptyView.setText(R.string.vpn_settings_not_available); + } + return; + } + final boolean pickLockdown = getActivity() .getIntent().getBooleanExtra(EXTRA_PICK_LOCKDOWN, false); if (pickLockdown) { @@ -214,6 +237,10 @@ public class VpnSettings extends SettingsPreferenceFragment implements public void onPause() { super.onPause(); + if (mUnavailable) { + return; + } + // Hide the dialog if there is one. if (mDialog != null) { mDialog.setOnDismissListener(null); diff --git a/src/com/android/settings/widget/ProportionalOuterFrame.java b/src/com/android/settings/widget/ProportionalOuterFrame.java new file mode 100644 index 0000000..d23d2c4 --- /dev/null +++ b/src/com/android/settings/widget/ProportionalOuterFrame.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * 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.widget; + +import android.content.Context; +import android.content.res.Resources; +import android.util.AttributeSet; +import android.view.View; +import android.widget.RelativeLayout; + +import com.android.settings.R; + +/** + * Used as the outer frame of all setup wizard pages that need to adjust their margins based + * on the total size of the available display. (e.g. side margins set to 10% of total width.) + */ +public class ProportionalOuterFrame extends RelativeLayout { + public ProportionalOuterFrame(Context context) { + super(context); + } + + public ProportionalOuterFrame(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ProportionalOuterFrame(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Set our margins and title area height proportionally to the available display size + */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int parentWidth = MeasureSpec.getSize(widthMeasureSpec); + final int parentHeight = MeasureSpec.getSize(heightMeasureSpec); + final Resources res = getContext().getResources(); + final float titleHeight = res.getFraction(R.dimen.setup_title_height, 1, 1); + final float sideMargin = res.getFraction(R.dimen.setup_border_width, 1, 1); + final int bottom = res.getDimensionPixelSize(R.dimen.setup_margin_bottom); + setPaddingRelative((int) (parentWidth * sideMargin), 0, + (int) (parentWidth * sideMargin), bottom); + final View title = findViewById(R.id.title_area); + if (title != null) { + title.setMinimumHeight((int) (parentHeight * titleHeight)); + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } +} diff --git a/src/com/android/settings/wifi/AccessPoint.java b/src/com/android/settings/wifi/AccessPoint.java index 688fc63..5c6ea1c 100644 --- a/src/com/android/settings/wifi/AccessPoint.java +++ b/src/com/android/settings/wifi/AccessPoint.java @@ -28,9 +28,13 @@ import android.net.wifi.WifiManager; import android.os.Bundle; import android.preference.Preference; import android.util.Log; +import android.util.LruCache; import android.view.View; import android.widget.ImageView; +import java.util.Map; + + class AccessPoint extends Preference { static final String TAG = "Settings.AccessPoint"; @@ -74,6 +78,21 @@ class AccessPoint extends Preference { private WifiInfo mInfo; private DetailedState mState; + private static final int VISIBILITY_MAX_AGE_IN_MILLI = 1000000; + private static final int VISIBILITY_OUTDATED_AGE_IN_MILLI = 20000; + private static final int LOWER_FREQ_24GHZ = 2400; + private static final int HIGHER_FREQ_24GHZ = 2500; + private static final int LOWER_FREQ_5GHZ = 4900; + private static final int HIGHER_FREQ_5GHZ = 5900; + private static final int SECOND_TO_MILLI = 1000; + + /** Experiemental: we should be able to show the user the list of BSSIDs and bands + * for that SSID. + * For now this data is used only with Verbose Logging so as to show the band and number + * of BSSIDs on which that network is seen. + */ + public LruCache<String, ScanResult> scanResultCache; + static int getSecurity(WifiConfiguration config) { if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { return SECURITY_PSK; @@ -201,6 +220,9 @@ class AccessPoint extends Preference { pskType = getPskType(result); mRssi = result.level; mScanResult = result; + if (result.seen > mSeen) { + mSeen = result.seen; + } } @Override @@ -267,6 +289,13 @@ class AccessPoint extends Preference { if (result.seen > mSeen) { mSeen = result.seen; } + if (WifiSettings.mVerboseLogging > 0) { + if (scanResultCache == null) { + scanResultCache = new LruCache<String, ScanResult>(32); + } + scanResultCache.put(result.BSSID, result); + } + if (ssid.equals(result.SSID) && security == getSecurity(result)) { if (WifiManager.compareSignalLevel(result.level, mRssi) > 0) { int oldLevel = getLevel(); @@ -339,26 +368,96 @@ class AccessPoint extends Preference { } /** visibility status of the WifiConfiguration - * @return RSSI and update indicator - * TODO: indicate both 2.4 and 5GHz RSSI as well as number of results + * @return autojoin debugging information + * TODO: use a string formatter * ["rssi 5Ghz", "num results on 5GHz" / "rssi 5Ghz", "num results on 5GHz"] * For instance [-40,5/-30,2] */ private String getVisibilityStatus() { - String visibility ; + StringBuilder visibility = new StringBuilder(); + long now = System.currentTimeMillis(); long age = (now - mSeen); - if (age < 1000000) { + if (age < VISIBILITY_MAX_AGE_IN_MILLI) { //show age in seconds, in the form xx - visibility = Long.toString((age / 1000) % 1000); + visibility.append(Long.toString((age / SECOND_TO_MILLI) % SECOND_TO_MILLI)) + .append("s"); } else { //not seen for more than 1000 seconds - visibility = "!"; + visibility.append("!"); } - if (mRssi != Integer.MAX_VALUE) { - visibility = visibility + ", " + Integer.toString(mRssi); + + if (mInfo != null) { + visibility.append(" sc=").append(Integer.toString(mInfo.score)); + visibility.append(" "); + visibility.append(String.format("tx=%.1f,", mInfo.txSuccessRate)); + visibility.append(String.format("%.1f,", mInfo.txRetriesRate)); + visibility.append(String.format("%.1f ", mInfo.txBadRate)); + visibility.append(String.format("rx=%.1f", mInfo.rxSuccessRate)); + } + + if (scanResultCache != null) { + int rssi5 = WifiConfiguration.INVALID_RSSI; + int rssi24 = WifiConfiguration.INVALID_RSSI; + int num5 = 0; + int num24 = 0; + Map<String, ScanResult> list = scanResultCache.snapshot(); + for (ScanResult result : list.values()) { + if (result.seen == 0) + continue; + + if (result.frequency > LOWER_FREQ_5GHZ + && result.frequency < HIGHER_FREQ_5GHZ) { + //strictly speaking: [4915, 5825] + //number of known BSSID on 5GHz band + num5 = num5 + 1; + } else if (result.frequency > LOWER_FREQ_24GHZ + && result.frequency < HIGHER_FREQ_24GHZ) { + //strictly speaking: [2412, 2482] + //number of known BSSID on 2.4Ghz band + num24 = num24 + 1; + } + + //ignore results seen, older than 20 seconds + if (now - result.seen > VISIBILITY_OUTDATED_AGE_IN_MILLI) continue; + + if (result.frequency > LOWER_FREQ_5GHZ + &&result.frequency < HIGHER_FREQ_5GHZ) { + if (result.level > rssi5) { + rssi5 = result.level; + } + } else if (result.frequency > LOWER_FREQ_24GHZ + && result.frequency < HIGHER_FREQ_24GHZ) { + if (result.level > rssi24) { + rssi24 = result.level; + } + } + } + visibility.append(" ["); + if (num24 > 0 || rssi24 > WifiConfiguration.INVALID_RSSI) { + visibility.append(Integer.toString(rssi24)); + visibility.append(","); + visibility.append(Integer.toString(num24)); + } + visibility.append(";"); + if (num5 > 0 || rssi5 > WifiConfiguration.INVALID_RSSI) { + visibility.append(Integer.toString(rssi5)); + visibility.append(","); + visibility.append(Integer.toString(num5)); + } + visibility.append("]"); + } else { + if (mRssi != Integer.MAX_VALUE) { + visibility.append(", ss="); + visibility.append(Integer.toString(mRssi)); + if (mScanResult != null) { + visibility.append(", "); + visibility.append(Integer.toString(mScanResult.frequency)); + } + } } - return visibility; + + return visibility.toString(); } /** Updates the title and summary; may indirectly call notifyChanged() */ @@ -367,9 +466,12 @@ class AccessPoint extends Preference { StringBuilder summary = new StringBuilder(); Context context = getContext(); - if (mConfig != null && (mConfig.status == WifiConfiguration.Status.DISABLED - || mConfig.autoJoinStatus != WifiConfiguration.AUTO_JOIN_ENABLED)) { - if (mConfig.autoJoinStatus != WifiConfiguration.AUTO_JOIN_ENABLED) { + + if (mState != null) { // This is the active connection + summary.append(Summary.get(context, mState)); + } else if (mConfig != null && (mConfig.status == WifiConfiguration.Status.DISABLED + || mConfig.autoJoinStatus >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE)) { + if (mConfig.autoJoinStatus >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) { summary.append(context.getString(R.string.wifi_disabled_password_failure)); } else { switch (mConfig.disableReason) { @@ -386,8 +488,6 @@ class AccessPoint extends Preference { } } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range summary.append(context.getString(R.string.wifi_not_in_range)); - } else if (mState != null) { // This is the active connection - summary.append(Summary.get(context, mState)); } else { // In range, not disabled. if (mConfig != null) { // Is saved network summary.append(context.getString(R.string.wifi_remembered)); @@ -415,6 +515,21 @@ class AccessPoint extends Preference { //add RSSI/band information for this config, what was seen up to 6 seconds ago //verbose WiFi Logging is only turned on thru developers settings summary.append(" " + getVisibilityStatus()); + if (mConfig != null && mConfig.autoJoinStatus > 0) { + summary.append(" (" + mConfig.autoJoinStatus); + if (mConfig.blackListTimestamp > 0) { + long now = System.currentTimeMillis(); + long diff = (now - mConfig.blackListTimestamp)/1000; + long sec = diff%60; //seconds + long min = (diff/60)%60; //minutes + long hour = (min/60)%60; //hours + summary.append(", "); + if (hour > 0) summary.append(Long.toString(hour) + "h "); + summary.append( Long.toString(min) + "m "); + summary.append( Long.toString(sec) + "s "); + } + summary.append(")"); + } } setSummary(summary.toString()); } diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java index 7ccfc6b..497132c 100644 --- a/src/com/android/settings/wifi/WifiConfigController.java +++ b/src/com/android/settings/wifi/WifiConfigController.java @@ -29,6 +29,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkUtils; import android.net.ProxyInfo; import android.net.RouteInfo; +import android.net.Uri; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.AuthAlgorithm; import android.net.wifi.WifiConfiguration.KeyMgmt; @@ -105,6 +106,7 @@ public class WifiConfigController implements TextWatcher, /* These values come from "wifi_proxy_settings" resource array */ public static final int PROXY_NONE = 0; public static final int PROXY_STATIC = 1; + public static final int PROXY_PAC = 2; /* These values come from "wifi_eap_method" resource array */ public static final int WIFI_EAP_METHOD_PEAP = 0; @@ -130,6 +132,7 @@ public class WifiConfigController implements TextWatcher, private TextView mProxyHostView; private TextView mProxyPortView; private TextView mProxyExclusionListView; + private TextView mProxyPacView; private IpAssignment mIpAssignment = IpAssignment.UNASSIGNED; private ProxySettings mProxySettings = ProxySettings.UNASSIGNED; @@ -257,11 +260,7 @@ public class WifiConfigController implements TextWatcher, mProxySettingsSpinner.setSelection(PROXY_STATIC); showAdvancedFields = true; } else if (config.getProxySettings() == ProxySettings.PAC) { - mProxySettingsSpinner.setVisibility(View.GONE); - TextView textView = (TextView)mView.findViewById(R.id.proxy_pac_info); - textView.setVisibility(View.VISIBLE); - textView.setText(context.getString(R.string.proxy_url) + - config.getLinkProperties().getHttpProxy().getPacFileUrl()); + mProxySettingsSpinner.setSelection(PROXY_PAC); showAdvancedFields = true; } else { mProxySettingsSpinner.setSelection(PROXY_NONE); @@ -466,11 +465,10 @@ public class WifiConfigController implements TextWatcher, } } - mProxySettings = (mProxySettingsSpinner != null && - mProxySettingsSpinner.getSelectedItemPosition() == PROXY_STATIC) ? - ProxySettings.STATIC : ProxySettings.NONE; - - if (mProxySettings == ProxySettings.STATIC && mProxyHostView != null) { + final int selectedPosition = mProxySettingsSpinner.getSelectedItemPosition(); + mProxySettings = ProxySettings.NONE; + if (selectedPosition == PROXY_STATIC && mProxyHostView != null) { + mProxySettings = ProxySettings.STATIC; String host = mProxyHostView.getText().toString(); String portStr = mProxyPortView.getText().toString(); String exclusionList = mProxyExclusionListView.getText().toString(); @@ -488,6 +486,18 @@ public class WifiConfigController implements TextWatcher, } else { return false; } + } else if (selectedPosition == PROXY_PAC && mProxyPacView != null) { + mProxySettings = ProxySettings.PAC; + CharSequence uriSequence = mProxyPacView.getText(); + if (TextUtils.isEmpty(uriSequence)) { + return false; + } + Uri uri = Uri.parse(uriSequence.toString()); + if (uri == null) { + return false; + } + ProxyInfo proxyInfo = new ProxyInfo(uri); + mLinkProperties.setHttpProxy(proxyInfo); } return true; } @@ -551,7 +561,7 @@ public class WifiConfigController implements TextWatcher, } catch (IllegalArgumentException e) { return R.string.wifi_ip_settings_invalid_dns; } - linkProperties.addDns(dnsAddr); + linkProperties.addDnsServer(dnsAddr); } if (mDns2View.length() > 0) { @@ -561,7 +571,7 @@ public class WifiConfigController implements TextWatcher, } catch (IllegalArgumentException e) { return R.string.wifi_ip_settings_invalid_dns; } - linkProperties.addDns(dnsAddr); + linkProperties.addDnsServer(dnsAddr); } return 0; } @@ -788,7 +798,7 @@ public class WifiConfigController implements TextWatcher, } } - Iterator<InetAddress> dnsIterator = linkProperties.getDnses().iterator(); + Iterator<InetAddress> dnsIterator = linkProperties.getDnsServers().iterator(); if (dnsIterator.hasNext()) { mDns1View.setText(dnsIterator.next().getHostAddress()); } @@ -811,8 +821,9 @@ public class WifiConfigController implements TextWatcher, } if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_STATIC) { - mView.findViewById(R.id.proxy_warning_limited_support).setVisibility(View.VISIBLE); - mView.findViewById(R.id.proxy_fields).setVisibility(View.VISIBLE); + setVisibility(R.id.proxy_warning_limited_support, View.VISIBLE); + setVisibility(R.id.proxy_fields, View.VISIBLE); + setVisibility(R.id.proxy_pac_field, View.GONE); if (mProxyHostView == null) { mProxyHostView = (TextView) mView.findViewById(R.id.proxy_hostname); mProxyHostView.addTextChangedListener(this); @@ -829,13 +840,34 @@ public class WifiConfigController implements TextWatcher, mProxyExclusionListView.setText(proxyProperties.getExclusionListAsString()); } } + } else if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_PAC) { + setVisibility(R.id.proxy_warning_limited_support, View.GONE); + setVisibility(R.id.proxy_fields, View.GONE); + setVisibility(R.id.proxy_pac_field, View.VISIBLE); + + if (mProxyPacView == null) { + mProxyPacView = (TextView) mView.findViewById(R.id.proxy_pac); + mProxyPacView.addTextChangedListener(this); + } + if (config != null) { + ProxyInfo proxyInfo = config.getLinkProperties().getHttpProxy(); + if (proxyInfo != null) { + mProxyPacView.setText(proxyInfo.getPacFileUrl().toString()); + } + } } else { - mView.findViewById(R.id.proxy_warning_limited_support).setVisibility(View.GONE); - mView.findViewById(R.id.proxy_fields).setVisibility(View.GONE); + setVisibility(R.id.proxy_warning_limited_support, View.GONE); + setVisibility(R.id.proxy_fields, View.GONE); + setVisibility(R.id.proxy_pac_field, View.GONE); } } - + private void setVisibility(int id, int visibility) { + final View v = mView.findViewById(id); + if (v != null) { + v.setVisibility(visibility); + } + } private void loadCertificates(Spinner spinner, String prefix) { final Context context = mConfigUi.getContext(); diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java index 9f0b6fa..d190045 100644 --- a/src/com/android/settings/wifi/WifiEnabler.java +++ b/src/com/android/settings/wifi/WifiEnabler.java @@ -27,6 +27,7 @@ import android.net.wifi.WifiManager; import android.os.Handler; import android.os.Message; import android.provider.Settings; +import android.view.View; import android.widget.CompoundButton; import android.widget.Switch; import android.widget.Toast; @@ -88,6 +89,11 @@ public class WifiEnabler implements SwitchBar.OnSwitchChangeListener { mContext = context; mSwitchBar = switchBar; mSwitch = switchBar.getSwitch(); + // This is a trick: as the Wi-Fi initial state is asynchronously coming from the + // BroadcastReceiver we cannot have the Switch visible at first otherwise you will notice + // its state change later on. So start it as VIEW.GONE and make it View.VISIBLE later + // when its state is defined. + mSwitch.setVisibility(View.GONE); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); @@ -133,6 +139,7 @@ public class WifiEnabler implements SwitchBar.OnSwitchChangeListener { mSwitch.setEnabled(true); updateSearchIndex(false); } + mSwitch.setVisibility(View.VISIBLE); } private void updateSearchIndex(boolean isWiFiOn) { diff --git a/src/com/android/settings/wifi/WifiPickerActivity.java b/src/com/android/settings/wifi/WifiPickerActivity.java index 6dea82e..4cb78bd 100644 --- a/src/com/android/settings/wifi/WifiPickerActivity.java +++ b/src/com/android/settings/wifi/WifiPickerActivity.java @@ -21,22 +21,28 @@ import com.android.settings.wifi.p2p.WifiP2pSettings; import android.content.Intent; +import java.lang.Class; + public class WifiPickerActivity extends SettingsActivity implements ButtonBarHandler { @Override public Intent getIntent() { Intent modIntent = new Intent(super.getIntent()); if (!modIntent.hasExtra(EXTRA_SHOW_FRAGMENT)) { - modIntent.putExtra(EXTRA_SHOW_FRAGMENT, WifiSettings.class.getName()); + modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getWifiSettingsClass().getName()); } return modIntent; } @Override protected boolean isValidFragment(String fragmentName) { - if (WifiSettings.class.getName().equals(fragmentName) + if (getWifiSettingsClass().getName().equals(fragmentName) || WifiP2pSettings.class.getName().equals(fragmentName) || AdvancedWifiSettings.class.getName().equals(fragmentName)) return true; return false; } + + /* package */ Class getWifiSettingsClass() { + return WifiSettings.class; + } }
\ No newline at end of file diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java index 604275a..3420f36 100644 --- a/src/com/android/settings/wifi/WifiSettings.java +++ b/src/com/android/settings/wifi/WifiSettings.java @@ -29,7 +29,6 @@ import com.android.settings.widget.SwitchBar; import com.android.settings.wifi.p2p.WifiP2pSettings; import android.app.Activity; -import android.app.AlertDialog; import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; @@ -40,7 +39,6 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.content.res.TypedArray; import android.location.LocationManager; -import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.wifi.ScanResult; @@ -54,23 +52,14 @@ import android.os.Handler; import android.os.Message; import android.preference.Preference; import android.preference.PreferenceScreen; -import android.util.AttributeSet; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; -import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; import android.widget.AdapterView.AdapterContextMenuInfo; -import android.widget.Button; -import android.widget.ImageButton; -import android.widget.PopupMenu; -import android.widget.PopupMenu.OnMenuItemClickListener; -import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; @@ -93,10 +82,10 @@ public class WifiSettings extends RestrictedSettingsFragment implements DialogInterface.OnClickListener, Indexable { private static final String TAG = "WifiSettings"; - private static final int MENU_ID_WPS_PBC = Menu.FIRST; + /* package */ static final int MENU_ID_WPS_PBC = Menu.FIRST; private static final int MENU_ID_WPS_PIN = Menu.FIRST + 1; private static final int MENU_ID_P2P = Menu.FIRST + 2; - private static final int MENU_ID_ADD_NETWORK = Menu.FIRST + 3; + /* package */ static final int MENU_ID_ADD_NETWORK = Menu.FIRST + 3; private static final int MENU_ID_ADVANCED = Menu.FIRST + 4; private static final int MENU_ID_SCAN = Menu.FIRST + 5; private static final int MENU_ID_CONNECT = Menu.FIRST + 6; @@ -105,10 +94,10 @@ public class WifiSettings extends RestrictedSettingsFragment private static final int MENU_ID_WRITE_NFC = Menu.FIRST + 9; private static final int WIFI_DIALOG_ID = 1; - private static final int WPS_PBC_DIALOG_ID = 2; + /* package */ static final int WPS_PBC_DIALOG_ID = 2; private static final int WPS_PIN_DIALOG_ID = 3; - private static final int WIFI_SKIPPED_DIALOG_ID = 4; - private static final int WIFI_AND_MOBILE_SKIPPED_DIALOG_ID = 5; + /* package */ static final int WIFI_SKIPPED_DIALOG_ID = 4; + /* package */ static final int WIFI_AND_MOBILE_SKIPPED_DIALOG_ID = 5; private static final int WRITE_NFC_DIALOG_ID = 6; // Combo scans can take 5-6s to complete - set to 10s. @@ -118,14 +107,11 @@ public class WifiSettings extends RestrictedSettingsFragment private static final String SAVE_DIALOG_EDIT_MODE = "edit_mode"; private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state"; - // Activity result when pressing the Skip button - private static final int RESULT_SKIP = Activity.RESULT_FIRST_USER; - private final IntentFilter mFilter; private final BroadcastReceiver mReceiver; private final Scanner mScanner; - private WifiManager mWifiManager; + /* package */ WifiManager mWifiManager; private WifiManager.ActionListener mConnectListener; private WifiManager.ActionListener mSaveListener; private WifiManager.ActionListener mForgetListener; @@ -145,39 +131,17 @@ public class WifiSettings extends RestrictedSettingsFragment private TextView mEmptyView; - /* Used in Wifi Setup context */ - - // this boolean extra specifies whether to disable the Next button when not connected - private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect"; - - // this boolean extra specifies whether to auto finish when connection is established - private static final String EXTRA_AUTO_FINISH_ON_CONNECT = "wifi_auto_finish_on_connect"; - - // this boolean extra shows a custom button that we can control - protected static final String EXTRA_SHOW_CUSTOM_BUTTON = "wifi_show_custom_button"; - - // show a text regarding data charges when wifi connection is required during setup wizard - protected static final String EXTRA_SHOW_WIFI_REQUIRED_INFO = "wifi_show_wifi_required_info"; - - // this boolean extra is set if we are being invoked by the Setup Wizard - private static final String EXTRA_IS_FIRST_RUN = "firstRun"; - - // should Next button only be enabled when we have a connection? - private boolean mEnableNextOnConnection; - - // should activity finish once we have a connection? - private boolean mAutoFinishOnConnection; - // Save the dialog details private boolean mDlgEdit; private AccessPoint mDlgAccessPoint; private Bundle mAccessPointSavedState; - // the action bar uses a different set of controls for Setup Wizard - private boolean mSetupWizardMode; - private SwitchBar mSwitchBar; + /** verbose logging flag. this flag is set thru developer debugging options + * and used so as to assist with in-the-field WiFi connectivity debugging */ + public static int mVerboseLogging = 0; + /* End of "used in Wifi Setup context" */ public WifiSettings() { @@ -203,93 +167,6 @@ public class WifiSettings extends RestrictedSettingsFragment } @Override - public void onCreate(Bundle icicle) { - // Set this flag early, as it's needed by getHelpResource(), which is called by super - mSetupWizardMode = getActivity().getIntent().getBooleanExtra(EXTRA_IS_FIRST_RUN, false); - super.onCreate(icicle); - } - - @Override - public View onCreateView(final LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - - if (mSetupWizardMode) { - View view = inflater.inflate(R.layout.setup_preference, container, false); - View other = view.findViewById(R.id.other_network); - other.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (mWifiManager.isWifiEnabled()) { - onAddNetworkPressed(); - } - } - }); - final ImageButton b = (ImageButton) view.findViewById(R.id.more); - if (b != null) { - b.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (mWifiManager.isWifiEnabled()) { - PopupMenu pm = new PopupMenu(inflater.getContext(), b); - pm.inflate(R.menu.wifi_setup); - pm.setOnMenuItemClickListener(new OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - if (R.id.wifi_wps == item.getItemId()) { - showDialog(WPS_PBC_DIALOG_ID); - return true; - } - return false; - } - }); - pm.show(); - } - } - }); - } - - Intent intent = getActivity().getIntent(); - if (intent.getBooleanExtra(EXTRA_SHOW_CUSTOM_BUTTON, false)) { - view.findViewById(R.id.button_bar).setVisibility(View.VISIBLE); - view.findViewById(R.id.back_button).setVisibility(View.INVISIBLE); - view.findViewById(R.id.skip_button).setVisibility(View.INVISIBLE); - view.findViewById(R.id.next_button).setVisibility(View.INVISIBLE); - - Button customButton = (Button) view.findViewById(R.id.custom_button); - customButton.setVisibility(View.VISIBLE); - customButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - boolean isConnected = false; - Activity activity = getActivity(); - final ConnectivityManager connectivity = (ConnectivityManager) - activity.getSystemService(Context.CONNECTIVITY_SERVICE); - if (connectivity != null) { - final NetworkInfo info = connectivity.getActiveNetworkInfo(); - isConnected = (info != null) && info.isConnected(); - } - if (isConnected) { - // Warn of possible data charges - showDialog(WIFI_SKIPPED_DIALOG_ID); - } else { - // Warn of lack of updates - showDialog(WIFI_AND_MOBILE_SKIPPED_DIALOG_ID); - } - } - }); - } - - if (intent.getBooleanExtra(EXTRA_SHOW_WIFI_REQUIRED_INFO, false)) { - view.findViewById(R.id.wifi_required_info).setVisibility(View.VISIBLE); - } - - return view; - } else { - return super.onCreateView(inflater, container, savedInstanceState); - } - } - - @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); @@ -347,60 +224,11 @@ public class WifiSettings extends RestrictedSettingsFragment mAccessPointSavedState = savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE); } - final Activity activity = getActivity(); - final Intent intent = activity.getIntent(); - - // first if we're supposed to finish once we have a connection - mAutoFinishOnConnection = intent.getBooleanExtra(EXTRA_AUTO_FINISH_ON_CONNECT, false); - - if (mAutoFinishOnConnection) { - // Hide the next button - if (hasNextButton()) { - getNextButton().setVisibility(View.GONE); - } - - final ConnectivityManager connectivity = (ConnectivityManager) - activity.getSystemService(Context.CONNECTIVITY_SERVICE); - if (connectivity != null - && connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected()) { - activity.setResult(Activity.RESULT_OK); - activity.finish(); - return; - } - } - - // if we're supposed to enable/disable the Next button based on our current connection - // state, start it off in the right state - mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false); - - if (mEnableNextOnConnection) { - if (hasNextButton()) { - final ConnectivityManager connectivity = (ConnectivityManager) - activity.getSystemService(Context.CONNECTIVITY_SERVICE); - if (connectivity != null) { - NetworkInfo info = connectivity.getNetworkInfo( - ConnectivityManager.TYPE_WIFI); - changeNextButtonState(info.isConnected()); - } - } - } - addPreferencesFromResource(R.xml.wifi_settings); - if (mSetupWizardMode) { - getView().setSystemUiVisibility( - View.STATUS_BAR_DISABLE_HOME | - View.STATUS_BAR_DISABLE_RECENT | - View.STATUS_BAR_DISABLE_NOTIFICATION_ALERTS | - View.STATUS_BAR_DISABLE_CLOCK); - } - mEmptyView = (TextView) getView().findViewById(android.R.id.empty); getListView().setEmptyView(mEmptyView); - - if (!mSetupWizardMode) { - registerForContextMenu(getListView()); - } + registerForContextMenu(getListView()); setHasOptionsMenu(true); } @@ -408,13 +236,16 @@ public class WifiSettings extends RestrictedSettingsFragment public void onStart() { super.onStart(); - // On/off switch is hidden for Setup Wizard - if (!mSetupWizardMode) { - final SettingsActivity activity = (SettingsActivity) getActivity(); + // On/off switch is hidden for Setup Wizard (returns null) + mWifiEnabler = createWifiEnabler(); + } - mSwitchBar = activity.getSwitchBar(); - mWifiEnabler = new WifiEnabler(activity, mSwitchBar); - } + /** + * @return new WifiEnabler or null (as overridden by WifiSettingsForSetupWizard) + */ + /* package */ WifiEnabler createWifiEnabler() { + final SettingsActivity activity = (SettingsActivity) getActivity(); + return new WifiEnabler(activity, activity.getSwitchBar()); } @Override @@ -445,44 +276,41 @@ public class WifiSettings extends RestrictedSettingsFragment // If the user is not allowed to configure wifi, do not show the menu. if (isRestrictedAndNotPinProtected()) return; + addOptionsMenuItems(menu); + super.onCreateOptionsMenu(menu, inflater); + } + + /** + * @param menu + */ + void addOptionsMenuItems(Menu menu) { final boolean wifiIsEnabled = mWifiManager.isWifiEnabled(); TypedArray ta = getActivity().getTheme().obtainStyledAttributes( new int[] {R.attr.ic_menu_add, R.attr.ic_wps}); - if (mSetupWizardMode) { - menu.add(Menu.NONE, MENU_ID_WPS_PBC, 0, R.string.wifi_menu_wps_pbc) - .setIcon(ta.getDrawable(1)) - .setEnabled(wifiIsEnabled) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - menu.add(Menu.NONE, MENU_ID_ADD_NETWORK, 0, R.string.wifi_add_network) - .setEnabled(wifiIsEnabled) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - } else { - menu.add(Menu.NONE, MENU_ID_WPS_PBC, 0, R.string.wifi_menu_wps_pbc) - .setIcon(ta.getDrawable(1)) - .setEnabled(wifiIsEnabled) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - menu.add(Menu.NONE, MENU_ID_ADD_NETWORK, 0, R.string.wifi_add_network) - .setIcon(ta.getDrawable(0)) - .setEnabled(wifiIsEnabled) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan) - //.setIcon(R.drawable.ic_menu_scan_network) - .setEnabled(wifiIsEnabled) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - menu.add(Menu.NONE, MENU_ID_WPS_PIN, 0, R.string.wifi_menu_wps_pin) + menu.add(Menu.NONE, MENU_ID_WPS_PBC, 0, R.string.wifi_menu_wps_pbc) + .setIcon(ta.getDrawable(1)) + .setEnabled(wifiIsEnabled) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + menu.add(Menu.NONE, MENU_ID_ADD_NETWORK, 0, R.string.wifi_add_network) + .setIcon(ta.getDrawable(0)) + .setEnabled(wifiIsEnabled) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan) + //.setIcon(R.drawable.ic_menu_scan_network) + .setEnabled(wifiIsEnabled) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + menu.add(Menu.NONE, MENU_ID_WPS_PIN, 0, R.string.wifi_menu_wps_pin) + .setEnabled(wifiIsEnabled) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + if (mP2pSupported) { + menu.add(Menu.NONE, MENU_ID_P2P, 0, R.string.wifi_menu_p2p) .setEnabled(wifiIsEnabled) .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - if (mP2pSupported) { - menu.add(Menu.NONE, MENU_ID_P2P, 0, R.string.wifi_menu_p2p) - .setEnabled(wifiIsEnabled) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - } - menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced) - //.setIcon(android.R.drawable.ic_menu_manage) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); } + menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced) + //.setIcon(android.R.drawable.ic_menu_manage) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); ta.recycle(); - super.onCreateOptionsMenu(menu, inflater); } @Override @@ -663,44 +491,6 @@ public class WifiSettings extends RestrictedSettingsFragment return new WpsDialog(getActivity(), WpsInfo.PBC); case WPS_PIN_DIALOG_ID: return new WpsDialog(getActivity(), WpsInfo.DISPLAY); - case WIFI_SKIPPED_DIALOG_ID: - return new AlertDialog.Builder(getActivity()) - .setMessage(R.string.wifi_skipped_message) - .setCancelable(false) - .setNegativeButton(R.string.wifi_skip_anyway, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - getActivity().setResult(RESULT_SKIP); - getActivity().finish(); - } - }) - .setPositiveButton(R.string.wifi_dont_skip, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - } - }) - .create(); - case WIFI_AND_MOBILE_SKIPPED_DIALOG_ID: - return new AlertDialog.Builder(getActivity()) - .setMessage(R.string.wifi_and_mobile_skipped_message) - .setCancelable(false) - .setNegativeButton(R.string.wifi_skip_anyway, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - getActivity().setResult(RESULT_SKIP); - getActivity().finish(); - } - }) - .setPositiveButton(R.string.wifi_dont_skip, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - } - }) - .create(); case WRITE_NFC_DIALOG_ID: if (mSelectedAccessPoint != null) { mWifiToNfcDialog = new WriteWifiConfigToNfcDialog( @@ -712,10 +502,8 @@ public class WifiSettings extends RestrictedSettingsFragment return super.onCreateDialog(dialogId); } - /** verbose logging flag is set only thru developer debugging options */ - public static int mVerboseLogging = 0; /** - * Shows the latest access points available with supplimental information like + * Shows the latest access points available with supplemental information like * the strength of network and the security for it. */ private void updateAccessPoints() { @@ -728,7 +516,7 @@ public class WifiSettings extends RestrictedSettingsFragment } final int wifiState = mWifiManager.getWifiState(); - //check if verbose logging has been turned on or off + //when we update the screen, check if verbose logging has been turned on or off mVerboseLogging = mWifiManager.getVerboseLoggingLevel(); switch (wifiState) { @@ -880,17 +668,8 @@ public class WifiSettings extends RestrictedSettingsFragment NetworkInfo info = (NetworkInfo) intent.getParcelableExtra( WifiManager.EXTRA_NETWORK_INFO); mConnected.set(info.isConnected()); - changeNextButtonState(info.isConnected()); updateAccessPoints(); updateConnectionState(info.getDetailedState()); - if (mAutoFinishOnConnection && info.isConnected()) { - Activity activity = getActivity(); - if (activity != null) { - activity.setResult(Activity.RESULT_OK); - activity.finish(); - } - return; - } } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) { updateConnectionState(null); } @@ -984,18 +763,6 @@ public class WifiSettings extends RestrictedSettingsFragment } } - /** - * Renames/replaces "Next" button when appropriate. "Next" button usually exists in - * Wifi setup screens, not in usual wifi settings screen. - * - * @param connected true when the device is connected to a wifi network. - */ - private void changeNextButtonState(boolean connected) { - if (mEnableNextOnConnection && hasNextButton()) { - getNextButton().setEnabled(connected); - } - } - @Override public void onClick(DialogInterface dialogInterface, int button) { if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) { @@ -1037,7 +804,7 @@ public class WifiSettings extends RestrictedSettingsFragment /* package */ void forget() { if (mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) { - // Should not happen, but a monkey seems to triger it + // Should not happen, but a monkey seems to trigger it Log.e(TAG, "Failed to forget invalid network " + mSelectedAccessPoint.getConfig()); return; } @@ -1048,9 +815,6 @@ public class WifiSettings extends RestrictedSettingsFragment mScanner.resume(); } updateAccessPoints(); - - // We need to rename/replace "Next" button in wifi setup context. - changeNextButtonState(false); } /** @@ -1102,51 +866,9 @@ public class WifiSettings extends RestrictedSettingsFragment @Override protected int getHelpResource() { - if (mSetupWizardMode) { - return 0; - } return R.string.help_url_wifi; } - /** - * Used as the outer frame of all setup wizard pages that need to adjust their margins based - * on the total size of the available display. (e.g. side margins set to 10% of total width.) - */ - public static class ProportionalOuterFrame extends RelativeLayout { - public ProportionalOuterFrame(Context context) { - super(context); - } - public ProportionalOuterFrame(Context context, AttributeSet attrs) { - super(context, attrs); - } - public ProportionalOuterFrame(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - /** - * Set our margins and title area height proportionally to the available display size - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int parentWidth = MeasureSpec.getSize(widthMeasureSpec); - int parentHeight = MeasureSpec.getSize(heightMeasureSpec); - final Resources res = getContext().getResources(); - float titleHeight = res.getFraction(R.dimen.setup_title_height, 1, 1); - float sideMargin = res.getFraction(R.dimen.setup_border_width, 1, 1); - int bottom = res.getDimensionPixelSize(R.dimen.setup_margin_bottom); - setPaddingRelative( - (int) (parentWidth * sideMargin), - 0, - (int) (parentWidth * sideMargin), - bottom); - View title = findViewById(R.id.title_area); - if (title != null) { - title.setMinimumHeight((int) (parentHeight * titleHeight)); - } - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - } - public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider() { @Override diff --git a/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java b/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java new file mode 100644 index 0000000..17fca9f --- /dev/null +++ b/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2014 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.app.AlertDialog; +import android.app.Dialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.TypedArray; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageButton; +import android.widget.PopupMenu; +import android.widget.PopupMenu.OnMenuItemClickListener; + +import com.android.settings.R; + +/** + * This customized version of WifiSettings is shown to the user only during Setup Wizard. Menu + * selections are limited, clicking on an access point will auto-advance to the next screen (once + * connected), and, if the user opts to skip ahead without a wifi connection, a warning message + * alerts of possible carrier data charges or missing software updates. + */ +public class WifiSettingsForSetupWizard extends WifiSettings { + + private static final String TAG = "WifiSettingsForSetupWizard"; + + /* Used in Wifi Setup context */ + + // this boolean extra specifies whether to disable the Next button when not connected + private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect"; + + // this boolean extra specifies whether to auto finish when connection is established + private static final String EXTRA_AUTO_FINISH_ON_CONNECT = "wifi_auto_finish_on_connect"; + + // this boolean extra shows a custom button that we can control + protected static final String EXTRA_SHOW_CUSTOM_BUTTON = "wifi_show_custom_button"; + + // show a text regarding data charges when wifi connection is required during setup wizard + protected static final String EXTRA_SHOW_WIFI_REQUIRED_INFO = "wifi_show_wifi_required_info"; + + // this boolean extra is set if we are being invoked by the Setup Wizard + private static final String EXTRA_IS_FIRST_RUN = "firstRun"; + + // Activity result when pressing the Skip button + private static final int RESULT_SKIP = Activity.RESULT_FIRST_USER; + + // From WizardManager (must match constants maintained there) + private static final String ACTION_NEXT = "com.android.wizard.NEXT"; + private static final String EXTRA_SCRIPT_URI = "scriptUri"; + private static final String EXTRA_ACTION_ID = "actionId"; + private static final String EXTRA_RESULT_CODE = "com.android.setupwizard.ResultCode"; + private static final int NEXT_REQUEST = 10000; + + // should Next button only be enabled when we have a connection? + private boolean mEnableNextOnConnection; + + // should activity finish once we have a connection? + private boolean mAutoFinishOnConnection; + + private final IntentFilter mFilter; + private final BroadcastReceiver mReceiver; + + public WifiSettingsForSetupWizard() { + super(); + + mFilter = new IntentFilter(); + mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + + mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + NetworkInfo info = (NetworkInfo) intent.getParcelableExtra( + WifiManager.EXTRA_NETWORK_INFO); + changeNextButtonState(info.isConnected()); + if (mAutoFinishOnConnection && info.isConnected()) { + Log.d(TAG, "mReceiver.onReceive context=" + context + " intent=" + intent); + finishOrNext(Activity.RESULT_OK); + } + } + }; + } + + @Override + public View onCreateView(final LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + final View view = inflater.inflate(R.layout.setup_preference, container, false); + final View other = view.findViewById(R.id.other_network); + other.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mWifiManager.isWifiEnabled()) { + onAddNetworkPressed(); + } + } + }); + final ImageButton b = (ImageButton) view.findViewById(R.id.more); + if (b != null) { + b.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mWifiManager.isWifiEnabled()) { + PopupMenu pm = new PopupMenu(inflater.getContext(), b); + pm.inflate(R.menu.wifi_setup); + pm.setOnMenuItemClickListener(new OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + if (R.id.wifi_wps == item.getItemId()) { + showDialog(WPS_PBC_DIALOG_ID); + return true; + } + return false; + } + }); + pm.show(); + } + } + }); + } + + final Intent intent = getActivity().getIntent(); + if (intent.getBooleanExtra(EXTRA_SHOW_CUSTOM_BUTTON, false)) { + view.findViewById(R.id.button_bar).setVisibility(View.VISIBLE); + view.findViewById(R.id.back_button).setVisibility(View.INVISIBLE); + view.findViewById(R.id.skip_button).setVisibility(View.INVISIBLE); + view.findViewById(R.id.next_button).setVisibility(View.INVISIBLE); + + Button customButton = (Button) view.findViewById(R.id.custom_button); + customButton.setVisibility(View.VISIBLE); + customButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + boolean isConnected = false; + Activity activity = getActivity(); + final ConnectivityManager connectivity = (ConnectivityManager) + activity.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivity != null) { + final NetworkInfo info = connectivity.getActiveNetworkInfo(); + isConnected = (info != null) && info.isConnected(); + } + if (isConnected) { + // Warn of possible data charges + showDialog(WIFI_SKIPPED_DIALOG_ID); + } else { + // Warn of lack of updates + showDialog(WIFI_AND_MOBILE_SKIPPED_DIALOG_ID); + } + } + }); + } + + if (intent.getBooleanExtra(EXTRA_SHOW_WIFI_REQUIRED_INFO, false)) { + view.findViewById(R.id.wifi_required_info).setVisibility(View.VISIBLE); + } + + return view; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + getView().setSystemUiVisibility( + View.STATUS_BAR_DISABLE_HOME | + View.STATUS_BAR_DISABLE_RECENT | + View.STATUS_BAR_DISABLE_NOTIFICATION_ALERTS | + View.STATUS_BAR_DISABLE_CLOCK); + + final Activity activity = getActivity(); + final Intent intent = activity.getIntent(); + + // first if we're supposed to finish once we have a connection + mAutoFinishOnConnection = intent.getBooleanExtra(EXTRA_AUTO_FINISH_ON_CONNECT, false); + + /* + * When entering with a savedInstanceState, we may be returning from a later activity in the + * setup flow. It's not clear yet if there are other possible circumstances. It's not + * appropriate to refire our activity results, so we skip that here. + */ + if (mAutoFinishOnConnection && null == savedInstanceState) { + // Hide the next button + if (hasNextButton()) { + getNextButton().setVisibility(View.GONE); + } + + final ConnectivityManager connectivity = (ConnectivityManager) + activity.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivity != null + && connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected()) { + Log.d(TAG, "onActivityCreated Auto-finishing"); + finishOrNext(Activity.RESULT_OK); + return; + } + } + + // if we're supposed to enable/disable the Next button based on our current connection + // state, start it off in the right state + mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false); + + if (mEnableNextOnConnection) { + if (hasNextButton()) { + final ConnectivityManager connectivity = (ConnectivityManager) + activity.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivity != null) { + NetworkInfo info = connectivity.getNetworkInfo( + ConnectivityManager.TYPE_WIFI); + changeNextButtonState(info.isConnected()); + } + } + } + } + + @Override + public Dialog onCreateDialog(int dialogId) { + switch (dialogId) { + case WIFI_SKIPPED_DIALOG_ID: + return new AlertDialog.Builder(getActivity()) + .setMessage(R.string.wifi_skipped_message) + .setCancelable(false) + .setNegativeButton(R.string.wifi_skip_anyway, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + finishOrNext(RESULT_SKIP); + } + }) + .setPositiveButton(R.string.wifi_dont_skip, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + } + }) + .create(); + case WIFI_AND_MOBILE_SKIPPED_DIALOG_ID: + return new AlertDialog.Builder(getActivity()) + .setMessage(R.string.wifi_and_mobile_skipped_message) + .setCancelable(false) + .setNegativeButton(R.string.wifi_skip_anyway, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + finishOrNext(RESULT_SKIP); + } + }) + .setPositiveButton(R.string.wifi_dont_skip, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + } + }) + .create(); + } + return super.onCreateDialog(dialogId); + } + + @Override + public void onResume() { + super.onResume(); + getActivity().registerReceiver(mReceiver, mFilter); + } + + @Override + public void onPause() { + super.onPause(); + getActivity().unregisterReceiver(mReceiver); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == Activity.RESULT_CANCELED) { + // Before returning to the settings panel, forget any current access point so it will + // not attempt to automatically reconnect and advance + // FIXME: when coming back, it would be better to keep the current connection and + // override the auto-advance feature + final WifiInfo info = mWifiManager.getConnectionInfo(); + if (null != info) { + int netId = info.getNetworkId(); + if (netId != WifiConfiguration.INVALID_NETWORK_ID) { + mWifiManager.forget(netId, null); + } + } + } + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + public void registerForContextMenu(View view) { + // Suppressed during setup wizard + } + + @Override + /* package */ WifiEnabler createWifiEnabler() { + // Not shown during setup wizard + return null; + } + + @Override + /* package */ void addOptionsMenuItems(Menu menu) { + final boolean wifiIsEnabled = mWifiManager.isWifiEnabled(); + final TypedArray ta = getActivity().getTheme() + .obtainStyledAttributes(new int[] {R.attr.ic_wps}); + menu.add(Menu.NONE, MENU_ID_WPS_PBC, 0, R.string.wifi_menu_wps_pbc) + .setIcon(ta.getDrawable(0)) + .setEnabled(wifiIsEnabled) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + menu.add(Menu.NONE, MENU_ID_ADD_NETWORK, 0, R.string.wifi_add_network) + .setEnabled(wifiIsEnabled) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + ta.recycle(); + } + + @Override + /* package */ void forget() { + super.forget(); + + // We need to rename/replace "Next" button in wifi setup context. + changeNextButtonState(false); + } + + /** + * Renames/replaces "Next" button when appropriate. "Next" button usually exists in + * Wifi setup screens, not in usual wifi settings screen. + * + * @param enabled true when the device is connected to a wifi network. + */ + private void changeNextButtonState(boolean enabled) { + if (mEnableNextOnConnection && hasNextButton()) { + getNextButton().setEnabled(enabled); + } + } + + /** + * Complete this activity and return the results to the caller. If using WizardManager, this + * will invoke the next scripted action; otherwise, we simply finish. + */ + private void finishOrNext(int resultCode) { + Log.d(TAG, "finishOrNext resultCode=" + resultCode + + " isUsingWizardManager=" + isUsingWizardManager()); + if (isUsingWizardManager()) { + sendResultsToSetupWizard(resultCode); + } else { + Activity activity = getActivity(); + activity.setResult(resultCode); + activity.finish(); + } + } + + private boolean isUsingWizardManager() { + return getActivity().getIntent().hasExtra(EXTRA_SCRIPT_URI); + } + + /** + * Send the results of this activity to WizardManager, which will then send out the next + * scripted activity. WizardManager does not actually return an activity result, but if we + * invoke WizardManager without requesting a result, the framework will choose not to issue a + * call to onActivityResult with RESULT_CANCELED when navigating backward. + */ + private void sendResultsToSetupWizard(int resultCode) { + final Intent intent = getActivity().getIntent(); + final Intent nextIntent = new Intent(ACTION_NEXT); + nextIntent.putExtra(EXTRA_SCRIPT_URI, intent.getStringExtra(EXTRA_SCRIPT_URI)); + nextIntent.putExtra(EXTRA_ACTION_ID, intent.getStringExtra(EXTRA_ACTION_ID)); + nextIntent.putExtra(EXTRA_RESULT_CODE, resultCode); + startActivityForResult(nextIntent, NEXT_REQUEST); + } +} diff --git a/src/com/android/settings/wifi/WifiSetupActivity.java b/src/com/android/settings/wifi/WifiSetupActivity.java index 70ee56d..d4811ed 100644 --- a/src/com/android/settings/wifi/WifiSetupActivity.java +++ b/src/com/android/settings/wifi/WifiSetupActivity.java @@ -19,6 +19,8 @@ import com.android.settings.ButtonBarHandler; import android.content.res.Resources; +import java.lang.Class; + public class WifiSetupActivity extends WifiPickerActivity implements ButtonBarHandler { // Extra containing the resource name of the theme to be used private static final String EXTRA_THEME = "theme"; @@ -41,4 +43,9 @@ public class WifiSetupActivity extends WifiPickerActivity implements ButtonBarHa } super.onApplyThemeResource(theme, resid, first); } + + @Override + /* package */ Class getWifiSettingsClass() { + return WifiSettingsForSetupWizard.class; + } } |