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
This commit is contained in:
Johnson Lu
2018-12-07 11:56:49 +08:00
parent 15cdfc4ec2
commit 5aef897e9b
8 changed files with 356 additions and 13 deletions

View File

@@ -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" />

View File

@@ -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"

View File

@@ -23,12 +23,14 @@ import android.view.LayoutInflater;
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 @@ public class AddNetworkFragment extends InstrumentedFragment implements WifiConf
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;
}

View File

@@ -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;
}
}

View File

@@ -21,10 +21,13 @@ import android.content.DialogInterface;
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 @@ public class WifiDialog extends AlertDialog implements WifiConfigUiBase,
@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);

View File

@@ -66,6 +66,7 @@ import com.android.settings.search.SearchIndexableRaw;
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 @@ public class WifiSettings extends RestrictedSettingsFragment
private PreferenceCategory mConnectedAccessPointPreferenceCategory;
private PreferenceCategory mAccessPointsPreferenceCategory;
private Preference mAddPreference;
private ButtonPreference mAddPreference;
@VisibleForTesting
Preference mConfigureWifiSettingsPreference;
@VisibleForTesting
@@ -235,9 +236,17 @@ public class WifiSettings extends RestrictedSettingsFragment
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());

View File

@@ -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 @@ public class WifiDppUtils {
* 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;
}
}

View File

@@ -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();
}
}