Ability to cancel swap. Made QR code larger.

Added a "Cancel" button to the swap QR code screen.
Also changed how the LocalRepoService deals with onDestroy(). Previously, it
would invoke `stopNetworkServices()` on the UI thread, blocking for a
significant portion of time (enough to cause ANR messages on my devices).
Now, it does this on a new thread.

As for the QR code size, it was getting quite small on my nexus 4,
which I think has a large screen (even though there is much larger about).
As a result, it couldn't be scanned properly using barcode scanner.
This is the first major diversion from carries mockups, in that the qr
view is now in a scroller, which means the "Open QR Code Scanner" button
may well not be visible on the main screen on small devices. Not sure about
how to manage this tradeoff between biggish qr code but everything
viewable on one screen.
This commit is contained in:
Peter Serwylo 2014-09-04 19:02:57 +09:30
parent de74d6457d
commit 92f71ca13a
9 changed files with 139 additions and 74 deletions

View File

@ -1,50 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<ScrollView
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:layout_gravity="center_horizontal"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:text="One person needs to scan the code, or type the URL of the other swapper into a browser."
style="@style/SwapTheme.Wizard.MainText"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/wifi_qr_code"
tools:src="@drawable/swap_qr_example"
android:layout_below="@+id/textView"
android:layout_above="@+id/device_ip_address"/>
<LinearLayout android:orientation="vertical"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!--
<Button style="@style/SwapTheme.Wizard.OptionButton"
android:id="@+id/btn_not_working"
android:text="@string/swap_wifi_qr_not_working"
android:layout_alignParentBottom="true" />
-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:text="One person needs to scan the code, or type the URL of the other swapper into a browser."
style="@style/SwapTheme.Wizard.MainText"/>
<Button style="@style/SwapTheme.Wizard.OptionButton"
android:text="@string/open_qr_code_scanner"
android:layout_gravity="center"
android:layout_alignParentBottom="true"
android:id="@+id/btn_qr_scanner"/>
<!-- android:layout_above="@id/btn_not_working" -->
<ImageView
android:layout_width="250dp"
android:layout_height="250dp"
android:maxHeight="20dp"
android:id="@+id/wifi_qr_code"
tools:src="@drawable/swap_qr_example"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/device_ip_address"
tools:text="192.168.1.1:8888"
android:layout_above="@+id/btn_qr_scanner"
android:layout_centerHorizontal="true"
style="@style/SwapTheme.Wizard.LocalIpAddress"/>
<!--
<Button style="@style/SwapTheme.Wizard.OptionButton"
android:id="@+id/btn_not_working"
android:text="@string/swap_wifi_qr_not_working"
android:layout_alignParentBottom="true" />
-->
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/device_ip_address"
tools:text="http://255.255.255.255:8888"
style="@style/SwapTheme.Wizard.LocalIpAddress"/>
<Button style="@style/SwapTheme.Wizard.OptionButton"
android:text="@string/open_qr_code_scanner"
android:layout_gravity="center"
android:id="@+id/btn_qr_scanner"/>
<Button style="@style/SwapTheme.Wizard.OptionButton"
android:id="@+id/btn_cancel_swap"
android:text="@string/cancel" />
</LinearLayout>
</ScrollView>

View File

