WIP: Moving from listener to broadcasts for discovered peers.

This commit is contained in:
Peter Serwylo 2015-06-23 23:12:57 +10:00
parent ff93f96959
commit e343918ef9
8 changed files with 48 additions and 69 deletions

View File

@ -1,9 +1,11 @@
package org.fdroid.fdroid.localrepo; package org.fdroid.fdroid.localrepo;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.IBinder; import android.os.IBinder;
@ -13,10 +15,8 @@ import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.FDroid;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.localrepo.peers.Peer; import org.fdroid.fdroid.localrepo.peers.Peer;
import org.fdroid.fdroid.localrepo.peers.PeerFinder;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -59,6 +59,16 @@ public class SwapManager {
this.appsToSwap = appsToSwap; this.appsToSwap = appsToSwap;
this.peers = new ArrayList<>(); this.peers = new ArrayList<>();
context.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Peer peer = (Peer) intent.getSerializableExtra(EXTRA_PEER);
if (!peers.contains(peer)) {
peers.add(peer);
}
}
}, new IntentFilter(ACTION_PEER_FOUND));
setupService(); setupService();
} }
@ -76,12 +86,6 @@ public class SwapManager {
// Search for peers to swap // Search for peers to swap
// ========================================================== // ==========================================================
private PeerFinder.Listener<Peer> peerListener;
public void setPeerListener(PeerFinder.Listener<Peer> listener) {
this.peerListener = listener;
}
public void scanForPeers() { public void scanForPeers() {
if (service != null) { if (service != null) {
Log.d(TAG, "Scanning for nearby devices to swap with..."); Log.d(TAG, "Scanning for nearby devices to swap with...");
@ -99,15 +103,6 @@ public class SwapManager {
} }
} }
public void onPeerFound(Peer peer) {
if (!peers.contains(peer)) {
peers.add(peer);
if (peerListener != null) {
peerListener.onPeerFound(peer);
}
}
}
@NonNull @NonNull
public List<Peer> getPeers() { public List<Peer> getPeers() {
return peers; return peers;
@ -336,4 +331,6 @@ public class SwapManager {
return service != null && service.isScanningForPeers(); return service != null && service.isScanningForPeers();
} }
public static final String ACTION_PEER_FOUND = "org.fdroid.fdroid.SwapManager.ACTION_PEER_FOUND";
public static final String EXTRA_PEER = "EXTRA_PEER";
} }

View File

@ -17,11 +17,7 @@ import android.util.Log;
import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.localrepo.peers.BluetoothFinder; import org.fdroid.fdroid.localrepo.peers.BluetoothFinder;
import org.fdroid.fdroid.localrepo.peers.BluetoothPeer;
import org.fdroid.fdroid.localrepo.peers.BonjourFinder; import org.fdroid.fdroid.localrepo.peers.BonjourFinder;
import org.fdroid.fdroid.localrepo.peers.BonjourPeer;
import org.fdroid.fdroid.localrepo.peers.Peer;
import org.fdroid.fdroid.localrepo.peers.PeerFinder;
import org.fdroid.fdroid.localrepo.type.BonjourType; import org.fdroid.fdroid.localrepo.type.BonjourType;
import org.fdroid.fdroid.localrepo.type.NfcType; import org.fdroid.fdroid.localrepo.type.NfcType;
import org.fdroid.fdroid.localrepo.type.WebServerType; import org.fdroid.fdroid.localrepo.type.WebServerType;
@ -79,22 +75,8 @@ public class SwapService extends Service {
nfcType = new NfcType(this); nfcType = new NfcType(this);
bonjourType = new BonjourType(this); bonjourType = new BonjourType(this);
webServerType = new WebServerType(this); webServerType = new WebServerType(this);
bonjourFinder = new BonjourFinder(this); bonjourFinder = new BonjourFinder(this);
bluetoothFinder = new BluetoothFinder(this); bluetoothFinder = new BluetoothFinder(this);
bonjourFinder.setListener(new PeerFinder.Listener<BonjourPeer>() {
@Override
public void onPeerFound(BonjourPeer peer) {
SwapManager.load(SwapService.this).onPeerFound(peer);
}
});
bluetoothFinder.setListener(new PeerFinder.Listener<BluetoothPeer>() {
@Override
public void onPeerFound(BluetoothPeer peer) {
SwapManager.load(SwapService.this).onPeerFound(peer);
}
});
} }
public void onCreate() { public void onCreate() {

View File

@ -13,11 +13,10 @@ public class BluetoothFinder extends PeerFinder<BluetoothPeer> {
private static final String TAG = "BluetoothFinder"; private static final String TAG = "BluetoothFinder";
private final Context context;
private final BluetoothAdapter adapter; private final BluetoothAdapter adapter;
public BluetoothFinder(Context context) { public BluetoothFinder(Context context) {
this.context = context; super(context);
adapter = BluetoothAdapter.getDefaultAdapter(); adapter = BluetoothAdapter.getDefaultAdapter();
} }

View File

@ -20,13 +20,12 @@ public class BonjourFinder extends PeerFinder<BonjourPeer> implements ServiceLis
public static final String HTTP_SERVICE_TYPE = "_http._tcp.local."; public static final String HTTP_SERVICE_TYPE = "_http._tcp.local.";
public static final String HTTPS_SERVICE_TYPE = "_https._tcp.local."; public static final String HTTPS_SERVICE_TYPE = "_https._tcp.local.";
private final Context context;
private JmDNS mJmdns; private JmDNS mJmdns;
private WifiManager wifiManager; private WifiManager wifiManager;
private WifiManager.MulticastLock mMulticastLock; private WifiManager.MulticastLock mMulticastLock;
public BonjourFinder(Context context) { public BonjourFinder(Context context) {
this.context = context; super(context);
} }
@Override @Override

View File

@ -2,7 +2,9 @@ package org.fdroid.fdroid.localrepo.peers;
import android.support.annotation.DrawableRes; import android.support.annotation.DrawableRes;
public interface Peer { import java.io.Serializable;
public interface Peer extends Serializable {
String getName(); String getName();

View File

@ -1,47 +1,40 @@
package org.fdroid.fdroid.localrepo.peers; package org.fdroid.fdroid.localrepo.peers;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.localrepo.SwapManager;
/** /**
* Searches for other devices in the vicinity, using specific technologies. * Searches for other devices in the vicinity, using specific technologies.
* Once found, alerts a listener through the * Once found, sends an {@link SwapManager#ACTION_PEER_FOUND} intent with the {@link SwapManager#EXTRA_PEER}
* {@link org.fdroid.fdroid.localrepo.peers.PeerFinder.Listener#onPeerFound(Object)} * extra attribute set to the subclass of {@link Peer} that was found.
* method. Note that this could have instead been done with {@link android.content.Context#sendBroadcast(Intent)}
* and {@link android.content.BroadcastReceiver}, but that would require making the {@link Peer}s
* {@link android.os.Parcelable}, which is difficult. The main reason it is difficult is because
* they encapsulate information about network connectivity, such as {@link android.bluetooth.BluetoothDevice}
* and {@link javax.jmdns.ServiceInfo}, which may be difficult to serialize and reconstruct again.
*/ */
public abstract class PeerFinder<T extends Peer> { public abstract class PeerFinder<T extends Peer> {
private static final String TAG = "PeerFinder"; private static final String TAG = "PeerFinder";
private Listener<T> listener;
protected boolean isScanning = false; protected boolean isScanning = false;
protected final Context context;
public abstract void scan(); public abstract void scan();
public abstract void cancel(); public abstract void cancel();
public PeerFinder(Context context) {
this.context = context;
}
public boolean isScanning() { public boolean isScanning() {
return isScanning; return isScanning;
} }
protected void foundPeer(T peer) { protected void foundPeer(T peer) {
Log.i(TAG, "Found peer " + peer.getName()); Log.i(TAG, "Found peer " + peer.getName());
if (listener != null) { Intent intent = new Intent(SwapManager.ACTION_PEER_FOUND);
listener.onPeerFound(peer); intent.putExtra(SwapManager.EXTRA_PEER, peer);
} context.sendBroadcast(intent);
}
public void setListener(Listener<T> listener) {
this.listener = listener;
}
public interface Listener<T> {
void onPeerFound(T peer);
// TODO: What about peers removed, e.g. as with jmdns ServiceListener#serviceRemoved()
} }
} }

View File

@ -2,13 +2,17 @@ package org.fdroid.fdroid.views.swap;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build; import android.os.Build;
import android.support.annotation.ColorRes; import android.support.annotation.ColorRes;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@ -30,6 +34,8 @@ import org.fdroid.fdroid.localrepo.peers.PeerFinder;
public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.InnerView { public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.InnerView {
private static final String TAG = "StartSwapView";
// TODO: Is there a way to guarangee which of these constructors the inflater will call? // TODO: Is there a way to guarangee which of these constructors the inflater will call?
// Especially on different API levels? It would be nice to only have the one which accepts // Especially on different API levels? It would be nice to only have the one which accepts
// a Context, but I'm not sure if that is correct or not. As it stands, this class provides // a Context, but I'm not sure if that is correct or not. As it stands, this class provides
@ -57,7 +63,7 @@ public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.
private class PeopleNearbyAdapter extends ArrayAdapter<Peer> { private class PeopleNearbyAdapter extends ArrayAdapter<Peer> {
public PeopleNearbyAdapter(Context context) { public PeopleNearbyAdapter(Context context) {
super(context, 0, SwapManager.load(context).getPeers()); super(context, 0, new Peer[] {});
} }
@Override @Override
@ -117,13 +123,15 @@ public class StartSwapView extends LinearLayout implements SwapWorkflowActivity.
peopleNearbyList.setAdapter(adapter); peopleNearbyList.setAdapter(adapter);
uiUpdatePeersInfo(); uiUpdatePeersInfo();
SwapManager.load(getActivity()).setPeerListener(new PeerFinder.Listener<Peer>() { getContext().registerReceiver(new BroadcastReceiver() {
@Override @Override
public void onPeerFound(Peer peer) { public void onReceive(Context context, Intent intent) {
adapter.notifyDataSetChanged(); Peer peer = intent.getParcelableExtra(SwapManager.EXTRA_PEER);
Log.d(TAG, "Found peer: " + peer + ", adding to list of peers in UI.");
adapter.add(peer);
uiUpdatePeersInfo(); uiUpdatePeersInfo();
} }
}); }, new IntentFilter(SwapManager.ACTION_PEER_FOUND));
} }

View File

@ -10,8 +10,7 @@ import android.os.Bundle;
import android.support.annotation.ColorRes; import android.support.annotation.ColorRes;
import android.support.annotation.LayoutRes; import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@ -35,7 +34,7 @@ import org.fdroid.fdroid.localrepo.SwapManager;
import java.util.Set; import java.util.Set;
public class SwapWorkflowActivity extends ActionBarActivity { public class SwapWorkflowActivity extends AppCompatActivity {
private ViewGroup container; private ViewGroup container;