Refactored SwapService + SwapManager into single SwapService
This commit is contained in:
parent
a3af6b8b9f
commit
0b1e2732c2
@ -6,16 +6,16 @@
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:titleTextAppearance="@style/SwapTheme.Wizard.Text"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary" />
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:titleTextAppearance="@style/SwapTheme.Wizard.Text"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fragment_container"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
android:id="@+id/fragment_container"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
|
||||
</LinearLayout>
|
26
F-Droid/res/layout/swap_initial_loading.xml
Normal file
26
F-Droid/res/layout/swap_initial_loading.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<org.fdroid.fdroid.views.swap.InitialLoadingView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/swap_blue"
|
||||
android:paddingTop="38.8dp"> <!-- 69px * 96dpi / 160dpi -->
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/loading"
|
||||
android:textSize="18sp"
|
||||
android:layout_below="@+id/progress"
|
||||
android:textColor="@android:color/white"
|
||||
android:layout_centerHorizontal="true" />
|
||||
|
||||
</org.fdroid.fdroid.views.swap.InitialLoadingView>
|
@ -347,4 +347,5 @@
|
||||
<string name="wifi_warning_public">May work</string>
|
||||
<string name="wifi_warning_private">Promising</string>
|
||||
<string name="wifi_warning_personal">Best bet</string>
|
||||
<string name="loading">Loading...</string>
|
||||
</resources>
|
||||
|
@ -56,7 +56,7 @@ import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
/**
|
||||
* The {@link SwapManager} deals with managing the entire workflow from selecting apps to
|
||||
* The {@link SwapService} deals with managing the entire workflow from selecting apps to
|
||||
* swap, to invoking this class to prepare the webroot, to enabling various communication protocols.
|
||||
* This class deals specifically with the webroot side of things, ensuring we have a valid index.jar
|
||||
* and the relevant .apk and icon files available.
|
||||
|
@ -1,461 +0,0 @@
|
||||
package org.fdroid.fdroid.localrepo;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.IntDef;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.UpdateService;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.Repo;
|
||||
import org.fdroid.fdroid.data.RepoProvider;
|
||||
import org.fdroid.fdroid.localrepo.peers.Peer;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class SwapManager {
|
||||
|
||||
private static final String TAG = "SwapState";
|
||||
private static final String SHARED_PREFERENCES = "swap-state";
|
||||
private static final String KEY_APPS_TO_SWAP = "appsToSwap";
|
||||
|
||||
private static SwapManager instance;
|
||||
|
||||
@NonNull
|
||||
public static SwapManager load(@NonNull Context context) {
|
||||
if (instance == null) {
|
||||
SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
|
||||
Set<String> appsToSwap = deserializePackages(preferences.getString(KEY_APPS_TO_SWAP, ""));
|
||||
instance = new SwapManager(context, appsToSwap);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private final Context context;
|
||||
|
||||
@NonNull
|
||||
private Set<String> appsToSwap;
|
||||
|
||||
@NonNull
|
||||
private List<Peer> peers;
|
||||
|
||||
private SwapManager(@NonNull Context context, @NonNull Set<String> appsToSwap) {
|
||||
this.context = context.getApplicationContext();
|
||||
this.appsToSwap = appsToSwap;
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Where relevant, the state of the swap process will be saved to disk using preferences.
|
||||
* Note that this is not always useful, for example saving the "current wifi network" is
|
||||
* bound to cause trouble when the user opens the swap process again and is connected to
|
||||
* a different network.
|
||||
*/
|
||||
private SharedPreferences persistence() {
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<Peer> getPeers() {
|
||||
return peers;
|
||||
}
|
||||
|
||||
|
||||
// ==========================================================
|
||||
// Manage the current step
|
||||
// ("Step" refers to the current view being shown in the UI)
|
||||
// ==========================================================
|
||||
|
||||
public static final int STEP_INTRO = 1;
|
||||
public static final int STEP_SELECT_APPS = 2;
|
||||
public static final int STEP_JOIN_WIFI = 3;
|
||||
public static final int STEP_SHOW_NFC = 4;
|
||||
public static final int STEP_WIFI_QR = 5;
|
||||
public static final int STEP_CONNECTING = 6;
|
||||
public static final int STEP_SUCCESS = 7;
|
||||
public static final int STEP_CONFIRM_SWAP = 8;
|
||||
|
||||
private @SwapStep int step = STEP_INTRO;
|
||||
|
||||
/**
|
||||
* Current screen that the swap process is up to.
|
||||
* Will be one of the SwapState.STEP_* values.
|
||||
*/
|
||||
@SwapStep
|
||||
public int getStep() {
|
||||
return step;
|
||||
}
|
||||
|
||||
public SwapManager setStep(@SwapStep int step) {
|
||||
this.step = step;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NonNull Set<String> getAppsToSwap() {
|
||||
return appsToSwap;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UpdateService.UpdateReceiver refreshSwap() {
|
||||
return this.peer != null ? connectTo(peer) : null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public UpdateService.UpdateReceiver connectTo(@NonNull Peer peer) {
|
||||
if (peer != this.peer) {
|
||||
Log.e(TAG, "Oops, got a different peer to swap with than initially planned.");
|
||||
}
|
||||
|
||||
peerRepo = ensureRepoExists(peer);
|
||||
|
||||
// Only ask server to swap with us, if we are actually running a local repo service.
|
||||
// It is possible to have a swap initiated without first starting a swap, in which
|
||||
// case swapping back is pointless.
|
||||
/*if (!newRepoConfig.preventFurtherSwaps() && isEnabled()) {
|
||||
askServerToSwapWithUs();
|
||||
}*/
|
||||
|
||||
return UpdateService.updateRepoNow(peer.getRepoAddress(), context, false);
|
||||
}
|
||||
/*
|
||||
private void askServerToSwapWithUs() {
|
||||
if (!newRepoConfig.isValidRepo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... args) {
|
||||
Uri repoUri = newRepoConfig.getRepoUri();
|
||||
String swapBackUri = Utils.getLocalRepoUri(FDroidApp.repo).toString();
|
||||
|
||||
AndroidHttpClient client = AndroidHttpClient.newInstance("F-Droid", ConnectSwapActivity.this);
|
||||
HttpPost request = new HttpPost("/request-swap");
|
||||
HttpHost host = new HttpHost(repoUri.getHost(), repoUri.getPort(), repoUri.getScheme());
|
||||
|
||||
try {
|
||||
Log.d(TAG, "Asking server at " + newRepoConfig.getRepoUriString() + " to swap with us in return (by POSTing to \"/request-swap\" with repo \"" + swapBackUri + "\")...");
|
||||
populatePostParams(swapBackUri, request);
|
||||
client.execute(host, request);
|
||||
} catch (IOException e) {
|
||||
notifyOfErrorOnUiThread();
|
||||
Log.e(TAG, "Error while asking server to swap with us: " + e.getMessage());
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void populatePostParams(String swapBackUri, HttpPost request) throws UnsupportedEncodingException {
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("repo", swapBackUri));
|
||||
UrlEncodedFormEntity encodedParams = new UrlEncodedFormEntity(params);
|
||||
request.setEntity(encodedParams);
|
||||
}
|
||||
|
||||
private void notifyOfErrorOnUiThread() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(
|
||||
ConnectSwapActivity.this,
|
||||
R.string.swap_reciprocate_failed,
|
||||
Toast.LENGTH_LONG
|
||||
).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}.execute();
|
||||
}*/
|
||||
private Repo ensureRepoExists(@NonNull Peer peer) {
|
||||
// TODO: newRepoConfig.getParsedUri() will include a fingerprint, which may not match with
|
||||
// the repos address in the database. Not sure on best behaviour in this situation.
|
||||
Repo repo = RepoProvider.Helper.findByAddress(context, peer.getRepoAddress());
|
||||
if (repo == null) {
|
||||
ContentValues values = new ContentValues(6);
|
||||
|
||||
// TODO: i18n and think about most appropriate name. Although it wont be visible in
|
||||
// the "Manage repos" UI after being marked as a swap repo here...
|
||||
values.put(RepoProvider.DataColumns.NAME, peer.getName());
|
||||
values.put(RepoProvider.DataColumns.ADDRESS, peer.getRepoAddress());
|
||||
values.put(RepoProvider.DataColumns.DESCRIPTION, ""); // TODO;
|
||||
values.put(RepoProvider.DataColumns.FINGERPRINT, peer.getFingerprint());
|
||||
values.put(RepoProvider.DataColumns.IN_USE, true);
|
||||
values.put(RepoProvider.DataColumns.IS_SWAP, true);
|
||||
Uri uri = RepoProvider.Helper.insert(context, values);
|
||||
repo = RepoProvider.Helper.findByUri(context, uri);
|
||||
}
|
||||
|
||||
return repo;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Repo getPeerRepo() {
|
||||
return peerRepo;
|
||||
}
|
||||
|
||||
public void install(@NonNull final App app) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that we don't get put into an incorrect state, by forcing people to pass valid
|
||||
* states to setStep. Ideally this would be done by requiring an enum or something to
|
||||
* be passed rather than in integer, however that is harder to persist on disk than an int.
|
||||
* This is the same as, e.g. {@link Context#getSystemService(String)}
|
||||
*/
|
||||
@IntDef({STEP_INTRO, STEP_SELECT_APPS, STEP_JOIN_WIFI, STEP_SHOW_NFC, STEP_WIFI_QR,
|
||||
STEP_CONNECTING, STEP_SUCCESS, STEP_CONFIRM_SWAP})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface SwapStep {}
|
||||
|
||||
|
||||
// =================================================
|
||||
// Have selected a specific peer to swap with
|
||||
// (Rather than showing a generic QR code to scan)
|
||||
// =================================================
|
||||
|
||||
@Nullable
|
||||
private Peer peer;
|
||||
|
||||
@Nullable
|
||||
private Repo peerRepo;
|
||||
|
||||
public void swapWith(Peer peer) {
|
||||
this.peer = peer;
|
||||
}
|
||||
|
||||
public boolean isConnectingWithPeer() {
|
||||
return peer != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Peer getPeer() {
|
||||
return peer;
|
||||
}
|
||||
|
||||
|
||||
// ==========================================
|
||||
// Remember apps user wants to swap
|
||||
// ==========================================
|
||||
|
||||
private void persistAppsToSwap() {
|
||||
persistence().edit().putString(KEY_APPS_TO_SWAP, serializePackages(appsToSwap)).commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement for {@link android.content.SharedPreferences.Editor#putStringSet(String, Set)}
|
||||
* which is only available in API >= 11.
|
||||
* Package names are reverse-DNS-style, so they should only have alpha numeric values. Thus,
|
||||
* this uses a comma as the separator.
|
||||
* @see SwapManager#deserializePackages(String)
|
||||
*/
|
||||
private static String serializePackages(Set<String> packages) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String pkg : packages) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(pkg);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SwapManager#deserializePackages(String)
|
||||
*/
|
||||
private static Set<String> deserializePackages(String packages) {
|
||||
Set<String> set = new HashSet<>();
|
||||
if (!TextUtils.isEmpty(packages)) {
|
||||
Collections.addAll(set, packages.split(","));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
public void ensureFDroidSelected() {
|
||||
String fdroid = context.getPackageName();
|
||||
if (!hasSelectedPackage(fdroid)) {
|
||||
selectPackage(fdroid);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasSelectedPackage(String packageName) {
|
||||
return appsToSwap.contains(packageName);
|
||||
}
|
||||
|
||||
public void selectPackage(String packageName) {
|
||||
appsToSwap.add(packageName);
|
||||
persistAppsToSwap();
|
||||
}
|
||||
|
||||
public void deselectPackage(String packageName) {
|
||||
if (appsToSwap.contains(packageName)) {
|
||||
appsToSwap.remove(packageName);
|
||||
}
|
||||
persistAppsToSwap();
|
||||
}
|
||||
|
||||
|
||||
// ==========================================
|
||||
// Local repo stop/start/restart handling
|
||||
// ==========================================
|
||||
|
||||
@Nullable
|
||||
private SwapService service = null;
|
||||
|
||||
private void setupService() {
|
||||
|
||||
ServiceConnection serviceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName className, IBinder binder) {
|
||||
Log.d(TAG, "Swap service connected, enabling SwapManager to communicate with SwapService.");
|
||||
service = ((SwapService.Binder)binder).getService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
Log.d(TAG, "Swap service disconnected");
|
||||
service = null;
|
||||
}
|
||||
};
|
||||
|
||||
// The server should not be doing anything or occupying any (noticable) resources
|
||||
// until we actually ask it to enable swapping. Therefore, we will start it nice and
|
||||
// early so we don't have to wait until it is connected later.
|
||||
Intent service = new Intent(context, SwapService.class);
|
||||
if (context.bindService(service, serviceConnection, Context.BIND_AUTO_CREATE)) {
|
||||
context.startService(service);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void enableSwapping() {
|
||||
if (service != null) {
|
||||
service.enableSwapping();
|
||||
} else {
|
||||
Log.e(TAG, "Couldn't enable swap, because service was not running.");
|
||||
}
|
||||
}
|
||||
|
||||
public void disableSwapping() {
|
||||
if (service != null) {
|
||||
service.disableSwapping();
|
||||
} else {
|
||||
Log.e(TAG, "Couldn't disable swap, because service was not running.");
|
||||
}
|
||||
setStep(STEP_INTRO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles checking if the {@link SwapService} is running, and only restarts it if it was running.
|
||||
*/
|
||||
public void restartIfEnabled() {
|
||||
if (service != null) {
|
||||
service.restartIfEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return service != null && service.isEnabled();
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Interacting with Bluetooth adapter
|
||||
// ==========================================
|
||||
|
||||
public boolean isBluetoothDiscoverable() {
|
||||
return service != null && service.getBluetooth().isConnected();
|
||||
}
|
||||
|
||||
public void ensureBluetoothDiscoverable() {
|
||||
if (service != null) {
|
||||
service.getBluetooth().start();
|
||||
}
|
||||
}
|
||||
|
||||
public void makeBluetoothNonDiscoverable() {
|
||||
if (service != null) {
|
||||
service.getBluetooth().stop();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWifiConnected() {
|
||||
return !TextUtils.isEmpty(FDroidApp.ssid);
|
||||
}
|
||||
|
||||
public boolean isBonjourDiscoverable() {
|
||||
return isWifiConnected() && service != null && service.isEnabled();
|
||||
}
|
||||
|
||||
public void ensureBonjourDiscoverable() {
|
||||
if (!isBonjourDiscoverable()) {
|
||||
// TODO: Enable bonjour (currently it is enabled by default when the service starts)
|
||||
}
|
||||
}
|
||||
|
||||
public void makeBonjourNotDiscoverable() {
|
||||
if (service != null) {
|
||||
// TODO: Disable bonjour (currently it is enabled by default when the service starts)
|
||||
}
|
||||
}
|
||||
|
||||
public boolean 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";
|
||||
}
|
@ -4,20 +4,32 @@ import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.IntDef;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.UpdateService;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.Repo;
|
||||
import org.fdroid.fdroid.data.RepoProvider;
|
||||
import org.fdroid.fdroid.localrepo.peers.BluetoothFinder;
|
||||
import org.fdroid.fdroid.localrepo.peers.BonjourFinder;
|
||||
import org.fdroid.fdroid.localrepo.peers.Peer;
|
||||
import org.fdroid.fdroid.localrepo.type.BluetoothType;
|
||||
import org.fdroid.fdroid.localrepo.type.BonjourType;
|
||||
import org.fdroid.fdroid.localrepo.type.SwapType;
|
||||
@ -25,6 +37,12 @@ import org.fdroid.fdroid.localrepo.type.WebServerType;
|
||||
import org.fdroid.fdroid.net.WifiStateChangeService;
|
||||
import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
@ -35,105 +53,290 @@ import java.util.TimerTask;
|
||||
*/
|
||||
public class SwapService extends Service {
|
||||
|
||||
private static final String TAG = "SwapService";
|
||||
private static final String TAG = "SwapManager";
|
||||
private static final String SHARED_PREFERENCES = "swap-state";
|
||||
private static final String KEY_APPS_TO_SWAP = "appsToSwap";
|
||||
|
||||
public static final String BONJOUR_STATE_CHANGE = "org.fdroid.fdroid.BONJOUR_STATE_CHANGE";
|
||||
public static final String BLUETOOTH_STATE_CHANGE = "org.fdroid.fdroid.BLUETOOTH_STATE_CHANGE";
|
||||
public static final String EXTRA_STARTING = "STARTING";
|
||||
public static final String EXTRA_STARTED = "STARTED";
|
||||
public static final String EXTRA_STOPPED = "STOPPED";
|
||||
@NonNull
|
||||
private Set<String> appsToSwap = new HashSet<>();
|
||||
|
||||
private static final int NOTIFICATION = 1;
|
||||
|
||||
private final Binder binder = new Binder();
|
||||
private SwapType bonjourType;
|
||||
private SwapType bluetoothType;
|
||||
private SwapType webServerType;
|
||||
|
||||
private BonjourFinder bonjourFinder;
|
||||
private BluetoothFinder bluetoothFinder;
|
||||
|
||||
private final static int TIMEOUT = 900000; // 15 mins
|
||||
public SwapService() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to automatically turn of swapping after a defined amount of time (15 mins).
|
||||
* Where relevant, the state of the swap process will be saved to disk using preferences.
|
||||
* Note that this is not always useful, for example saving the "current wifi network" is
|
||||
* bound to cause trouble when the user opens the swap process again and is connected to
|
||||
* a different network.
|
||||
*/
|
||||
@Nullable
|
||||
private Timer timer;
|
||||
|
||||
public boolean isScanningForPeers() {
|
||||
return bonjourFinder.isScanning() || bluetoothFinder.isScanning();
|
||||
private SharedPreferences persistence() {
|
||||
return getSharedPreferences(SHARED_PREFERENCES, MODE_APPEND);
|
||||
}
|
||||
|
||||
public SwapType getBluetooth() {
|
||||
return bluetoothType;
|
||||
}
|
||||
|
||||
public SwapType getBonjour() {
|
||||
return bluetoothType;
|
||||
}
|
||||
|
||||
public class Binder extends android.os.Binder {
|
||||
public SwapService getService() {
|
||||
return SwapService.this;
|
||||
}
|
||||
}
|
||||
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
bonjourType = new BonjourType(this);
|
||||
bluetoothType = BluetoothType.create(this);
|
||||
webServerType = new WebServerType(this);
|
||||
bonjourFinder = new BonjourFinder(this);
|
||||
bluetoothFinder = new BluetoothFinder(this);
|
||||
|
||||
Log.d(TAG, "Creating service, will register appropriate listeners.");
|
||||
Preferences.get().registerLocalRepoBonjourListeners(bonjourEnabledListener);
|
||||
Preferences.get().registerLocalRepoHttpsListeners(httpsEnabledListener);
|
||||
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(onWifiChange,
|
||||
new IntentFilter(WifiStateChangeService.BROADCAST));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return binder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
Log.d(TAG, "Destroying service, will disable swapping if required, and unregister listeners.");
|
||||
disableSwapping();
|
||||
Preferences.get().unregisterLocalRepoBonjourListeners(bonjourEnabledListener);
|
||||
Preferences.get().unregisterLocalRepoHttpsListeners(httpsEnabledListener);
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(onWifiChange);
|
||||
}
|
||||
|
||||
private Notification createNotification() {
|
||||
Intent intent = new Intent(this, SwapWorkflowActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
return new NotificationCompat.Builder(this)
|
||||
.setContentTitle(getText(R.string.local_repo_running))
|
||||
.setContentText(getText(R.string.touch_to_configure_local_repo))
|
||||
.setSmallIcon(R.drawable.ic_swap)
|
||||
.setContentIntent(contentIntent)
|
||||
.build();
|
||||
}
|
||||
// ==========================================================
|
||||
// Search for peers to swap
|
||||
// ==========================================================
|
||||
|
||||
public void scanForPeers() {
|
||||
Log.d(TAG, "Scanning for nearby devices to swap with...");
|
||||
bonjourFinder.scan();
|
||||
bluetoothFinder.scan();
|
||||
}
|
||||
|
||||
public void cancelScanningForPeers() {
|
||||
public void stopScanningForPeers() {
|
||||
bonjourFinder.cancel();
|
||||
bluetoothFinder.cancel();
|
||||
}
|
||||
|
||||
private boolean enabled = false;
|
||||
|
||||
// ==========================================================
|
||||
// Manage the current step
|
||||
// ("Step" refers to the current view being shown in the UI)
|
||||
// ==========================================================
|
||||
|
||||
public static final int STEP_INTRO = 1;
|
||||
public static final int STEP_SELECT_APPS = 2;
|
||||
public static final int STEP_JOIN_WIFI = 3;
|
||||
public static final int STEP_SHOW_NFC = 4;
|
||||
public static final int STEP_WIFI_QR = 5;
|
||||
public static final int STEP_CONNECTING = 6;
|
||||
public static final int STEP_SUCCESS = 7;
|
||||
public static final int STEP_CONFIRM_SWAP = 8;
|
||||
|
||||
/**
|
||||
* Special view, that we don't really want to actually store against the
|
||||
* {@link SwapService#step}. Rather, we use it for the purpose of specifying
|
||||
* we are in the state waiting for the {@link SwapService} to get started and
|
||||
* bound to the {@link SwapWorkflowActivity}.
|
||||
*/
|
||||
public static final int STEP_INITIAL_LOADING = 9;
|
||||
|
||||
private @SwapStep int step = STEP_INTRO;
|
||||
|
||||
/**
|
||||
* Current screen that the swap process is up to.
|
||||
* Will be one of the SwapState.STEP_* values.
|
||||
*/
|
||||
@SwapStep
|
||||
public int getStep() {
|
||||
return step;
|
||||
}
|
||||
|
||||
public SwapService setStep(@SwapStep int step) {
|
||||
this.step = step;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NonNull Set<String> getAppsToSwap() {
|
||||
return appsToSwap;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UpdateService.UpdateReceiver refreshSwap() {
|
||||
return this.peer != null ? connectTo(peer) : null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public UpdateService.UpdateReceiver connectTo(@NonNull Peer peer) {
|
||||
if (peer != this.peer) {
|
||||
Log.e(TAG, "Oops, got a different peer to swap with than initially planned.");
|
||||
}
|
||||
|
||||
peerRepo = ensureRepoExists(peer);
|
||||
|
||||
// Only ask server to swap with us, if we are actually running a local repo service.
|
||||
// It is possible to have a swap initiated without first starting a swap, in which
|
||||
// case swapping back is pointless.
|
||||
/*if (!newRepoConfig.preventFurtherSwaps() && isEnabled()) {
|
||||
askServerToSwapWithUs();
|
||||
}*/
|
||||
|
||||
return UpdateService.updateRepoNow(peer.getRepoAddress(), this, false);
|
||||
}
|
||||
/*
|
||||
private void askServerToSwapWithUs() {
|
||||
if (!newRepoConfig.isValidRepo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... args) {
|
||||
Uri repoUri = newRepoConfig.getRepoUri();
|
||||
String swapBackUri = Utils.getLocalRepoUri(FDroidApp.repo).toString();
|
||||
|
||||
AndroidHttpClient client = AndroidHttpClient.newInstance("F-Droid", ConnectSwapActivity.this);
|
||||
HttpPost request = new HttpPost("/request-swap");
|
||||
HttpHost host = new HttpHost(repoUri.getHost(), repoUri.getPort(), repoUri.getScheme());
|
||||
|
||||
try {
|
||||
Log.d(TAG, "Asking server at " + newRepoConfig.getRepoUriString() + " to swap with us in return (by POSTing to \"/request-swap\" with repo \"" + swapBackUri + "\")...");
|
||||
populatePostParams(swapBackUri, request);
|
||||
client.execute(host, request);
|
||||
} catch (IOException e) {
|
||||
notifyOfErrorOnUiThread();
|
||||
Log.e(TAG, "Error while asking server to swap with us: " + e.getMessage());
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void populatePostParams(String swapBackUri, HttpPost request) throws UnsupportedEncodingException {
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("repo", swapBackUri));
|
||||
UrlEncodedFormEntity encodedParams = new UrlEncodedFormEntity(params);
|
||||
request.setEntity(encodedParams);
|
||||
}
|
||||
|
||||
private void notifyOfErrorOnUiThread() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(
|
||||
ConnectSwapActivity.this,
|
||||
R.string.swap_reciprocate_failed,
|
||||
Toast.LENGTH_LONG
|
||||
).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}.execute();
|
||||
}*/
|
||||
|
||||
private Repo ensureRepoExists(@NonNull Peer peer) {
|
||||
// TODO: newRepoConfig.getParsedUri() will include a fingerprint, which may not match with
|
||||
// the repos address in the database. Not sure on best behaviour in this situation.
|
||||
Repo repo = RepoProvider.Helper.findByAddress(this, peer.getRepoAddress());
|
||||
if (repo == null) {
|
||||
ContentValues values = new ContentValues(6);
|
||||
|
||||
// TODO: i18n and think about most appropriate name. Although it wont be visible in
|
||||
// the "Manage repos" UI after being marked as a swap repo here...
|
||||
values.put(RepoProvider.DataColumns.NAME, peer.getName());
|
||||
values.put(RepoProvider.DataColumns.ADDRESS, peer.getRepoAddress());
|
||||
values.put(RepoProvider.DataColumns.DESCRIPTION, ""); // TODO;
|
||||
values.put(RepoProvider.DataColumns.FINGERPRINT, peer.getFingerprint());
|
||||
values.put(RepoProvider.DataColumns.IN_USE, true);
|
||||
values.put(RepoProvider.DataColumns.IS_SWAP, true);
|
||||
Uri uri = RepoProvider.Helper.insert(this, values);
|
||||
repo = RepoProvider.Helper.findByUri(this, uri);
|
||||
}
|
||||
|
||||
return repo;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Repo getPeerRepo() {
|
||||
return peerRepo;
|
||||
}
|
||||
|
||||
public void install(@NonNull final App app) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that we don't get put into an incorrect state, by forcing people to pass valid
|
||||
* states to setStep. Ideally this would be done by requiring an enum or something to
|
||||
* be passed rather than in integer, however that is harder to persist on disk than an int.
|
||||
* This is the same as, e.g. {@link Context#getSystemService(String)}
|
||||
*/
|
||||
@IntDef({STEP_INTRO, STEP_SELECT_APPS, STEP_JOIN_WIFI, STEP_SHOW_NFC, STEP_WIFI_QR,
|
||||
STEP_CONNECTING, STEP_SUCCESS, STEP_CONFIRM_SWAP, STEP_INITIAL_LOADING})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface SwapStep {}
|
||||
|
||||
|
||||
// =================================================
|
||||
// Have selected a specific peer to swap with
|
||||
// (Rather than showing a generic QR code to scan)
|
||||
// =================================================
|
||||
|
||||
@Nullable
|
||||
private Peer peer;
|
||||
|
||||
@Nullable
|
||||
private Repo peerRepo;
|
||||
|
||||
public void swapWith(Peer peer) {
|
||||
this.peer = peer;
|
||||
}
|
||||
|
||||
public boolean isConnectingWithPeer() {
|
||||
return peer != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Peer getPeer() {
|
||||
return peer;
|
||||
}
|
||||
|
||||
|
||||
// ==========================================
|
||||
// Remember apps user wants to swap
|
||||
// ==========================================
|
||||
|
||||
private void persistAppsToSwap() {
|
||||
persistence().edit().putString(KEY_APPS_TO_SWAP, serializePackages(appsToSwap)).commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement for {@link android.content.SharedPreferences.Editor#putStringSet(String, Set)}
|
||||
* which is only available in API >= 11.
|
||||
* Package names are reverse-DNS-style, so they should only have alpha numeric values. Thus,
|
||||
* this uses a comma as the separator.
|
||||
* @see SwapService#deserializePackages(String)
|
||||
*/
|
||||
private static String serializePackages(Set<String> packages) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String pkg : packages) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(pkg);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SwapService#deserializePackages(String)
|
||||
*/
|
||||
private static Set<String> deserializePackages(String packages) {
|
||||
Set<String> set = new HashSet<>();
|
||||
if (!TextUtils.isEmpty(packages)) {
|
||||
Collections.addAll(set, packages.split(","));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
public void ensureFDroidSelected() {
|
||||
String fdroid = getPackageName();
|
||||
if (!hasSelectedPackage(fdroid)) {
|
||||
selectPackage(fdroid);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasSelectedPackage(String packageName) {
|
||||
return appsToSwap.contains(packageName);
|
||||
}
|
||||
|
||||
public void selectPackage(String packageName) {
|
||||
appsToSwap.add(packageName);
|
||||
persistAppsToSwap();
|
||||
}
|
||||
|
||||
public void deselectPackage(String packageName) {
|
||||
if (appsToSwap.contains(packageName)) {
|
||||
appsToSwap.remove(packageName);
|
||||
}
|
||||
persistAppsToSwap();
|
||||
}
|
||||
|
||||
|
||||
// ==========================================
|
||||
// Local repo stop/start/restart handling
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* Ensures that the webserver is running, as are the other services which make swap work.
|
||||
@ -165,17 +368,6 @@ public class SwapService extends Service {
|
||||
initTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* The guts of this class - responsible for enabling the relevant services for swapping.
|
||||
* Doesn't know anything about enabled/disabled state, you should check that before invoking
|
||||
* this method so it doesn't start something that is already started.
|
||||
* Runs asynchronously on several background threads.
|
||||
*/
|
||||
private void enableSwappingAsynchronous() {
|
||||
webServerType.startInBackground();
|
||||
bonjourType.startInBackground();
|
||||
}
|
||||
|
||||
public void disableSwapping() {
|
||||
if (enabled) {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@ -206,18 +398,8 @@ public class SwapService extends Service {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SwapService#enableSwappingAsynchronous()
|
||||
* Handles checking if the {@link SwapService} is running, and only restarts it if it was running.
|
||||
*/
|
||||
private void disableSwappingSynchronous() {
|
||||
Log.d(TAG, "Disabling SwapService (bonjour, webserver, etc)");
|
||||
bonjourType.stop();
|
||||
webServerType.stop();
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void restartIfEnabled() {
|
||||
if (enabled) {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@ -232,6 +414,169 @@ public class SwapService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Interacting with Bluetooth adapter
|
||||
// ==========================================
|
||||
|
||||
public boolean isBluetoothDiscoverable() {
|
||||
return bluetoothType.isConnected();
|
||||
}
|
||||
|
||||
public void ensureBluetoothDiscoverable() {
|
||||
bluetoothType.start();
|
||||
}
|
||||
|
||||
public void makeBluetoothNonDiscoverable() {
|
||||
bluetoothType.stop();
|
||||
}
|
||||
|
||||
private boolean isWifiConnected() {
|
||||
return !TextUtils.isEmpty(FDroidApp.ssid);
|
||||
}
|
||||
|
||||
public boolean isBonjourDiscoverable() {
|
||||
return isWifiConnected() && isEnabled();
|
||||
}
|
||||
|
||||
public void ensureBonjourDiscoverable() {
|
||||
if (!isBonjourDiscoverable()) {
|
||||
// TODO: Enable bonjour (currently it is enabled by default when the service starts)
|
||||
}
|
||||
}
|
||||
|
||||
public void makeBonjourNotDiscoverable() {
|
||||
// TODO: Disable bonjour (currently it is enabled by default when the service starts)
|
||||
}
|
||||
|
||||
public boolean isScanningForPeers() {
|
||||
return bonjourFinder.isScanning() || bluetoothFinder.isScanning();
|
||||
}
|
||||
|
||||
public static final String ACTION_PEER_FOUND = "org.fdroid.fdroid.SwapManager.ACTION_PEER_FOUND";
|
||||
public static final String EXTRA_PEER = "EXTRA_PEER";
|
||||
|
||||
|
||||
// ===============================================================
|
||||
// Old SwapService stuff being merged into that.
|
||||
// ===============================================================
|
||||
|
||||
public static final String BONJOUR_STATE_CHANGE = "org.fdroid.fdroid.BONJOUR_STATE_CHANGE";
|
||||
public static final String BLUETOOTH_STATE_CHANGE = "org.fdroid.fdroid.BLUETOOTH_STATE_CHANGE";
|
||||
public static final String EXTRA_STARTING = "STARTING";
|
||||
public static final String EXTRA_STARTED = "STARTED";
|
||||
public static final String EXTRA_STOPPED = "STOPPED";
|
||||
|
||||
private static final int NOTIFICATION = 1;
|
||||
|
||||
private final Binder binder = new Binder();
|
||||
private SwapType bonjourType;
|
||||
private SwapType bluetoothType;
|
||||
private SwapType webServerType;
|
||||
|
||||
private BonjourFinder bonjourFinder;
|
||||
private BluetoothFinder bluetoothFinder;
|
||||
|
||||
private final static int TIMEOUT = 900000; // 15 mins
|
||||
|
||||
/**
|
||||
* Used to automatically turn of swapping after a defined amount of time (15 mins).
|
||||
*/
|
||||
@Nullable
|
||||
private Timer timer;
|
||||
|
||||
public SwapType getBluetooth() {
|
||||
return bluetoothType;
|
||||
}
|
||||
|
||||
public SwapType getBonjour() {
|
||||
return bluetoothType;
|
||||
}
|
||||
|
||||
public class Binder extends android.os.Binder {
|
||||
public SwapService getService() {
|
||||
return SwapService.this;
|
||||
}
|
||||
}
|
||||
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
Log.d(TAG, "Creating swap service.");
|
||||
|
||||
SharedPreferences preferences = getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
|
||||
|
||||
appsToSwap.addAll(deserializePackages(preferences.getString(KEY_APPS_TO_SWAP, "")));
|
||||
bonjourType = new BonjourType(this);
|
||||
bluetoothType = BluetoothType.create(this);
|
||||
webServerType = new WebServerType(this);
|
||||
bonjourFinder = new BonjourFinder(this);
|
||||
bluetoothFinder = new BluetoothFinder(this);
|
||||
|
||||
Preferences.get().registerLocalRepoBonjourListeners(bonjourEnabledListener);
|
||||
Preferences.get().registerLocalRepoHttpsListeners(httpsEnabledListener);
|
||||
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(onWifiChange, new IntentFilter(WifiStateChangeService.BROADCAST));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return binder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
Log.d(TAG, "Destroying service, will disable swapping if required, and unregister listeners.");
|
||||
disableSwapping();
|
||||
Preferences.get().unregisterLocalRepoBonjourListeners(bonjourEnabledListener);
|
||||
Preferences.get().unregisterLocalRepoHttpsListeners(httpsEnabledListener);
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(onWifiChange);
|
||||
}
|
||||
|
||||
private Notification createNotification() {
|
||||
Intent intent = new Intent(this, SwapWorkflowActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
return new NotificationCompat.Builder(this)
|
||||
.setContentTitle(getText(R.string.local_repo_running))
|
||||
.setContentText(getText(R.string.touch_to_configure_local_repo))
|
||||
.setSmallIcon(R.drawable.ic_swap)
|
||||
.setContentIntent(contentIntent)
|
||||
.build();
|
||||
}
|
||||
|
||||
private boolean enabled = false;
|
||||
|
||||
/**
|
||||
* The guts of this class - responsible for enabling the relevant services for swapping.
|
||||
* Doesn't know anything about enabled/disabled state, you should check that before invoking
|
||||
* this method so it doesn't start something that is already started.
|
||||
* Runs asynchronously on several background threads.
|
||||
*/
|
||||
private void enableSwappingAsynchronous() {
|
||||
webServerType.startInBackground();
|
||||
bonjourType.startInBackground();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SwapService#enableSwappingAsynchronous()
|
||||
*/
|
||||
private void disableSwappingSynchronous() {
|
||||
Log.d(TAG, "Disabling SwapService (bonjour, webserver, etc)");
|
||||
bonjourType.stop();
|
||||
webServerType.stop();
|
||||
}
|
||||
|
||||
private void initTimer() {
|
||||
if (timer != null) {
|
||||
Log.d(TAG, "Cancelling existing timer");
|
||||
|
@ -2,14 +2,13 @@ package org.fdroid.fdroid.localrepo.peers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.localrepo.SwapManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
|
||||
/**
|
||||
* Searches for other devices in the vicinity, using specific technologies.
|
||||
* Once found, sends an {@link SwapManager#ACTION_PEER_FOUND} intent with the {@link SwapManager#EXTRA_PEER}
|
||||
* Once found, sends an {@link SwapService#ACTION_PEER_FOUND} intent with the {@link SwapService#EXTRA_PEER}
|
||||
* extra attribute set to the subclass of {@link Peer} that was found.
|
||||
*/
|
||||
public abstract class PeerFinder<T extends Peer> {
|
||||
@ -32,8 +31,8 @@ public abstract class PeerFinder<T extends Peer> {
|
||||
|
||||
protected void foundPeer(T peer) {
|
||||
Log.i(TAG, "Found peer " + peer.getName());
|
||||
Intent intent = new Intent(SwapManager.ACTION_PEER_FOUND);
|
||||
intent.putExtra(SwapManager.EXTRA_PEER, peer);
|
||||
Intent intent = new Intent(SwapService.ACTION_PEER_FOUND);
|
||||
intent.putExtra(SwapService.EXTRA_PEER, peer);
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@ package org.fdroid.fdroid.localrepo.type;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.FDroid;
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
|
@ -1,8 +1,10 @@
|
||||
package org.fdroid.fdroid.net;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
@ -17,7 +19,7 @@ import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.localrepo.LocalRepoKeyStore;
|
||||
import org.fdroid.fdroid.localrepo.LocalRepoManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
@ -159,7 +161,17 @@ public class WifiStateChangeService extends Service {
|
||||
Intent intent = new Intent(BROADCAST);
|
||||
LocalBroadcastManager.getInstance(WifiStateChangeService.this).sendBroadcast(intent);
|
||||
WifiStateChangeService.this.stopSelf();
|
||||
SwapManager.load(WifiStateChangeService.this).restartIfEnabled();
|
||||
|
||||
Intent swapService = new Intent(WifiStateChangeService.this, SwapService.class);
|
||||
bindService(swapService, new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
((SwapService.Binder)service).getService().restartIfEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {}
|
||||
}, BIND_AUTO_CREATE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,18 +5,13 @@ import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.localrepo.SwapManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
|
||||
public class ConfirmReceive extends RelativeLayout implements SwapWorkflowActivity.InnerView {
|
||||
|
||||
@ -41,7 +36,7 @@ public class ConfirmReceive extends RelativeLayout implements SwapWorkflowActivi
|
||||
return (SwapWorkflowActivity)getContext();
|
||||
}
|
||||
|
||||
private SwapManager getManager() {
|
||||
private SwapService getManager() {
|
||||
return getActivity().getState();
|
||||
}
|
||||
|
||||
@ -59,12 +54,12 @@ public class ConfirmReceive extends RelativeLayout implements SwapWorkflowActivi
|
||||
|
||||
@Override
|
||||
public int getStep() {
|
||||
return SwapManager.STEP_CONFIRM_SWAP;
|
||||
return SwapService.STEP_CONFIRM_SWAP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousStep() {
|
||||
return SwapManager.STEP_INTRO;
|
||||
return SwapService.STEP_INTRO;
|
||||
}
|
||||
|
||||
@ColorRes
|
||||
|
@ -1,12 +1,15 @@
|
||||
package org.fdroid.fdroid.views.swap;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.net.Uri;
|
||||
import android.net.http.AndroidHttpClient;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.util.Log;
|
||||
@ -27,7 +30,7 @@ import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.NewRepoConfig;
|
||||
import org.fdroid.fdroid.data.Repo;
|
||||
import org.fdroid.fdroid.data.RepoProvider;
|
||||
import org.fdroid.fdroid.localrepo.SwapManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
@ -152,16 +155,39 @@ public class ConnectSwapActivity extends ActionBarActivity implements ProgressLi
|
||||
repo = RepoProvider.Helper.findByUri(this, uri);
|
||||
}
|
||||
|
||||
// Only ask server to swap with us, if we are actually running a local repo service.
|
||||
// It is possible to have a swap initiated without first starting a swap, in which
|
||||
// case swapping back is pointless.
|
||||
if (!newRepoConfig.preventFurtherSwaps() && SwapManager.load(this).isEnabled()) {
|
||||
askServerToSwapWithUs();
|
||||
}
|
||||
attemptSwapBack();
|
||||
|
||||
return repo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only ask server to swap with us, if we are actually running a local repo service.
|
||||
* It is possible to have a swap initiated without first starting a swap, in which
|
||||
* case swapping back is pointless.
|
||||
*/
|
||||
private void attemptSwapBack() {
|
||||
|
||||
if (newRepoConfig.preventFurtherSwaps()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceConnection connection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder binder) {
|
||||
SwapService service = ((SwapService.Binder) binder).getService();
|
||||
if (service.isEnabled()) {
|
||||
askServerToSwapWithUs();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {}
|
||||
};
|
||||
|
||||
Intent intent = new Intent(this, SwapService.class);
|
||||
bindService(intent, connection, BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
private void askServerToSwapWithUs() {
|
||||
if (!newRepoConfig.isValidRepo()) {
|
||||
return;
|
||||
|
@ -0,0 +1,68 @@
|
||||
package org.fdroid.fdroid.views.swap;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
|
||||
public class InitialLoadingView extends RelativeLayout implements SwapWorkflowActivity.InnerView {
|
||||
|
||||
public InitialLoadingView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public InitialLoadingView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public InitialLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public InitialLoadingView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
private SwapWorkflowActivity getActivity() {
|
||||
return (SwapWorkflowActivity)getContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStep() {
|
||||
return SwapService.STEP_INITIAL_LOADING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousStep() {
|
||||
return SwapService.STEP_JOIN_WIFI;
|
||||
}
|
||||
|
||||
@ColorRes
|
||||
public int getToolbarColour() {
|
||||
return getResources().getColor(R.color.swap_blue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolbarTitle() {
|
||||
return getResources().getString(R.string.swap);
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ import android.widget.TextView;
|
||||
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.localrepo.SwapManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
import org.fdroid.fdroid.net.WifiStateChangeService;
|
||||
|
||||
public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity.InnerView {
|
||||
@ -122,12 +122,12 @@ public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity
|
||||
|
||||
@Override
|
||||
public int getStep() {
|
||||
return SwapManager.STEP_JOIN_WIFI;
|
||||
return SwapService.STEP_JOIN_WIFI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousStep() {
|
||||
return SwapManager.STEP_INTRO;
|
||||
return SwapService.STEP_INTRO;
|
||||
}
|
||||
|
||||
@ColorRes
|
||||
|
@ -16,7 +16,7 @@ import android.widget.RelativeLayout;
|
||||
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.localrepo.SwapManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
|
||||
public class NfcView extends RelativeLayout implements SwapWorkflowActivity.InnerView {
|
||||
|
||||
@ -70,12 +70,12 @@ public class NfcView extends RelativeLayout implements SwapWorkflowActivity.Inne
|
||||
|
||||
@Override
|
||||
public int getStep() {
|
||||
return SwapManager.STEP_SHOW_NFC;
|
||||
return SwapService.STEP_SHOW_NFC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousStep() {
|
||||
return SwapManager.STEP_JOIN_WIFI;
|
||||
return SwapService.STEP_JOIN_WIFI;
|
||||
}
|
||||
|
||||
@ColorRes
|
||||
|
@ -36,7 +36,7 @@ import android.widget.TextView;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.data.InstalledAppProvider;
|
||||
import org.fdroid.fdroid.localrepo.SwapManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
|
||||
public class SelectAppsView extends ListView implements
|
||||
SwapWorkflowActivity.InnerView,
|
||||
@ -64,7 +64,7 @@ public class SelectAppsView extends ListView implements
|
||||
return (SwapWorkflowActivity)getContext();
|
||||
}
|
||||
|
||||
private SwapManager getState() {
|
||||
private SwapService getState() {
|
||||
return getActivity().getState();
|
||||
}
|
||||
|
||||
@ -119,12 +119,12 @@ public class SelectAppsView extends ListView implements
|
||||
|
||||
@Override
|
||||
public int getStep() {
|
||||
return SwapManager.STEP_SELECT_APPS;
|
||||
return SwapService.STEP_SELECT_APPS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousStep() {
|
||||
return getState().isConnectingWithPeer() ? SwapManager.STEP_JOIN_WIFI : SwapManager.STEP_INTRO;
|
||||
return getState().isConnectingWithPeer() ? SwapService.STEP_JOIN_WIFI : SwapService.STEP_INTRO;
|
||||
}
|
||||
|
||||
@ColorRes
|
||||
|
@ -6,8 +6,6 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.annotation.NonNull;
|
||||
@ -23,10 +21,8 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.ScrollView;
|
||||
@ -35,7 +31,6 @@ import android.widget.TextView;
|
||||
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.localrepo.SwapManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
import org.fdroid.fdroid.localrepo.peers.Peer;
|
||||
import org.fdroid.fdroid.net.WifiStateChangeService;
|
||||
@ -97,7 +92,7 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In
|
||||
return (SwapWorkflowActivity)getContext();
|
||||
}
|
||||
|
||||
private SwapManager getManager() {
|
||||
private SwapService getManager() {
|
||||
return getActivity().getState();
|
||||
}
|
||||
|
||||
@ -175,7 +170,7 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In
|
||||
getContext().registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Peer peer = intent.getParcelableExtra(SwapManager.EXTRA_PEER);
|
||||
Peer peer = intent.getParcelableExtra(SwapService.EXTRA_PEER);
|
||||
if (adapter.getPosition(peer) >= 0) {
|
||||
Log.d(TAG, "Found peer: " + peer + ", ignoring though, because it is already in our list.");
|
||||
} else {
|
||||
@ -184,7 +179,7 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In
|
||||
uiUpdatePeersInfo();
|
||||
}
|
||||
}
|
||||
}, new IntentFilter(SwapManager.ACTION_PEER_FOUND));
|
||||
}, new IntentFilter(SwapService.ACTION_PEER_FOUND));
|
||||
|
||||
}
|
||||
|
||||
@ -241,12 +236,12 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In
|
||||
if (intent.hasExtra(SwapService.EXTRA_STARTING)) {
|
||||
Log.d(TAG, "Bluetooth service is starting...");
|
||||
bluetoothSwitch.setEnabled(false);
|
||||
bluetoothSwitch.setChecked(true);
|
||||
// bluetoothSwitch.setChecked(true);
|
||||
} else {
|
||||
bluetoothSwitch.setEnabled(true);
|
||||
if (intent.hasExtra(SwapService.EXTRA_STARTED)) {
|
||||
Log.d(TAG, "Bluetooth service has started.");
|
||||
bluetoothSwitch.setChecked(true);
|
||||
// bluetoothSwitch.setChecked(true);
|
||||
} else {
|
||||
Log.d(TAG, "Bluetooth service has stopped.");
|
||||
bluetoothSwitch.setChecked(false);
|
||||
@ -336,7 +331,7 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In
|
||||
|
||||
@Override
|
||||
public int getStep() {
|
||||
return SwapManager.STEP_INTRO;
|
||||
return SwapService.STEP_INTRO;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -345,7 +340,7 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In
|
||||
// if getStep is STEP_INTRO, don't even bother asking for getPreviousStep. But that is a
|
||||
// bit messy. It would be nicer if this was handled using the same mechanism as everything
|
||||
// else.
|
||||
return SwapManager.STEP_INTRO;
|
||||
return SwapService.STEP_INTRO;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -20,7 +20,6 @@ import android.support.v7.widget.SearchView;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
@ -39,7 +38,7 @@ import org.fdroid.fdroid.UpdateService;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
import org.fdroid.fdroid.data.Repo;
|
||||
import org.fdroid.fdroid.localrepo.SwapManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
@ -70,7 +69,7 @@ public class SwapAppsView extends ListView implements
|
||||
return (SwapWorkflowActivity)getContext();
|
||||
}
|
||||
|
||||
private SwapManager getState() {
|
||||
private SwapService getState() {
|
||||
return getActivity().getState();
|
||||
}
|
||||
|
||||
@ -175,12 +174,12 @@ public class SwapAppsView extends ListView implements
|
||||
|
||||
@Override
|
||||
public int getStep() {
|
||||
return SwapManager.STEP_SUCCESS;
|
||||
return SwapService.STEP_SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousStep() {
|
||||
return SwapManager.STEP_INTRO;
|
||||
return SwapService.STEP_INTRO;
|
||||
}
|
||||
|
||||
@ColorRes
|
||||
|
@ -5,28 +5,19 @@ import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.ProgressListener;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.UpdateService;
|
||||
import org.fdroid.fdroid.localrepo.SwapManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
import org.fdroid.fdroid.localrepo.peers.Peer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity.InnerView {
|
||||
|
||||
private final static String TAG = "SwapConnecting";
|
||||
@ -52,7 +43,7 @@ public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity
|
||||
return (SwapWorkflowActivity)getContext();
|
||||
}
|
||||
|
||||
private SwapManager getManager() {
|
||||
private SwapService getManager() {
|
||||
return getActivity().getState();
|
||||
}
|
||||
|
||||
@ -116,12 +107,12 @@ public class SwapConnecting extends LinearLayout implements SwapWorkflowActivity
|
||||
|
||||
@Override
|
||||
public int getStep() {
|
||||
return SwapManager.STEP_CONNECTING;
|
||||
return SwapService.STEP_CONNECTING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousStep() {
|
||||
return SwapManager.STEP_SELECT_APPS;
|
||||
return SwapService.STEP_SELECT_APPS;
|
||||
}
|
||||
|
||||
@ColorRes
|
||||
|
@ -2,14 +2,18 @@ package org.fdroid.fdroid.views.swap;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
@ -31,7 +35,7 @@ import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.NewRepoConfig;
|
||||
import org.fdroid.fdroid.localrepo.LocalRepoManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
import org.fdroid.fdroid.localrepo.peers.Peer;
|
||||
|
||||
import java.util.Arrays;
|
||||
@ -45,7 +49,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
/**
|
||||
* A UI component (subclass of {@link View}) which forms part of the swap workflow.
|
||||
* There is a one to one mapping between an {@link org.fdroid.fdroid.views.swap.SwapWorkflowActivity.InnerView}
|
||||
* and a {@link org.fdroid.fdroid.localrepo.SwapManager.SwapStep}, and these views know what
|
||||
* and a {@link SwapService.SwapStep}, and these views know what
|
||||
* the previous view before them should be.
|
||||
*/
|
||||
public interface InnerView {
|
||||
@ -53,9 +57,9 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
boolean buildMenu(Menu menu, @NonNull MenuInflater inflater);
|
||||
|
||||
/** @return The step that this view represents. */
|
||||
@SwapManager.SwapStep int getStep();
|
||||
@SwapService.SwapStep int getStep();
|
||||
|
||||
@SwapManager.SwapStep int getPreviousStep();
|
||||
@SwapService.SwapStep int getPreviousStep();
|
||||
|
||||
@ColorRes int getToolbarColour();
|
||||
|
||||
@ -66,18 +70,57 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
private static final int CONNECT_TO_SWAP = 1;
|
||||
|
||||
private Toolbar toolbar;
|
||||
private SwapManager state;
|
||||
private InnerView currentView;
|
||||
private boolean hasPreparedLocalRepo = false;
|
||||
private PrepareSwapRepo updateSwappableAppsTask = null;
|
||||
|
||||
@Nullable
|
||||
private SwapService service = null;
|
||||
|
||||
@NonNull
|
||||
public SwapService getService() {
|
||||
if (service == null) {
|
||||
// *Slightly* more informative than a null-pointer error that would otherwise happen.
|
||||
throw new IllegalStateException("Trying to access swap service before it was initialized.");
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
private void setupService() {
|
||||
|
||||
ServiceConnection serviceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName className, IBinder binder) {
|
||||
Log.d(TAG, "Swap service connected, enabling SwapManager to communicate with SwapService.");
|
||||
service = ((SwapService.Binder)binder).getService();
|
||||
showRelevantView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
Log.d(TAG, "Swap service disconnected");
|
||||
service = null;
|
||||
// TODO: What to do about the UI in this instance?
|
||||
}
|
||||
};
|
||||
|
||||
// The server should not be doing anything or occupying any (noticeable) resources
|
||||
// until we actually ask it to enable swapping. Therefore, we will start it nice and
|
||||
// early so we don't have to wait until it is connected later.
|
||||
Intent service = new Intent(this, SwapService.class);
|
||||
if (bindService(service, serviceConnection, Context.BIND_AUTO_CREATE)) {
|
||||
startService(service);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (currentView.getStep() == SwapManager.STEP_INTRO) {
|
||||
if (currentView.getStep() == SwapService.STEP_INTRO) {
|
||||
finish();
|
||||
} else {
|
||||
int nextStep = currentView.getPreviousStep();
|
||||
state.setStep(nextStep);
|
||||
getService().setStep(nextStep);
|
||||
showRelevantView();
|
||||
}
|
||||
}
|
||||
@ -85,7 +128,9 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
state = SwapManager.load(this);
|
||||
|
||||
setupService();
|
||||
|
||||
setContentView(R.layout.swap_activity);
|
||||
|
||||
toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
@ -93,14 +138,13 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
container = (ViewGroup) findViewById(R.id.fragment_container);
|
||||
showRelevantView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
menu.clear();
|
||||
boolean parent = super.onPrepareOptionsMenu(menu);
|
||||
boolean inner = currentView.buildMenu(menu, getMenuInflater());
|
||||
boolean inner = currentView != null && currentView.buildMenu(menu, getMenuInflater());
|
||||
return parent || inner;
|
||||
}
|
||||
|
||||
@ -111,32 +155,38 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void showRelevantView() {
|
||||
if (currentView != null && currentView.getStep() == state.getStep()) {
|
||||
// Already showing the currect step, so don't bother changing anything.
|
||||
|
||||
if (service == null) {
|
||||
showInitialLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
switch(state.getStep()) {
|
||||
case SwapManager.STEP_INTRO:
|
||||
if (container.getVisibility() == View.GONE || currentView != null && currentView.getStep() == service.getStep()) {
|
||||
// Already showing the correct step, so don't bother changing anything.
|
||||
return;
|
||||
}
|
||||
|
||||
switch(service.getStep()) {
|
||||
case SwapService.STEP_INTRO:
|
||||
showIntro();
|
||||
break;
|
||||
case SwapManager.STEP_SELECT_APPS:
|
||||
case SwapService.STEP_SELECT_APPS:
|
||||
showSelectApps();
|
||||
break;
|
||||
case SwapManager.STEP_SHOW_NFC:
|
||||
case SwapService.STEP_SHOW_NFC:
|
||||
showNfc();
|
||||
break;
|
||||
case SwapManager.STEP_JOIN_WIFI:
|
||||
case SwapService.STEP_JOIN_WIFI:
|
||||
showJoinWifi();
|
||||
break;
|
||||
case SwapManager.STEP_WIFI_QR:
|
||||
case SwapService.STEP_WIFI_QR:
|
||||
showWifiQr();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public SwapManager getState() {
|
||||
return state;
|
||||
public SwapService getState() {
|
||||
return service;
|
||||
}
|
||||
|
||||
private void showNfc() {
|
||||
@ -149,7 +199,16 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
container.removeAllViews();
|
||||
View view = ((LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE)).inflate(viewRes, container, false);
|
||||
currentView = (InnerView)view;
|
||||
state.setStep(currentView.getStep());
|
||||
|
||||
// Don't actually set the step to STEP_INITIAL_LOADING, as we are going to use this view
|
||||
// purely as a placeholder for _whatever view is meant to be shown_.
|
||||
if (currentView.getStep() != SwapService.STEP_INITIAL_LOADING) {
|
||||
if (service == null) {
|
||||
throw new IllegalStateException("We are not in the STEP_INITIAL_LOADING state, but the service is not ready.");
|
||||
}
|
||||
service.setStep(currentView.getStep());
|
||||
}
|
||||
|
||||
toolbar.setBackgroundColor(currentView.getToolbarColour());
|
||||
toolbar.setTitle(currentView.getToolbarTitle());
|
||||
toolbar.setNavigationIcon(R.drawable.ic_close_white);
|
||||
@ -164,15 +223,19 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void onToolbarCancel() {
|
||||
SwapManager.load(this).disableSwapping();
|
||||
getService().disableSwapping();
|
||||
finish();
|
||||
}
|
||||
|
||||
private void showInitialLoading() {
|
||||
inflateInnerView(R.layout.swap_initial_loading);
|
||||
}
|
||||
|
||||
private void showIntro() {
|
||||
if (!state.isEnabled()) {
|
||||
if (!getService().isEnabled()) {
|
||||
prepareInitialRepo();
|
||||
}
|
||||
SwapManager.load(this).scanForPeers();
|
||||
getService().scanForPeers();
|
||||
inflateInnerView(R.layout.swap_blank);
|
||||
}
|
||||
|
||||
@ -190,7 +253,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
// Otherwise, probably will need to scan the file system.
|
||||
public void onAppsSelected() {
|
||||
if (updateSwappableAppsTask == null && !hasPreparedLocalRepo) {
|
||||
updateSwappableAppsTask = new PrepareFullSwapRepo(state.getAppsToSwap());
|
||||
updateSwappableAppsTask = new PrepareFullSwapRepo(getService().getAppsToSwap());
|
||||
updateSwappableAppsTask.execute();
|
||||
} else if (!attemptToShowNfc()) {
|
||||
showWifiQr();
|
||||
@ -218,11 +281,11 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
private void onLocalRepoPrepared() {
|
||||
updateSwappableAppsTask = null;
|
||||
hasPreparedLocalRepo = true;
|
||||
if (state.isConnectingWithPeer()) {
|
||||
if (getService().isConnectingWithPeer()) {
|
||||
startSwappingWithPeer();
|
||||
} else if (!attemptToShowNfc()) {
|
||||
showWifiQr();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void startSwappingWithPeer() {
|
||||
@ -263,7 +326,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
public void swapWith(Peer peer) {
|
||||
state.swapWith(peer);
|
||||
getService().swapWith(peer);
|
||||
showSelectApps();
|
||||
}
|
||||
|
||||
@ -291,7 +354,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
state.enableSwapping();
|
||||
getService().enableSwapping();
|
||||
super.onPreExecute();
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.QrGenAsyncTask;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.localrepo.SwapManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
import org.fdroid.fdroid.net.WifiStateChangeService;
|
||||
|
||||
import java.net.URI;
|
||||
@ -114,13 +114,13 @@ public class WifiQrView extends ScrollView implements SwapWorkflowActivity.Inner
|
||||
|
||||
@Override
|
||||
public int getStep() {
|
||||
return SwapManager.STEP_WIFI_QR;
|
||||
return SwapService.STEP_WIFI_QR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousStep() {
|
||||
// TODO: Find a way to make this optionally go back to the NFC screen if appropriate.
|
||||
return SwapManager.STEP_JOIN_WIFI;
|
||||
return SwapService.STEP_JOIN_WIFI;
|
||||
}
|
||||
|
||||
@ColorRes
|
||||
|
Loading…
x
Reference in New Issue
Block a user