OSDN Git Service

VPN settings: gray out always-on checkbox dynamically
authorCharles He <qiurui@google.com>
Mon, 20 Mar 2017 14:00:06 +0000 (14:00 +0000)
committerCharles He <qiurui@google.com>
Wed, 22 Mar 2017 20:29:46 +0000 (20:29 +0000)
In the ConfigDialog for legacy VPNs, many configurations do not support
Always-on VPN. Previously, when a user entered an unsupported set of
settings, the Always-on VPN checkbox could still be ticked, and the
Save or Connect action buttons would be disabled. This was not intuitive
as the user could not easily figure out which part of the settings was
incompatible that grayed out the action buttons.

With this change, we disable the Always-on VPN checkbox immediately as
the user enters any incompatible setting. We also display the reason why
Always-on VPN is disabled. This will make it more straightforward for
the users to understand which setting is conflicting with the Always-on
feature.

This change is also the first step towards refactoring the ConfigDialog
for legacy VPNs with PreferenceFragment.

Test: manual
Bug: 29208008
Bug: 28072644
Change-Id: I1e6d32a1069ca0b936513f4985ffb9a9412b249c

res/layout/vpn_dialog.xml
res/values/strings.xml
res/values/styles.xml
src/com/android/settings/vpn2/ConfigDialog.java

index 61b0861..7731e6d 100644 (file)
         <LinearLayout android:id="@+id/login"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:orientation="vertical">
+                android:orientation="vertical"
+                android:animateLayoutChanges="true">
 
             <TextView style="@style/vpn_label" android:text="@string/vpn_username"/>
             <EditText style="@style/vpn_value" android:id="@+id/username"/>
             <CheckBox style="@style/vpn_value" android:id="@+id/always_on_vpn"
                 android:singleLine="false"
                 android:text="@string/vpn_menu_lockdown"/>
+            <TextView style="@style/vpn_warning" android:id="@+id/always_on_invalid_reason"
+                android:singleLine="false"
+                android:visibility="gone"/>
         </LinearLayout>
     </LinearLayout>
 </ScrollView>
index e7a0535..fab3a8e 100644 (file)
     <string name="vpn_no_ca_cert">(don\u2019t verify server)</string>
     <!-- Option to use the server certificate received from the VPN server. [CHAR LIMIT=40] -->
     <string name="vpn_no_server_cert">(received from server)</string>
+    <!-- Reason for Always-on VPN checkbox being disabled: the selected VPN type doesn't support always-on. [CHAR LIMIT=120] -->
+    <string name="vpn_always_on_invalid_reason_type">The selected VPN type can\u2019t be always on</string>
+    <!-- Reason for Always-on VPN checkbox being disabled: the server address is invalid. [CHAR LIMIT=120] -->
+    <string name="vpn_always_on_invalid_reason_server">Always-on VPN only supports numeric server addresses</string>
+    <!-- Reason for Always-on VPN checkbox being disabled: no DNS is found. [CHAR LIMIT=120] -->
+    <string name="vpn_always_on_invalid_reason_no_dns">A DNS server must be specified for always-on VPN</string>
+    <!-- Reason for Always-on VPN checkbox being disabled: DNS server addresses are invalid. [CHAR LIMIT=120] -->
+    <string name="vpn_always_on_invalid_reason_dns">DNS server addresses must be numeric for always-on VPN</string>
+    <!-- Reason for Always-on VPN checkbox being disabled: generic reason. [CHAR LIMIT=120] -->
+    <string name="vpn_always_on_invalid_reason_other">The information entered doesn\u2019t support always-on VPN</string>
 
     <!-- Button label to cancel changing a VPN profile. [CHAR LIMIT=40] -->
     <string name="vpn_cancel">Cancel</string>
index 2692508..b63f0da 100644 (file)
         <item name="android:singleLine">true</item>
     </style>
 
+    <style name="vpn_warning">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:paddingStart">8dip</item>
+        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+    </style>
+
     <style name="TextAppearance.PagerTabs" parent="@android:style/TextAppearance.Material.Widget.TabWidget" />
 
     <style name="KeyguardAppWidgetItem">
index dd63d13..4eecd28 100644 (file)
@@ -76,6 +76,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
     private CheckBox mSaveLogin;
     private CheckBox mShowOptions;
     private CheckBox mAlwaysOnVpn;
+    private TextView mAlwaysOnInvalidReason;
 
     ConfigDialog(Context context, DialogInterface.OnClickListener listener,
             VpnProfile profile, boolean editing, boolean exists) {
@@ -113,6 +114,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
         mSaveLogin = (CheckBox) mView.findViewById(R.id.save_login);
         mShowOptions = (CheckBox) mView.findViewById(R.id.show_options);
         mAlwaysOnVpn = (CheckBox) mView.findViewById(R.id.always_on_vpn);
+        mAlwaysOnInvalidReason = (TextView) mView.findViewById(R.id.always_on_invalid_reason);
 
         // Second, copy values from the profile.
         mName.setText(mProfile.name);
@@ -136,9 +138,6 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
                 R.string.vpn_no_server_cert, mProfile.ipsecServerCert);
         mSaveLogin.setChecked(mProfile.saveLogin);
         mAlwaysOnVpn.setChecked(mProfile.key.equals(VpnUtils.getLockdownVpn()));
-        mAlwaysOnVpn.setOnCheckedChangeListener(this);
-        // Update SaveLogin checkbox after Always-on checkbox is updated
-        updateSaveLoginStatus();
 
         // Hide lockdown VPN on devices that require IMS authentication
         if (SystemProperties.getBoolean("persist.radio.imsregrequired", false)) {
@@ -156,10 +155,10 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
         mIpsecSecret.addTextChangedListener(this);
         mIpsecUserCert.setOnItemSelectedListener(this);
         mShowOptions.setOnClickListener(this);
+        mAlwaysOnVpn.setOnCheckedChangeListener(this);
 
         // Fourth, determine whether to do editing or connecting.
-        boolean valid = validate(true);
-        mEditing = mEditing || !valid;
+        mEditing = mEditing || !validate(true /*editing*/);
 
         if (mEditing) {
             setTitle(R.string.vpn_edit);
@@ -203,9 +202,8 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
         // Let AlertDialog create everything.
         super.onCreate(savedState);
 
-        // Disable the action button if necessary.
-        getButton(DialogInterface.BUTTON_POSITIVE)
-                .setEnabled(mEditing ? valid : validate(false));
+        // Update UI controls according to the current configuration.
+        updateUiControls();
 
         // Workaround to resize the dialog for the input method.
         getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE |
@@ -225,7 +223,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
 
     @Override
     public void afterTextChanged(Editable field) {
-        getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validate(mEditing));
+        updateUiControls();
     }
 
     @Override
@@ -248,7 +246,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
         if (parent == mType) {
             changeType(position);
         }
-        getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validate(mEditing));
+        updateUiControls();
     }
 
     @Override
@@ -258,8 +256,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
     @Override
     public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
         if (compoundButton == mAlwaysOnVpn) {
-            updateSaveLoginStatus();
-            getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validate(mEditing));
+            updateUiControls();
         }
     }
 
@@ -267,7 +264,40 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
         return mAlwaysOnVpn.isChecked();
     }
 
-    private void updateSaveLoginStatus() {
+    /**
+     * Updates the UI according to the current configuration entered by the user.
+     *
+     * These include:
+     * "Always-on VPN" checkbox
+     * Reason for "Always-on VPN" being disabled, when necessary
+     * "Save account information" checkbox
+     * "Save" and "Connect" buttons
+     */
+    private void updateUiControls() {
+        VpnProfile profile = getProfile();
+
+        // Always-on VPN
+        if (profile.isValidLockdownProfile()) {
+            mAlwaysOnVpn.setEnabled(true);
+            mAlwaysOnInvalidReason.setVisibility(View.GONE);
+        } else {
+            mAlwaysOnVpn.setChecked(false);
+            mAlwaysOnVpn.setEnabled(false);
+            if (!profile.isTypeValidForLockdown()) {
+                mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_type);
+            } else if (!profile.isServerAddressNumeric()) {
+                mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_server);
+            } else if (!profile.hasDns()) {
+                mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_no_dns);
+            } else if (!profile.areDnsAddressesNumeric()) {
+                mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_dns);
+            } else {
+                mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_other);
+            }
+            mAlwaysOnInvalidReason.setVisibility(View.VISIBLE);
+        }
+
+        // Save account information
         if (mAlwaysOnVpn.isChecked()) {
             mSaveLogin.setChecked(true);
             mSaveLogin.setEnabled(false);
@@ -275,6 +305,9 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
             mSaveLogin.setChecked(mProfile.saveLogin);
             mSaveLogin.setEnabled(true);
         }
+
+        // Save or Connect button
+        getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validate(mEditing));
     }
 
     private void showAdvancedOptions() {