diff --git a/F-Droid/res/layout/swap_wifi_qr.xml b/F-Droid/res/layout/swap_wifi_qr.xml
index 44967077a..3e461aeaa 100644
--- a/F-Droid/res/layout/swap_wifi_qr.xml
+++ b/F-Droid/res/layout/swap_wifi_qr.xml
@@ -1,6 +1,6 @@
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java
index 8580e1b2d..f8fc37ace 100644
--- a/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java
+++ b/F-Droid/src/org/fdroid/fdroid/views/swap/SwapWorkflowActivity.java
@@ -1,7 +1,9 @@
package org.fdroid.fdroid.views.swap;
+import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
+import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -15,11 +17,16 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
+import com.google.zxing.integration.android.IntentIntegrator;
+import com.google.zxing.integration.android.IntentResult;
+
+import org.fdroid.fdroid.FDroid;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.NfcHelper;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
+import org.fdroid.fdroid.data.NewRepoConfig;
import org.fdroid.fdroid.localrepo.LocalRepoManager;
import java.util.Set;
@@ -39,6 +46,8 @@ public class SwapWorkflowActivity extends FragmentActivity {
boolean buildMenu(Menu menu, @NonNull MenuInflater inflater);
}
+ private static final int CONNECT_TO_SWAP = 1;
+
private State currentState = State.INTRO;
private InnerView currentView;
private boolean hasPreparedLocalRepo = false;
@@ -115,10 +124,14 @@ public class SwapWorkflowActivity extends FragmentActivity {
public void onJoinWifiComplete() {
ensureLocalRepoRunning();
if (!attemptToShowNfc()) {
- // showWifiQr();
+ showWifiQr();
}
}
+ public void showWifiQr() {
+ inflateInnerView(R.layout.swap_wifi_qr);
+ }
+
private boolean attemptToShowNfc() {
// TODO: What if NFC is disabled? Hook up with NfcNotEnabledActivity? Or maybe only if they
// click a relevant button?
@@ -169,6 +182,23 @@ public class SwapWorkflowActivity extends FragmentActivity {
finish();
}
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
+ if (scanResult != null) {
+ if (scanResult.getContents() != null) {
+ NewRepoConfig repoConfig = new NewRepoConfig(this, scanResult.getContents());
+ if (repoConfig.isValidRepo()) {
+ startActivityForResult(new Intent(FDroid.ACTION_ADD_REPO, Uri.parse(scanResult.getContents()), this, ConnectSwapActivity.class), CONNECT_TO_SWAP);
+ } else {
+ Toast.makeText(this, "The QR code you scanned doesn't look like a swap code.", Toast.LENGTH_SHORT).show();
+ }
+ }
+ } else if (requestCode == CONNECT_TO_SWAP && resultCode == Activity.RESULT_OK) {
+ finish();
+ }
+ }
+
class UpdateAsyncTask extends AsyncTask {
@SuppressWarnings("UnusedDeclaration")
diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/views/NfcView.java b/F-Droid/src/org/fdroid/fdroid/views/swap/views/NfcView.java
index 8faf61da3..63ce23c61 100644
--- a/F-Droid/src/org/fdroid/fdroid/views/swap/views/NfcView.java
+++ b/F-Droid/src/org/fdroid/fdroid/views/swap/views/NfcView.java
@@ -36,6 +36,11 @@ public class NfcView extends RelativeLayout implements SwapWorkflowActivity.Inne
super(context, attrs, defStyleAttr, defStyleRes);
}
+ private SwapWorkflowActivity getActivity() {
+ // TODO: Try and find a better way to get to the SwapActivity, which makes less asumptions.
+ return (SwapWorkflowActivity)getContext();
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -56,7 +61,7 @@ public class NfcView extends RelativeLayout implements SwapWorkflowActivity.Inne
next.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
- // TODO: Show QR Code.
+ getActivity().showWifiQr();
return true;
}
});
diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/views/WifiQrView.java b/F-Droid/src/org/fdroid/fdroid/views/swap/views/WifiQrView.java
new file mode 100644
index 000000000..09b5d66c6
--- /dev/null
+++ b/F-Droid/src/org/fdroid/fdroid/views/swap/views/WifiQrView.java
@@ -0,0 +1,159 @@
+package org.fdroid.fdroid.views.swap.views;
+
+import android.annotation.TargetApi;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.LightingColorFilter;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.v4.content.LocalBroadcastManager;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.google.zxing.integration.android.IntentIntegrator;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.fdroid.fdroid.FDroidApp;
+import org.fdroid.fdroid.Preferences;
+import org.fdroid.fdroid.QrGenAsyncTask;
+import org.fdroid.fdroid.R;
+import org.fdroid.fdroid.Utils;
+import org.fdroid.fdroid.net.WifiStateChangeService;
+import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Locale;
+
+public class WifiQrView extends ScrollView implements SwapWorkflowActivity.InnerView {
+
+ private static final String TAG = "WifiQrView";
+
+ public WifiQrView(Context context) {
+ super(context);
+ }
+
+ public WifiQrView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public WifiQrView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public WifiQrView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ private SwapWorkflowActivity getActivity() {
+ // TODO: Try and find a better way to get to the SwapActivity, which makes less asumptions.
+ return (SwapWorkflowActivity)getContext();
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ setUIFromWifi();
+
+ ImageView qrImage = (ImageView)findViewById(R.id.wifi_qr_code);
+
+ // Replace all blacks with the background blue.
+ qrImage.setColorFilter(new LightingColorFilter(0xffffffff, getResources().getColor(R.color.swap_blue)));
+
+ Button openQr = (Button)findViewById(R.id.btn_qr_scanner);
+ openQr.setOnClickListener(new Button.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ IntentIntegrator integrator = new IntentIntegrator(getActivity());
+ integrator.initiateScan();
+ }
+ });
+
+ Button cancel = (Button)findViewById(R.id.btn_cancel_swap);
+ cancel.setOnClickListener(new Button.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ getActivity().stopSwapping();
+ }
+ });
+
+ LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ setUIFromWifi();
+ }
+ },
+ new IntentFilter(WifiStateChangeService.BROADCAST)
+ );
+ }
+
+ @Override
+ public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
+ return false;
+ }
+
+ private void setUIFromWifi() {
+
+ if (TextUtils.isEmpty(FDroidApp.repo.address))
+ return;
+
+ String scheme = Preferences.get().isLocalRepoHttpsEnabled() ? "https://" : "http://";
+
+ // the fingerprint is not useful on the button label
+ String buttonLabel = scheme + FDroidApp.ipAddressString + ":" + FDroidApp.port;
+ TextView ipAddressView = (TextView) findViewById(R.id.device_ip_address);
+ ipAddressView.setText(buttonLabel);
+
+ /*
+ * Set URL to UPPER for compact QR Code, FDroid will translate it back.
+ * Remove the SSID from the query string since SSIDs are case-sensitive.
+ * Instead the receiver will have to rely on the BSSID to find the right
+ * wifi AP to join. Lots of QR Scanners are buggy and do not respect
+ * custom URI schemes, so we have to use http:// or https:// :-(
+ */
+ Uri sharingUri = Utils.getSharingUri(FDroidApp.repo);
+ String qrUriString = (scheme + sharingUri.getHost()).toUpperCase(Locale.ENGLISH);
+ if (sharingUri.getPort() != 80) {
+ qrUriString += ":" + sharingUri.getPort();
+ }
+ qrUriString += sharingUri.getPath().toUpperCase(Locale.ENGLISH);
+ boolean first = true;
+
+ // Andorid provides an API for getting the query parameters and iterating over them:
+ // Uri.getQueryParameterNames()
+ // But it is only available on later Android versions. As such we use URLEncodedUtils instead.
+ List parameters = URLEncodedUtils.parse(URI.create(sharingUri.toString()), "UTF-8");
+ for (NameValuePair parameter : parameters) {
+ if (!parameter.getName().equals("ssid")) {
+ if (first) {
+ qrUriString += "?";
+ first = false;
+ } else {
+ qrUriString += "&";
+ }
+ qrUriString += parameter.getName().toUpperCase(Locale.ENGLISH) + "=" +
+ parameter.getValue().toUpperCase(Locale.ENGLISH);
+ }
+ }
+
+ Log.i(TAG, "Encoded swap URI in QR Code: " + qrUriString);
+
+ new QrGenAsyncTask(getActivity(), R.id.wifi_qr_code).execute(qrUriString);
+
+ }
+
+}