Add Cloudflare DNS as a private DNS provider

Change-Id: I7e8a320d47e7c5ddbcb9acfaf23032ae92d5d70d
diff --git a/res/layout/private_dns_mode_dialog.xml b/res/layout/private_dns_mode_dialog.xml
index 12e29e6..7c765d5 100644
--- a/res/layout/private_dns_mode_dialog.xml
+++ b/res/layout/private_dns_mode_dialog.xml
@@ -36,6 +36,10 @@
                 layout="@layout/preference_widget_dialog_radiobutton"/>
 
             <include
+                android:id="@+id/private_dns_mode_cloudflare"
+                layout="@layout/preference_widget_dialog_radiobutton"/>
+
+            <include
                 android:id="@+id/private_dns_mode_opportunistic"
                 layout="@layout/preference_widget_dialog_radiobutton"/>
 
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
index d9ca157..9cda169 100644
--- a/res/values/cm_strings.xml
+++ b/res/values/cm_strings.xml
@@ -15,6 +15,11 @@
      limitations under the License.
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Private DNS -->
+    <string name="private_dns_mode_cloudflare" translatable="false">Cloudflare DNS</string>
+    <!-- Alternative: 1dot1dot1dot1.cloudflare-dns.com -->
+    <string name="private_dns_hostname_cloudflare" translatable="false">one.one.one.one</string>
+
     <!-- Advanced keyboard settings -->
     <string name="keyboard_extras_title">Extras</string>
     <string name="advanced_keyboard_settings_title">Advanced settings</string>
diff --git a/src/com/android/settings/network/PrivateDnsModeDialogPreference.java b/src/com/android/settings/network/PrivateDnsModeDialogPreference.java
index 5c7c54e..66575c3 100644
--- a/src/com/android/settings/network/PrivateDnsModeDialogPreference.java
+++ b/src/com/android/settings/network/PrivateDnsModeDialogPreference.java
@@ -72,9 +72,13 @@
     // DNS_MODE -> RadioButton id
     private static final Map<Integer, Integer> PRIVATE_DNS_MAP;
 
+    // Only used in Settings, update on additions to ConnectivitySettingsUtils
+    private static final int PRIVATE_DNS_MODE_CLOUDFLARE = 4;
+
     static {
         PRIVATE_DNS_MAP = new HashMap<>();
         PRIVATE_DNS_MAP.put(PRIVATE_DNS_MODE_OFF, R.id.private_dns_mode_off);
+        PRIVATE_DNS_MAP.put(PRIVATE_DNS_MODE_CLOUDFLARE, R.id.private_dns_mode_cloudflare);
         PRIVATE_DNS_MAP.put(PRIVATE_DNS_MODE_OPPORTUNISTIC, R.id.private_dns_mode_opportunistic);
         PRIVATE_DNS_MAP.put(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, R.id.private_dns_mode_provider);
     }
@@ -144,6 +148,15 @@
         final ContentResolver contentResolver = context.getContentResolver();
 
         mMode = ConnectivitySettingsManager.getPrivateDnsMode(context);
+        if (mMode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) {
+            final String privateDnsHostname =
+                    ConnectivitySettingsManager.getPrivateDnsHostname(context);
+            final String cloudflareHostname =
+                    context.getString(R.string.private_dns_hostname_cloudflare);
+            if (privateDnsHostname.equals(cloudflareHostname)) {
+                mMode = PRIVATE_DNS_MODE_CLOUDFLARE;
+            }
+        }
 
         mEditText = view.findViewById(R.id.private_dns_mode_provider_hostname);
         mEditText.addTextChangedListener(this);
@@ -156,6 +169,9 @@
         // Initial radio button text
         final RadioButton offRadioButton = view.findViewById(R.id.private_dns_mode_off);
         offRadioButton.setText(R.string.private_dns_mode_off);
+        final RadioButton cloudflareRadioButton =
+                view.findViewById(R.id.private_dns_mode_cloudflare);
+        cloudflareRadioButton.setText(R.string.private_dns_mode_cloudflare);
         final RadioButton opportunisticRadioButton =
                 view.findViewById(R.id.private_dns_mode_opportunistic);
         opportunisticRadioButton.setText(R.string.private_dns_mode_opportunistic);