@ -113,7 +113,7 @@
</style>
<style name="SwapTheme.Wizard.LocalIpAddress" parent="@style/SwapTheme.Wizard.Text">
<item name="android:textSize">32.5sp</item> <!-- 58px * 96dpi / 160dpi -->
<item name="android:textSize">26.5sp</item> <!-- 58px * 96dpi / 160dpi = 32.5sp (ended up making a bit smaller, because longer addresses didn't fit well) -->
<item name="android:paddingLeft">40dp</item>
<item name="android:paddingRight">40dp</item>
<item name="android:paddingTop">22.5dp</item> <!-- 40px * 96dpi / 160dpi -->

View File

@ -41,13 +41,11 @@ import android.os.Messenger;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.widget.Toast;
import com.nostra13.universalimageloader.cache.disc.impl.LimitedAgeDiscCache;
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.utils.StorageUtils;
import org.fdroid.fdroid.Preferences.ChangeListener;
import org.fdroid.fdroid.compat.PRNGFixes;
import org.fdroid.fdroid.data.AppProvider;
@ -57,6 +55,9 @@ import org.fdroid.fdroid.localrepo.LocalRepoService;
import org.fdroid.fdroid.net.IconDownloader;
import org.fdroid.fdroid.net.WifiStateChangeService;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import java.io.File;
import java.util.Set;
@ -73,6 +74,8 @@ public class FDroidApp extends Application {
private static Messenger localRepoServiceMessenger = null;
private static boolean localRepoServiceIsBound = false;
private static final String TAG = "org.fdroid.fdroid.FDroidApp";
BluetoothAdapter bluetoothAdapter = null;
public static enum Theme {
@ -266,8 +269,7 @@ public class FDroidApp extends Application {
if (!localRepoServiceIsBound) {
Context app = context.getApplicationContext();
Intent service = new Intent(app, LocalRepoService.class);
localRepoServiceIsBound = app.bindService(service, serviceConnection,
Context.BIND_AUTO_CREATE);
localRepoServiceIsBound = app.bindService(service, serviceConnection, Context.BIND_AUTO_CREATE);
if (localRepoServiceIsBound)
app.startService(service);
}
@ -285,8 +287,7 @@ public class FDroidApp extends Application {
public static void restartLocalRepoService() {
if (localRepoServiceMessenger != null) {
try {
Message msg = Message.obtain(null,
LocalRepoService.RESTART, LocalRepoService.RESTART, 0);
Message msg = Message.obtain(null, LocalRepoService.RESTART, LocalRepoService.RESTART, 0);
localRepoServiceMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
@ -294,7 +295,7 @@ public class FDroidApp extends Application {
}
}
public static boolean isLocalRepoServiceRunnig() {
public static boolean isLocalRepoServiceRunning() {
return localRepoServiceIsBound;
}
}

View File

@ -70,6 +70,11 @@ public class QrGenAsyncTask extends AsyncTask<String, Void, Void> {
@Override
protected void onPostExecute(Void v) {
ImageView qrCodeImageView = (ImageView) activity.findViewById(viewId);
qrCodeImageView.setImageBitmap(qrBitmap);
// If the generation takes too long for whatever reason, then this view, and indeed the entire
// activity may not be around any more.
if (qrCodeImageView != null) {
qrCodeImageView.setImageBitmap(qrBitmap);
}
}
}

View File

@ -58,25 +58,35 @@ public class LocalRepoService extends Service {
final Messenger messenger = new Messenger(new StartStopHandler(this));
/**
* This is most likely going to be created on the UI thread, hence all of
* the message handling will take place on a new thread to prevent blocking
* the UI.
*/
static class StartStopHandler extends Handler {
private static LocalRepoService service;
private final LocalRepoService service;
public StartStopHandler(LocalRepoService service) {
StartStopHandler.service = service;
this.service = service;
}
@Override
public void handleMessage(Message msg) {
if (msg.arg1 == START) {
service.startNetworkServices();
} else if (msg.arg1 == STOP) {
service.stopNetworkServices();
} else if (msg.arg1 == RESTART) {
service.stopNetworkServices();
service.startNetworkServices();
} else {
Log.e(TAG, "unsupported msg.arg1, ignored");
}
public void handleMessage(final Message msg) {
new Thread() {
public void run() {
if (msg.arg1 == START) {
service.startNetworkServices();
} else if (msg.arg1 == STOP) {
service.stopNetworkServices();
} else if (msg.arg1 == RESTART) {
service.stopNetworkServices();
service.startNetworkServices();
} else {
Log.e(TAG, "Unsupported msg.arg1 (" + msg.arg1 + "), ignored");
}
}
}.start();
}
}
@ -116,14 +126,12 @@ public class LocalRepoService extends Service {
}
};
@Override
public void onCreate() {
private void showNotification() {
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// launch LocalRepoActivity if the user selects this notification
Intent intent = new Intent(this, SwapActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
notification = new NotificationCompat.Builder(this)
.setContentTitle(getText(R.string.local_repo_running))
.setContentText(getText(R.string.touch_to_configure_local_repo))
@ -131,6 +139,11 @@ public class LocalRepoService extends Service {
.setContentIntent(contentIntent)
.build();
startForeground(NOTIFICATION, notification);
}
@Override
public void onCreate() {
showNotification();
startNetworkServices();
Preferences.get().registerLocalRepoBonjourListeners(localRepoBonjourChangeListener);
@ -147,7 +160,12 @@ public class LocalRepoService extends Service {
@Override
public void onDestroy() {
stopNetworkServices();
new Thread() {
public void run() {
stopNetworkServices();
}
}.start();
notificationManager.cancel(NOTIFICATION);
LocalBroadcastManager.getInstance(this).unregisterReceiver(onWifiChange);
Preferences.get().unregisterLocalRepoBonjourListeners(localRepoBonjourChangeListener);
@ -159,6 +177,7 @@ public class LocalRepoService extends Service {
}
private void startNetworkServices() {
Log.d(TAG, "Starting local repo network services");
startWebServer();
if (Preferences.get().isLocalRepoBonjourEnabled())
registerMDNSService();
@ -166,8 +185,13 @@ public class LocalRepoService extends Service {
}
private void stopNetworkServices() {
Log.d(TAG, "Stopping local repo network services");
Preferences.get().unregisterLocalRepoHttpsListeners(localRepoHttpsChangeListener);
Log.d(TAG, "Unregistering MDNS service...");
unregisterMDNSService();
Log.d(TAG, "Stopping web server...");
stopWebServer();
}

View File

@ -74,7 +74,7 @@ public class LocalRepoActivity extends ActionBarActivity {
public void onResume() {
super.onResume();
resetNetworkInfo();
setRepoSwitchChecked(FDroidApp.isLocalRepoServiceRunnig());
setRepoSwitchChecked(FDroidApp.isLocalRepoServiceRunning());
LocalBroadcastManager.getInstance(this).registerReceiver(onWifiChange,
new IntentFilter(WifiStateChangeService.BROADCAST));

View File

@ -121,7 +121,7 @@ public class SwapActivity extends ActionBarActivity implements SwapProcessManage
if (savedInstanceState == null) {
if (FDroidApp.isLocalRepoServiceRunnig()) {
if (FDroidApp.isLocalRepoServiceRunning()) {
onWifiQr();
} else {
@ -218,9 +218,13 @@ public class SwapActivity extends ActionBarActivity implements SwapProcessManage
}
private void startLocalRepo() {
if (!FDroidApp.isLocalRepoServiceRunnig()) {
if (!FDroidApp.isLocalRepoServiceRunning()) {
FDroidApp.startLocalRepoService(this);
initLocalRepoTimer(900000); // 15 mins
}
}
private void initLocalRepoTimer(long timeoutMilliseconds) {
// reset the timer if viewing this Activity again
if (shutdownLocalRepoTimer != null)
@ -233,7 +237,19 @@ public class SwapActivity extends ActionBarActivity implements SwapProcessManage
public void run() {
FDroidApp.stopLocalRepoService(SwapActivity.this);
}
}, 900000); // 15 minutes
}, timeoutMilliseconds);
}
@Override
public void stopSwapping() {
if (FDroidApp.isLocalRepoServiceRunning()) {
if (shutdownLocalRepoTimer != null) {
shutdownLocalRepoTimer.cancel();
}
FDroidApp.stopLocalRepoService(SwapActivity.this);
}
finish();
}
class UpdateAsyncTask extends AsyncTask<Void, String, Void> {

View File

@ -2,4 +2,5 @@ package org.fdroid.fdroid.views.swap;
public interface SwapProcessManager {
public void nextStep();
public void stopSwapping();
}

View File

@ -45,6 +45,8 @@ public class WifiQrFragment extends Fragment {
}
};
private SwapProcessManager swapManager;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.swap_wifi_qr, container, false);
@ -62,9 +64,22 @@ public class WifiQrFragment extends Fragment {
}
});
Button cancel = (Button)view.findViewById(R.id.btn_cancel_swap);
cancel.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
swapManager.stopSwapping();
}
});
return view;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
swapManager = (SwapProcessManager)activity;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);