Snap for 5206983 from f6deebffaa to qt-release

Change-Id: I0bd3fa2bbe66c2573b426873168884ffce28fc1e
This commit is contained in:
android-build-team Robot
2019-01-03 04:12:27 +00:00
27 changed files with 912 additions and 390 deletions

View File

@@ -1,18 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="4">
<issue
id="LintError"
severity="Error"
message="No `.class` files were found in project &quot;.&quot;, so none of the classfile based checks could be run. Does the project need to be built first?"
category="Lint"
priority="10"
summary="Lint Failure"
explanation="This issue type represents a problem running lint itself. Examples include failure to find bytecode for source files (which means certain detectors could not be run), parsing errors in lint configuration files, etc.&#xA;These errors are not errors in your own code, but they are shown to make it clear that some checks were not completed.">
<location
file="."/>
</issue>
<issue
id="HardCodedColor"
severity="Error"
@@ -1293,6 +1281,54 @@
column="5"/>
</issue>
<issue
id="HardCodedColor"
severity="Error"
message="Avoid using hardcoded color"
category="Correctness"
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;color name=&quot;qr_corner_line_color&quot;>#ffdadce0&lt;/color>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="133"
column="5"/>
</issue>
<issue
id="HardCodedColor"
severity="Error"
message="Avoid using hardcoded color"
category="Correctness"
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;color name=&quot;qr_focused_corner_line_color&quot;>#ff1a73e8&lt;/color>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="134"
column="5"/>
</issue>
<issue
id="HardCodedColor"
severity="Error"
message="Avoid using hardcoded color"
category="Correctness"
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;color name=&quot;qr_background_color&quot;>#b3ffffff&lt;/color> &lt;!-- 70% white transparency -->"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="135"
column="5"/>
</issue>
<issue
id="HardCodedColor"
severity="Error"
@@ -2441,7 +2477,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/strings.xml"
line="5805"
line="5883"
column="36"/>
</issue>
@@ -2473,7 +2509,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
line="425"
line="415"
column="44"/>
</issue>
@@ -2489,7 +2525,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
line="431"
line="421"
column="44"/>
</issue>
@@ -2505,7 +2541,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
line="432"
line="422"
column="44"/>
</issue>
@@ -2521,23 +2557,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
line="467"
column="34"/>
</issue>
<issue
id="HardCodedColor"
severity="Error"
message="Avoid using hardcoded color"
category="Correctness"
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;item name=&quot;strokeColor&quot;>@color/homepage_card_stroke_color&lt;/item>"
errorLine2=" ^">
<location
file="res/values/styles.xml"
line="474"
line="457"
column="34"/>
</issue>
@@ -2553,7 +2573,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="54"
line="57"
column="39"/>
</issue>
@@ -2569,7 +2589,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="55"
line="58"
column="40"/>
</issue>
@@ -2585,7 +2605,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="56"
line="59"
column="38"/>
</issue>
@@ -2601,7 +2621,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="90"
line="97"
column="47"/>
</issue>
@@ -2617,7 +2637,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="90"
line="97"
column="47"/>
</issue>
@@ -2633,7 +2653,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="96"
line="103"
column="40"/>
</issue>
@@ -2649,7 +2669,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="96"
line="103"
column="40"/>
</issue>
@@ -2665,7 +2685,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="159"
line="166"
column="45"/>
</issue>
@@ -2681,7 +2701,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="160"
line="167"
column="49"/>
</issue>
@@ -2697,7 +2717,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="168"
line="175"
column="45"/>
</issue>
@@ -2713,7 +2733,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="169"
line="176"
column="49"/>
</issue>
@@ -2729,7 +2749,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="185"
line="192"
column="39"/>
</issue>
@@ -2745,7 +2765,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="186"
line="193"
column="40"/>
</issue>
@@ -2761,7 +2781,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
line="187"
line="194"
column="38"/>
</issue>

View File

@@ -27,13 +27,13 @@
android:paddingEnd="16dp">
<ImageView
android:id="@+id/header_icon"
android:id="@android:id/icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:scaleType="fitCenter"/>
<TextView
android:id="@+id/title"
android:id="@android:id/title"
style="@style/TextAppearance.EntityHeaderTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -44,7 +44,7 @@
android:paddingEnd="32dp"/>
<TextView
android:id="@+id/description"
android:id="@android:id/summary"
style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@@ -39,10 +39,15 @@
android:layout_gravity="center"/>
</com.android.settings.wifi.qrcode.QrPreviewLayout>
<TextView android:id="@+id/error_message"
<TextView
android:id="@+id/error_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
android:layout_gravity="center"
android:layout_marginTop="8dp"
android:text="@string/wifi_dpp_could_not_detect_valid_qr_code"
android:visibility="invisible"
android:textColor="?android:attr/colorError"/>
</LinearLayout>

View File

@@ -1105,8 +1105,8 @@
</string-array>
<string-array name="wifi_privacy_entries">
<item>Default (use randomized MAC)</item>
<item>Trusted</item>
<item>Use device MAC</item>
<item>Use randomized MAC (default)</item>
</string-array>
<string-array name="wifi_hidden_entries">

View File

@@ -128,5 +128,10 @@
<!-- launcher icon color -->
<color name="icon_launcher_setting_color">@*android:color/accent_device_default_light</color>
</resources>
<!-- QR code scanner colors -->
<color name="qr_corner_line_color">#ffdadce0</color>
<color name="qr_focused_corner_line_color">#ff1a73e8</color>
<color name="qr_background_color">#b3ffffff</color> <!-- 70% white transparency -->
<!-- End of QR code scanner colors -->
</resources>

View File

@@ -2090,6 +2090,8 @@
<string name="wifi_dpp_share_wifi">Share Wi\u2011Fi</string>
<!-- Hint for the user to use another device to scan QR code on screen to join Wi-Fi [CHAR LIMIT=NONE] -->
<string name="wifi_dpp_scan_qr_code_with_another_device">Scan this QR code with another device to join \u201c<xliff:g id="ssid" example="OfficeWifi">%1$s</xliff:g>\u201d</string>
<!-- Hint for QR code detection [CHAR LIMIT=NONE] -->
<string name="wifi_dpp_could_not_detect_valid_qr_code">Could not detect valid QR code</string>
<!-- Label for the check box to share a network with other users on the same device -->
<string name="wifi_shared">Share with other device users</string>
<!-- Hint for unchanged fields -->
@@ -10338,9 +10340,9 @@
<string name="see_less">See less</string>
<!-- Title for Network connection request Dialog [CHAR LIMIT=30] -->
<string name="network_connection_request_dialog_title">Choose device</string>
<string name="network_connection_request_dialog_title">Choose a device</string>
<!-- Message for Network connection timeout Dialog [CHAR LIMIT=NONE] -->
<string name="network_connection_timeout_dialog_message">No devices found. Make sure the device is turned on and available to connect.</string>
<string name="network_connection_timeout_dialog_message">No devices found. Make sure devices are turned on and available to connect.</string>
<!-- OK button for Network connection timeout Dialog [CHAR LIMIT=30] -->
<string name="network_connection_timeout_dialog_ok">Try again</string>
<!-- Message for Network connection error state Dialog [CHAR LIMIT=NONE] -->

View File

