WIP: Refactoring Bonjour from manage repos to swap.
Implementing the bare bones of a generic "peer finder" framework. This may or may not eventuate to something which can live in its own library and be used by other projects. Might go hand in hand with Carries idea of having a common UI to be shared among projects.
This commit is contained in:
parent
593aaf3894
commit
a30ec646b2
@ -12,9 +12,5 @@
|
|||||||
android:icon="@drawable/ic_add_white"
|
android:icon="@drawable/ic_add_white"
|
||||||
android:title="@string/menu_add_repo"
|
android:title="@string/menu_add_repo"
|
||||||
app:showAsAction="always|withText"/>
|
app:showAsAction="always|withText"/>
|
||||||
<item
|
|
||||||
android:id="@+id/action_find_local_repos"
|
|
||||||
android:title="@string/menu_scan_repo"
|
|
||||||
app:showAsAction="ifRoom|withText"/>
|
|
||||||
|
|
||||||
</menu>
|
</menu>
|
@ -113,7 +113,6 @@
|
|||||||
<string name="menu_search">Search</string>
|
<string name="menu_search">Search</string>
|
||||||
<string name="menu_add_repo">New Repository</string>
|
<string name="menu_add_repo">New Repository</string>
|
||||||
<string name="menu_rem_repo">Remove Repository</string>
|
<string name="menu_rem_repo">Remove Repository</string>
|
||||||
<string name="menu_scan_repo">Find Local Repos</string>
|
|
||||||
|
|
||||||
<string name="menu_launch">Run</string>
|
<string name="menu_launch">Run</string>
|
||||||
<string name="menu_share">Share</string>
|
<string name="menu_share">Share</string>
|
||||||
|
@ -12,8 +12,13 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -43,9 +48,13 @@ public class SwapManager {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private Set<String> appsToSwap;
|
private Set<String> appsToSwap;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private Collection<Peer> peers;
|
||||||
|
|
||||||
private SwapManager(@NonNull Context context, @NonNull Set<String> appsToSwap) {
|
private SwapManager(@NonNull Context context, @NonNull Set<String> appsToSwap) {
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
this.appsToSwap = appsToSwap;
|
this.appsToSwap = appsToSwap;
|
||||||
|
this.peers = new ArrayList<>();
|
||||||
|
|
||||||
setupService();
|
setupService();
|
||||||
}
|
}
|
||||||
@ -60,6 +69,32 @@ public class SwapManager {
|
|||||||
return context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_APPEND);
|
return context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_APPEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==========================================================
|
||||||
|
// Search for peers to swap
|
||||||
|
// ==========================================================
|
||||||
|
|
||||||
|
public void scanForPeers() {
|
||||||
|
if (service != null) {
|
||||||
|
Log.d(TAG, "Scanning for nearby devices to swap with...");
|
||||||
|
service.scanForPeers();
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Couldn't scan for peers, because service was not running.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelScanningForPeers() {
|
||||||
|
if (service != null) {
|
||||||
|
service.cancelScanningForPeers();
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Couldn't cancel scanning for peers, because service was not running.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPeerFound(Peer peer) {
|
||||||
|
peers.add(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ==========================================================
|
// ==========================================================
|
||||||
// Manage the current step
|
// Manage the current step
|
||||||
// ("Step" refers to the current view being shown in the UI)
|
// ("Step" refers to the current view being shown in the UI)
|
||||||
|
@ -16,6 +16,12 @@ 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.BluetoothPeer;
|
||||||
|
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;
|
||||||
@ -42,6 +48,10 @@ public class SwapService extends Service {
|
|||||||
private final BonjourType bonjourType;
|
private final BonjourType bonjourType;
|
||||||
private final WebServerType webServerType;
|
private final WebServerType webServerType;
|
||||||
|
|
||||||
|
private final BonjourFinder bonjourFinder;
|
||||||
|
private final BluetoothFinder bluetoothFinder;
|
||||||
|
|
||||||
|
|
||||||
// TODO: The NFC type can't really be managed by the service, because it is intrinsically tied
|
// TODO: The NFC type can't really be managed by the service, because it is intrinsically tied
|
||||||
// to a specific _Activity_, and will only be active while that activity is shown. This service
|
// to a specific _Activity_, and will only be active while that activity is shown. This service
|
||||||
// knows nothing about activities.
|
// knows nothing about activities.
|
||||||
@ -65,6 +75,22 @@ 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);
|
||||||
|
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() {
|
||||||
@ -104,6 +130,20 @@ public class SwapService extends Service {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void scanForPeers() {
|
||||||
|
bonjourFinder.scan();
|
||||||
|
bluetoothFinder.scan();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelScanningForPeers() {
|
||||||
|
bonjourFinder.cancel();
|
||||||
|
bluetoothFinder.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPeerFound(Peer peer) {
|
||||||
|
SwapManager.load(this).onPeerFound(peer);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean enabled = false;
|
private boolean enabled = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package org.fdroid.fdroid.localrepo.peers;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
// TODO: Still to be implemented
|
||||||
|
public class BluetoothFinder extends PeerFinder<BluetoothPeer> {
|
||||||
|
|
||||||
|
private static final String TAG = "BluetoothFinder";
|
||||||
|
|
||||||
|
public BluetoothFinder(Context context) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scan() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package org.fdroid.fdroid.localrepo.peers;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
|
||||||
|
// TODO: Still to be implemented.
|
||||||
|
public class BluetoothPeer implements Peer {
|
||||||
|
|
||||||
|
private BluetoothDevice device;
|
||||||
|
|
||||||
|
public BluetoothPeer(BluetoothDevice device) {
|
||||||
|
this.device = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Bluetooth: " + device.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIcon() {
|
||||||
|
return android.R.drawable.stat_sys_data_bluetooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
114
F-Droid/src/org/fdroid/fdroid/localrepo/peers/BonjourFinder.java
Normal file
114
F-Droid/src/org/fdroid/fdroid/localrepo/peers/BonjourFinder.java
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package org.fdroid.fdroid.localrepo.peers;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
|
import javax.jmdns.JmDNS;
|
||||||
|
import javax.jmdns.ServiceEvent;
|
||||||
|
import javax.jmdns.ServiceInfo;
|
||||||
|
import javax.jmdns.ServiceListener;
|
||||||
|
|
||||||
|
public class BonjourFinder extends PeerFinder<BonjourPeer> implements ServiceListener {
|
||||||
|
|
||||||
|
private static final String TAG = "BonjourFinder";
|
||||||
|
|
||||||
|
public static final String HTTP_SERVICE_TYPE = "_http._tcp.local.";
|
||||||
|
public static final String HTTPS_SERVICE_TYPE = "_https._tcp.local.";
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
private JmDNS mJmdns;
|
||||||
|
private WifiManager wifiManager;
|
||||||
|
private WifiManager.MulticastLock mMulticastLock;
|
||||||
|
|
||||||
|
public BonjourFinder(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scan() {
|
||||||
|
|
||||||
|
if (wifiManager == null) {
|
||||||
|
wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
mMulticastLock = wifiManager.createMulticastLock(context.getPackageName());
|
||||||
|
mMulticastLock.setReferenceCounted(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
mMulticastLock.acquire();
|
||||||
|
new AsyncTask<Void, Void, Void>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... params) {
|
||||||
|
try {
|
||||||
|
int ip = wifiManager.getConnectionInfo().getIpAddress();
|
||||||
|
byte[] byteIp = {
|
||||||
|
(byte) (ip & 0xff),
|
||||||
|
(byte) (ip >> 8 & 0xff),
|
||||||
|
(byte) (ip >> 16 & 0xff),
|
||||||
|
(byte) (ip >> 24 & 0xff)
|
||||||
|
};
|
||||||
|
Log.d(TAG, "Searching for mDNS clients...");
|
||||||
|
mJmdns = JmDNS.create(InetAddress.getByAddress(byteIp));
|
||||||
|
Log.d(TAG, "Finished searching for mDNS clients.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void result) {
|
||||||
|
Log.d(TAG, "Cleaning up mDNS service listeners.");
|
||||||
|
if (mJmdns != null) {
|
||||||
|
mJmdns.addServiceListener(HTTP_SERVICE_TYPE, BonjourFinder.this);
|
||||||
|
mJmdns.addServiceListener(HTTPS_SERVICE_TYPE, BonjourFinder.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serviceRemoved(ServiceEvent event) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serviceAdded(final ServiceEvent event) {
|
||||||
|
addFDroidService(event);
|
||||||
|
new AsyncTask<Void, Void, Void>() {
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... params) {
|
||||||
|
mJmdns.requestServiceInfo(event.getType(), event.getName(), true);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serviceResolved(ServiceEvent event) {
|
||||||
|
addFDroidService(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFDroidService(ServiceEvent event) {
|
||||||
|
final ServiceInfo serviceInfo = event.getInfo();
|
||||||
|
if (serviceInfo.getPropertyString("type").startsWith("fdroidrepo")) {
|
||||||
|
foundPeer(new BonjourPeer(serviceInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
mMulticastLock.release();
|
||||||
|
if (mJmdns == null)
|
||||||
|
return;
|
||||||
|
mJmdns.removeServiceListener(HTTP_SERVICE_TYPE, this);
|
||||||
|
mJmdns.removeServiceListener(HTTPS_SERVICE_TYPE, this);
|
||||||
|
mJmdns = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package org.fdroid.fdroid.localrepo.peers;
|
||||||
|
|
||||||
|
import org.fdroid.fdroid.R;
|
||||||
|
|
||||||
|
import javax.jmdns.ServiceInfo;
|
||||||
|
|
||||||
|
public class BonjourPeer implements Peer {
|
||||||
|
|
||||||
|
private ServiceInfo serviceInfo;
|
||||||
|
|
||||||
|
public BonjourPeer(ServiceInfo serviceInfo) {
|
||||||
|
this.serviceInfo = serviceInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Bonjour: " + serviceInfo.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIcon() {
|
||||||
|
return R.drawable.wifi;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
11
F-Droid/src/org/fdroid/fdroid/localrepo/peers/Peer.java
Normal file
11
F-Droid/src/org/fdroid/fdroid/localrepo/peers/Peer.java
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package org.fdroid.fdroid.localrepo.peers;
|
||||||
|
|
||||||
|
import android.support.annotation.DrawableRes;
|
||||||
|
|
||||||
|
public interface Peer {
|
||||||
|
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
@DrawableRes int getIcon();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package org.fdroid.fdroid.localrepo.peers;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for other devices in the vicinity, using specific technologies.
|
||||||
|
* Once found, alerts a listener through the
|
||||||
|
* {@link org.fdroid.fdroid.localrepo.peers.PeerFinder.Listener#onPeerFound(Object)}
|
||||||
|
* 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> {
|
||||||
|
|
||||||
|
private static final String TAG = "PeerFinder";
|
||||||
|
|
||||||
|
private Listener<T> listener;
|
||||||
|
|
||||||
|
public abstract void scan();
|
||||||
|
public abstract void cancel();
|
||||||
|
|
||||||
|
protected void foundPeer(T peer) {
|
||||||
|
Log.i(TAG, "Found peer " + peer.getName());
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onPeerFound(peer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,7 +15,7 @@ import javax.jmdns.ServiceInfo;
|
|||||||
|
|
||||||
public class BonjourType implements SwapType {
|
public class BonjourType implements SwapType {
|
||||||
|
|
||||||
private static final String TAG = "BonjourType";
|
private static final String TAG = "BonjourBroadcastType";
|
||||||
|
|
||||||
private JmDNS jmdns;
|
private JmDNS jmdns;
|
||||||
private ServiceInfo pairService;
|
private ServiceInfo pairService;
|
||||||
|
@ -1,270 +0,0 @@
|
|||||||
package org.fdroid.fdroid.net;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.wifi.WifiManager;
|
|
||||||
import android.net.wifi.WifiManager.MulticastLock;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.BaseAdapter;
|
|
||||||
import android.widget.RelativeLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.fdroid.fdroid.R;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.jmdns.JmDNS;
|
|
||||||
import javax.jmdns.ServiceEvent;
|
|
||||||
import javax.jmdns.ServiceInfo;
|
|
||||||
import javax.jmdns.ServiceListener;
|
|
||||||
|
|
||||||
public class MDnsHelper implements ServiceListener {
|
|
||||||
|
|
||||||
private static final String TAG = "MDnsHelper";
|
|
||||||
public static final String HTTP_SERVICE_TYPE = "_http._tcp.local.";
|
|
||||||
public static final String HTTPS_SERVICE_TYPE = "_https._tcp.local.";
|
|
||||||
|
|
||||||
final Activity mActivity;
|
|
||||||
final RepoScanListAdapter mAdapter;
|
|
||||||
|
|
||||||
private JmDNS mJmdns;
|
|
||||||
private final WifiManager wifiManager;
|
|
||||||
private final MulticastLock mMulticastLock;
|
|
||||||
|
|
||||||
public MDnsHelper(Activity activity, final RepoScanListAdapter adapter) {
|
|
||||||
mActivity = activity;
|
|
||||||
mAdapter = adapter;
|
|
||||||
wifiManager = (WifiManager) activity.getSystemService(Context.WIFI_SERVICE);
|
|
||||||
mMulticastLock = wifiManager.createMulticastLock(activity.getPackageName());
|
|
||||||
mMulticastLock.setReferenceCounted(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void serviceRemoved(ServiceEvent event) {
|
|
||||||
// a ListView Adapter can only be updated on the UI thread
|
|
||||||
final ServiceInfo serviceInfo = event.getInfo();
|
|
||||||
mActivity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mAdapter.removeItem(serviceInfo);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void serviceAdded(final ServiceEvent event) {
|
|
||||||
addFDroidService(event);
|
|
||||||
new AsyncTask<Void, Void, Void>() {
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... params) {
|
|
||||||
mJmdns.requestServiceInfo(event.getType(), event.getName(), true);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void serviceResolved(ServiceEvent event) {
|
|
||||||
addFDroidService(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addFDroidService(ServiceEvent event) {
|
|
||||||
// a ListView Adapter can only be updated on the UI thread
|
|
||||||
final ServiceInfo serviceInfo = event.getInfo();
|
|
||||||
String type = serviceInfo.getPropertyString("type");
|
|
||||||
if (type.startsWith("fdroidrepo"))
|
|
||||||
mActivity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mAdapter.addItem(serviceInfo);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void discoverServices() {
|
|
||||||
mMulticastLock.acquire();
|
|
||||||
new AsyncTask<Void, Void, Void>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... params) {
|
|
||||||
try {
|
|
||||||
int ip = wifiManager.getConnectionInfo().getIpAddress();
|
|
||||||
byte[] byteIp = {
|
|
||||||
(byte) (ip & 0xff),
|
|
||||||
(byte) (ip >> 8 & 0xff),
|
|
||||||
(byte) (ip >> 16 & 0xff),
|
|
||||||
(byte) (ip >> 24 & 0xff)
|
|
||||||
};
|
|
||||||
mJmdns = JmDNS.create(InetAddress.getByAddress(byteIp));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Void result) {
|
|
||||||
if (mJmdns != null) {
|
|
||||||
mJmdns.addServiceListener(HTTP_SERVICE_TYPE, MDnsHelper.this);
|
|
||||||
mJmdns.addServiceListener(HTTPS_SERVICE_TYPE, MDnsHelper.this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopDiscovery() {
|
|
||||||
mMulticastLock.release();
|
|
||||||
if (mJmdns == null)
|
|
||||||
return;
|
|
||||||
mJmdns.removeServiceListener(HTTP_SERVICE_TYPE, MDnsHelper.this);
|
|
||||||
mJmdns.removeServiceListener(HTTPS_SERVICE_TYPE, MDnsHelper.this);
|
|
||||||
mJmdns = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class RepoScanListAdapter extends BaseAdapter {
|
|
||||||
private final Context mContext;
|
|
||||||
private final LayoutInflater mLayoutInflater;
|
|
||||||
private final List<DiscoveredRepo> mEntries = new ArrayList<>();
|
|
||||||
|
|
||||||
public RepoScanListAdapter(Context context) {
|
|
||||||
mContext = context;
|
|
||||||
mLayoutInflater = (LayoutInflater) mContext
|
|
||||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCount() {
|
|
||||||
return mEntries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getItem(int position) {
|
|
||||||
return mEntries.get(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getItemId(int position) {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled(int position) {
|
|
||||||
DiscoveredRepo service = mEntries.get(position);
|
|
||||||
ServiceInfo serviceInfo = service.getServiceInfo();
|
|
||||||
InetAddress[] addresses = serviceInfo.getInetAddresses();
|
|
||||||
return (addresses != null && addresses.length > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
|
||||||
RelativeLayout itemView;
|
|
||||||
if (convertView == null) {
|
|
||||||
itemView = (RelativeLayout) mLayoutInflater.inflate(
|
|
||||||
R.layout.repodiscoveryitem, parent, false);
|
|
||||||
} else {
|
|
||||||
itemView = (RelativeLayout) convertView;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextView nameLabel = (TextView) itemView.findViewById(R.id.reposcanitemname);
|
|
||||||
TextView addressLabel = (TextView) itemView.findViewById(R.id.reposcanitemaddress);
|
|
||||||
|
|
||||||
final DiscoveredRepo service = mEntries.get(position);
|
|
||||||
final ServiceInfo serviceInfo = service.getServiceInfo();
|
|
||||||
|
|
||||||
nameLabel.setText(serviceInfo.getName());
|
|
||||||
|
|
||||||
InetAddress[] addresses = serviceInfo.getInetAddresses();
|
|
||||||
if (addresses != null && addresses.length > 0) {
|
|
||||||
String addressTxt = "Hosted @ " + addresses[0] + ":" + serviceInfo.getPort();
|
|
||||||
addressLabel.setText(addressTxt);
|
|
||||||
}
|
|
||||||
|
|
||||||
return itemView;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addItem(ServiceInfo item) {
|
|
||||||
if (item == null || item.getName() == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Construct a DiscoveredRepo wrapper for the service being
|
|
||||||
// added in order to use a name based equals().
|
|
||||||
DiscoveredRepo newDRepo = new DiscoveredRepo(item);
|
|
||||||
// if an unresolved entry with the same name exists, remove it
|
|
||||||
for (DiscoveredRepo dr : mEntries)
|
|
||||||
if (dr.equals(newDRepo)) {
|
|
||||||
InetAddress[] addresses = dr.mServiceInfo.getInetAddresses();
|
|
||||||
if (addresses == null || addresses.length == 0)
|
|
||||||
mEntries.remove(dr);
|
|
||||||
}
|
|
||||||
mEntries.add(newDRepo);
|
|
||||||
|
|
||||||
notifyUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeItem(ServiceInfo item) {
|
|
||||||
if (item == null || item.getName() == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Construct a DiscoveredRepo wrapper for the service being
|
|
||||||
// removed in order to use a name based equals().
|
|
||||||
DiscoveredRepo lostServiceBean = new DiscoveredRepo(item);
|
|
||||||
|
|
||||||
if (mEntries.contains(lostServiceBean)) {
|
|
||||||
mEntries.remove(lostServiceBean);
|
|
||||||
notifyUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyUpdate() {
|
|
||||||
// Need to call notifyDataSetChanged from the UI thread
|
|
||||||
// in order for it to update the ListView without error
|
|
||||||
Handler refresh = new Handler(Looper.getMainLooper());
|
|
||||||
refresh.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DiscoveredRepo {
|
|
||||||
private final ServiceInfo mServiceInfo;
|
|
||||||
|
|
||||||
public DiscoveredRepo(ServiceInfo serviceInfo) {
|
|
||||||
if (serviceInfo == null || serviceInfo.getName() == null)
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Parameters \"serviceInfo\" and \"name\" must not be null.");
|
|
||||||
mServiceInfo = serviceInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServiceInfo getServiceInfo() {
|
|
||||||
return mServiceInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return mServiceInfo.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object other) {
|
|
||||||
if (!(other instanceof DiscoveredRepo))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Treat two services the same based on name. Eventually
|
|
||||||
// there should be a persistent mapping between fingerprint
|
|
||||||
// of the repo key and the discovered service such that we
|
|
||||||
// could maintain trust across hostnames/ips/networks
|
|
||||||
DiscoveredRepo otherRepo = (DiscoveredRepo) other;
|
|
||||||
return getName().equals(otherRepo.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -71,9 +71,6 @@ import org.fdroid.fdroid.compat.ClipboardCompat;
|
|||||||
import org.fdroid.fdroid.data.NewRepoConfig;
|
import org.fdroid.fdroid.data.NewRepoConfig;
|
||||||
import org.fdroid.fdroid.data.Repo;
|
import org.fdroid.fdroid.data.Repo;
|
||||||
import org.fdroid.fdroid.data.RepoProvider;
|
import org.fdroid.fdroid.data.RepoProvider;
|
||||||
import org.fdroid.fdroid.net.MDnsHelper;
|
|
||||||
import org.fdroid.fdroid.net.MDnsHelper.DiscoveredRepo;
|
|
||||||
import org.fdroid.fdroid.net.MDnsHelper.RepoScanListAdapter;
|
|
||||||
import org.fdroid.fdroid.views.fragments.RepoDetailsFragment;
|
import org.fdroid.fdroid.views.fragments.RepoDetailsFragment;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -84,8 +81,6 @@ import java.net.URL;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import javax.jmdns.ServiceInfo;
|
|
||||||
|
|
||||||
public class ManageReposActivity extends ActionBarActivity {
|
public class ManageReposActivity extends ActionBarActivity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -212,9 +207,6 @@ public class ManageReposActivity extends ActionBarActivity {
|
|||||||
case R.id.action_update_repo:
|
case R.id.action_update_repo:
|
||||||
updateRepos();
|
updateRepos();
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_find_local_repos:
|
|
||||||
scanForRepos();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
@ -239,55 +231,6 @@ public class ManageReposActivity extends ActionBarActivity {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scanForRepos() {
|
|
||||||
final RepoScanListAdapter adapter = new RepoScanListAdapter(this);
|
|
||||||
final MDnsHelper mDnsHelper = new MDnsHelper(this, adapter);
|
|
||||||
|
|
||||||
final View view = getLayoutInflater().inflate(R.layout.repodiscoverylist, null);
|
|
||||||
final ListView repoScanList = (ListView) view.findViewById(R.id.reposcanlist);
|
|
||||||
|
|
||||||
final AlertDialog alrt = new AlertDialog.Builder(this).setView(view)
|
|
||||||
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
mDnsHelper.stopDiscovery();
|
|
||||||
dialog.dismiss();
|
|
||||||
}
|
|
||||||
}).create();
|
|
||||||
|
|
||||||
alrt.setTitle(R.string.local_repos_title);
|
|
||||||
alrt.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
|
||||||
@Override
|
|
||||||
public void onDismiss(DialogInterface dialog) {
|
|
||||||
mDnsHelper.stopDiscovery();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
repoScanList.setAdapter(adapter);
|
|
||||||
repoScanList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onItemClick(AdapterView<?> parent, final View view,
|
|
||||||
int position, long id) {
|
|
||||||
|
|
||||||
final DiscoveredRepo discoveredService =
|
|
||||||
(DiscoveredRepo) parent.getItemAtPosition(position);
|
|
||||||
|
|
||||||
final ServiceInfo serviceInfo = discoveredService.getServiceInfo();
|
|
||||||
String type = serviceInfo.getPropertyString("type");
|
|
||||||
String protocol = type.contains("fdroidrepos") ? "https:/" : "http:/";
|
|
||||||
String path = serviceInfo.getPropertyString("path");
|
|
||||||
if (TextUtils.isEmpty(path))
|
|
||||||
path = "/fdroid/repo";
|
|
||||||
String serviceUrl = protocol + serviceInfo.getInetAddresses()[0]
|
|
||||||
+ ":" + serviceInfo.getPort() + path;
|
|
||||||
showAddRepo(serviceUrl, serviceInfo.getPropertyString("fingerprint"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
alrt.show();
|
|
||||||
mDnsHelper.discoverServices();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showAddRepo() {
|
private void showAddRepo() {
|
||||||
/*
|
/*
|
||||||
* If there is text in the clipboard, and it looks like a URL, use that.
|
* If there is text in the clipboard, and it looks like a URL, use that.
|
||||||
|
@ -165,6 +165,7 @@ public class SwapWorkflowActivity extends ActionBarActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showIntro() {
|
private void showIntro() {
|
||||||
|
SwapManager.load(this).scanForPeers();
|
||||||
inflateInnerView(R.layout.swap_blank);
|
inflateInnerView(R.layout.swap_blank);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user