mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 19:59:05 +01:00
Create a dedicated qrCodeView
This commit is contained in:
@@ -29,7 +29,7 @@ import org.briarproject.briar.android.introduction.IntroductionMessageFragment;
|
|||||||
import org.briarproject.briar.android.keyagreement.ContactExchangeActivity;
|
import org.briarproject.briar.android.keyagreement.ContactExchangeActivity;
|
||||||
import org.briarproject.briar.android.keyagreement.IntroFragment;
|
import org.briarproject.briar.android.keyagreement.IntroFragment;
|
||||||
import org.briarproject.briar.android.keyagreement.KeyAgreementActivity;
|
import org.briarproject.briar.android.keyagreement.KeyAgreementActivity;
|
||||||
import org.briarproject.briar.android.keyagreement.ShowQrCodeFragment;
|
import org.briarproject.briar.android.keyagreement.KeyAgreementFragment;
|
||||||
import org.briarproject.briar.android.login.AuthorNameFragment;
|
import org.briarproject.briar.android.login.AuthorNameFragment;
|
||||||
import org.briarproject.briar.android.login.ChangePasswordActivity;
|
import org.briarproject.briar.android.login.ChangePasswordActivity;
|
||||||
import org.briarproject.briar.android.login.DozeFragment;
|
import org.briarproject.briar.android.login.DozeFragment;
|
||||||
@@ -188,7 +188,7 @@ public interface ActivityComponent {
|
|||||||
|
|
||||||
void inject(IntroFragment fragment);
|
void inject(IntroFragment fragment);
|
||||||
|
|
||||||
void inject(ShowQrCodeFragment fragment);
|
void inject(KeyAgreementFragment fragment);
|
||||||
|
|
||||||
void inject(ContactChooserFragment fragment);
|
void inject(ContactChooserFragment fragment);
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ import android.hardware.Camera.Size;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.view.Display;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
@@ -21,6 +23,7 @@ import java.io.IOException;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import static android.content.Context.WINDOW_SERVICE;
|
||||||
import static android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK;
|
import static android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK;
|
||||||
import static android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT;
|
import static android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT;
|
||||||
import static android.hardware.Camera.Parameters.FLASH_MODE_OFF;
|
import static android.hardware.Camera.Parameters.FLASH_MODE_OFF;
|
||||||
@@ -97,7 +100,7 @@ public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
public void start(int rotationDegrees) throws CameraException {
|
public void start() throws CameraException {
|
||||||
LOG.info("Opening camera");
|
LOG.info("Opening camera");
|
||||||
try {
|
try {
|
||||||
int cameras = Camera.getNumberOfCameras();
|
int cameras = Camera.getNumberOfCameras();
|
||||||
@@ -122,7 +125,7 @@ public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
throw new CameraException(e);
|
throw new CameraException(e);
|
||||||
}
|
}
|
||||||
setDisplayOrientation(rotationDegrees);
|
setDisplayOrientation(getScreenRotationDegrees());
|
||||||
// Use barcode scene mode if it's available
|
// Use barcode scene mode if it's available
|
||||||
Parameters params = camera.getParameters();
|
Parameters params = camera.getParameters();
|
||||||
params = setSceneMode(camera, params);
|
params = setSceneMode(camera, params);
|
||||||
@@ -157,6 +160,27 @@ public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
camera = null;
|
camera = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See {@link Camera#setDisplayOrientation(int)}.
|
||||||
|
*/
|
||||||
|
private int getScreenRotationDegrees() {
|
||||||
|
WindowManager wm =
|
||||||
|
(WindowManager) getContext().getSystemService(WINDOW_SERVICE);
|
||||||
|
Display d = wm.getDefaultDisplay();
|
||||||
|
switch (d.getRotation()) {
|
||||||
|
case Surface.ROTATION_0:
|
||||||
|
return 0;
|
||||||
|
case Surface.ROTATION_90:
|
||||||
|
return 90;
|
||||||
|
case Surface.ROTATION_180:
|
||||||
|
return 180;
|
||||||
|
case Surface.ROTATION_270:
|
||||||
|
return 270;
|
||||||
|
default:
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void startPreview(SurfaceHolder holder) throws CameraException {
|
private void startPreview(SurfaceHolder holder) throws CameraException {
|
||||||
LOG.info("Starting preview");
|
LOG.info("Starting preview");
|
||||||
|
|||||||
@@ -193,8 +193,8 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
|
|||||||
continueClicked = false;
|
continueClicked = false;
|
||||||
// FIXME #824
|
// FIXME #824
|
||||||
FragmentManager fm = getSupportFragmentManager();
|
FragmentManager fm = getSupportFragmentManager();
|
||||||
if (fm.findFragmentByTag(ShowQrCodeFragment.TAG) == null) {
|
if (fm.findFragmentByTag(KeyAgreementFragment.TAG) == null) {
|
||||||
BaseFragment f = ShowQrCodeFragment.newInstance();
|
BaseFragment f = KeyAgreementFragment.newInstance();
|
||||||
fm.beginTransaction()
|
fm.beginTransaction()
|
||||||
.replace(R.id.fragmentContainer, f, f.getUniqueTag())
|
.replace(R.id.fragmentContainer, f, f.getUniqueTag())
|
||||||
.addToBackStack(f.getUniqueTag())
|
.addToBackStack(f.getUniqueTag())
|
||||||
|
|||||||
@@ -2,18 +2,12 @@ package org.briarproject.briar.android.keyagreement;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.hardware.Camera;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.view.Display;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Surface;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.animation.AlphaAnimation;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.LinearLayout.LayoutParams;
|
import android.widget.LinearLayout.LayoutParams;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -41,6 +35,7 @@ import org.briarproject.briar.R;
|
|||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.fragment.BaseEventFragment;
|
import org.briarproject.briar.android.fragment.BaseEventFragment;
|
||||||
import org.briarproject.briar.android.fragment.ErrorFragment;
|
import org.briarproject.briar.android.fragment.ErrorFragment;
|
||||||
|
import org.briarproject.briar.android.view.QrCodeView;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
@@ -63,10 +58,10 @@ import static org.briarproject.bramble.util.LogUtils.logException;
|
|||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public class ShowQrCodeFragment extends BaseEventFragment
|
public class KeyAgreementFragment extends BaseEventFragment
|
||||||
implements QrCodeDecoder.ResultCallback {
|
implements QrCodeDecoder.ResultCallback, QrCodeView.FullscreenListener {
|
||||||
|
|
||||||
static final String TAG = ShowQrCodeFragment.class.getName();
|
static final String TAG = KeyAgreementFragment.class.getName();
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger(TAG);
|
private static final Logger LOG = Logger.getLogger(TAG);
|
||||||
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
||||||
@@ -84,21 +79,18 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
|||||||
EventBus eventBus;
|
EventBus eventBus;
|
||||||
|
|
||||||
private CameraView cameraView;
|
private CameraView cameraView;
|
||||||
|
private LinearLayout cameraOverlay;
|
||||||
private View statusView;
|
private View statusView;
|
||||||
|
private QrCodeView qrCodeView;
|
||||||
private TextView status;
|
private TextView status;
|
||||||
private View qrCodeContainer;
|
|
||||||
private ImageView qrCode;
|
|
||||||
private boolean fullscreen = false;
|
|
||||||
|
|
||||||
private boolean gotRemotePayload;
|
private boolean gotRemotePayload;
|
||||||
private volatile boolean gotLocalPayload;
|
private volatile boolean gotLocalPayload;
|
||||||
private KeyAgreementTask task;
|
private KeyAgreementTask task;
|
||||||
|
|
||||||
public static ShowQrCodeFragment newInstance() {
|
public static KeyAgreementFragment newInstance() {
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
|
KeyAgreementFragment fragment = new KeyAgreementFragment();
|
||||||
ShowQrCodeFragment fragment = new ShowQrCodeFragment();
|
|
||||||
fragment.setArguments(args);
|
fragment.setArguments(args);
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
@@ -118,7 +110,6 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
|||||||
public View onCreateView(LayoutInflater inflater,
|
public View onCreateView(LayoutInflater inflater,
|
||||||
@Nullable ViewGroup container,
|
@Nullable ViewGroup container,
|
||||||
@Nullable Bundle savedInstanceState) {
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
|
||||||
return inflater.inflate(R.layout.fragment_keyagreement_qr, container,
|
return inflater.inflate(R.layout.fragment_keyagreement_qr, container,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
@@ -126,45 +117,17 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
|||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
cameraView = view.findViewById(R.id.camera_view);
|
cameraView = view.findViewById(R.id.camera_view);
|
||||||
|
cameraOverlay = view.findViewById(R.id.camera_overlay);
|
||||||
statusView = view.findViewById(R.id.status_container);
|
statusView = view.findViewById(R.id.status_container);
|
||||||
status = view.findViewById(R.id.connect_status);
|
status = view.findViewById(R.id.connect_status);
|
||||||
qrCodeContainer = view.findViewById(R.id.qr_code_container);
|
qrCodeView = view.findViewById(R.id.qr_code_view);
|
||||||
qrCode = view.findViewById(R.id.qr_code);
|
qrCodeView.setFullscreenListener(this);
|
||||||
ImageView fullscreenButton = view.findViewById(R.id.fullscreen_button);
|
|
||||||
fullscreenButton.setOnClickListener(v -> {
|
|
||||||
LinearLayout cameraOverlay = view.findViewById(R.id.camera_overlay);
|
|
||||||
LayoutParams statusParams, qrCodeParams;
|
|
||||||
if (fullscreen) {
|
|
||||||
// Shrink the QR code container to fill half its parent
|
|
||||||
if (cameraOverlay.getOrientation() == HORIZONTAL) {
|
|
||||||
statusParams = new LayoutParams(0, MATCH_PARENT, 1f);
|
|
||||||
qrCodeParams = new LayoutParams(0, MATCH_PARENT, 1f);
|
|
||||||
} else {
|
|
||||||
statusParams = new LayoutParams(MATCH_PARENT, 0, 1f);
|
|
||||||
qrCodeParams = new LayoutParams(MATCH_PARENT, 0, 1f);
|
|
||||||
}
|
|
||||||
fullscreenButton.setImageResource(
|
|
||||||
R.drawable.ic_fullscreen_black_48dp);
|
|
||||||
} else {
|
|
||||||
// Grow the QR code container to fill its parent
|
|
||||||
statusParams = new LayoutParams(0, 0, 0f);
|
|
||||||
qrCodeParams = new LayoutParams(MATCH_PARENT, MATCH_PARENT, 1f);
|
|
||||||
fullscreenButton.setImageResource(
|
|
||||||
R.drawable.ic_fullscreen_exit_black_48dp);
|
|
||||||
}
|
|
||||||
statusView.setLayoutParams(statusParams);
|
|
||||||
qrCodeContainer.setLayoutParams(qrCodeParams);
|
|
||||||
cameraOverlay.invalidate();
|
|
||||||
fullscreen = !fullscreen;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||||
super.onActivityCreated(savedInstanceState);
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
|
||||||
getActivity().setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR);
|
getActivity().setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR);
|
||||||
cameraView.setPreviewConsumer(new QrCodeDecoder(this));
|
cameraView.setPreviewConsumer(new QrCodeDecoder(this));
|
||||||
}
|
}
|
||||||
@@ -173,30 +136,33 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
|||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
try {
|
try {
|
||||||
cameraView.start(getScreenRotationDegrees());
|
cameraView.start();
|
||||||
} catch (CameraException e) {
|
} catch (CameraException e) {
|
||||||
logCameraExceptionAndFinish(e);
|
logCameraExceptionAndFinish(e);
|
||||||
}
|
}
|
||||||
startListening();
|
startListening();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* See {@link Camera#setDisplayOrientation(int)}.
|
public void toggleFullscreen(boolean fullscreen) {
|
||||||
*/
|
LinearLayout.LayoutParams statusParams, qrCodeParams;
|
||||||
private int getScreenRotationDegrees() {
|
if (fullscreen) {
|
||||||
Display d = getActivity().getWindowManager().getDefaultDisplay();
|
// Grow the QR code view to fill its parent
|
||||||
switch (d.getRotation()) {
|
statusParams = new LayoutParams(0, 0, 0f);
|
||||||
case Surface.ROTATION_0:
|
qrCodeParams = new LayoutParams(MATCH_PARENT, MATCH_PARENT, 1f);
|
||||||
return 0;
|
} else {
|
||||||
case Surface.ROTATION_90:
|
// Shrink the QR code view to fill half its parent
|
||||||
return 90;
|
if (cameraOverlay.getOrientation() == HORIZONTAL) {
|
||||||
case Surface.ROTATION_180:
|
statusParams = new LayoutParams(0, MATCH_PARENT, 1f);
|
||||||
return 180;
|
qrCodeParams = new LayoutParams(0, MATCH_PARENT, 1f);
|
||||||
case Surface.ROTATION_270:
|
} else {
|
||||||
return 270;
|
statusParams = new LayoutParams(MATCH_PARENT, 0, 1f);
|
||||||
default:
|
qrCodeParams = new LayoutParams(MATCH_PARENT, 0, 1f);
|
||||||
throw new AssertionError();
|
}
|
||||||
}
|
}
|
||||||
|
statusView.setLayoutParams(statusParams);
|
||||||
|
qrCodeView.setLayoutParams(qrCodeParams);
|
||||||
|
cameraOverlay.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -242,7 +208,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
|||||||
// If we've stopped the camera view, restart it
|
// If we've stopped the camera view, restart it
|
||||||
if (gotRemotePayload) {
|
if (gotRemotePayload) {
|
||||||
try {
|
try {
|
||||||
cameraView.start(getScreenRotationDegrees());
|
cameraView.start();
|
||||||
} catch (CameraException e) {
|
} catch (CameraException e) {
|
||||||
logCameraExceptionAndFinish(e);
|
logCameraExceptionAndFinish(e);
|
||||||
return;
|
return;
|
||||||
@@ -299,51 +265,10 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
|||||||
KeyAgreementAbortedEvent event = (KeyAgreementAbortedEvent) e;
|
KeyAgreementAbortedEvent event = (KeyAgreementAbortedEvent) e;
|
||||||
keyAgreementAborted(event.didRemoteAbort());
|
keyAgreementAborted(event.didRemoteAbort());
|
||||||
} else if (e instanceof KeyAgreementFinishedEvent) {
|
} else if (e instanceof KeyAgreementFinishedEvent) {
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
keyAgreementFinished();
|
||||||
statusView.setVisibility(VISIBLE);
|
|
||||||
status.setText(R.string.exchanging_contact_details);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
|
||||||
private void generateBitmapQR(Payload payload) {
|
|
||||||
// Get narrowest screen dimension
|
|
||||||
Context context = getContext();
|
|
||||||
if (context == null) return;
|
|
||||||
DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
|
||||||
new AsyncTask<Void, Void, Bitmap>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
protected Bitmap doInBackground(Void... params) {
|
|
||||||
byte[] payloadBytes = payloadEncoder.encode(payload);
|
|
||||||
if (LOG.isLoggable(INFO)) {
|
|
||||||
LOG.info("Local payload is " + payloadBytes.length
|
|
||||||
+ " bytes");
|
|
||||||
}
|
|
||||||
// Use ISO 8859-1 to encode bytes directly as a string
|
|
||||||
String content = new String(payloadBytes, ISO_8859_1);
|
|
||||||
return QrCodeUtils.createQrCode(dm, content);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(@Nullable Bitmap bitmap) {
|
|
||||||
if (bitmap != null && !isDetached()) {
|
|
||||||
qrCode.setImageBitmap(bitmap);
|
|
||||||
// Simple fade-in animation
|
|
||||||
AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
|
|
||||||
anim.setDuration(200);
|
|
||||||
qrCode.startAnimation(anim);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setQrCode(Payload localPayload) {
|
|
||||||
runOnUiThreadUnlessDestroyed(() -> generateBitmapQR(localPayload));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void keyAgreementFailed() {
|
private void keyAgreementFailed() {
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
runOnUiThreadUnlessDestroyed(() -> {
|
||||||
reset();
|
reset();
|
||||||
@@ -353,25 +278,25 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void keyAgreementWaiting() {
|
|
||||||
runOnUiThreadUnlessDestroyed(
|
|
||||||
() -> status.setText(R.string.waiting_for_contact_to_scan));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void keyAgreementStarted() {
|
private void keyAgreementStarted() {
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
runOnUiThreadUnlessDestroyed(() -> {
|
||||||
qrCodeContainer.setVisibility(INVISIBLE);
|
qrCodeView.setVisibility(INVISIBLE);
|
||||||
statusView.setVisibility(VISIBLE);
|
statusView.setVisibility(VISIBLE);
|
||||||
status.setText(R.string.authenticating_with_device);
|
status.setText(R.string.authenticating_with_device);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void keyAgreementWaiting() {
|
||||||
|
runOnUiThreadUnlessDestroyed(
|
||||||
|
() -> status.setText(R.string.waiting_for_contact_to_scan));
|
||||||
|
}
|
||||||
|
|
||||||
private void keyAgreementAborted(boolean remoteAborted) {
|
private void keyAgreementAborted(boolean remoteAborted) {
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
runOnUiThreadUnlessDestroyed(() -> {
|
||||||
reset();
|
reset();
|
||||||
qrCodeContainer.setVisibility(VISIBLE);
|
qrCodeView.setVisibility(VISIBLE);
|
||||||
statusView.setVisibility(INVISIBLE);
|
statusView.setVisibility(INVISIBLE);
|
||||||
status.setText(null);
|
status.setText("");
|
||||||
// TODO show abort somewhere persistent?
|
// TODO show abort somewhere persistent?
|
||||||
Toast.makeText(getActivity(),
|
Toast.makeText(getActivity(),
|
||||||
remoteAborted ? R.string.connection_aborted_remote :
|
remoteAborted ? R.string.connection_aborted_remote :
|
||||||
@@ -380,6 +305,30 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void keyAgreementFinished() {
|
||||||
|
runOnUiThreadUnlessDestroyed(() -> {
|
||||||
|
statusView.setVisibility(VISIBLE);
|
||||||
|
status.setText(R.string.exchanging_contact_details);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setQrCode(Payload localPayload) {
|
||||||
|
Context context = getContext();
|
||||||
|
if (context == null) return;
|
||||||
|
DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
||||||
|
ioExecutor.execute(() -> {
|
||||||
|
byte[] payloadBytes = payloadEncoder.encode(localPayload);
|
||||||
|
if (LOG.isLoggable(INFO)) {
|
||||||
|
LOG.info("Local payload is " + payloadBytes.length
|
||||||
|
+ " bytes");
|
||||||
|
}
|
||||||
|
// Use ISO 8859-1 to encode bytes directly as a string
|
||||||
|
String content = new String(payloadBytes, ISO_8859_1);
|
||||||
|
Bitmap qrCode = QrCodeUtils.createQrCode(dm, content);
|
||||||
|
runOnUiThreadUnlessDestroyed(() -> qrCodeView.setQrCode(qrCode));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleResult(Result result) {
|
public void handleResult(Result result) {
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
runOnUiThreadUnlessDestroyed(() -> {
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package org.briarproject.briar.android.view;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.annotation.UiThread;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.animation.AlphaAnimation;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
|
public class QrCodeView extends FrameLayout {
|
||||||
|
|
||||||
|
private final ImageView qrCodeImageView;
|
||||||
|
private boolean fullscreen = false;
|
||||||
|
private FullscreenListener listener;
|
||||||
|
|
||||||
|
public QrCodeView(@NonNull Context context,
|
||||||
|
@Nullable AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
LayoutInflater inflater = (LayoutInflater) context
|
||||||
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
inflater.inflate(R.layout.qr_code_view, this, true);
|
||||||
|
qrCodeImageView = findViewById(R.id.qr_code);
|
||||||
|
ImageView fullscreenButton = findViewById(R.id.fullscreen_button);
|
||||||
|
fullscreenButton.setOnClickListener(v -> {
|
||||||
|
fullscreen = !fullscreen;
|
||||||
|
if (!fullscreen)
|
||||||
|
fullscreenButton.setImageResource(
|
||||||
|
R.drawable.ic_fullscreen_black_48dp);
|
||||||
|
else
|
||||||
|
fullscreenButton.setImageResource(
|
||||||
|
R.drawable.ic_fullscreen_exit_black_48dp);
|
||||||
|
if (listener != null)
|
||||||
|
listener.toggleFullscreen(fullscreen);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQrCode(Bitmap qrCode) {
|
||||||
|
qrCodeImageView.setImageBitmap(qrCode);
|
||||||
|
// Simple fade-in animation
|
||||||
|
AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
|
||||||
|
anim.setDuration(200);
|
||||||
|
qrCodeImageView.startAnimation(anim);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
public void setFullscreenListener(FullscreenListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface FullscreenListener {
|
||||||
|
void toggleFullscreen(boolean isFullscreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<org.briarproject.briar.android.keyagreement.CameraView
|
|
||||||
android:id="@+id/camera_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/camera_overlay"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:baselineAligned="false">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/status_container"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="@android:color/background_light"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="@dimen/margin_medium"
|
|
||||||
android:visibility="invisible">
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
style="?android:attr/progressBarStyleLarge"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/connect_status"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:paddingTop="@dimen/margin_large"
|
|
||||||
tools:text="Connection failed"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/qr_code_container"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="@android:color/white">
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
style="?android:attr/progressBarStyleLarge"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"/>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/qr_code"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:contentDescription="@string/qr_code"
|
|
||||||
android:scaleType="fitCenter"/>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/fullscreen_button"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
android:src="@drawable/ic_fullscreen_black_48dp"
|
|
||||||
android:alpha="0.54"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="@dimen/margin_small"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:contentDescription="@string/show_qr_code_fullscreen"/>
|
|
||||||
</RelativeLayout>
|
|
||||||
</FrameLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/container_progress"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@android:color/white"
|
|
||||||
android:visibility="invisible">
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/progress_bar"
|
|
||||||
style="?android:attr/progressBarStyleLarge"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_above="@+id/title_progress_bar"
|
|
||||||
android:layout_centerHorizontal="true"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/title_progress_bar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:gravity="center"
|
|
||||||
android:paddingTop="@dimen/margin_large"
|
|
||||||
tools:text="@string/waiting_for_contact_to_scan"/>
|
|
||||||
</RelativeLayout>
|
|
||||||
</FrameLayout>
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
@@ -43,45 +42,11 @@
|
|||||||
tools:text="Connection failed"/>
|
tools:text="Connection failed"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<org.briarproject.briar.android.view.QrCodeView
|
||||||
android:id="@+id/qr_code_container"
|
android:id="@+id/qr_code_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="@android:color/white">
|
android:background="@android:color/white"/>
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
style="?android:attr/progressBarStyleLarge"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"/>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/qr_code"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:contentDescription="@string/qr_code"
|
|
||||||
android:scaleType="fitCenter"
|
|
||||||
tools:src="@drawable/startup_lock"/>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/fullscreen_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_margin="@dimen/margin_small"
|
|
||||||
android:alpha="0.54"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
android:contentDescription="@string/show_qr_code_fullscreen"
|
|
||||||
android:src="@drawable/ic_fullscreen_black_48dp"/>
|
|
||||||
</RelativeLayout>
|
|
||||||
</FrameLayout>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|||||||
43
briar-android/src/main/res/layout/qr_code_view.xml
Normal file
43
briar-android/src/main/res/layout/qr_code_view.xml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<merge
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:showIn="@layout/list_item_forum">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
style="?android:attr/progressBarStyleLarge"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
|
<android.support.constraint.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/qr_code"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:contentDescription="@string/qr_code"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:src="@drawable/startup_lock"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/fullscreen_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/margin_small"
|
||||||
|
android:alpha="0.54"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:contentDescription="@string/show_qr_code_fullscreen"
|
||||||
|
android:src="@drawable/ic_fullscreen_black_48dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"/>
|
||||||
|
</android.support.constraint.ConstraintLayout>
|
||||||
|
</merge>
|
||||||
Reference in New Issue
Block a user