@@ -1,6 +1,5 @@
package com.android.settings.location;
import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
@@ -11,6 +10,7 @@ import android.content.IntentFilter;
import android.location.LocationManager;
import android.permission.RuntimePermissionPresenter;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import com.android.settings.R;
@@ -20,7 +20,6 @@ import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import java.util.Arrays;
import java.util.Collections;
public class TopLevelLocationPreferenceController extends BasePreferenceController implements
LifecycleObserver, OnStart, OnStop {
@@ -56,6 +55,12 @@ public class TopLevelLocationPreferenceController extends BasePreferenceControll
}
}
@VisibleForTesting
void setLocationAppCount(int numApps) {
mNumTotal = numApps;
refreshSummary(mPreference);
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
@@ -68,8 +73,7 @@ public class TopLevelLocationPreferenceController extends BasePreferenceControll
RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), false, false,
(numApps) -> {
mNumTotal = numApps;
refreshSummary(preference);
setLocationAppCount(numApps);
}, null);
}

View File

@@ -16,6 +16,7 @@
package com.android.settings.wifi;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
@@ -328,8 +329,12 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
@Override
public void onUserSelectionConnectSuccess(WifiConfiguration wificonfiguration) {
// Dismisses current dialog, since connection is success.
// Dismisses current dialog and finishes Activity, since connection is success.
dismiss();
final Activity activity = getActivity();
if (activity != null) {
activity.finish();
}
}
@Override

View File

@@ -17,6 +17,13 @@
package com.android.settings.wifi.dpp;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
@@ -26,10 +33,11 @@ import com.android.settings.R;
* to the Wi-Fi network.
*/
public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment {
@Override
protected int getLayout() {
return R.layout.wifi_dpp_add_device_fragment;
}
private ProgressBar mProgressBar;
private ImageView mWifiApPictureView;
private TextView mChooseDifferentNetwork;
private Button mButtonLeft;
private Button mButtonRight;
@Override
public int getMetricsCategory() {
@@ -37,7 +45,20 @@ public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment {
}
@Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
public final View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.wifi_dpp_add_device_fragment, container,
/* attachToRoot */ false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mProgressBar = view.findViewById(R.id.progress_bar);
mWifiApPictureView = view.findViewById(R.id.wifi_ap_picture_view);
mChooseDifferentNetwork = view.findViewById(R.id.choose_different_network);
mButtonLeft = view.findViewById(R.id.button_left);
mButtonRight = view.findViewById(R.id.button_right);
}
}

View File

@@ -17,6 +17,11 @@
package com.android.settings.wifi.dpp;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ListView;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
@@ -26,10 +31,9 @@ import com.android.settings.R;
* {@code WifiDppConfiguratorActivity} to start with this fragment to choose a saved Wi-Fi network.
*/
public class WifiDppChooseSavedWifiNetworkFragment extends WifiDppQrCodeBaseFragment {
@Override
protected int getLayout() {
return R.layout.wifi_dpp_choose_saved_wifi_network_fragment;
}
private ListView mSavedWifiNetworkList;
private Button mButtonLeft;
private Button mButtonRight;
@Override
public int getMetricsCategory() {
@@ -37,7 +41,18 @@ public class WifiDppChooseSavedWifiNetworkFragment extends WifiDppQrCodeBaseFrag
}
@Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
public final View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.wifi_dpp_choose_saved_wifi_network_fragment, container,
/* attachToRoot */ false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mSavedWifiNetworkList = view.findViewById(R.id.saved_wifi_network_list);
mButtonLeft = view.findViewById(R.id.button_left);
mButtonRight = view.findViewById(R.id.button_right);
}
}

View File

@@ -49,7 +49,9 @@ import com.android.settings.R;
*/
public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
WifiNetworkConfig.Retriever,
WifiDppQrCodeGeneratorFragment.OnQrCodeGeneratorFragmentAddButtonClickedListener {
WifiDppQrCodeGeneratorFragment.OnQrCodeGeneratorFragmentAddButtonClickedListener,
WifiDppQrCodeScannerFragment.OnScanWifiDppSuccessListener,
WifiDppQrCodeScannerFragment.OnScanZxingWifiFormatSuccessListener {
private static final String TAG = "WifiDppConfiguratorActivity";
public static final String ACTION_CONFIGURATOR_QR_CODE_SCANNER =
@@ -64,6 +66,12 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
/** The Wi-Fi network which will be configured */
private WifiNetworkConfig mWifiNetworkConfig;
/** The public key from Wi-Fi DPP QR code */
private String mPublicKey;
/** The information from Wi-Fi DPP QR code */
private String mInformation;
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
@@ -127,8 +135,8 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
return;
}
WifiDppQrCodeScannerFragment fragment = new WifiDppQrCodeScannerFragment();
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
final WifiDppQrCodeScannerFragment fragment = new WifiDppQrCodeScannerFragment();
final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment,
WifiDppUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
@@ -145,8 +153,8 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
return;
}
WifiDppQrCodeGeneratorFragment fragment = new WifiDppQrCodeGeneratorFragment();
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
final WifiDppQrCodeGeneratorFragment fragment = new WifiDppQrCodeGeneratorFragment();
final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment,
WifiDppUtils.TAG_FRAGMENT_QR_CODE_GENERATOR);
@@ -160,9 +168,9 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
return;
}
WifiDppChooseSavedWifiNetworkFragment fragment =
final WifiDppChooseSavedWifiNetworkFragment fragment =
new WifiDppChooseSavedWifiNetworkFragment();
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment,
WifiDppUtils.TAG_FRAGMENT_CHOOSE_SAVED_WIFI_NETWORK);
@@ -172,11 +180,38 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
fragmentTransaction.commit();
}
private void showAddDeviceFragment(boolean addToBackStack) {
// Avoid to replace the same fragment during configuration change
if (mFragmentManager.findFragmentByTag(
WifiDppUtils.TAG_FRAGMENT_ADD_DEVICE) != null) {
return;
}
final WifiDppAddDeviceFragment fragment =
new WifiDppAddDeviceFragment();
final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment,
WifiDppUtils.TAG_FRAGMENT_ADD_DEVICE);
if (addToBackStack) {
fragmentTransaction.addToBackStack(/* name */ null);
}
fragmentTransaction.commit();
}
@Override
public WifiNetworkConfig getWifiNetworkConfig() {
return mWifiNetworkConfig;
}
public String getPublicKey() {
return mPublicKey;
}
public String getInformation() {
return mInformation;
}
@Override
public boolean setWifiNetworkConfig(WifiNetworkConfig config) {
if(!WifiNetworkConfig.isValidConfig(config)) {
@@ -201,7 +236,26 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
return false;
}
@Override public void onQrCodeGeneratorFragmentAddButtonClicked() {
@Override
public void onQrCodeGeneratorFragmentAddButtonClicked() {
showQrCodeScannerFragment(/* addToBackStack */ true);
}
@Override
public void onScanWifiDppSuccess(String publicKey, String information) {
mPublicKey = publicKey;
mInformation = information;
mWifiNetworkConfig = null;
showAddDeviceFragment(/* addToBackStack */ true);
}
@Override
public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig) {
mPublicKey = null;
mInformation = null;
mWifiNetworkConfig = new WifiNetworkConfig(wifiNetworkConfig);
showAddDeviceFragment(/* addToBackStack */ true);
}
}

