diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 82186447..02a8b7fa 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -16,6 +16,10 @@
+
+
diff --git a/app/src/main/java/com/wireguard/android/ProfileListActivity.java b/app/src/main/java/com/wireguard/android/ProfileListActivity.java
index afa8a123..9094efaf 100644
--- a/app/src/main/java/com/wireguard/android/ProfileListActivity.java
+++ b/app/src/main/java/com/wireguard/android/ProfileListActivity.java
@@ -1,64 +1,57 @@
package com.wireguard.android;
import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
import android.databinding.DataBindingUtil;
-import android.databinding.ObservableArrayList;
-import android.databinding.ObservableList;
-import android.os.AsyncTask;
import android.os.Bundle;
-import android.util.Log;
+import android.os.IBinder;
import com.wireguard.android.databinding.ProfileListActivityBinding;
-import com.wireguard.config.Profile;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
public class ProfileListActivity extends Activity {
- private final ObservableList profiles = new ObservableArrayList<>();
+ private final ServiceConnection connection = new ProfileServiceConnection();
+ private ProfileListActivityBinding binding;
+ private ProfileServiceInterface service;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- final ProfileListActivityBinding binding =
- DataBindingUtil.setContentView(this, R.layout.profile_list_activity);
- binding.setProfiles(profiles);
- new ProfileLoader().execute(getFilesDir().listFiles());
+ binding = DataBindingUtil.setContentView(this, R.layout.profile_list_activity);
+ // Ensure the long-running service is started. This only needs to happen once.
+ Intent intent = new Intent(this, ProfileService.class);
+ startService(intent);
}
- private class ProfileLoader extends AsyncTask> {
- private static final String TAG = "WGProfileLoader";
+ @Override
+ public void onStart() {
+ super.onStart();
+ Intent intent = new Intent(this, ProfileService.class);
+ bindService(intent, connection, Context.BIND_AUTO_CREATE);
+ }
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (service != null) {
+ unbindService(connection);
+ service = null;
+ }
+ }
+
+ private class ProfileServiceConnection implements ServiceConnection {
@Override
- protected ArrayList doInBackground(File... files) {
- final ArrayList loadedProfiles = new ArrayList<>();
- for (File file : files) {
- final String fileName = file.getName();
- final int suffixStart = fileName.lastIndexOf(".conf");
- if (suffixStart <= 0) {
- Log.w(TAG, "Ignoring stray file " + fileName);
- continue;
- }
- final Profile profile = new Profile(fileName.substring(0, suffixStart));
- try {
- final FileInputStream inputStream = openFileInput(fileName);
- profile.fromStream(inputStream);
- loadedProfiles.add(profile);
- } catch (IOException e) {
- Log.w(TAG, "Failed to load profile from " + fileName, e);
- }
- if (isCancelled())
- break;
- }
- return loadedProfiles;
+ public void onServiceConnected(ComponentName component, IBinder binder) {
+ service = (ProfileServiceInterface) binder;
+ binding.setProfiles(service.getProfiles());
}
@Override
- protected void onPostExecute(ArrayList loadedProfiles) {
- // FIXME: This should replace an existing profile if the name matches.
- profiles.addAll(loadedProfiles);
+ public void onServiceDisconnected(ComponentName component) {
+ // This function is only called when the service crashes or goes away unexpectedly.
+ service = null;
}
}
}
diff --git a/app/src/main/java/com/wireguard/android/ProfileService.java b/app/src/main/java/com/wireguard/android/ProfileService.java
new file mode 100644
index 00000000..172f230c
--- /dev/null
+++ b/app/src/main/java/com/wireguard/android/ProfileService.java
@@ -0,0 +1,75 @@
+package com.wireguard.android;
+
+import android.app.Service;
+import android.content.Intent;
+import android.databinding.ObservableArrayList;
+import android.databinding.ObservableList;
+import android.os.AsyncTask;
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.wireguard.config.Profile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Service that handles profile state coordination and all background processing for the app.
+ */
+
+public class ProfileService extends Service {
+ private static final String TAG = "ProfileService";
+
+ private final IBinder binder = new ProfileServiceBinder();
+ private final ObservableList profiles = new ObservableArrayList<>();
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return binder;
+ }
+
+ @Override
+ public void onCreate() {
+ new ProfileLoader().execute(getFilesDir().listFiles());
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ return START_STICKY;
+ }
+
+ private class ProfileLoader extends AsyncTask> {
+ @Override
+ protected List doInBackground(File... files) {
+ final List loadedProfiles = new LinkedList<>();
+ for (File file : files) {
+ final String fileName = file.getName();
+ final String profileName = fileName.substring(0, fileName.length() - 5);
+ final Profile profile = new Profile(profileName);
+ try {
+ profile.parseFrom(openFileInput(fileName));
+ loadedProfiles.add(profile);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to load profile from " + fileName, e);
+ }
+ if (isCancelled())
+ break;
+ }
+ return loadedProfiles;
+ }
+
+ @Override
+ protected void onPostExecute(List loadedProfiles) {
+ profiles.addAll(loadedProfiles);
+ }
+ }
+
+ private class ProfileServiceBinder extends Binder implements ProfileServiceInterface {
+ public ObservableList getProfiles() {
+ return profiles;
+ }
+ }
+}
diff --git a/app/src/main/java/com/wireguard/android/ProfileServiceInterface.java b/app/src/main/java/com/wireguard/android/ProfileServiceInterface.java
new file mode 100644
index 00000000..6eb310ad
--- /dev/null
+++ b/app/src/main/java/com/wireguard/android/ProfileServiceInterface.java
@@ -0,0 +1,13 @@
+package com.wireguard.android;
+
+import android.databinding.ObservableList;
+
+import com.wireguard.config.Profile;
+
+/**
+ * Interface for the background connection service.
+ */
+
+public interface ProfileServiceInterface {
+ ObservableList getProfiles();
+}