Implement receiver flow of WiFi sharing feature

1.Add a button to launch QR code scanner when add a network.
2.Scan button added in AddNetworkFragment / WifiDialog / WifiSettings.

Bug: 120630683
Test: make RunSettingsRoboTests
Change-Id: I340bfa2247e092f586dd90dfea37c355e681ffee
diff --git a/res/layout/wifi_button_preference_widget.xml b/res/layout/wifi_button_preference_widget.xml
new file mode 100644
index 0000000..55078c2
--- /dev/null
+++ b/res/layout/wifi_button_preference_widget.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2018 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.
+-->
+
+<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
+           android:id="@+id/button_icon"
+           android:layout_width="wrap_content"
+           android:layout_height="wrap_content"
+           android:layout_gravity="center"
+           android:background="@null"
+           android:visibility="gone"
+           android:contentDescription="@string/wifi_add_network" />
diff --git a/res/layout/wifi_dialog.xml b/res/layout/wifi_dialog.xml
index bb2946d..2a395b6 100644
--- a/res/layout/wifi_dialog.xml
+++ b/res/layout/wifi_dialog.xml
@@ -50,13 +50,28 @@
                         android:text="@string/wifi_ssid"
                         android:textDirection="locale" />
 
-                <EditText android:id="@+id/ssid"
+                <RelativeLayout
                         android:layout_width="match_parent"
+                        android:layout_height="wrap_content" >
+                    <EditText android:id="@+id/ssid"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            style="@style/wifi_item_edit_content"
+                            android:hint="@string/wifi_ssid_hint"
+                            android:singleLine="true"
+                            android:inputType="textNoSuggestions" />
+                    <ImageButton
+                        android:id="@+id/ssid_scanner_button"
+                        android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        style="@style/wifi_item_edit_content"
-                        android:hint="@string/wifi_ssid_hint"
-                        android:singleLine="true"
-                        android:inputType="textNoSuggestions" />
+                        android:layout_alignParentRight="true"
+                        android:layout_centerVertical="true"
+                        android:layout_margin="5dp"
+                        android:background="@null"
+                        android:src="@drawable/ic_qrcode_24dp"
+                        android:visibility="gone"
+                        android:contentDescription="@string/wifi_add_network" />
+                </RelativeLayout>
 
                 <LinearLayout android:id="@+id/ssid_too_long_warning"
                               android:layout_width="match_parent"
@@ -270,12 +285,28 @@
                         style="@style/wifi_item_label"
                         android:text="@string/wifi_password" />
 
-                <EditText android:id="@+id/password"
-                        android:layout_width="match_parent"
+                <RelativeLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content" >
+                    <EditText android:id="@+id/password"
+                              android:layout_width="match_parent"
+                              android:layout_height="wrap_content"
+                              style="@style/wifi_item_edit_content"
+                              android:singleLine="true"
+                              android:password="true" />
+
+                    <ImageButton
+                        android:id="@+id/password_scanner_button"
+                        android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        style="@style/wifi_item_edit_content"
-                        android:singleLine="true"
-                        android:password="true" />
+                        android:layout_alignParentRight="true"
+                        android:layout_centerVertical="true"
+                        android:layout_margin="5dp"
+                        android:background="@null"
+                        android:src="@drawable/ic_qrcode_24dp"
+                        android:visibility="gone"
+                        android:contentDescription="@string/wifi_add_network" />
+                </RelativeLayout>
             </LinearLayout>
 
             <LinearLayout android:id="@+id/show_password_layout"
diff --git a/src/com/android/settings/wifi/AddNetworkFragment.java b/src/com/android/settings/wifi/AddNetworkFragment.java
index 814b358..72d878b 100644
--- a/src/com/android/settings/wifi/AddNetworkFragment.java
+++ b/src/com/android/settings/wifi/AddNetworkFragment.java
@@ -23,12 +23,14 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
+import android.widget.ImageButton;
 
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 import com.android.settings.core.InstrumentedFragment;
+import com.android.settings.wifi.dpp.WifiDppUtils;
 
 public class AddNetworkFragment extends InstrumentedFragment implements WifiConfigUiBase,
         View.OnClickListener {
@@ -64,6 +66,18 @@
         mCancelBtn.setOnClickListener(this);
         mUIController = new WifiConfigController(this, rootView, null, getMode());
 
+        if (WifiDppUtils.isSharingNetworkEnabled(getContext())) {
+            final ImageButton scannerButton = rootView.findViewById(R.id.ssid_scanner_button);
+            if (scannerButton != null) {
+                scannerButton.setVisibility(View.VISIBLE);
+                scannerButton.setOnClickListener((View v) -> {
+                    // Launch QR code scanner to join a network.
+                    getContext().startActivity(
+                            WifiDppUtils.getConfiguratorQRCodeScannerIntent(/* ssid */ null));
+                });
+            }
+        }
+
         return rootView;
     }
 