View File

@@ -16,9 +16,11 @@
package com.android.settings.wifi.dpp;
import android.provider.Settings;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.util.Log;
@@ -36,7 +38,10 @@ import com.android.settings.R;
* To use intent action {@code ACTION_ENROLLEE_QR_CODE_SCANNER}, specify the SSID string of the
* Wi-Fi network to be provisioned in {@code WifiDppUtils.EXTRA_WIFI_SSID}.
*/
public class WifiDppEnrolleeActivity extends InstrumentedActivity {
public class WifiDppEnrolleeActivity extends InstrumentedActivity implements
WifiManager.ActionListener,
WifiDppQrCodeScannerFragment.OnScanWifiDppSuccessListener,
WifiDppQrCodeScannerFragment.OnScanZxingWifiFormatSuccessListener {
private static final String TAG = "WifiDppEnrolleeActivity";
public static final String ACTION_ENROLLEE_QR_CODE_SCANNER =
@@ -101,4 +106,31 @@ public class WifiDppEnrolleeActivity extends InstrumentedActivity {
finish();
return true;
}
@Override
public void onScanWifiDppSuccess(String publicKey, String information) {
// TODO(b/1023597): starts DPP enrollee handshake here
}
@Override
public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig) {
wifiNetworkConfig.connect(/* context */ this, /* listener */ this);
}
@Override
public void onSuccess() {
startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
setResult(Activity.RESULT_OK);
finish();
}
@Override
public void onFailure(int reason) {
Log.d(TAG, "Wi-Fi connect onFailure reason - " + reason);
final Fragment fragment = mFragmentManager.findFragmentById(R.id.fragment_container);
if (fragment instanceof WifiDppQrCodeScannerFragment) {
((WifiDppQrCodeScannerFragment)fragment).showErrorMessage(true);
}
}
}

View File

@@ -17,25 +17,16 @@
package com.android.settings.wifi.dpp;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.settings.core.InstrumentedFragment;
import com.android.settings.R;
/**
* TODO: b/120645817 should refine code to only initiate UI component in each child fragment.
*/
/**
* There are below 4 fragments for Wi-Fi DPP UI flow, to reduce redundant code of UI components,
* this parent fragment instantiates all UI components and provides setting APIs for them.
* this parent fragment instantiates common UI components
*
* {@code WifiDppQrCodeScannerFragment}
* {@code WifiDppQrCodeGeneratorFragment}
@@ -43,128 +34,16 @@ import com.android.settings.R;
* {@code WifiDppAddDeviceFragment}
*/
public abstract class WifiDppQrCodeBaseFragment extends InstrumentedFragment {
private ImageView mHeaderIcon;
private TextView mTitle;
private TextView mDescription;
private TextView mErrorMessage; //optional, for WifiDppQrCodeScannerFragment
private ListView mSavedWifiNetworkList; //optional, for WifiDppChooseSavedWifiNetworkFragment
private ProgressBar mProgressBar; //optional, for WifiDppAddDeviceFragment
private ImageView mWifiApPictureView; //optional, for WifiDppAddDeviceFragment
private TextView mChooseDifferentNetwork;//optional, for WifiDppAddDeviceFragment
private Button mButtonLeft; //optional, for WifiDppChooseSavedWifiNetworkFragment,
// WifiDppAddDeviceFragment
private Button mButtonRight; //optional, for WifiDppChooseSavedWifiNetworkFragment,
// WifiDppAddDeviceFragment
abstract protected int getLayout();
protected ImageView mHeaderIcon;
protected TextView mTitle;
protected TextView mSummary;
@Override
public final void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(getLayout(), container, false);
initView(view);
return view;
}
private void initView(View view) {
mHeaderIcon = view.findViewById(R.id.header_icon);
mTitle = view.findViewById(R.id.title);
mDescription = view.findViewById(R.id.description);
mErrorMessage = view.findViewById(R.id.error_message);
mSavedWifiNetworkList = view.findViewById(R.id.saved_wifi_network_list);
mProgressBar = view.findViewById(R.id.progress_bar);
mWifiApPictureView = view.findViewById(R.id.wifi_ap_picture_view);
mChooseDifferentNetwork = view.findViewById(R.id.choose_different_network);
mButtonLeft = view.findViewById(R.id.button_left);
mButtonRight = view.findViewById(R.id.button_right);
}
protected void setHeaderIconImageResource(int resId) {
mHeaderIcon.setImageResource(resId);
}
protected void setTitle(String title) {
mTitle.setText(title);
}
protected void setDescription(String description) {
mDescription.setText(description);
}
/** optional, for WifiDppQrCodeScannerFragment */
protected void setErrorMessage(String errorMessage) {
if (mErrorMessage != null) {
mErrorMessage.setText(errorMessage);
}
}
/**
* optional, for WifiDppChooseSavedWifiNetworkFragment,
* WifiDppAddDeviceFragment
*/
protected void setLeftButtonText(String text) {
if (mButtonLeft != null) {
mButtonLeft.setText(text);
}
}
/**
* optional, for WifiDppChooseSavedWifiNetworkFragment,
* WifiDppAddDeviceFragment
*/
protected void setRightButtonText(String text) {
if (mButtonRight != null) {
mButtonRight.setText(text);
}
}
/**
* optional, for WifiDppChooseSavedWifiNetworkFragment,
* WifiDppAddDeviceFragment
*/
protected void hideLeftButton() {
if (mButtonLeft != null) {
mButtonLeft.setVisibility(View.INVISIBLE);
}
}
/**
* optional, for WifiDppChooseSavedWifiNetworkFragment,
* WifiDppAddDeviceFragment
*/
protected void hideRightButton() {
if (mButtonRight != null) {
mButtonRight.setVisibility(View.INVISIBLE);
}
}
/**
* optional, for WifiDppChooseSavedWifiNetworkFragment,
* WifiDppAddDeviceFragment
*/
protected void setLeftButtonOnClickListener(View.OnClickListener listener) {
if (mButtonLeft != null) {
mButtonLeft.setOnClickListener(listener);
}
}
/**
* optional, for WifiDppChooseSavedWifiNetworkFragment,
* WifiDppAddDeviceFragment
*/
protected void setRightButtonOnClickListener(View.OnClickListener listener) {
if (mButtonRight != null) {
mButtonRight.setOnClickListener(listener);
}
mHeaderIcon = view.findViewById(android.R.id.icon);
mTitle = view.findViewById(android.R.id.title);
mSummary = view.findViewById(android.R.id.summary);
}
}

View File

