diff --git a/res/values/strings.xml b/res/values/strings.xml index de6073c47..12baeeb47 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -34,7 +34,10 @@ Install using system-permissions Use system permissions to install, update, and remove packages Do not use system permissions to install, update, and remove packages - + Broadcast Local Repo + Advertize your local repo using Bonjour (mDNS) + Do not advertize your local repo. + Search Results App Details No such app found diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index fa534900f..aca5061f6 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -43,6 +43,12 @@ android:defaultValue="false" android:key="ignoreTouchscreen" /> + + + compactLayoutListeners = new ArrayList(); private List filterAppsRequiringRootListeners = new ArrayList(); private List updateHistoryListeners = new ArrayList(); + private List localRepoBonjourListeners = new ArrayList(); private boolean isInitialized(String key) { return initialized.containsKey(key) && initialized.get(key); @@ -74,6 +77,10 @@ public class Preferences implements SharedPreferences.OnSharedPreferenceChangeLi return preferences.getBoolean(PREF_SYSTEM_INSTALLER, DEFAULT_SYSTEM_INSTALLER); } + public boolean isLocalRepoBonjourEnabled() { + return preferences.getBoolean(PREF_LOCAL_REPO_BONJOUR, DEFAULT_LOCAL_REPO_BONJOUR); + } + public boolean hasCompactLayout() { if (!isInitialized(PREF_COMPACT_LAYOUT)) { initialize(PREF_COMPACT_LAYOUT); @@ -146,6 +153,10 @@ public class Preferences implements SharedPreferences.OnSharedPreferenceChangeLi for ( ChangeListener listener : updateHistoryListeners ) { listener.onPreferenceChange(); } + } else if (key.equals(PREF_LOCAL_REPO_BONJOUR)) { + for ( ChangeListener listener : localRepoBonjourListeners ) { + listener.onPreferenceChange(); + } } } @@ -157,6 +168,14 @@ public class Preferences implements SharedPreferences.OnSharedPreferenceChangeLi updateHistoryListeners.remove(listener); } + public void registerLocalRepoBonjourListeners(ChangeListener listener) { + localRepoBonjourListeners.add(listener); + } + + public void unregisterLocalRepoBonjourListeners(ChangeListener listener) { + localRepoBonjourListeners.remove(listener); + } + public static interface ChangeListener { public void onPreferenceChange(); } diff --git a/src/org/fdroid/fdroid/PreferencesActivity.java b/src/org/fdroid/fdroid/PreferencesActivity.java index 55c36ec3e..2d7d40191 100644 --- a/src/org/fdroid/fdroid/PreferencesActivity.java +++ b/src/org/fdroid/fdroid/PreferencesActivity.java @@ -54,6 +54,7 @@ public class PreferencesActivity extends PreferenceActivity implements Preferences.PREF_PERMISSIONS, Preferences.PREF_COMPACT_LAYOUT, Preferences.PREF_IGN_TOUCH, + Preferences.PREF_LOCAL_REPO_BONJOUR, Preferences.PREF_CACHE_APK, Preferences.PREF_EXPERT, Preferences.PREF_ROOT_INSTALLER, @@ -146,6 +147,10 @@ public class PreferencesActivity extends PreferenceActivity implements onoffSummary(key, R.string.ignoreTouch_on, R.string.ignoreTouch_off); + } else if (key.equals(Preferences.PREF_LOCAL_REPO_BONJOUR)) { + onoffSummary(key, R.string.local_repo_bonjour_on, + R.string.local_repo_bonjour_off); + } else if (key.equals(Preferences.PREF_CACHE_APK)) { onoffSummary(key, R.string.cache_downloaded_on, R.string.cache_downloaded_off); diff --git a/src/org/fdroid/fdroid/localrepo/LocalRepoService.java b/src/org/fdroid/fdroid/localrepo/LocalRepoService.java index c9d6511c6..4ecc8e23e 100644 --- a/src/org/fdroid/fdroid/localrepo/LocalRepoService.java +++ b/src/org/fdroid/fdroid/localrepo/LocalRepoService.java @@ -2,26 +2,17 @@ package org.fdroid.fdroid.localrepo; import android.annotation.SuppressLint; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.Messenger; +import android.app.*; +import android.content.*; +import android.os.*; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import org.fdroid.fdroid.FDroidApp; +import org.fdroid.fdroid.Preferences; +import org.fdroid.fdroid.Preferences.ChangeListener; import org.fdroid.fdroid.R; import org.fdroid.fdroid.net.LocalHTTPD; import org.fdroid.fdroid.net.WifiStateChangeService; @@ -29,8 +20,12 @@ import org.fdroid.fdroid.views.LocalRepoActivity; import java.io.IOException; import java.net.BindException; +import java.util.HashMap; import java.util.Random; +import javax.jmdns.JmDNS; +import javax.jmdns.ServiceInfo; + public class LocalRepoService extends Service { private static final String TAG = "LocalRepoService"; @@ -39,11 +34,15 @@ public class LocalRepoService extends Service { public static final String STOPPED = "org.fdroid.fdroid.category.LOCAL_REPO_STOPPED"; private NotificationManager notificationManager; + private Notification notification; // Unique Identification Number for the Notification. // We use it on Notification start, and to cancel it. private int NOTIFICATION = R.string.local_repo_running; private Handler webServerThreadHandler = null; + private LocalHTTPD localHttpd; + private JmDNS jmdns; + private ServiceInfo pairService; public static int START = 1111111; public static int STOP = 12345678; @@ -61,12 +60,12 @@ public class LocalRepoService extends Service { @Override public void handleMessage(Message msg) { if (msg.arg1 == START) { - service.startWebServer(); + service.startNetworkServices(); } else if (msg.arg1 == STOP) { - service.stopWebServer(); + service.stopNetworkServices(); } else if (msg.arg1 == RESTART) { - service.stopWebServer(); - service.startWebServer(); + service.stopNetworkServices(); + service.startNetworkServices(); } else { Log.e(TAG, "unsupported msg.arg1, ignored"); } @@ -76,8 +75,19 @@ public class LocalRepoService extends Service { private BroadcastReceiver onWifiChange = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent i) { - stopWebServer(); - startWebServer(); + stopNetworkServices(); + startNetworkServices(); + } + }; + + private ChangeListener localRepoBonjourChangeListener = new ChangeListener() { + @Override + public void onPreferenceChange() { + if (localHttpd.isAlive()) + if (Preferences.get().isLocalRepoBonjourEnabled()) + registerMDNSService(); + else + unregisterMDNSService(); } }; @@ -88,14 +98,16 @@ public class LocalRepoService extends Service { Intent intent = new Intent(this, LocalRepoActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0); - Notification notification = new NotificationCompat.Builder(this) + notification = new NotificationCompat.Builder(this) .setContentTitle(getText(R.string.local_repo_running)) .setContentText(getText(R.string.touch_to_configure_local_repo)) .setSmallIcon(android.R.drawable.ic_dialog_info) .setContentIntent(contentIntent) .build(); startForeground(NOTIFICATION, notification); - startWebServer(); + startNetworkServices(); + Preferences.get().registerLocalRepoBonjourListeners(localRepoBonjourChangeListener); + LocalBroadcastManager.getInstance(this).registerReceiver(onWifiChange, new IntentFilter(WifiStateChangeService.BROADCAST)); } @@ -109,9 +121,10 @@ public class LocalRepoService extends Service { @Override public void onDestroy() { - stopWebServer(); + stopNetworkServices(); notificationManager.cancel(NOTIFICATION); LocalBroadcastManager.getInstance(this).unregisterReceiver(onWifiChange); + Preferences.get().unregisterLocalRepoBonjourListeners(localRepoBonjourChangeListener); } @Override @@ -119,6 +132,17 @@ public class LocalRepoService extends Service { return messenger.getBinder(); } + private void startNetworkServices() { + startWebServer(); + if (Preferences.get().isLocalRepoBonjourEnabled()) + registerMDNSService(); + } + + private void stopNetworkServices() { + unregisterMDNSService(); + stopWebServer(); + } + private void startWebServer() { final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); @@ -127,7 +151,7 @@ public class LocalRepoService extends Service { @SuppressLint("HandlerLeak") @Override public void run() { - final LocalHTTPD localHttpd = new LocalHTTPD(getFilesDir(), + localHttpd = new LocalHTTPD(getFilesDir(), prefs.getBoolean("use_https", false)); Looper.prepare(); // must be run before creating a Handler @@ -169,4 +193,46 @@ public class LocalRepoService extends Service { intent.putExtra(STATE, STOPPED); LocalBroadcastManager.getInstance(LocalRepoService.this).sendBroadcast(intent); } + + private void registerMDNSService() { + final HashMap values = new HashMap(); + values.put("path", "/fdroid/repo"); + values.put("name", FDroidApp.repo.name); + // TODO set type based on "use HTTPS" pref + // values.put("fingerprint", FDroidApp.repo.fingerprint); + values.put("type", "fdroidrepo"); + pairService = ServiceInfo.create("_http._tcp.local.", + FDroidApp.repo.name, FDroidApp.port, 0, 0, values); + new Thread(new Runnable() { + + @Override + public void run() { + try { + jmdns = JmDNS.create(); + jmdns.registerService(pairService); + } catch (IOException e) { + e.printStackTrace(); + } + } + }).start(); + } + + private void unregisterMDNSService() { + if (localRepoBonjourChangeListener != null) { + Preferences.get().unregisterLocalRepoBonjourListeners(localRepoBonjourChangeListener); + localRepoBonjourChangeListener = null; + } + if (jmdns != null) { + if (pairService != null) + jmdns.unregisterService(pairService); + pairService = null; + jmdns.unregisterAllServices(); + try { + jmdns.close(); + } catch (IOException e) { + e.printStackTrace(); + } + jmdns = null; + } + } }