diff --git a/src/com/android/settings/wifi/ButtonPreference.java b/src/com/android/settings/wifi/ButtonPreference.java
new file mode 100644
index 0000000..62e8caf
--- /dev/null
+++ b/src/com/android/settings/wifi/ButtonPreference.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.wifi;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageButton;
+
+import com.android.settings.R;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.annotation.DrawableRes;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+/**
+ * This preference provides one button layout with Settings style.
+ * It looks like below
+ *
+ * --------------------------------------------------------------
+ * | icon | title                                    |  button  |
+ * --------------------------------------------------------------
+ *
+ * User can set icon / click listener for button.
+ * By default, the button is invisible.
+ */
+public class ButtonPreference extends Preference {
+
+    private static final String TAG = "ButtonPreference";
+
+    private ImageButton mImageButton;
+    private Drawable mButtonIcon;
+    private View.OnClickListener mClickListener;
+
+    // Used for dummy pref.
+    public ButtonPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setWidgetLayoutResource(R.layout.wifi_button_preference_widget);
+        mImageButton = null;
+        mButtonIcon = null;
+        mClickListener = null;
+    }
+
+    public ButtonPreference(Context context) {
+        this(context, /* attrs */ null);
+    }
+
+    @Override
+    public void onBindViewHolder(final PreferenceViewHolder view) {
+        super.onBindViewHolder(view);
+        initButton(view);
+    }
+
+    @Override
+    public void setOrder(int order) {
+        super.setOrder(order);
+        setButtonVisibility();
+    }
+
+    @VisibleForTesting
+    protected void initButton(final PreferenceViewHolder view) {
+        if (mImageButton == null) {
+            mImageButton = (ImageButton) view.findViewById(R.id.button_icon);
+        }
+        if (mImageButton != null) {
+            mImageButton.setImageDrawable(mButtonIcon);
+            mImageButton.setOnClickListener(mClickListener);
+        }
+        setButtonVisibility();
+    }
+
+    private void setButtonVisibility() {
+        if(mImageButton != null) {
+            mImageButton.setVisibility(mButtonIcon == null ? View.GONE : View.VISIBLE);
+        }
+    }
+
+    /**
+     * Sets the drawable to be displayed in button.
+     */
+    public ButtonPreference setButtonIcon(@DrawableRes int iconResId) {
+        if (iconResId == 0) {
+            return this;
+        }
+
+        try {
+            mButtonIcon = getContext().getDrawable(iconResId);
+            notifyChanged();
+        } catch (Resources.NotFoundException exception) {
+            Log.e(TAG, "Resource does not exist: " + iconResId);
+        }
+        return this;
+    }
+
+    /**
+     * Register a callback to be invoked when button is clicked.
+     */
+    public ButtonPreference setButtonOnClickListener(View.OnClickListener listener) {
+        if (listener != mClickListener) {
+            mClickListener = listener;
+            notifyChanged();
+        }
+        return this;
+    }
+}
diff --git a/src/com/android/settings/wifi/WifiDialog.java b/src/com/android/settings/wifi/WifiDialog.java
index 2b8fb2d..0e2ca60 100644
--- a/src/com/android/settings/wifi/WifiDialog.java
+++ b/src/com/android/settings/wifi/WifiDialog.java
@@ -21,10 +21,13 @@
 import android.os.Bundle;
 import android.view.View;
 import android.widget.Button;
+import android.widget.ImageButton;
 
 import androidx.appcompat.app.AlertDialog;
 
 import com.android.settings.R;
+import com.android.settings.wifi.dpp.WifiDppUtils;
+
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.wifi.AccessPoint;
@@ -77,7 +80,18 @@
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        mView = getLayoutInflater().inflate(R.layout.wifi_dialog, null);
+        mView = getLayoutInflater().inflate(R.layout.wifi_dialog, /* root */ null);
+        if (WifiDppUtils.isSharingNetworkEnabled(getContext())) {
+            final ImageButton scannerButton = mView.findViewById(R.id.password_scanner_button);
+            if (scannerButton != null) {
+                scannerButton.setVisibility(View.VISIBLE);
+                scannerButton.setOnClickListener((View v) -> {
+                    // Launch QR code scanner to join a network.
+                    getContext().startActivity(
+                            WifiDppUtils.getConfiguratorQRCodeScannerIntent(/* ssid */ null));
+                });
+            }
+        }
         setView(mView);
         mController = new WifiConfigController(this, mView, mAccessPoint, mMode);
         super.onCreate(savedInstanceState);
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 1c9a5e1..54de28d 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -66,6 +66,7 @@
 import com.android.settings.widget.SummaryUpdater.OnSummaryChangeListener;
 import com.android.settings.widget.SwitchBarController;
 import com.android.settings.wifi.details.WifiNetworkDetailsFragment;
+import com.android.settings.wifi.dpp.WifiDppUtils;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.search.SearchIndexable;
@@ -175,7 +176,7 @@
 
     private PreferenceCategory mConnectedAccessPointPreferenceCategory;
     private PreferenceCategory mAccessPointsPreferenceCategory;
-    private Preference mAddPreference;
+    private ButtonPreference mAddPreference;
     @VisibleForTesting
     Preference mConfigureWifiSettingsPreference;
     @VisibleForTesting