@@ -21,10 +21,12 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.android.internal.logging.nano.MetricsProto;
@@ -43,11 +45,6 @@ public class WifiDppQrCodeGeneratorFragment extends WifiDppQrCodeBaseFragment {
private ImageView mQrCodeView;
private String mQrCode;
@Override
protected int getLayout() {
return R.layout.wifi_dpp_qrcode_generator_fragment;
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
@@ -63,25 +60,12 @@ public class WifiDppQrCodeGeneratorFragment extends WifiDppQrCodeBaseFragment {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHeaderIconImageResource(R.drawable.ic_qrcode_24dp);
WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
.getWifiNetworkConfig();
if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
throw new IllegalArgumentException("Invalid Wi-Fi network for configuring");
}
setTitle(getString(R.string.wifi_dpp_share_wifi));
setDescription(getString(R.string.wifi_dpp_scan_qr_code_with_another_device,
wifiNetworkConfig.getSsid()));
setHasOptionsMenu(true);
ActionBar actionBar = getActivity().getActionBar();
final ActionBar actionBar = getActivity().getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.show();
}
mQrCode = wifiNetworkConfig.getQrCode();
setQrCode();
}
@Override
@@ -118,10 +102,31 @@ public class WifiDppQrCodeGeneratorFragment extends WifiDppQrCodeBaseFragment {
}
}
@Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.wifi_dpp_qrcode_generator_fragment, container,
/* attachToRoot */ false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mQrCodeView = view.findViewById(R.id.qrcode_view);
mHeaderIcon.setImageResource(R.drawable.ic_qrcode_24dp);
WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
.getWifiNetworkConfig();
if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
throw new IllegalStateException("Invalid Wi-Fi network for configuring");
}
mTitle.setText(R.string.wifi_dpp_share_wifi);
mSummary.setText(getString(R.string.wifi_dpp_scan_qr_code_with_another_device,
wifiNetworkConfig.getSsid()));
mQrCode = wifiNetworkConfig.getQrCode();
setQrCode();
}
private void setQrCode() {

View File

@@ -16,7 +16,6 @@
package com.android.settings.wifi.dpp;
import android.annotation.Nullable;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
@@ -25,13 +24,18 @@ import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Size;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.TextureView;
import android.view.TextureView.SurfaceTextureListener;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
@@ -41,37 +45,69 @@ import com.android.settings.wifi.qrcode.QrDecorateView;
public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment implements
SurfaceTextureListener,
QrCamera.ScannerCallback {
private static final String TAG = "WifiDppQrCodeScannerFragment";
/** Message sent to hide error message */
private static final int MESSAGE_HIDE_ERROR_MESSAGE = 1;
/** Message sent to show error message */
private static final int MESSAGE_SHOW_ERROR_MESSAGE = 2;
/** Message sent to manipulate Wi-Fi DPP QR code */
private static final int MESSAGE_SCAN_WIFI_DPP_SUCCESS = 3;
/** Message sent to manipulate ZXing Wi-Fi QR code */
private static final int MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS = 4;
private static final long SHOW_ERROR_MESSAGE_INTERVAL = 2000;
private static final long SHOW_SUCCESS_SQUARE_INTERVAL = 1000;
// Keys for Bundle usage
private static final String KEY_PUBLIC_KEY = "key_public_key";
private static final String KEY_INFORMATION = "key_information";
private QrCamera mCamera;
private TextureView mTextureView;
private QrDecorateView mDecorateView;
private TextView mErrorMessage;
/** true if the fragment working for configurator, false enrollee*/
private final boolean mConfiguratorMode;
private final boolean mIsConfiguratorMode;
/** The SSID of the Wi-Fi network which the user specify to enroll */
private String mSsid;
@Override
protected int getLayout() {
return R.layout.wifi_dpp_qrcode_scanner_fragment;
}
/** QR code data scanned by camera */
private WifiQrCode mWifiQrCode;
@Override
public int getMetricsCategory() {
if (mConfiguratorMode) {
if (mIsConfiguratorMode) {
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
} else {
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_ENROLLEE;
}
}
// Container Activity must implement this interface
public interface OnScanWifiDppSuccessListener {
public void onScanWifiDppSuccess(String publicKey, String information);
}
OnScanWifiDppSuccessListener mScanWifiDppSuccessListener;
// Container Activity must implement this interface
public interface OnScanZxingWifiFormatSuccessListener {
public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig);
}
OnScanZxingWifiFormatSuccessListener mScanScanZxingWifiFormatSuccessListener;
/**
* Configurator container activity of the fragment should create instance with this constructor.
*/
public WifiDppQrCodeScannerFragment() {
super();
mConfiguratorMode = true;
mIsConfiguratorMode = true;
}
/**
@@ -81,7 +117,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
public WifiDppQrCodeScannerFragment(String ssid) {
super();
mConfiguratorMode = false;
mIsConfiguratorMode = false;
mSsid = ssid;
}
@@ -89,30 +125,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHeaderIconImageResource(R.drawable.ic_scan_24dp);
if (mConfiguratorMode) {
setTitle(getString(R.string.wifi_dpp_add_device_to_network));
WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
.getWifiNetworkConfig();
if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
throw new IllegalArgumentException("Invalid Wi-Fi network for configuring");
}
setDescription(getString(R.string.wifi_dpp_center_qr_code, wifiNetworkConfig.getSsid()));
} else {
setTitle(getString(R.string.wifi_dpp_scan_qr_code));
String description;
if (TextUtils.isEmpty(mSsid)) {
description = getString(R.string.wifi_dpp_scan_qr_code_join_unknown_network, mSsid);
} else {
description = getString(R.string.wifi_dpp_scan_qr_code_join_network, mSsid);
}
setDescription(description);
}
ActionBar actionBar = getActivity().getActionBar();
final ActionBar actionBar = getActivity().getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.show();
@@ -120,13 +133,61 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
public void onAttach(Context context) {
super.onAttach(context);
mScanWifiDppSuccessListener = (OnScanWifiDppSuccessListener) context;
mScanScanZxingWifiFormatSuccessListener = (OnScanZxingWifiFormatSuccessListener) context;
}
@Override
public void onDetach() {
mScanWifiDppSuccessListener = null;
mScanScanZxingWifiFormatSuccessListener = null;
super.onDetach();
}
@Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.wifi_dpp_qrcode_scanner_fragment, container,
/* attachToRoot */ false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mTextureView = (TextureView) view.findViewById(R.id.preview_view);
mTextureView.setSurfaceTextureListener(this);
mDecorateView = (QrDecorateView) view.findViewById(R.id.decorate_view);
mHeaderIcon.setImageResource(R.drawable.ic_scan_24dp);
if (mIsConfiguratorMode) {
mTitle.setText(R.string.wifi_dpp_add_device_to_network);
WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
.getWifiNetworkConfig();
if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
throw new IllegalStateException("Invalid Wi-Fi network for configuring");
}
mSummary.setText(getString(R.string.wifi_dpp_center_qr_code,
wifiNetworkConfig.getSsid()));
} else {
mTitle.setText(R.string.wifi_dpp_scan_qr_code);
String description;
if (TextUtils.isEmpty(mSsid)) {
description = getString(R.string.wifi_dpp_scan_qr_code_join_unknown_network, mSsid);
} else {
description = getString(R.string.wifi_dpp_scan_qr_code_join_network, mSsid);
}
mSummary.setText(description);
}
mErrorMessage = view.findViewById(R.id.error_message);
}
@Override
@@ -172,11 +233,76 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
mTextureView.setTransform(transform);
}
@Override
public boolean isValid(String qrCode) {
try {
mWifiQrCode = new WifiQrCode(qrCode);
} catch (IllegalArgumentException e) {
mHandler.sendEmptyMessage(MESSAGE_SHOW_ERROR_MESSAGE);
return false;
}
final String scheme = mWifiQrCode.getScheme();
// When SSID is specified for enrollee, avoid to connect to the Wi-Fi of different SSID
if (!mIsConfiguratorMode && WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG.equals(scheme)) {
final String ssidQrCode = mWifiQrCode.getWifiNetworkConfig().getSsid();
if (!TextUtils.isEmpty(mSsid) && !mSsid.equals(ssidQrCode)) {
mHandler.sendEmptyMessage(MESSAGE_SHOW_ERROR_MESSAGE);
return false;
}
}
// It's impossible to provision other device with ZXing Wi-Fi Network config format
if (mIsConfiguratorMode && WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG.equals(scheme)) {
mHandler.sendEmptyMessage(MESSAGE_SHOW_ERROR_MESSAGE);
return false;
}
return true;
}
/**
* This method is only called when QrCamera.ScannerCallback.isValid returns true;
*/
@Override
public void handleSuccessfulResult(String qrCode) {
switch (mWifiQrCode.getScheme()) {
case WifiQrCode.SCHEME_DPP:
handleWifiDpp(mWifiQrCode.getPublicKey(), mWifiQrCode.getInformation());
break;
case WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG:
handleZxingWifiFormat(mWifiQrCode.getWifiNetworkConfig());
break;
default:
// continue below
}
}
private void handleWifiDpp(String publicKey, String information) {
destroyCamera();
mDecorateView.setFocused(true);
// TODO(b/120243131): Add a network by Wi-Fi Network config shared via QR code.
final Bundle bundle = new Bundle();
bundle.putString(KEY_PUBLIC_KEY, publicKey);
bundle.putString(KEY_INFORMATION, information);
Message message = mHandler.obtainMessage(MESSAGE_SCAN_WIFI_DPP_SUCCESS);
message.setData(bundle);
mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL);
}
private void handleZxingWifiFormat(WifiNetworkConfig wifiNetworkConfig) {
destroyCamera();
mDecorateView.setFocused(true);
Message message = mHandler.obtainMessage(MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS);
message.obj = wifiNetworkConfig;
mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL);
}
@Override
@@ -198,4 +324,51 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
mCamera = null;
}
}
public void showErrorMessage(boolean show) {
mErrorMessage.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
if (show) {
mHandler.removeMessages(MESSAGE_HIDE_ERROR_MESSAGE);
mHandler.sendEmptyMessageDelayed(MESSAGE_HIDE_ERROR_MESSAGE,
SHOW_ERROR_MESSAGE_INTERVAL);
}
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_HIDE_ERROR_MESSAGE:
showErrorMessage(false);
break;
case MESSAGE_SHOW_ERROR_MESSAGE:
showErrorMessage(true);
break;
case MESSAGE_SCAN_WIFI_DPP_SUCCESS:
if (mScanWifiDppSuccessListener == null) {
return;
}
final Bundle bundle = msg.getData();
final String publicKey = bundle.getString(KEY_PUBLIC_KEY);
final String information = bundle.getString(KEY_INFORMATION);
mScanWifiDppSuccessListener.onScanWifiDppSuccess(publicKey, information);
break;
case MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS:
if (mScanScanZxingWifiFormatSuccessListener == null) {
return;
}
mScanScanZxingWifiFormatSuccessListener.onScanZxingWifiFormatSuccess(
(WifiNetworkConfig)msg.obj);
break;
default:
return;
}
}
};
}

