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(); +}