@@ -235,9 +236,17 @@
         mSavedNetworksPreference = findPreference(PREF_KEY_SAVED_NETWORKS);
 
         Context prefContext = getPrefContext();
-        mAddPreference = new Preference(prefContext);
+        mAddPreference = new ButtonPreference(prefContext);
         mAddPreference.setIcon(R.drawable.ic_menu_add);
         mAddPreference.setTitle(R.string.wifi_add_network);
+        if (WifiDppUtils.isSharingNetworkEnabled(getContext())) {
+            mAddPreference.setButtonIcon(R.drawable.ic_qrcode_24dp);
+            mAddPreference.setButtonOnClickListener((View v) -> {
+                // Launch QR code scanner to join a network.
+                getContext().startActivity(
+                        WifiDppUtils.getConfiguratorQRCodeScannerIntent(/* ssid */ null));
+            });
+        }
         mStatusMessagePreference = (LinkablePreference) findPreference(PREF_KEY_STATUS_MESSAGE);
 
         mUserBadgeCache = new AccessPointPreference.UserBadgeCache(getPackageManager());
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index 70ef3a8..ae144ba 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -16,7 +16,10 @@
 
 package com.android.settings.wifi.dpp;
 
+import android.content.Context;
 import android.content.Intent;
+import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
 
 /**
  * Here are the items shared by both WifiDppConfiguratorActivity & WifiDppEnrolleeActivity
@@ -54,4 +57,46 @@
      * H         true       Optional. True if the network SSID is hidden.
      */
     public static final String EXTRA_QR_CODE = "qrCode";
+
+    /**
+     * Returns whether the user can share the network represented by this preference with QR code.
+     */
+    public static boolean isSharingNetworkEnabled(Context context) {
+        return FeatureFlagUtils.isEnabled(context,
+                com.android.settings.core.FeatureFlags.WIFI_SHARING);
+    }
+
+    /**
+     * Returns an intent to launch QR code scanner.
+     *
+     * @param ssid The data corresponding to {@code WifiConfiguration} SSID
+     * @return Intent for launching QR code scanner
+     */
+    public static Intent getConfiguratorQRCodeScannerIntent(String ssid) {
+        final Intent intent = new Intent(
+                WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_SCANNER);
+        if (!TextUtils.isEmpty(ssid)) {
+            intent.putExtra(EXTRA_WIFI_SSID, ssid);
+        }
+        return intent;
+    }
+
+    /**
+     * Returns an intent to launch QR code generator.
+     *
+     * @param ssid     The data corresponding to {@code WifiConfiguration} SSID
+     * @param Security The data is from {@code AccessPoint.securityToString}
+     * @return Intent for launching QR code generator
+     */
+    public static Intent getConfiguratorQRCodeGeneratorIntent(String ssid, String Security) {
+        final Intent intent = new Intent(
+                WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
+        if (!TextUtils.isEmpty(ssid)) {
+            intent.putExtra(EXTRA_WIFI_SSID, ssid);
+        }
+        if (!TextUtils.isEmpty(Security)) {
+            intent.putExtra(EXTRA_WIFI_SECURITY, Security);
+        }
+        return intent;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/wifi/ButtonPreferenceTest.java b/tests/robotests/src/com/android/settings/wifi/ButtonPreferenceTest.java
new file mode 100644
index 0000000..3dc109f
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/ButtonPreferenceTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 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 static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.ImageButton;
+
+import com.android.settings.R;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import androidx.preference.PreferenceViewHolder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class ButtonPreferenceTest {
+
+    private Context mContext;
+    private View mRootView;
+    private ButtonPreference mPref;
+    private PreferenceViewHolder mHolder;
+    private boolean mClicked;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = RuntimeEnvironment.application;
+        mPref = new ButtonPreference(mContext);
+        mRootView = View.inflate(mContext, R.layout.wifi_button_preference_widget, /* parent */
+                null);
+        mHolder = PreferenceViewHolder.createInstanceForTests(mRootView);
+    }
+
+    @Test
+    public void initButton_noIcon_shouldInvisible() {
+        mPref.initButton(mHolder);
+        assertThat(mRootView.findViewById(R.id.button_icon).getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void initButton_withIcon_shouldVisible() {
+        mPref.setButtonIcon(R.drawable.ic_qrcode_24dp);
+        mPref.initButton(mHolder);
+        assertThat(mRootView.findViewById(R.id.button_icon).getVisibility()).isEqualTo(
+                View.VISIBLE);
+    }
+
+    @Test
+    public void initButton_whenClick_shouldCallback() {
+        mClicked = false;
+        mPref.setButtonIcon(R.drawable.ic_qrcode_24dp);
+        mPref.setButtonOnClickListener((View v) -> {
+            mClicked = true;
+        });
+        mPref.initButton(mHolder);
+        ImageButton button = (ImageButton) mRootView.findViewById(R.id.button_icon);
+        button.performClick();
+        assertThat(mClicked).isTrue();
+    }
+}