From 38eafdeeddf75710a287cc40840a50488c0c06ff Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Sat, 23 May 2015 01:11:16 +1000 Subject: [PATCH] WIP: Refactored wifi QR fragment into view. As per the select apps list, there is quite a bit of business logic in this class, which is now spread between the activity and the view. The activity needs to handle some stuff, because the zxing library routes intents to either an activity or a fragment. --- F-Droid/res/layout/swap_wifi_qr.xml | 4 +- .../views/swap/SwapWorkflowActivity.java | 32 +++- .../fdroid/views/swap/views/NfcView.java | 7 +- .../fdroid/views/swap/views/WifiQrView.java | 159 ++++++++++++++++++ 4 files changed, 198 insertions(+), 4 deletions(-) create mode 100644 F-Droid/src/org/fdroid/fdroid/views/swap/views/WifiQrView.java 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); + + } + +}