Merge "Implement host flow of WiFi sharing feature"
diff --git a/res/drawable/ic_qrcode_24dp.xml b/res/drawable/ic_qrcode_24dp.xml
new file mode 100644
index 0000000..ff7806f
--- /dev/null
+++ b/res/drawable/ic_qrcode_24dp.xml
@@ -0,0 +1,39 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M7,4v3H4V4H7M9,2H2v7h7V2L9,2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M15,11l-8,0l0,2l8,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M13,2l-2,0l0,11l2,0l0,-11z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,15l-11,0l0,2l11,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M13,17l-2,0l0,5l2,0l0,-5z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M17,13l-2,0l0,9l2,0l0,-9z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,19l-3,0l0,3l3,0l0,-3z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M5,11l-3,0l0,2l3,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,11l-5,0l0,2l5,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M20,4v3h-3V4H20M22,2h-7v7h7V2L22,2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M7,17v3H4v-3H7M9,15H2v7h7V15L9,15z"/>
+</vector>
diff --git a/res/drawable/ic_scan_24dp.xml b/res/drawable/ic_scan_24dp.xml
new file mode 100644
index 0000000..bcef8e3
--- /dev/null
+++ b/res/drawable/ic_scan_24dp.xml
@@ -0,0 +1,33 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M9,2l-7,0l0,2l7,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,2l-7,0l0,2l7,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,11l-20,0l0,2l20,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,2l-2,0l0,7l2,0l0,-7z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M4,2l-2,0l0,7l2,0l0,-7z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M9,20l-7,0l0,2l7,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,20l-7,0l0,2l7,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,15l-2,0l0,7l2,0l0,-7z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M4,15l-2,0l0,7l2,0l0,-7z"/>
+</vector>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index cbb5e3b..0116ed4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -653,6 +653,8 @@
     <string name="done">Done</string>
     <!-- Button label for generic apply action [CHAR LIMIT=20] -->
     <string name="apply">Apply</string>
+    <!-- Button label for generic share action [CHAR LIMIT=20] -->
+    <string name="share">Share</string>
 
     <!-- Title of the Settings activity shown within the application itself. -->
     <string name="settings_label">Settings</string>
@@ -3765,6 +3767,8 @@
     <string name="lockpassword_choose_your_pattern_header_for_face">To use face authentication, set pattern</string>
     <!-- Header on first screen of choose password/PIN as backup for face authentication flow. If this string cannot be translated in under 40 characters, please translate "Set face authentication backup" [CHAR LIMIT=40] -->
     <string name="lockpassword_choose_your_pin_header_for_face">To use face authentication, set PIN</string>
+    <!-- Message on Wi-Fi Sharing screen [CHAR LIMIT=NONE] -->
+    <string name="wifi_sharing_message">Your Wi\u2011Fi name and password for \"<xliff:g id="SSID" example="GoogleGuest">%1$s</xliff:g>\" will be shared.</string>
 
     <!-- Message to be used to explain the user that he needs to enter his pattern to continue a
          particular operation. [CHAR LIMIT=70]-->
diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java
index daa1e7b..b350778 100644
--- a/src/com/android/settings/core/FeatureFlags.java
+++ b/src/com/android/settings/core/FeatureFlags.java
@@ -26,4 +26,5 @@
     public static final String MOBILE_NETWORK_V2 = "settings_mobile_network_v2";
     public static final String WIFI_MAC_RANDOMIZATION = "settings_wifi_mac_randomization";
     public static final String NETWORK_INTERNET_V2 = "settings_network_and_internet_v2";
+    public static final String WIFI_SHARING = "settings_wifi_sharing";
 }
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index a676bfa..e1179f8 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -20,6 +20,7 @@
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 
 import android.app.Activity;
+import android.app.KeyguardManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -40,6 +41,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
 import android.util.Log;
 import android.widget.ImageView;
 import android.widget.Toast;
@@ -54,8 +56,11 @@
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.Utils;
+import com.android.settings.core.FeatureFlags;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.widget.EntityHeaderController;
+import com.android.settings.wifi.dpp.WifiDppConfiguratorActivity;
+import com.android.settings.wifi.dpp.WifiDppUtils;
 import com.android.settings.wifi.WifiDialog;
 import com.android.settings.wifi.WifiDialog.WifiDialogListener;
 import com.android.settings.wifi.WifiUtils;
@@ -280,7 +285,10 @@
                 .setButton1Icon(R.drawable.ic_settings_delete)
                 .setButton1OnClickListener(view -> forgetNetwork())
                 .setButton2Text(R.string.wifi_sign_in_button_text)