View File

@@ -16,8 +16,18 @@
package com.android.settings.wifi.dpp;
import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_NO_PASSWORD;
import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_WEP;
import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_WPA;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.AuthAlgorithm;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiManager;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Keep;
@@ -30,8 +40,7 @@ import androidx.annotation.Keep;
* EXTRA_QR_CODE
*/
public class WifiNetworkConfig {
// Ignores password if security is NO_PASSWORD or absent
public static final String NO_PASSWORD = "nopass";
private static final String TAG = "WifiNetworkConfig";
private String mSecurity;
private String mSsid;
@@ -47,18 +56,9 @@ public class WifiNetworkConfig {
}
public WifiNetworkConfig(WifiNetworkConfig config) {
if (config.mSecurity != null) {
mSecurity = new String(config.mSecurity);
}
if (config.mSsid != null) {
mSsid = new String(config.mSsid);
}
if (config.mPreSharedKey != null) {
mPreSharedKey = new String(config.mPreSharedKey);
}
mSecurity = config.mSecurity;
mSsid = config.mSsid;
mPreSharedKey = config.mPreSharedKey;
mHiddenSsid = config.mHiddenSsid;
}
@@ -106,7 +106,7 @@ public class WifiNetworkConfig {
public static boolean isValidConfig(String security, String ssid, String preSharedKey,
boolean hiddenSsid) {
if (!TextUtils.isEmpty(security) && !NO_PASSWORD.equals(security)) {
if (!TextUtils.isEmpty(security) && !SECURITY_NO_PASSWORD.equals(security)) {
if (TextUtils.isEmpty(preSharedKey)) {
return false;
}
@@ -183,4 +183,77 @@ public class WifiNetworkConfig {
public boolean getHiddenSsid() {
return mHiddenSsid;
}
public void connect(Context context, WifiManager.ActionListener listener) {
WifiConfiguration wifiConfiguration = getWifiConfigurationOrNull();
if (wifiConfiguration == null) {
if (listener != null) {
listener.onFailure(WifiManager.ERROR);
}
return;
}
WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
wifiManager.connect(wifiConfiguration, listener);
}
/**
* This is a simplified method from {@code WifiConfigController.getConfig()}
*/
private WifiConfiguration getWifiConfigurationOrNull() {
if (!isValidConfig(this)) {
return null;
}
final WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.SSID = addQuotationIfNeeded(mSsid);
wifiConfiguration.hiddenSSID = mHiddenSsid;
if (TextUtils.isEmpty(mSecurity) || SECURITY_NO_PASSWORD.equals(mSecurity)) {
wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
return wifiConfiguration;
}
if (mSecurity.startsWith(SECURITY_WEP)) {
wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
wifiConfiguration.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
wifiConfiguration.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
// WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
final int length = mPreSharedKey.length();
if ((length == 10 || length == 26 || length == 58)
&& mPreSharedKey.matches("[0-9A-Fa-f]*")) {
wifiConfiguration.wepKeys[0] = mPreSharedKey;
} else {
wifiConfiguration.wepKeys[0] = addQuotationIfNeeded(mPreSharedKey);
}
} else if (mSecurity.startsWith(SECURITY_WPA)) {
wifiConfiguration.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
if (mPreSharedKey.matches("[0-9A-Fa-f]{64}")) {
wifiConfiguration.preSharedKey = mPreSharedKey;
} else {
wifiConfiguration.preSharedKey = addQuotationIfNeeded(mPreSharedKey);
}
} else {
Log.w(TAG, "Unsupported security");
return null;
}
return wifiConfiguration;
}
private String addQuotationIfNeeded(String input) {
if (TextUtils.isEmpty(input)) {
return "";
}
if (input.length() >= 2 && input.startsWith("\"") && input.endsWith("\"")) {
return input;
}
StringBuilder sb = new StringBuilder();
sb.append("\"").append(input).append("\"");
return sb.toString();
}
}

View File

@@ -22,7 +22,8 @@ import android.text.TextUtils;
import androidx.annotation.Keep;
import androidx.annotation.VisibleForTesting;
import java.util.regex.Matcher;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
/**
@@ -62,7 +63,12 @@ public class WifiQrCode {
public static final String PREFIX_ZXING_PASSWORD = "P:";
public static final String PREFIX_ZXING_HIDDEN_SSID = "H:";
public static final String SUFFIX_QR_CODE = ";";
public static final String DELIMITER_QR_CODE = ";";
// Ignores password if security is SECURITY_NO_PASSWORD or absent
public static final String SECURITY_NO_PASSWORD = "nopass";
public static final String SECURITY_WEP = "WEP";
public static final String SECURITY_WPA = "WPA";
private String mQrCode;
@@ -100,22 +106,27 @@ public class WifiQrCode {
/** Parses Wi-Fi DPP QR code string */
private void parseWifiDppQrCode(String qrCode) throws IllegalArgumentException {
String publicKey = getSubStringOrNull(qrCode, PREFIX_DPP_PUBLIC_KEY, SUFFIX_QR_CODE);
List keyValueList = getKeyValueList(qrCode, PREFIX_DPP, DELIMITER_QR_CODE);
String publicKey = getValueOrNull(keyValueList, PREFIX_DPP_PUBLIC_KEY);
if (TextUtils.isEmpty(publicKey)) {
throw new IllegalArgumentException("Invalid format");
}
mPublicKey = publicKey;
mInformation = getSubStringOrNull(qrCode, PREFIX_DPP_INFORMATION, SUFFIX_QR_CODE);
mInformation = getValueOrNull(keyValueList, PREFIX_DPP_INFORMATION);
}
/** Parses ZXing reader library's Wi-Fi Network config format */
private void parseZxingWifiQrCode(String qrCode) throws IllegalArgumentException {
String security = getSubStringOrNull(qrCode, PREFIX_ZXING_SECURITY, SUFFIX_QR_CODE);
String ssid = getSubStringOrNull(qrCode, PREFIX_ZXING_SSID, SUFFIX_QR_CODE);
String password = getSubStringOrNull(qrCode, PREFIX_ZXING_PASSWORD, SUFFIX_QR_CODE);
String hiddenSsidString = getSubStringOrNull(qrCode, PREFIX_ZXING_HIDDEN_SSID,
SUFFIX_QR_CODE);
List keyValueList = getKeyValueList(qrCode, PREFIX_ZXING_WIFI_NETWORK_CONFIG,
DELIMITER_QR_CODE);
String security = getValueOrNull(keyValueList, PREFIX_ZXING_SECURITY);
String ssid = getValueOrNull(keyValueList, PREFIX_ZXING_SSID);
String password = getValueOrNull(keyValueList, PREFIX_ZXING_PASSWORD);
String hiddenSsidString = getValueOrNull(keyValueList, PREFIX_ZXING_HIDDEN_SSID);
boolean hiddenSsid = "true".equalsIgnoreCase(hiddenSsidString);
//"\", ";", "," and ":" are escaped with a backslash "\", should remove at first
@@ -132,33 +143,37 @@ public class WifiQrCode {
}
/**
* Gets the substring between prefix & suffix from input.
* Splits key/value pairs from qrCode
*
* @param prefix the string before the returned substring
* @param suffix the string after the returned substring
* @return null if not exists, non-null otherwise
* @param qrCode the QR code raw string
* @param prefixQrCode the string before all key/value pairs in qrCode
* @param delimiter the string to split key/value pairs, can't contain a backslash
* @return a list contains string of key/value (e.g. K:key1)
*/
private static String getSubStringOrNull(String input, String prefix, String suffix) {
StringBuilder sb = new StringBuilder();
String regex = sb.append(prefix).append("(.*?)").append(suffix).toString();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
private List<String> getKeyValueList(String qrCode, String prefixQrCode,
String delimiter) {
String keyValueString = qrCode.substring(prefixQrCode.length());
if (!matcher.find()) {
return null;
// Should not treat \delimiter as a delimiter
String regex = "(?<!\\\\)" + Pattern.quote(delimiter);
List<String> result = Arrays.asList(keyValueString.split(regex));
return result;
}
private String getValueOrNull(List<String> keyValueList, String prefix) {
for (String keyValue : keyValueList) {
if (keyValue.startsWith(prefix)) {
return keyValue.substring(prefix.length());
}
}
String target = matcher.group(1);
if (TextUtils.isEmpty(target)) {
return null;
}
return target;
return null;
}
@Keep
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
protected static String removeBackSlash(String input) {
protected String removeBackSlash(String input) {
if (input == null) {
return null;
}

View File

@@ -152,6 +152,15 @@ public class QrCamera extends Handler {
* @param transform The transform to apply to the content of preview
*/
void setTransform(Matrix transform);
/**
* Verify QR code is valid or not. The camera will stop scanning if this callback returns
* true.
*
* @param qrCode The result QR code after decoding.
* @return Returns true if qrCode hold valid information.
*/
boolean isValid(String qrCode);
}
private void setCameraParameter() {
@@ -245,7 +254,9 @@ public class QrCamera extends Handler {
mReader.reset();
}
if (qrCode != null) {
return qrCode.getText();
if (mScannerCallback.isValid(qrCode.getText())) {
return qrCode.getText();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();

View File

@@ -17,10 +17,13 @@
package com.android.settings.wifi.qrcode;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
@@ -33,11 +36,26 @@ import com.android.settings.R;
* Draws the lines at the corner of the inner frame.
*/
public class QrDecorateView extends View {
private static final float CORNER_STROKE_WIDTH = 3f; // 3dp
private static final float CORNER_LINE_LENGTH = 20f; // 20dp
private static final float CORNER_STROKE_WIDTH = 4f; // 4dp
private static final float CORNER_LINE_LENGTH = 264f; // 264dp
private static final float CORNER_RADIUS = 16f; // 16dp
final private int mCornerColor;
final private int mFocusedCornerColor;
final private int mBackgroundColor;
final private Paint mStrokePaint;
final private Paint mTransparentPaint;
final private Paint mBackgroundPaint;
final private float mRadius;
private Bitmap mMaskBitmap;
private Canvas mMaskCanvas;
private RectF mOuterFrame;
private RectF mInnerFrame;
final private Paint mPaint;
private RectF mFrame;
private boolean mFocused;
public QrDecorateView(Context context) {
@@ -54,78 +72,66 @@ public class QrDecorateView extends View {
public QrDecorateView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
final float strokeWidth = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
CORNER_STROKE_WIDTH,
getResources().getDisplayMetrics()
);
mPaint = new Paint();
mPaint.setStrokeWidth(strokeWidth);
mFocused = false;
mRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS,
getResources().getDisplayMetrics());
mCornerColor = context.getResources().getColor(R.color.qr_corner_line_color);
mFocusedCornerColor = context.getResources().getColor(R.color.qr_focused_corner_line_color);
mBackgroundColor = context.getResources().getColor(R.color.qr_background_color);
mStrokePaint = new Paint();
mStrokePaint.setAntiAlias(true);
mTransparentPaint = new Paint();
mTransparentPaint.setAntiAlias(true);
mTransparentPaint.setColor(getResources().getColor(android.R.color.transparent));
mTransparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(mBackgroundColor);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if(mMaskBitmap == null) {
mMaskBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
mMaskCanvas = new Canvas(mMaskBitmap);
}
calculateFramePos();
}
@Override
protected void onDraw(Canvas canvas) {
calculateFramePos();
final float cornerLineLength = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
CORNER_LINE_LENGTH,
getResources().getDisplayMetrics()
);
mPaint.setColor(mFocused ? Color.GREEN : Color.WHITE);
drawCorner(mFrame, cornerLineLength, canvas);
super.onDraw(canvas);
}
// Set frame line color.
mStrokePaint.setColor(mFocused ? mFocusedCornerColor : mCornerColor);
// Draw background color.
mMaskCanvas.drawColor(mBackgroundColor);
// Draw outer corner.
mMaskCanvas.drawRoundRect(mOuterFrame, mRadius, mRadius, mStrokePaint);
// Draw inner transparent corner.
mMaskCanvas.drawRoundRect(mInnerFrame, mRadius, mRadius, mTransparentPaint);
private void drawCorner(RectF frame, float lineLength, Canvas canvas) {
final float strokeWidth = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
CORNER_STROKE_WIDTH,
getResources().getDisplayMetrics()
);
// Draw top-left corner.
canvas.drawLine(
frame.left - strokeWidth / 2,
frame.top,
frame.left + lineLength,
frame.top,
mPaint);
canvas.drawLine(frame.left, frame.top, frame.left, frame.top + lineLength, mPaint);
// Draw top-right corner.
canvas.drawLine(
frame.right + strokeWidth / 2,
frame.top,
frame.right - lineLength,
frame.top,
mPaint);
canvas.drawLine(frame.right, frame.top, frame.right, frame.top + lineLength, mPaint);
// Draw bottom-left corner.
canvas.drawLine(
frame.left - strokeWidth / 2,
frame.bottom,
frame.left + lineLength,
frame.bottom,
mPaint);
canvas.drawLine(frame.left, frame.bottom, frame.left, frame.bottom - lineLength, mPaint);
// Draw bottom-right corner.
canvas.drawLine(
frame.right + strokeWidth / 2,
frame.bottom,
frame.right - lineLength,
frame.bottom,
mPaint);
canvas.drawLine(frame.right, frame.bottom, frame.right, frame.bottom - lineLength, mPaint);
canvas.drawBitmap(mMaskBitmap, 0, 0, mBackgroundPaint);
super.onDraw(canvas);
}
private void calculateFramePos() {
final int centralX = getWidth() / 2;
final int centralY = getHeight() / 2;
final float halfFrameWidth = getWidth() / 3;
mFrame = new RectF(
centralX - halfFrameWidth,
centralY - halfFrameWidth,
centralX + halfFrameWidth,
centralY + halfFrameWidth);
final float cornerLineLength = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
CORNER_LINE_LENGTH, getResources().getDisplayMetrics()) / 2;
final float strokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
CORNER_STROKE_WIDTH, getResources().getDisplayMetrics()) / 2;
mOuterFrame = new RectF(centralX - cornerLineLength, centralY - cornerLineLength,
centralX + cornerLineLength, centralY + cornerLineLength);
mInnerFrame = new RectF(mOuterFrame.left + strokeWidth, mOuterFrame.top + strokeWidth,
mOuterFrame.right - strokeWidth, mOuterFrame.bottom - strokeWidth);
}
// Draws green lines if focued. Otherwise, draws white lines.

View File

@@ -178,6 +178,8 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
controllers.add(new WifiTetherSecurityPreferenceController(context, listener));
controllers.add(new WifiTetherPasswordPreferenceController(context, listener));
controllers.add(new WifiTetherApBandPreferenceController(context, listener));
controllers.add(
new WifiTetherAutoOffPreferenceController(context, KEY_WIFI_TETHER_AUTO_OFF));
return controllers;
}

View File

@@ -0,0 +1,86 @@
/*
* 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.location;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.location.LocationManager;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class TopLevelLocationPreferenceControllerTest {
private static final String PREFERENCE_KEY = "top_level_location";
private Context mContext;
private TopLevelLocationPreferenceController mController;
private LocationManager mLocationManager;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mController = new TopLevelLocationPreferenceController(mContext, PREFERENCE_KEY);
mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
}
@Test
public void isAvailable_byDefault_shouldReturnTrue() {
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void getSummary_whenLocationIsOff_shouldReturnStringForOff() {
mLocationManager.setLocationEnabledForUser(false, android.os.Process.myUserHandle());
assertThat(mController.getSummary()).isEqualTo(
mContext.getString(R.string.location_settings_summary_location_off));
}
@Test
public void getSummary_whenLocationIsOn_shouldShowLoadingString() {
mLocationManager.setLocationEnabledForUser(true, android.os.Process.myUserHandle());
assertThat(mController.getSummary()).isEqualTo(
mContext.getString(R.string.location_settings_loading_app_permission_stats));
}
@Test
public void getSummary_whenLocationAppCountIsOne_shouldShowSingularString() {
final int LOCATION_APP_COUNT = 1;
mLocationManager.setLocationEnabledForUser(true, android.os.Process.myUserHandle());
mController.setLocationAppCount(LOCATION_APP_COUNT);
assertThat(mController.getSummary()).isEqualTo(
mContext.getResources().getQuantityString(
R.plurals.location_settings_summary_location_on,
LOCATION_APP_COUNT, LOCATION_APP_COUNT));
}
@Test
public void getSummary_whenLocationAppCountIsGreaterThanOne_shouldShowPluralString() {
final int LOCATION_APP_COUNT = 5;
mLocationManager.setLocationEnabledForUser(true, android.os.Process.myUserHandle());
mController.setLocationAppCount(LOCATION_APP_COUNT);
assertThat(mController.getSummary()).isEqualTo(
mContext.getResources().getQuantityString(
R.plurals.location_settings_summary_location_on,
LOCATION_APP_COUNT, LOCATION_APP_COUNT));
}
}

View File

@@ -38,8 +38,8 @@ import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class WifiPrivacyPreferenceControllerTest {
private static final int PRIVACY_RANDOMIZED = 0;
private static final int PRIVACY_TRUSTED = 1;
private static final int PRIVACY_RANDOMIZED = WifiConfiguration.RANDOMIZATION_PERSISTENT;
private static final int PRIVACY_TRUSTED = WifiConfiguration.RANDOMIZATION_NONE;
@Mock
private WifiConfiguration mWifiConfiguration;
@@ -47,6 +47,7 @@ public class WifiPrivacyPreferenceControllerTest {
private WifiPrivacyPreferenceController mPreferenceController;
private Context mContext;
private DropDownPreference mDropDownPreference;
private String[] perferenceString;
@Before
public void setUp() {
@@ -59,6 +60,8 @@ public class WifiPrivacyPreferenceControllerTest {
mDropDownPreference = new DropDownPreference(mContext);
mDropDownPreference.setEntries(R.array.wifi_privacy_entries);
mDropDownPreference.setEntryValues(R.array.wifi_privacy_values);
perferenceString = mContext.getResources().getStringArray(R.array.wifi_privacy_entries);
}
@Test
@@ -67,7 +70,8 @@ public class WifiPrivacyPreferenceControllerTest {
mPreferenceController.updateState(mDropDownPreference);
assertThat(mDropDownPreference.getEntry()).isEqualTo("Trusted");
assertThat(mDropDownPreference.getEntry()).isEqualTo(perferenceString[PRIVACY_TRUSTED]);
}
@Test
@@ -76,7 +80,7 @@ public class WifiPrivacyPreferenceControllerTest {
mPreferenceController.updateState(mDropDownPreference);
assertThat(mDropDownPreference.getEntry()).isEqualTo("Default (use randomized MAC)");
assertThat(mDropDownPreference.getEntry()).isEqualTo(perferenceString[PRIVACY_RANDOMIZED]);
}
@Test

View File

@@ -85,6 +85,11 @@ public class QrCameraTest {
public void setTransform(Matrix transform) {
// Do nothing
}
@Override
public boolean isValid(String qrCode) {
return true;
}
}
private ScannerTestCallback mScannerCallback;

View File

@@ -35,6 +35,9 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.widget.TextView;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceScreen;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowWifiManager;
@@ -51,15 +54,13 @@ import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.List;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceScreen;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowWifiManager.class})
public class WifiTetherSettingsTest {
private static final String[] WIFI_REGEXS = {"wifi_regexs"};
private Context mContext;
private WifiTetherSettings mWifiTetherSettings;
@Mock
private ConnectivityManager mConnectivityManager;
@@ -75,6 +76,8 @@ public class WifiTetherSettingsTest {
.when(mContext).getSystemService(Context.CONNECTIVITY_SERVICE);
doReturn(WIFI_REGEXS).when(mConnectivityManager).getTetherableWifiRegexs();
doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
mWifiTetherSettings = new WifiTetherSettings();
}
@Test
@@ -136,6 +139,15 @@ public class WifiTetherSettingsTest {
verify(screen).removeAll();
}
@Test
public void createPreferenceControllers_hasAutoOffPreference() {
assertThat(mWifiTetherSettings.createPreferenceControllers(mContext)
.stream()
.filter(controller -> controller instanceof WifiTetherAutoOffPreferenceController)
.count())
.isEqualTo(1);
}
private void setupIsTetherAvailable(boolean returnValue) {
when(mConnectivityManager.isTetheringSupported()).thenReturn(true);

View File

@@ -80,4 +80,20 @@ public class WifiDppConfiguratorActivityTest {
assertThat(activity instanceof WifiDppQrCodeGeneratorFragment
.OnQrCodeGeneratorFragmentAddButtonClickedListener).isEqualTo(true);
}
@Test
public void testActivity_shouldImplementsOnScanWifiDppSuccessCallback() {
WifiDppConfiguratorActivity activity = mActivityRule.getActivity();
assertThat(activity instanceof WifiDppQrCodeScannerFragment
.OnScanWifiDppSuccessListener).isEqualTo(true);
}
@Test
public void testActivity_shouldImplementsOnScanZxingWifiFormatSuccessCallback() {
WifiDppConfiguratorActivity activity = mActivityRule.getActivity();
assertThat(activity instanceof WifiDppQrCodeScannerFragment
.OnScanZxingWifiFormatSuccessListener).isEqualTo(true);
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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.dpp;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class WifiDppEnrolleeActivityTest {
@Rule
public final ActivityTestRule<WifiDppEnrolleeActivity> mActivityRule =
new ActivityTestRule<>(WifiDppEnrolleeActivity.class);
@Test
public void testActivity_shouldImplementsOnScanWifiDppSuccessCallback() {
WifiDppEnrolleeActivity activity = mActivityRule.getActivity();
assertThat(activity instanceof WifiDppQrCodeScannerFragment
.OnScanWifiDppSuccessListener).isEqualTo(true);
}
@Test
public void testActivity_shouldImplementsOnScanZxingWifiFormatSuccessCallback() {
WifiDppEnrolleeActivity activity = mActivityRule.getActivity();
assertThat(activity instanceof WifiDppQrCodeScannerFragment
.OnScanZxingWifiFormatSuccessListener).isEqualTo(true);
}
}

View File

@@ -29,7 +29,7 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class WifiQrCodetest {
public class WifiQrCodeTest {
// Valid Wi-Fi DPP QR code & it's parameters
private static final String VALID_WIFI_DPP_QR_CODE = "DPP:I:SN=4774LH2b4044;M:010203040506;K:"
+ "MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgADURzxmttZoIRIPWGoQMV00XHWCAQIhXruVWOz0NjlkIA=;;";
@@ -57,6 +57,13 @@ public class WifiQrCodetest {
private static final String SSID_OF_VALID_ZXING_WIFI_QR_CODE = "mynetwork";
private static final String PASSWORD_OF_VALID_ZXING_WIFI_QR_CODE = "mypass";
// Valid ZXing reader library's Wi-Fi Network config format - escaped characters
private static final String VALID_ZXING_WIFI_QR_CODE_SPECIAL_CHARACTERS =
"WIFI:T:WPA;S:mynetwork;P:m\\;y\\:p\\\\a\\,ss;H:true;;";
private static final String PASSWORD_OF_VALID_ZXING_WIFI_QR_CODE_SPECIAL_CHARACTERS =
"m;y:p\\a,ss";
// Invalid scheme QR code
private static final String INVALID_SCHEME_QR_CODE = "BT:T:WPA;S:mynetwork;P:mypass;H:true;;";
@@ -118,19 +125,35 @@ public class WifiQrCodetest {
assertEquals(WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG, wifiQrCode.getScheme());
assertNotNull(config);
assertNull(config.getSecurity());
assertEquals("", config.getSecurity());
assertEquals(SSID_OF_VALID_ZXING_WIFI_QR_CODE, config.getSsid());
assertNull(config.getPreSharedKey());
assertEquals("", config.getPreSharedKey());
assertEquals(false, config.getHiddenSsid());
}
@Test
public void parseValidZxingWifiQrCode_specialCharacters() {
WifiQrCode wifiQrCode = new WifiQrCode(VALID_ZXING_WIFI_QR_CODE_SPECIAL_CHARACTERS);
WifiNetworkConfig config = wifiQrCode.getWifiNetworkConfig();
assertEquals(WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG, wifiQrCode.getScheme());
assertNotNull(config);
assertEquals(SECURITY_OF_VALID_ZXING_WIFI_QR_CODE, config.getSecurity());
assertEquals(SSID_OF_VALID_ZXING_WIFI_QR_CODE, config.getSsid());
assertEquals(PASSWORD_OF_VALID_ZXING_WIFI_QR_CODE_SPECIAL_CHARACTERS,
config.getPreSharedKey());
assertEquals(true, config.getHiddenSsid());
}
@Test
public void testRemoveBackSlash() {
assertEquals("\\", WifiQrCode.removeBackSlash("\\\\"));
assertEquals("ab", WifiQrCode.removeBackSlash("a\\b"));
assertEquals("a", WifiQrCode.removeBackSlash("\\a"));
assertEquals("\\b", WifiQrCode.removeBackSlash("\\\\b"));
assertEquals("c\\", WifiQrCode.removeBackSlash("c\\\\"));
WifiQrCode wifiQrCode = new WifiQrCode(VALID_WIFI_DPP_QR_CODE);
assertEquals("\\", wifiQrCode.removeBackSlash("\\\\"));
assertEquals("ab", wifiQrCode.removeBackSlash("a\\b"));
assertEquals("a", wifiQrCode.removeBackSlash("\\a"));
assertEquals("\\b", wifiQrCode.removeBackSlash("\\\\b"));
assertEquals("c\\", wifiQrCode.removeBackSlash("c\\\\"));
}
@Test