@@ -181,15 +197,21 @@
     public void onClick(DialogInterface dialog, int which) {
         if (which == DialogInterface.BUTTON_POSITIVE) {
             final Context context = getContext();
+            int modeToSet = mMode;
             if (mMode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) {
                 // Only clickable if hostname is valid, so we could save it safely
                 ConnectivitySettingsManager.setPrivateDnsHostname(context,
                         mEditText.getText().toString());
+            } else if (mMode == PRIVATE_DNS_MODE_CLOUDFLARE) {
+                final String cloudflareHostname =
+                        context.getString(R.string.private_dns_hostname_cloudflare);
+                ConnectivitySettingsManager.setPrivateDnsHostname(context, cloudflareHostname);
+                modeToSet = PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
             }
 
             FeatureFactory.getFactory(context).getMetricsFeatureProvider().action(context,
-                    SettingsEnums.ACTION_PRIVATE_DNS_MODE, mMode);
-            ConnectivitySettingsManager.setPrivateDnsMode(context, mMode);
+                    SettingsEnums.ACTION_PRIVATE_DNS_MODE, modeToSet);
+            ConnectivitySettingsManager.setPrivateDnsMode(context, modeToSet);
         }
     }
 
@@ -197,6 +219,8 @@
     public void onCheckedChanged(RadioGroup group, int checkedId) {
         if (checkedId == R.id.private_dns_mode_off) {
             mMode = PRIVATE_DNS_MODE_OFF;
+        } else if (checkedId == R.id.private_dns_mode_cloudflare) {
+            mMode = PRIVATE_DNS_MODE_CLOUDFLARE;
         } else if (checkedId == R.id.private_dns_mode_opportunistic) {
             mMode = PRIVATE_DNS_MODE_OPPORTUNISTIC;
         } else if (checkedId == R.id.private_dns_mode_provider) {
diff --git a/src/com/android/settings/network/PrivateDnsPreferenceController.java b/src/com/android/settings/network/PrivateDnsPreferenceController.java
index ed6f9ed..b64ce06 100644
--- a/src/com/android/settings/network/PrivateDnsPreferenceController.java
+++ b/src/com/android/settings/network/PrivateDnsPreferenceController.java
@@ -65,6 +65,9 @@
         Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER),
     };
 
+    // Only used in Settings, update on additions to ConnectivitySettingsUtils
+    private static final int PRIVATE_DNS_MODE_CLOUDFLARE = 4;
+
     private final Handler mHandler;
     private final ContentObserver mSettingsObserver;
     private final ConnectivityManager mConnectivityManager;
@@ -129,13 +132,22 @@
         switch (mode) {
             case PRIVATE_DNS_MODE_OFF:
                 return res.getString(R.string.private_dns_mode_off);
+            case PRIVATE_DNS_MODE_CLOUDFLARE:
             case PRIVATE_DNS_MODE_OPPORTUNISTIC:
                 return dnsesResolved ? res.getString(R.string.private_dns_mode_on)
                         : res.getString(R.string.private_dns_mode_opportunistic);
             case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
-                return dnsesResolved
-                        ? PrivateDnsModeDialogPreference.getHostnameFromSettings(cr)
-                        : res.getString(R.string.private_dns_mode_provider_failure);
+                if (!dnsesResolved) {
+                    return res.getString(R.string.private_dns_mode_provider_failure);
+                }
+                final String privateDnsHostname =
+                        ConnectivitySettingsManager.getPrivateDnsHostname(mContext);
+                final String cloudflareHostname =
+                        res.getString(R.string.private_dns_hostname_cloudflare);
+                if (privateDnsHostname.equals(cloudflareHostname)) {
+                    return res.getString(R.string.private_dns_mode_cloudflare);
+                }
+                return PrivateDnsModeDialogPreference.getHostnameFromSettings(cr);
         }
         return "";
     }