-                .setButton2OnClickListener(view -> signIntoNetwork());
+                .setButton2OnClickListener(view -> signIntoNetwork())
+                .setButton3Text(R.string.share)
+                .setButton3Icon(R.drawable.ic_qrcode_24dp)
+                .setButton3OnClickListener(view -> shareNetwork());
 
         mSignalStrengthPref = screen.findPreference(KEY_SIGNAL_STRENGTH_PREF);
         mLinkSpeedPref = screen.findPreference(KEY_LINK_SPEED);
@@ -296,7 +304,7 @@
         mIpv6Category = (PreferenceCategory) screen.findPreference(KEY_IPV6_CATEGORY);
         mIpv6AddressPref = screen.findPreference(KEY_IPV6_ADDRESSES_PREF);
 
-        mSecurityPref.setSummary(mAccessPoint.getSecurityString(false /* concise */));
+        mSecurityPref.setSummary(mAccessPoint.getSecurityString(/* concise */ false));
     }
 
     private void setupEntityHeader(PreferenceScreen screen) {
@@ -425,7 +433,9 @@
 
     private void updateIpLayerInfo() {
         mButtonsPref.setButton2Visible(canSignIntoNetwork());
-        mButtonsPref.setVisible(canSignIntoNetwork() || canForgetNetwork());
+        mButtonsPref.setButton3Visible(isSharingNetworkEnabled());
+        mButtonsPref.setVisible(
+                canSignIntoNetwork() || canForgetNetwork() || isSharingNetworkEnabled());
 
         if (mNetwork == null || mLinkProperties == null) {
             mIpAddressPref.setVisible(false);
@@ -511,6 +521,13 @@
     }
 
     /**
+     * Returns whether the user can share the network represented by this preference with QR code.
+     */
+    private boolean isSharingNetworkEnabled() {
+        return FeatureFlagUtils.isEnabled(mContext, FeatureFlags.WIFI_SHARING);
+    }
+
+    /**
      * Forgets the wifi network associated with this preference.
      */
     private void forgetNetwork() {
@@ -529,6 +546,42 @@
     }
 
     /**
+     * Show QR code to share the network represented by this preference.
+     */
+    public void launchQRCodeGenerator() {
+        final Intent intent = new Intent(
+                WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
+        intent.putExtra(WifiDppUtils.EXTRA_WIFI_SECURITY,
+                mAccessPoint.getSecurityString(/* concise */ false));
+        intent.putExtra(WifiDppUtils.EXTRA_WIFI_SSID, mAccessPoint.getSsidStr());
+        mContext.startActivity(intent);
+    }
+
+    /**
+     * Share the wifi network with QR code.
+     */
+    private void shareNetwork() {
+        final KeyguardManager keyguardManager = (KeyguardManager) mContext.getSystemService(
+                Context.KEYGUARD_SERVICE);
+        if (keyguardManager.isKeyguardSecure()) {
+            // Show authentication screen to confirm credentials (pin, pattern or password) for
+            // the current user of the device.
+            final String description = String.format(
+                    mContext.getString(R.string.wifi_sharing_message),
+                    mAccessPoint.getSsidStr());
+            final Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(
+                    mContext.getString(R.string.lockpassword_confirm_your_pattern_header),
+                    description);
+            if (intent != null) {
+                mFragment.startActivityForResult(intent,
+                        WifiNetworkDetailsFragment.REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
+            }
+        } else {
+            launchQRCodeGenerator();
+        }
+    }
+
+    /**
      * Sign in to the captive portal found on this wifi network associated with this preference.
      */
     private void signIntoNetwork() {
diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
index 7f0e8ee..9814486 100644
--- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
+++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
@@ -17,8 +17,10 @@
 
 import static com.android.settings.wifi.WifiSettings.WIFI_DIALOG_ID;
 
+import android.app.Activity;
 import android.app.Dialog;
 import android.content.Context;
+import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
@@ -52,6 +54,8 @@
 
     private static final String TAG = "WifiNetworkDetailsFrg";
 
+    public static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 1;
+
     private AccessPoint mAccessPoint;
     private WifiDetailPreferenceController mWifiDetailPreferenceController;
 
@@ -142,4 +146,14 @@
 
         return controllers;
     }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+
+        if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS
+                && resultCode == Activity.RESULT_OK) {
+            mWifiDetailPreferenceController.launchQRCodeGenerator();
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
index 39215c1..eab9e51 100644
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
@@ -865,6 +865,12 @@
         when(pref.setButton2Visible(anyBoolean())).thenReturn(pref);
         when(pref.setButton2OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
 
+        when(pref.setButton3Text(anyInt())).thenReturn(pref);
+        when(pref.setButton3Icon(anyInt())).thenReturn(pref);
+        when(pref.setButton3Enabled(anyBoolean())).thenReturn(pref);
+        when(pref.setButton3Visible(anyBoolean())).thenReturn(pref);
+        when(pref.setButton3OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
+
         return pref;
     }
 }