Commit ce89d40e authored by Adam Langley's avatar Adam Langley Committed by Commit Bot

webauthn: update caBLEv2 mobile UI a little.

Far from complete, but a little more standard and now using layout XMLs,
like the rest of the code.

BUG=1002262

Change-Id: I2f9334fab4fc46374b76606d1e5acc29232a6793
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2511973Reviewed-by: default avatarMartin Kreichgauer <martinkr@google.com>
Commit-Queue: Adam Langley <agl@chromium.org>
Cr-Commit-Position: refs/heads/master@{#823353}
parent 53bcd0d3
...@@ -15,6 +15,7 @@ android_library("java") { ...@@ -15,6 +15,7 @@ android_library("java") {
] ]
deps = [ deps = [
":java_resources",
"$google_play_services_package:google_play_services_base_java", "$google_play_services_package:google_play_services_base_java",
"$google_play_services_package:google_play_services_fido_java", "$google_play_services_package:google_play_services_fido_java",
"$google_play_services_package:google_play_services_tasks_java", "$google_play_services_package:google_play_services_tasks_java",
...@@ -30,6 +31,7 @@ android_library("java") { ...@@ -30,6 +31,7 @@ android_library("java") {
] ]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
resources_package = "org.chromium.chrome.browser.webauth.authenticator"
} }
generate_jni("jni_headers") { generate_jni("jni_headers") {
...@@ -40,6 +42,16 @@ generate_jni("jni_headers") { ...@@ -40,6 +42,16 @@ generate_jni("jni_headers") {
] ]
} }
android_resources("java_resources") {
sources = [
"java/res/drawable/header.xml",
"java/res/layout/cablev2_fcm.xml",
"java/res/layout/cablev2_qr_scan.xml",
"java/res/layout/cablev2_usb_attached.xml",
]
deps = [ "//chrome/android:chrome_app_java_resources" ]
}
source_set("native") { source_set("native") {
sources = [ "native/cablev2_authenticator_android.cc" ] sources = [ "native/cablev2_authenticator_android.cc" ]
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="52dp"
android:viewportWidth="500"
android:viewportHeight="130">
<path
android:pathData="m106.179,98.477 l3.705,-3.705c7.6,7.6 15.7,11.43 24.075,11.4 13.17,-0.03 22.855,-9.655 22.95,-9.75L160.644,100.117C160.194,100.577 149.409,111.367 134.044,111.432 124.179,111.462 114.809,107.117 106.179,98.477Z"
android:fillColor="@color/google_red_600"
android:fillType="nonZero"/>
<path
android:pathData="m59.859,95.697 l-3.705,-3.705a40.45,40.45 0,0 1,16.25 -9.18c9.075,-2.57 22.945,-2.58 37.5,11.96L106.199,98.477C95.959,88.247 85.059,84.672 73.829,87.852A35.342,35.342 0,0 0,59.859 95.697Z"
android:fillColor="@color/modern_grey_200"
android:fillType="nonZero"/>
<path
android:pathData="M329.278,37.36L329.278,32.145c10.735,0 19.175,-3 25.1,-8.955 9.3,-9.36 9.325,-23.015 9.325,-23.15l5.25,-0.04c0,0.645 0,15.9 -10.815,26.82 -6.935,6.995 -16.645,10.54 -28.85,10.54z"
android:fillColor="@color/modern_grey_200"
android:fillType="nonZero"/>
<path
android:pathData="m294.563,68.145h-5.245a40.45,40.45 0,0 1,5 -18c4.605,-8.2 14.4,-18 34.96,-18v5.215c-14.465,0 -24.685,5.17 -30.385,15.36A35.35,35.35 0,0 0,294.563 68.145Z"
android:fillColor="@color/google_blue_grey_500"
android:fillType="nonZero"/>
<path
android:pathData="m285.609,35.639h-17.28a8.64,8.64 0,0 1,17.28 0zM203.784,55.404h20v4h-20z"
android:fillColor="@color/modern_grey_200"
android:fillType="nonZero"/>
<path
android:pathData="m207.052,65.064 l10,-17.32 3.464,2 -10,17.32z"
android:fillColor="@color/modern_grey_200"
android:fillType="nonZero"/>
<path
android:pathData="m217.052,67.064 l-10,-17.32 3.464,-2 10,17.32z"
android:fillColor="@color/modern_grey_200"
android:fillType="nonZero"/>
<path
android:pathData="m138.241,24.453a12.935,12.935 0,0 0,-10.1 4.82,8.62 8.62,0 0,0 -11.5,8.14h34.56c0,-7.158 -5.802,-12.96 -12.96,-12.96z"
android:fillColor="@color/modern_white"
android:fillType="nonZero"/>
<path
android:pathData="m281.082,31.359h-35.1v-0.27a8.89,8.89 0,0 1,11.695 -8.455,13.23 13.23,0 0,1 23.405,8.455zM246.527,30.819h34a12.69,12.69 0,0 0,-22.56 -7.7l-0.12,0.15 -0.18,-0.065a8.35,8.35 0,0 0,-11.155 7.615z"
android:fillColor="@color/modern_grey_400"
android:fillType="nonZero"/>
<path
android:pathData="m448.872,95.573a14.37,14.37 0,0 0,-11.205 5.355,9.58 9.58,0 0,0 -12.795,9.045h38.4c0,-7.953 -6.447,-14.4 -14.4,-14.4z"
android:fillColor="@color/modern_white"
android:fillType="nonZero"/>
<path
android:pathData="m488.408,29.047h-39v-0.3a9.88,9.88 0,0 1,13 -9.395,14.7 14.7,0 0,1 26,9.395zM450.013,28.447h37.795a14.1,14.1 0,0 0,-25.065 -8.555l-0.135,0.165 -0.2,-0.07c-2.795,-0.998 -5.898,-0.598 -8.35,1.075 -2.452,1.673 -3.953,4.42 -4.04,7.385z"
android:fillColor="@color/modern_grey_400"
android:fillType="nonZero"/>
<path
android:pathData="m407.542,32.173 l35.66,-30.405"
android:fillColor="@color/modern_grey_100"
android:fillType="nonZero"/>
<path
android:pathData="M39.297,23.65L69.526,23.65A8.613,8.613 0,0 1,78.139 32.263L78.139,100.309A8.613,8.613 0,0 1,69.526 108.923L39.297,108.923A8.613,8.613 0,0 1,30.684 100.309L30.684,32.263A8.613,8.613 0,0 1,39.297 23.65z"
android:strokeAlpha="1"
android:strokeWidth="1.368"
android:strokeColor="@color/modern_grey_500"
android:strokeLineCap="round"/>
<path
android:pathData="M84.304,41.552m-18.974,0a18.974,18.974 0,1 1,37.948 0a18.974,18.974 0,1 1,-37.948 0"
android:strokeAlpha="0.7"
android:strokeWidth="1.36839"
android:fillColor="@color/modern_blue_800"
android:fillAlpha="0.7"
android:strokeLineCap="round"/>
<path
android:pathData="m84.736,31.159 l-1.26,1.36v1.275l1.346,0.842 -1.346,0.995v0.075l1.365,0.852 -1.365,1.008v0.368l0.875,0.546 -0.875,0.647v0.326l1.519,0.95 -1.519,1.123v0.157l1.028,0.643 -1.028,0.759v1.823a4.753,4.647 0,0 0,-3.522 4.487,4.753 4.647,0 0,0 4.753,4.647 4.753,4.647 0,0 0,4.752 -4.647,4.753 4.647,0 0,0 -3.521,-4.487L85.939,32.418ZM84.749,50.291a1.239,1.239 0,0 1,0.035 0,1.239 1.239,0 0,1 1.239,1.24 1.239,1.239 0,0 1,-1.239 1.239,1.239 1.239,0 0,1 -1.24,-1.239 1.239,1.239 0,0 1,1.205 -1.24z"
android:strokeAlpha="1"
android:strokeWidth="1.04232"
android:fillColor="@color/modern_white"
android:fillAlpha="1"
android:strokeLineCap="round"/>
<path
android:pathData="m370.758,33.052c-2.393,0 -4.318,1.926 -4.318,4.318v59.451c0,0.185 0.03,0.362 0.053,0.541h90.072c0.022,-0.179 0.055,-0.356 0.055,-0.541L456.619,37.37c0,-2.393 -1.926,-4.318 -4.318,-4.318z"
android:strokeWidth="1.368"
android:strokeColor="@color/modern_grey_500"
android:fillAlpha="1"
android:strokeLineCap="round"/>
<path
android:pathData="m352.895,101.668h116.65"
android:strokeAlpha="1"
android:strokeLineJoin="miter"
android:strokeWidth="1.368"
android:strokeColor="@color/modern_grey_500"
android:fillType="evenOdd"
android:strokeLineCap="butt"/>
<path
android:pathData="M234.641,68.098m-23.188,0a23.188,23.188 0,1 1,46.377 0a23.188,23.188 0,1 1,-46.377 0"
android:strokeAlpha="1"
android:strokeWidth="1.92357"
android:strokeColor="@color/modern_grey_500"
android:strokeLineCap="round"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2020 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="HardcodedText"
style="@style/TextAppearance.TextLarge.Primary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Connected. Awaiting command from device." />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2020 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/qr_image"
android:importantForAccessibility="no"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginBottom="24dp"
android:background ="@color/modern_grey_50"
android:src="@drawable/header" />
<LinearLayout
android:id="@+id/qr_scan"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical">
<TextView
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="HardcodedText"
style="@style/TextAppearance.TextLarge.Primary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Scan QR code" />
<TextView
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="HardcodedText"
style="@style/TextAppearance.TextMedium.Secondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Scan a QR code from a trusted computer in order to authenticate yourself with this device." />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height= "1dp"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/unlink"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical">
<TextView
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="HardcodedText"
style="@style/TextAppearance.TextLarge.Primary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Unlink all devices" />
<TextView
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="HardcodedText"
style="@style/TextAppearance.TextMedium.Secondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Disconnect all previously linked devices." />
</LinearLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2020 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="HardcodedText"
style="@style/TextAppearance.TextLarge.Primary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Attached via USB. Awaiting command from device." />
</LinearLayout>
...@@ -13,21 +13,16 @@ import android.content.pm.PackageManager; ...@@ -13,21 +13,16 @@ import android.content.pm.PackageManager;
import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager; import android.hardware.usb.UsbManager;
import android.os.Bundle; import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import org.chromium.chrome.R;
import org.chromium.ui.base.ActivityAndroidPermissionDelegate; import org.chromium.ui.base.ActivityAndroidPermissionDelegate;
import org.chromium.ui.base.AndroidPermissionDelegate; import org.chromium.ui.base.AndroidPermissionDelegate;
import org.chromium.ui.widget.ButtonCompat;
import org.chromium.ui.widget.Toast; import org.chromium.ui.widget.Toast;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
...@@ -37,15 +32,15 @@ import java.lang.ref.WeakReference; ...@@ -37,15 +32,15 @@ import java.lang.ref.WeakReference;
*/ */
public class CableAuthenticatorUI extends Fragment public class CableAuthenticatorUI extends Fragment
implements OnClickListener, QRScanDialog.Callback, CableAuthenticator.Callback { implements OnClickListener, QRScanDialog.Callback, CableAuthenticator.Callback {
/** True if this UI was created because the user connected a desktop via USB. */ private enum Mode {
private boolean mCreatedByUsbIntent; QR, // Triggered from Settings; can scan QR code to start handshake.
FCM, // Triggered by user selecting notification; handshake already running.
USB, // Triggered by connecting via USB.
}
private Mode mMode;
private AndroidPermissionDelegate mPermissionDelegate; private AndroidPermissionDelegate mPermissionDelegate;
private CableAuthenticator mAuthenticator; private CableAuthenticator mAuthenticator;
private LinearLayout mQRButton;
private ButtonCompat mQRButton;
private ProgressBar mSpinner;
private TextView mStatus;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
...@@ -55,69 +50,55 @@ public class CableAuthenticatorUI extends Fragment ...@@ -55,69 +50,55 @@ public class CableAuthenticatorUI extends Fragment
Bundle arguments = getArguments(); Bundle arguments = getArguments();
final UsbAccessory accessory = final UsbAccessory accessory =
(UsbAccessory) arguments.getParcelable(UsbManager.EXTRA_ACCESSORY); (UsbAccessory) arguments.getParcelable(UsbManager.EXTRA_ACCESSORY);
mCreatedByUsbIntent = (accessory != null); if (accessory != null) {
mMode = Mode.USB;
} else if (arguments.getBoolean("org.chromium.chrome.modules.cablev2_authenticator.FCM")) {
mMode = Mode.FCM;
} else {
mMode = Mode.QR;
}
final long networkContext = arguments.getLong( final long networkContext = arguments.getLong(
"org.chromium.chrome.modules.cablev2_authenticator.NetworkContext"); "org.chromium.chrome.modules.cablev2_authenticator.NetworkContext");
final long registration = final long registration =
arguments.getLong("org.chromium.chrome.modules.cablev2_authenticator.Registration"); arguments.getLong("org.chromium.chrome.modules.cablev2_authenticator.Registration");
final String activityClassName = arguments.getString( final String activityClassName = arguments.getString(
"org.chromium.chrome.modules.cablev2_authenticator.ActivityClassName"); "org.chromium.chrome.modules.cablev2_authenticator.ActivityClassName");
final boolean isFcmNotification =
arguments.getBoolean("org.chromium.chrome.modules.cablev2_authenticator.FCM");
mPermissionDelegate = new ActivityAndroidPermissionDelegate( mPermissionDelegate = new ActivityAndroidPermissionDelegate(
new WeakReference<Activity>((Activity) context)); new WeakReference<Activity>((Activity) context));
mAuthenticator = new CableAuthenticator(getContext(), this, networkContext, registration, mAuthenticator = new CableAuthenticator(getContext(), this, networkContext, registration,
activityClassName, isFcmNotification, accessory); activityClassName, mMode == Mode.FCM, accessory);
} }
@Override @Override
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
public View onCreateView( public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Shows a placeholder UI that provides a very basic animation and status text informing of
// progress, as well as a button to scan QR codes.
// TODO: should check FEATURE_BLUETOOTH with
// https://developer.android.com/reference/android/content/pm/PackageManager.html#hasSystemFeature(java.lang.String)
// TODO: strings should be translated but this will be replaced during
// the UI process.
getActivity().setTitle("Security Key"); getActivity().setTitle("Security Key");
final Context context = getContext(); switch (mMode) {
case USB:
return inflater.inflate(R.layout.cablev2_usb_attached, container, false);
ProgressBar mSpinner = new ProgressBar(context); case FCM:
mSpinner.setIndeterminate(true); return inflater.inflate(R.layout.cablev2_fcm, container, false);
mSpinner.setPadding(0, 60, 0, 60);
mStatus = new TextView(context); case QR:
mStatus.setPadding(0, 60, 0, 60); // TODO: should check FEATURE_BLUETOOTH with
// https://developer.android.com/reference/android/content/pm/PackageManager.html#hasSystemFeature(java.lang.String)
// TODO: strings should be translated but this will be replaced during
// the UI process.
if (mCreatedByUsbIntent) { View v = inflater.inflate(R.layout.cablev2_qr_scan, container, false);
mStatus.setText("Connected via USB. Awaiting command."); mQRButton = v.findViewById(R.id.qr_scan);
} else { mQRButton.setOnClickListener(this);
mStatus.setText("Looking for known devices nearby");
}
LinearLayout layout = new LinearLayout(context); return v;
layout.setOrientation(LinearLayout.VERTICAL);
layout.setGravity(Gravity.CENTER_HORIZONTAL);
layout.addView(mSpinner);
layout.addView(mStatus,
new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
if (!mCreatedByUsbIntent) {
mQRButton = new ButtonCompat(context, R.style.TextButtonThemeOverlay);
mQRButton.setText("Connect a new device");
mQRButton.setOnClickListener(this);
layout.addView(mQRButton,
new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
} }
return layout; assert false;
return null;
} }
/** /**
...@@ -154,7 +135,6 @@ public class CableAuthenticatorUI extends Fragment ...@@ -154,7 +135,6 @@ public class CableAuthenticatorUI extends Fragment
@Override @Override
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
public void onQRCode(String value) { public void onQRCode(String value) {
mStatus.setText("Looking for your new device nearby");
mAuthenticator.onQRCode(value); mAuthenticator.onQRCode(value);
} }
...@@ -184,12 +164,7 @@ public class CableAuthenticatorUI extends Fragment ...@@ -184,12 +164,7 @@ public class CableAuthenticatorUI extends Fragment
@Override @Override
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
public void onAuthenticatorConnected() { public void onAuthenticatorConnected() {}
getActivity().runOnUiThread(() -> {
mStatus.setText("Connected. Verifying it's you.");
mQRButton.setEnabled(false);
});
}
@Override @Override
public void onAuthenticatorResult(CableAuthenticator.Result result) { public void onAuthenticatorResult(CableAuthenticator.Result result) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment