Loading android/ArtiToyVPN/app/src/main/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ package="org.torproject.artitoyvpn"> <application android:name=".ArtiToyVPNApp" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" Loading android/ArtiToyVPN/app/src/main/java/org/torproject/artitoyvpn/ArtiToyVPNApp.java 0 → 100644 +15 −0 Original line number Diff line number Diff line package org.torproject.artitoyvpn; import android.app.Application; import org.torproject.artitoyvpn.vpn.VpnStatusObservable; public class ArtiToyVPNApp extends Application { VpnStatusObservable vpnStatusObservable; @Override public void onCreate() { super.onCreate(); vpnStatusObservable = VpnStatusObservable.getInstance(); } } android/ArtiToyVPN/app/src/main/java/org/torproject/artitoyvpn/ui/home/HomeFragment.java +32 −3 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import androidx.annotation.NonNull; Loading @@ -14,6 +15,12 @@ import androidx.lifecycle.ViewModelProvider; import org.torproject.artitoyvpn.R; import org.torproject.artitoyvpn.databinding.FragmentHomeBinding; import org.torproject.artitoyvpn.utils.Utils; import org.torproject.artitoyvpn.vpn.VpnStatusObservable; import org.torproject.artitoyvpn.vpn.VpnStatusObservable.Status; import java.util.Timer; import java.util.TimerTask; public class HomeFragment extends Fragment { Loading @@ -29,15 +36,37 @@ public class HomeFragment extends Fragment { View root = binding.getRoot(); final TextView textView = binding.textVpnState; homeViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() { homeViewModel.getText().observe(getViewLifecycleOwner(), s -> textView.setText(s)); final Button vpnButton = binding.buttonMain; VpnStatusObservable.getStatus().observe(getViewLifecycleOwner(), status -> homeViewModel.update(status, getContext())); homeViewModel.getButtonText().observe(getViewLifecycleOwner(), text -> vpnButton.setText(text)); homeViewModel.isButtonEnabled().observe(getViewLifecycleOwner(), enabled -> vpnButton.setEnabled(enabled)); vpnButton.setOnClickListener(new View.OnClickListener() { @Override public void onChanged(@Nullable String s) { textView.setText(s); public void onClick(View view) { // TODO: start/stop VPN here Status status = VpnStatusObservable.getStatus().getValue(); if (status == Status.RUNNING) { VpnStatusObservable.update(Status.STOPPING); Utils.runWithDelay(1000, () -> VpnStatusObservable.update(Status.STOPPED)); } else if (status == Status.STOPPED) { VpnStatusObservable.update(Status.STARTING); Utils.runWithDelay(1000, () -> VpnStatusObservable.update(Status.RUNNING)); } } }); return root; } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); homeViewModel.stateText.setValue(getContext().getString(R.string.state_description_off)); homeViewModel.buttonText.setValue(getContext().getString(R.string.start)); } @Override public void onDestroyView() { super.onDestroyView(); Loading android/ArtiToyVPN/app/src/main/java/org/torproject/artitoyvpn/ui/home/HomeViewModel.java +52 −4 Original line number Diff line number Diff line package org.torproject.artitoyvpn.ui.home; import android.content.Context; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; import org.torproject.artitoyvpn.R; import org.torproject.artitoyvpn.vpn.VpnStatusObservable; public class HomeViewModel extends ViewModel { private MutableLiveData<String> mText; final MutableLiveData<String> stateText; final MutableLiveData<String> buttonText; final MutableLiveData<Boolean> isButtonEnabled; public HomeViewModel() { mText = new MutableLiveData<>(); mText.setValue("This is the home fragment"); super(); stateText = new MutableLiveData<>(); buttonText = new MutableLiveData<>(); isButtonEnabled = new MutableLiveData<>(); } public LiveData<String> getText() { return mText; return stateText; } public LiveData<String> getButtonText() { return buttonText; } public LiveData<Boolean> isButtonEnabled() { return isButtonEnabled; } public void update(VpnStatusObservable.Status status, Context context) { switch (status) { case STARTING: stateText.postValue(context.getString(R.string.state_description_starting)); buttonText.postValue(context.getString(R.string.stop)); isButtonEnabled.postValue(false); break; case RUNNING: stateText.postValue(context.getString(R.string.state_description_running)); buttonText.postValue(context.getString(R.string.stop)); isButtonEnabled.postValue(true); break; case STOPPING: stateText.postValue(context.getString(R.string.state_description_stopping)); buttonText.postValue(context.getString(R.string.stop)); isButtonEnabled.postValue(false); break; case STOPPED: stateText.postValue(context.getString(R.string.state_description_off)); buttonText.postValue(context.getString(R.string.start)); isButtonEnabled.postValue(true); break; case ERROR: stateText.postValue(context.getString(R.string.state_description_error)); buttonText.postValue(context.getString(R.string.stop)); isButtonEnabled.postValue(true); break; } } } No newline at end of file android/ArtiToyVPN/app/src/main/java/org/torproject/artitoyvpn/utils/Utils.java 0 → 100644 +22 −0 Original line number Diff line number Diff line package org.torproject.artitoyvpn.utils; import android.os.Looper; import java.util.Timer; import java.util.TimerTask; public class Utils { public static boolean isRunningOnMainThread() { return Looper.getMainLooper().getThread() == Thread.currentThread(); } public static void runWithDelay(long delay, Runnable runnable) { new Timer().schedule(new TimerTask() { @Override public void run() { runnable.run(); } }, delay); } } Loading
android/ArtiToyVPN/app/src/main/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ package="org.torproject.artitoyvpn"> <application android:name=".ArtiToyVPNApp" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" Loading
android/ArtiToyVPN/app/src/main/java/org/torproject/artitoyvpn/ArtiToyVPNApp.java 0 → 100644 +15 −0 Original line number Diff line number Diff line package org.torproject.artitoyvpn; import android.app.Application; import org.torproject.artitoyvpn.vpn.VpnStatusObservable; public class ArtiToyVPNApp extends Application { VpnStatusObservable vpnStatusObservable; @Override public void onCreate() { super.onCreate(); vpnStatusObservable = VpnStatusObservable.getInstance(); } }
android/ArtiToyVPN/app/src/main/java/org/torproject/artitoyvpn/ui/home/HomeFragment.java +32 −3 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import androidx.annotation.NonNull; Loading @@ -14,6 +15,12 @@ import androidx.lifecycle.ViewModelProvider; import org.torproject.artitoyvpn.R; import org.torproject.artitoyvpn.databinding.FragmentHomeBinding; import org.torproject.artitoyvpn.utils.Utils; import org.torproject.artitoyvpn.vpn.VpnStatusObservable; import org.torproject.artitoyvpn.vpn.VpnStatusObservable.Status; import java.util.Timer; import java.util.TimerTask; public class HomeFragment extends Fragment { Loading @@ -29,15 +36,37 @@ public class HomeFragment extends Fragment { View root = binding.getRoot(); final TextView textView = binding.textVpnState; homeViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() { homeViewModel.getText().observe(getViewLifecycleOwner(), s -> textView.setText(s)); final Button vpnButton = binding.buttonMain; VpnStatusObservable.getStatus().observe(getViewLifecycleOwner(), status -> homeViewModel.update(status, getContext())); homeViewModel.getButtonText().observe(getViewLifecycleOwner(), text -> vpnButton.setText(text)); homeViewModel.isButtonEnabled().observe(getViewLifecycleOwner(), enabled -> vpnButton.setEnabled(enabled)); vpnButton.setOnClickListener(new View.OnClickListener() { @Override public void onChanged(@Nullable String s) { textView.setText(s); public void onClick(View view) { // TODO: start/stop VPN here Status status = VpnStatusObservable.getStatus().getValue(); if (status == Status.RUNNING) { VpnStatusObservable.update(Status.STOPPING); Utils.runWithDelay(1000, () -> VpnStatusObservable.update(Status.STOPPED)); } else if (status == Status.STOPPED) { VpnStatusObservable.update(Status.STARTING); Utils.runWithDelay(1000, () -> VpnStatusObservable.update(Status.RUNNING)); } } }); return root; } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); homeViewModel.stateText.setValue(getContext().getString(R.string.state_description_off)); homeViewModel.buttonText.setValue(getContext().getString(R.string.start)); } @Override public void onDestroyView() { super.onDestroyView(); Loading
android/ArtiToyVPN/app/src/main/java/org/torproject/artitoyvpn/ui/home/HomeViewModel.java +52 −4 Original line number Diff line number Diff line package org.torproject.artitoyvpn.ui.home; import android.content.Context; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; import org.torproject.artitoyvpn.R; import org.torproject.artitoyvpn.vpn.VpnStatusObservable; public class HomeViewModel extends ViewModel { private MutableLiveData<String> mText; final MutableLiveData<String> stateText; final MutableLiveData<String> buttonText; final MutableLiveData<Boolean> isButtonEnabled; public HomeViewModel() { mText = new MutableLiveData<>(); mText.setValue("This is the home fragment"); super(); stateText = new MutableLiveData<>(); buttonText = new MutableLiveData<>(); isButtonEnabled = new MutableLiveData<>(); } public LiveData<String> getText() { return mText; return stateText; } public LiveData<String> getButtonText() { return buttonText; } public LiveData<Boolean> isButtonEnabled() { return isButtonEnabled; } public void update(VpnStatusObservable.Status status, Context context) { switch (status) { case STARTING: stateText.postValue(context.getString(R.string.state_description_starting)); buttonText.postValue(context.getString(R.string.stop)); isButtonEnabled.postValue(false); break; case RUNNING: stateText.postValue(context.getString(R.string.state_description_running)); buttonText.postValue(context.getString(R.string.stop)); isButtonEnabled.postValue(true); break; case STOPPING: stateText.postValue(context.getString(R.string.state_description_stopping)); buttonText.postValue(context.getString(R.string.stop)); isButtonEnabled.postValue(false); break; case STOPPED: stateText.postValue(context.getString(R.string.state_description_off)); buttonText.postValue(context.getString(R.string.start)); isButtonEnabled.postValue(true); break; case ERROR: stateText.postValue(context.getString(R.string.state_description_error)); buttonText.postValue(context.getString(R.string.stop)); isButtonEnabled.postValue(true); break; } } } No newline at end of file
android/ArtiToyVPN/app/src/main/java/org/torproject/artitoyvpn/utils/Utils.java 0 → 100644 +22 −0 Original line number Diff line number Diff line package org.torproject.artitoyvpn.utils; import android.os.Looper; import java.util.Timer; import java.util.TimerTask; public class Utils { public static boolean isRunningOnMainThread() { return Looper.getMainLooper().getThread() == Thread.currentThread(); } public static void runWithDelay(long delay, Runnable runnable) { new Timer().schedule(new TimerTask() { @Override public void run() { runnable.run(); } }, delay); } }