├── .github └── workflows │ └── check.yaml ├── .gitignore ├── .gitmodules ├── CHANGES.md ├── COPYING ├── NEW_RELEASE.md ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── nl │ │ └── eduvpn │ │ └── app │ │ ├── BaseRobot.kt │ │ ├── EspressoExtensions.kt │ │ ├── UnitTestSuite.java │ │ ├── WaitUntilGoneAction.kt │ │ ├── service │ │ ├── HistoryServiceTest.kt │ │ ├── PreferencesServiceTest.kt │ │ └── SerializerServiceTest.java │ │ ├── ui_test │ │ ├── BrowserTest.kt │ │ ├── ConnectVpnTest.kt │ │ ├── ConnectionLogTest.kt │ │ ├── InstituteAccessDemoTest.kt │ │ └── ProviderSearchTest.kt │ │ └── utils │ │ ├── FormattingUtilsTest.java │ │ └── ParcelableTest.kt │ ├── dev │ └── res │ │ └── values │ │ ├── colors.xml │ │ └── strings.xml │ ├── gov │ └── res │ │ ├── drawable-hdpi │ │ └── logo_black.png │ │ ├── drawable-mdpi │ │ └── logo_black.png │ │ ├── drawable-xhdpi │ │ └── logo_black.png │ │ ├── drawable-xxhdpi │ │ └── logo_black.png │ │ ├── drawable-xxxhdpi │ │ └── logo_black.png │ │ ├── drawable │ │ └── ic_application_logo.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_round.webp │ │ └── values │ │ ├── colors.xml │ │ ├── ic_launcher_background.xml │ │ └── strings.xml │ ├── home │ └── res │ │ ├── drawable-hdpi │ │ └── logo_black.png │ │ ├── drawable-mdpi │ │ └── logo_black.png │ │ ├── drawable-xhdpi │ │ └── logo_black.png │ │ ├── drawable-xxhdpi │ │ └── logo_black.png │ │ ├── drawable │ │ ├── ic_application_logo.xml │ │ └── ic_launcher_foreground.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ └── ic_launcher_round.png │ │ ├── values-de │ │ └── strings.xml │ │ ├── values-es │ │ └── strings.xml │ │ └── values │ │ ├── colors.xml │ │ └── strings.xml │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── licenses.html │ ├── java │ └── nl │ │ └── eduvpn │ │ └── app │ │ ├── ApiLogsActivity.kt │ │ ├── CertExpiredBroadcastReceiver.kt │ │ ├── Constants.kt │ │ ├── DisconnectVPNBroadcastReceiver.kt │ │ ├── EduVPNApplication.java │ │ ├── LicenseActivity.kt │ │ ├── MainActivity.kt │ │ ├── OpenVpnLogsActivity.kt │ │ ├── SettingsActivity.kt │ │ ├── adapter │ │ ├── OrganizationAdapter.kt │ │ ├── ProfileAdapter.kt │ │ └── viewholder │ │ │ ├── OrganizationViewHolder.kt │ │ │ └── ProfileViewHolder.kt │ │ ├── base │ │ ├── BaseActivity.kt │ │ └── BaseFragment.kt │ │ ├── entity │ │ ├── AddedServers.kt │ │ ├── AuthorizationType.kt │ │ ├── CertExpiryTimes.kt │ │ ├── CookieAndProfileMapData.kt │ │ ├── CookieAndStringData.kt │ │ ├── CurrentServer.kt │ │ ├── Instance.kt │ │ ├── Organization.kt │ │ ├── OrganizationList.kt │ │ ├── Profile.kt │ │ ├── SerializedVpnConfig.kt │ │ ├── ServerList.kt │ │ ├── TranslatableString.kt │ │ ├── VPNConfig.kt │ │ └── exception │ │ │ ├── CommonException.kt │ │ │ ├── EduVPNException.kt │ │ │ └── ExceptionMessage.kt │ │ ├── fragment │ │ ├── AddServerFragment.kt │ │ ├── ConnectionStatusFragment.kt │ │ ├── OrganizationSelectionFragment.kt │ │ ├── ProfileSelectionFragment.kt │ │ ├── ServerSelectionFragment.kt │ │ └── SettingsFragment.kt │ │ ├── inject │ │ ├── ApplicationModule.kt │ │ ├── EduVPNComponent.kt │ │ ├── ViewModelKey.kt │ │ └── ViewModelModule.kt │ │ ├── livedata │ │ ├── ByteCount.kt │ │ ├── ConnectionTimeLiveData.kt │ │ ├── IPs.kt │ │ ├── LiveEvent.kt │ │ ├── UnlessDisconnectedLiveData.kt │ │ └── openvpn │ │ │ ├── ByteCountLiveData.kt │ │ │ └── IPLiveData.kt │ │ ├── service │ │ ├── BackendService.kt │ │ ├── EduVPNOpenVPNService.java │ │ ├── HistoryService.kt │ │ ├── OrganizationService.kt │ │ ├── PreferencesService.kt │ │ ├── SerializerService.kt │ │ ├── VPNConnectionService.kt │ │ ├── VPNService.kt │ │ └── WireGuardService.kt │ │ ├── utils │ │ ├── BindingAdapters.kt │ │ ├── ErrorDialog.kt │ │ ├── FormattingUtils.kt │ │ ├── GeneralExtensions.kt │ │ ├── ItemClickSupport.kt │ │ ├── Listener.kt │ │ ├── LiveEvent.kt │ │ ├── Log.java │ │ ├── WireGuardTunnel.kt │ │ └── serializer │ │ │ ├── DateSerializer.kt │ │ │ └── TranslatableStringSerializer.kt │ │ └── viewmodel │ │ ├── AddServerViewModel.kt │ │ ├── ApiLogsViewModel.kt │ │ ├── BaseConnectionViewModel.kt │ │ ├── ConnectionState.kt │ │ ├── ConnectionStatusViewModel.kt │ │ ├── MainViewModel.kt │ │ ├── OrganizationSelectionViewModel.kt │ │ ├── ProfileSelectionViewModel.kt │ │ ├── ServerSelectionViewModel.kt │ │ ├── SettingsViewModel.kt │ │ └── ViewModelFactory.kt │ └── res │ ├── anim │ ├── fade_in.xml │ ├── fade_out.xml │ ├── progress_indeterminate_horizontal_rect1.xml │ └── progress_indeterminate_horizontal_rect2.xml │ ├── color │ └── bg_big_button.xml │ ├── drawable-hdpi │ └── logo_black.png │ ├── drawable-mdpi │ └── logo_black.png │ ├── drawable-xhdpi │ └── logo_black.png │ ├── drawable-xxhdpi │ ├── external_provider.png │ ├── icon_shield_access_white_full.png │ ├── icon_shield_internet_white_full.png │ ├── logo_black.png │ ├── maintenance_icon.png │ └── surfnet_logo.png │ ├── drawable │ ├── access_type_bg.xml │ ├── bg_progress_indeterminate_layers.xml │ ├── bg_progressbar_indeterminate.xml │ ├── bg_search.xml │ ├── button_bg.xml │ ├── delete_icon.xml │ ├── dialog_background.xml │ ├── dialog_button_bg.xml │ ├── ic_add.xml │ ├── ic_add_server.xml │ ├── ic_application_logo.xml │ ├── ic_arrow_drop_down.xml │ ├── ic_chevron_right.xml │ ├── ic_connection_status_connected.xml │ ├── ic_connection_status_connecting.xml │ ├── ic_connection_status_disconnected.xml │ ├── ic_find_your_institute.xml │ ├── ic_help.xml │ ├── ic_institute.xml │ ├── ic_search.xml │ ├── ic_secure_internet.xml │ ├── ic_server.xml │ ├── ic_settings.xml │ ├── ic_vpn_profile.xml │ ├── ic_warning.xml │ ├── loading_gradient.xml │ ├── scrollbar_thumb.xml │ ├── switch_thumb.xml │ └── switch_track.xml │ ├── font │ ├── open_sans_bold.ttf │ ├── open_sans_bold_italic.ttf │ ├── open_sans_extra_bold.ttf │ ├── open_sans_extra_bold_italic.ttf │ ├── open_sans_italic.ttf │ ├── open_sans_light.ttf │ ├── open_sans_light_italic.ttf │ ├── open_sans_regular.ttf │ ├── open_sans_semibold.ttf │ └── open_sans_semibold_italic.ttf │ ├── interpolator │ ├── progress_indeterminate_horizontal_rect1_scalex.xml │ ├── progress_indeterminate_horizontal_rect1_translatex.xml │ ├── progress_indeterminate_horizontal_rect2_scalex.xml │ └── progress_indeterminate_horizontal_rect2_translatex.xml │ ├── layout │ ├── activity_api_logs.xml │ ├── activity_licenses.xml │ ├── activity_main.xml │ ├── activity_openvpn_logs.xml │ ├── activity_settings.xml │ ├── dialog_error.xml │ ├── fragment_add_server.xml │ ├── fragment_connection_status.xml │ ├── fragment_organization_selection.xml │ ├── fragment_profile_selection.xml │ ├── fragment_provider_selection.xml │ ├── fragment_server_selection.xml │ ├── fragment_settings.xml │ ├── include_loading.xml │ ├── include_toolbar.xml │ ├── list_item_header.xml │ ├── list_item_message.xml │ ├── list_item_profile.xml │ ├── list_item_provider.xml │ └── list_item_server.xml │ ├── menu │ └── logmenu.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ ├── ic_launcher_background.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ ├── ic_launcher_background.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ ├── ic_launcher_background.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_background.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_background.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── values-ca │ ├── content_description.xml │ └── strings.xml │ ├── values-de │ ├── content_description.xml │ └── strings.xml │ ├── values-es │ ├── content_description.xml │ └── strings.xml │ └── values │ ├── attrs.xml │ ├── colors.xml │ ├── content_description.xml │ ├── dimens.xml │ ├── ids.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle.kts ├── build_app_git.sh ├── build_app_tar.sh ├── builder_setup.sh ├── common ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── libs │ └── CMakeLists.txt ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── cpp │ └── jni.cpp │ └── java │ └── org │ └── eduvpn │ └── common │ ├── DataErrorTuple.java │ ├── FailoverResult.java │ ├── GoBackend.java │ ├── Protocol.java │ └── ServerType.java ├── create_release_tar.sh ├── fastlane └── metadata │ └── android │ └── en-US │ ├── changelogs │ ├── 10.txt │ ├── 11.txt │ ├── 12.txt │ ├── 13.txt │ ├── 14.txt │ ├── 15.txt │ ├── 16.txt │ ├── 17.txt │ ├── 18.txt │ ├── 19.txt │ ├── 20.txt │ ├── 21.txt │ ├── 22.txt │ ├── 23.txt │ ├── 24.txt │ ├── 25.txt │ ├── 26.txt │ ├── 27.txt │ ├── 28.txt │ ├── 29.txt │ ├── 30.txt │ ├── 31.txt │ ├── 6.txt │ ├── 7.txt │ └── 9.txt │ ├── full_description.txt │ ├── images │ ├── featureGraphic.png │ ├── icon.png │ └── phoneScreenshots │ │ ├── 010-FirstScreenFirstUse.jpg │ │ ├── 011-FirstScreenNthUse.jpg │ │ ├── 030-ServerSearchResults.jpg │ │ ├── 031-ServerSearchResultsWith2dots.jpg │ │ ├── 040-ConnectingToSecureInternet.jpg │ │ ├── 050-ConnectedToSecureInternet.jpg │ │ ├── 061-ConnectedToInstituteAccess.jpg │ │ ├── 070-NotConnectedToSecureInternet.jpg │ │ ├── 080-ConnectionInfo.jpg │ │ └── 090-Settings.jpg │ ├── short_description.txt │ └── title.txt ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | /.idea 7 | /captures 8 | *.apk 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ics-openvpn"] 2 | path = ics-openvpn 3 | url = https://codeberg.org/eduVPN/ics-openvpn 4 | [submodule "common/libs/eduvpn-common"] 5 | path = common/libs/eduvpn-common 6 | url = https://github.com/eduvpn/eduvpn-common 7 | [submodule "wireguard"] 8 | path = wireguard 9 | url = https://codeberg.org/eduVPN/wireguard-android 10 | -------------------------------------------------------------------------------- /NEW_RELEASE.md: -------------------------------------------------------------------------------- 1 | # Tag a Release 2 | 3 | Walk through the following steps when making a new release: 4 | 5 | * Update `CHANGES.md` to make sure all changes are recorded for the new release 6 | including the release date, e.g.: `3.2.0 (2023-12-22)`; 7 | * Increment the `versionCode` and set `versionName` to the correct version tag 8 | in `app/build.gradle`; 9 | * Copy the entries from the `CHANGES.md` file you made also to 10 | `fastlane/metadata/android/en-US/changelogs/$versionCode.txt`; 11 | * Update the `build_app_git.sh`, `build_app_tar.sh`, `create_release_tar.sh`, 12 | and if necessary `builder_setup.sh`; 13 | * Create an "annotated" tag with e.g. `git tag 3.2.0 -a -m '3.2.0'`; 14 | * Push the tag, e.g.: `git push origin 3.2.0`; 15 | * Create a release with `create_release_tar.sh` and "attach" the `.tar.xz` and 16 | `.tar.xz.minisig` files to the release on the forge 17 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # This will allow us to get the correct file line numbers to the errors 2 | -keepattributes SourceFile,LineNumberTable 3 | 4 | -dontwarn com.google.errorprone.annotations.* 5 | -dontwarn org.bouncycastle.jsse.** 6 | -dontwarn org.conscrypt.* 7 | -dontwarn org.openjsse.javax.net.ssl.* 8 | -dontwarn org.openjsse.net.ssl.* 9 | 10 | -keepclassmembers class com.wireguard.android.backend.GoBackend { 11 | ; 12 | } 13 | -keepclassmembers class com.wireguard.android.backend.GoBackend$GhettoCompletableFuture { 14 | ; 15 | } 16 | -keepclassmembers class android.net.VpnService { 17 | ; 18 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/nl/eduvpn/app/UnitTestSuite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | */ 17 | 18 | package nl.eduvpn.app; 19 | 20 | import nl.eduvpn.app.service.HistoryServiceTest; 21 | import nl.eduvpn.app.service.PreferencesServiceTest; 22 | import nl.eduvpn.app.service.SerializerServiceTest; 23 | import nl.eduvpn.app.utils.FormattingUtilsTest; 24 | 25 | import org.junit.runner.RunWith; 26 | import org.junit.runners.Suite; 27 | 28 | /** 29 | * Suite used to run all unit tests. 30 | * Created by Daniel Zolnai on 2016-10-18. 31 | */ 32 | @RunWith(Suite.class) 33 | @Suite.SuiteClasses({SerializerServiceTest.class, PreferencesServiceTest.class, 34 | HistoryServiceTest.class, FormattingUtilsTest.class}) 35 | public class UnitTestSuite { 36 | // Test suite used to run all unit tests at once. 37 | // To run the tests, right click on the class name, and select "Run 'UnitTestSuite'". 38 | // The tests will run on your device. 39 | } 40 | -------------------------------------------------------------------------------- /app/src/androidTest/java/nl/eduvpn/app/WaitUntilGoneAction.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | * 17 | * Taken from: https://stackoverflow.com/a/63454552/1395437 18 | */ 19 | 20 | package nl.eduvpn.app 21 | 22 | import android.view.View 23 | import androidx.test.espresso.PerformException 24 | import androidx.test.espresso.UiController 25 | import androidx.test.espresso.ViewAction 26 | import androidx.test.espresso.util.HumanReadables 27 | import org.hamcrest.CoreMatchers.any 28 | import org.hamcrest.Matcher 29 | import java.util.concurrent.TimeoutException 30 | 31 | class WaitUntilGoneAction(private val timeout: Long) : ViewAction { 32 | 33 | override fun getConstraints(): Matcher { 34 | return any(View::class.java) 35 | } 36 | 37 | override fun getDescription(): String { 38 | return "wait up to $timeout milliseconds for the view to be gone" 39 | } 40 | 41 | override fun perform(uiController: UiController, view: View) { 42 | 43 | val endTime = System.currentTimeMillis() + timeout 44 | 45 | do { 46 | if (view.visibility == View.GONE) return 47 | uiController.loopMainThreadForAtLeast(50) 48 | } while (System.currentTimeMillis() < endTime) 49 | 50 | throw PerformException.Builder() 51 | .withActionDescription(description) 52 | .withCause(TimeoutException("Waited $timeout milliseconds")) 53 | .withViewDescription(HumanReadables.describe(view)) 54 | .build() 55 | } 56 | } 57 | 58 | /** 59 | * @return a [WaitUntilGoneAction] instance created with the given [timeout] parameter. 60 | */ 61 | fun waitUntilGone(timeout: Long): ViewAction { 62 | return WaitUntilGoneAction(timeout) 63 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/nl/eduvpn/app/ui_test/BrowserTest.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.ui_test 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.uiautomator.UiDevice 5 | import androidx.test.uiautomator.UiObjectNotFoundException 6 | import androidx.test.uiautomator.UiSelector 7 | import nl.eduvpn.app.utils.Log 8 | 9 | abstract class BrowserTest { 10 | 11 | companion object { 12 | private val TAG = BrowserTest::class.java.name 13 | } 14 | fun prepareBrowser() { 15 | // Switch over to UI Automator now, to control the browser 16 | val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) 17 | // Wait for the browser to open and load 18 | Thread.sleep(2_000L) 19 | try { 20 | // Newer Chrome versions ask if you want to log in 21 | val acceptButton = device.findObject(UiSelector().text("Use without an account")) 22 | acceptButton.click() 23 | } catch (ex: UiObjectNotFoundException) { 24 | Log.w(TAG, "No Chrome user account shown, continuing", ex) 25 | } 26 | try { 27 | // Chrome asks at first launch to accept data usage 28 | val acceptButton = device.findObject(UiSelector().className("android.widget.Button").text("Accept & continue")) 29 | acceptButton.click() 30 | } catch (ex: UiObjectNotFoundException) { 31 | Log.w(TAG, "No Chrome accept window shown, continuing", ex) 32 | } 33 | try { 34 | // Do not send all our web traffic to Google 35 | val liteModeToggle = device.findObject(UiSelector().className("android.widget.Switch")) 36 | if(liteModeToggle.isChecked) { 37 | liteModeToggle.click() 38 | } 39 | val nextButton = device.findObject(UiSelector().className("android.widget.Button").text("Next")) 40 | nextButton.click() 41 | } catch (ex: UiObjectNotFoundException) { 42 | Log.w(TAG, "No lite mode window shown, continuing", ex) 43 | } 44 | try { 45 | // Now it wants us to Sign in... 46 | val noThanksButton = device.findObject(UiSelector().text("No thanks")) 47 | noThanksButton.click() 48 | } catch (ex: UiObjectNotFoundException) { 49 | Log.w(TAG, "No request for sign in, continung", ex) 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/nl/eduvpn/app/utils/ParcelableTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | */ 17 | 18 | package nl.eduvpn.app.utils 19 | 20 | import android.os.Parcel 21 | import androidx.test.ext.junit.runners.AndroidJUnit4 22 | import nl.eduvpn.app.entity.TranslatableString 23 | import org.junit.Assert 24 | import org.junit.Test 25 | import org.junit.runner.RunWith 26 | 27 | @RunWith(AndroidJUnit4::class) 28 | class ParcelableTest { 29 | 30 | @Test 31 | fun testTranslatableStringParcelable() { 32 | val expected = TranslatableString( 33 | mapOf("en" to "Hello", "es" to "Hola", "nl" to "Hallo") 34 | ) 35 | val parcel = Parcel.obtain() 36 | expected.writeToParcel(parcel, 0) 37 | // Reset parcel for reading 38 | parcel.setDataPosition(0) 39 | val actual = TranslatableString.CREATOR.createFromParcel(parcel) 40 | parcel.recycle() 41 | Assert.assertEquals(expected, actual) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/dev/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | #A0A0A0 21 | #A0A0A0 22 | #808080 23 | #FF9800 24 | #D0D0D0 25 | #FFFFFF 26 | #FFFFFF 27 | #808080 28 | #FF5722 29 | #000000 30 | #202020 31 | #C0C0C0 32 | #FFFFFF 33 | #CF0000 34 | #F0F0F0 35 | #00000000 36 | #000000 37 | #FF8700 38 | #303030 39 | #505050 40 | #606060 41 | 42 | -------------------------------------------------------------------------------- /app/src/dev/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | eduVPN (dev) 20 | eduVPN (dev) 21 | 22 | -------------------------------------------------------------------------------- /app/src/gov/res/drawable-hdpi/logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/drawable-hdpi/logo_black.png -------------------------------------------------------------------------------- /app/src/gov/res/drawable-mdpi/logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/drawable-mdpi/logo_black.png -------------------------------------------------------------------------------- /app/src/gov/res/drawable-xhdpi/logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/drawable-xhdpi/logo_black.png -------------------------------------------------------------------------------- /app/src/gov/res/drawable-xxhdpi/logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/drawable-xxhdpi/logo_black.png -------------------------------------------------------------------------------- /app/src/gov/res/drawable-xxxhdpi/logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/drawable-xxxhdpi/logo_black.png -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-hdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-hdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-mdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-mdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-xhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-xhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-xxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-xxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-xxxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-xxxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /app/src/gov/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/gov/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/gov/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | #A0A0A0 21 | #A0A0A0 22 | #808080 23 | #a0a0a0 24 | #D0D0D0 25 | #303030 26 | #FFFFFF 27 | #808080 28 | #22B9FF 29 | #f0f0f0 30 | #202020 31 | #C8C8C8 32 | #FFFFFF 33 | #CF0000 34 | #808080 35 | #00000000 36 | #000000 37 | #808080 38 | #A0A0A0 39 | #303030 40 | #505050 41 | #606060 42 | 43 | -------------------------------------------------------------------------------- /app/src/gov/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #000000 4 | -------------------------------------------------------------------------------- /app/src/gov/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | govVPN 20 | govVPN 21 | 22 | -------------------------------------------------------------------------------- /app/src/home/res/drawable-hdpi/logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/drawable-hdpi/logo_black.png -------------------------------------------------------------------------------- /app/src/home/res/drawable-mdpi/logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/drawable-mdpi/logo_black.png -------------------------------------------------------------------------------- /app/src/home/res/drawable-xhdpi/logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/drawable-xhdpi/logo_black.png -------------------------------------------------------------------------------- /app/src/home/res/drawable-xxhdpi/logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/drawable-xxhdpi/logo_black.png -------------------------------------------------------------------------------- /app/src/home/res/drawable/ic_application_logo.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/home/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/home/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/home/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/home/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /app/src/home/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/home/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/home/res/values-de/strings.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | Let\'s Connect! 20 | Let\'s Connect! 21 | Anbieter hinzufügen 22 | Server 23 | 27 | Profile 28 | 29 | -------------------------------------------------------------------------------- /app/src/home/res/values-es/strings.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | Let\'s Connect! 20 | Let\'s Connect! 21 | Agregar Proveedor 22 | Servidores 23 | 27 | Perfiles 28 | 29 | -------------------------------------------------------------------------------- /app/src/home/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #1193F5 4 | #1193F5 5 | #0666AF 6 | #1193F5 7 | #1193F5 8 | #808080 9 | #101010 10 | #505050 11 | #FFFFFF 12 | #FFFFFF 13 | #101010 14 | #E0E0E0 15 | #FFFFFF 16 | #E9E9E9 17 | #D0D0D0 18 | #C0C0C0 19 | #00A2C8 20 | #505050 21 | #FFFFFF 22 | #CCCCCC 23 | #00FFFFFF 24 | #FFFFFF 25 | #216aed 26 | #7DA7F3 27 | #F0F0F0 28 | 29 | #16a566 30 | #b2b2b2 31 | #E4E4E4 32 | #FFFFFF 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/home/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | Let\'s Connect! 20 | Let\'s Connect! 21 | Add Provider 22 | Servers 23 | 27 | Profiles 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/ApiLogsActivity.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app 2 | 3 | import android.os.Bundle 4 | import android.view.MenuItem 5 | import androidx.activity.viewModels 6 | import androidx.core.view.isVisible 7 | import nl.eduvpn.app.base.BaseActivity 8 | import nl.eduvpn.app.databinding.ActivityApiLogsBinding 9 | import nl.eduvpn.app.viewmodel.ApiLogsViewModel 10 | import nl.eduvpn.app.viewmodel.ViewModelFactory 11 | import javax.inject.Inject 12 | 13 | class ApiLogsActivity : BaseActivity() { 14 | 15 | override val layout = R.layout.activity_api_logs 16 | 17 | @Inject 18 | protected lateinit var viewModelFactory: ViewModelFactory 19 | 20 | private val viewModel by viewModels { viewModelFactory } 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | EduVPNApplication.get(this).component().inject(this) 24 | setSupportActionBar(binding.toolbar.toolbar) 25 | supportActionBar?.setDisplayHomeAsUpEnabled(true) 26 | binding.toolbar.settingsButton.isVisible = false 27 | 28 | } 29 | 30 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 31 | return if (item.itemId == android.R.id.home) { 32 | onBackPressedDispatcher.onBackPressed() 33 | true 34 | } else { 35 | super.onOptionsItemSelected(item) 36 | } 37 | } 38 | 39 | override fun onResume() { 40 | super.onResume() 41 | binding.logContents.text = viewModel.getLogFileContents() 42 | } 43 | } -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/CertExpiredBroadcastReceiver.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app 2 | 3 | import android.app.NotificationManager 4 | import android.app.PendingIntent 5 | import android.content.BroadcastReceiver 6 | import android.content.Context 7 | import android.content.Intent 8 | import androidx.core.app.NotificationCompat 9 | import nl.eduvpn.app.service.VPNService 10 | import nl.eduvpn.app.utils.pendingIntentImmutableFlag 11 | import javax.inject.Inject 12 | 13 | class CertExpiredBroadcastReceiver : BroadcastReceiver() { 14 | 15 | @Inject 16 | protected lateinit var vpnService: VPNService 17 | 18 | override fun onReceive(context: Context, intent: Intent) { 19 | EduVPNApplication.get(context).component().inject(this) 20 | if (intent.action != ACTION) { 21 | return 22 | } 23 | if (vpnService.getStatus() == VPNService.VPNStatus.DISCONNECTED) { 24 | return 25 | } 26 | val channelID = Constants.CERT_EXPIRY_NOTIFICATION_CHANNEL_ID 27 | val notification = NotificationCompat.Builder(context, channelID) 28 | .setSmallIcon(R.drawable.logo_black) 29 | .setContentTitle(context.getString(R.string.cert_expiry_notification_title)) 30 | .setContentText(context.getString(R.string.cert_expiry_notification_text)) 31 | .setContentIntent( 32 | PendingIntent.getActivity( 33 | context, 34 | 0, 35 | Intent(context, MainActivity::class.java), 36 | pendingIntentImmutableFlag 37 | ) 38 | ) 39 | .setAutoCancel(true) 40 | .setPriority(NotificationCompat.PRIORITY_DEFAULT) // Only used on Android <= 7.1 41 | .build() 42 | 43 | val notificationManager = 44 | context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 45 | 46 | notificationManager.notify(Constants.CERT_EXPIRY_NOTIFICATION_ID, notification) 47 | } 48 | 49 | companion object { 50 | val ACTION = this::class.qualifiedName!!.plus(".cert_expiry") 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/Constants.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | */ 17 | package nl.eduvpn.app 18 | 19 | import android.net.Uri 20 | import java.util.* 21 | 22 | /** 23 | * Contains application-wide constant values. 24 | * Created by Daniel Zolnai on 2016-09-14. 25 | */ 26 | object Constants { 27 | @JvmField 28 | val DEBUG = BuildConfig.BUILD_TYPE.equals("debug", ignoreCase = true) 29 | 30 | @JvmField 31 | val LOCALE = Locale.getDefault() 32 | val ENGLISH_LOCALE = Locale.ENGLISH 33 | 34 | const val SERVER_LIST_VALID_FOR_MS: Long = 3600000 // 1 hour 35 | 36 | const val CERT_EXPIRY_NOTIFICATION_CHANNEL_ID = "cert_expiry" 37 | const val CERT_EXPIRY_NOTIFICATION_ID = 1 38 | 39 | const val VPN_CONNECTION_NOTIFICATION_CHANNEL_ID = "vpn_connection" 40 | const val VPN_CONNECTION_NOTIFICATION_ID = 2 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/DisconnectVPNBroadcastReceiver.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app 2 | 3 | import android.content.BroadcastReceiver 4 | import android.content.Context 5 | import android.content.Intent 6 | import nl.eduvpn.app.service.VPNConnectionService 7 | import nl.eduvpn.app.service.VPNService 8 | import javax.inject.Inject 9 | 10 | class DisconnectVPNBroadcastReceiver : BroadcastReceiver() { 11 | 12 | @Inject 13 | protected lateinit var vpnConnectionService: VPNConnectionService 14 | 15 | @Inject 16 | protected lateinit var vpnService: VPNService 17 | 18 | companion object { 19 | val ACTION = this::class.qualifiedName!!.plus(".disconnect_vpn") 20 | } 21 | 22 | override fun onReceive(context: Context, intent: Intent) { 23 | EduVPNApplication.get(context).component().inject(this) 24 | if (intent.action != ACTION) { 25 | return 26 | } 27 | vpnConnectionService.disconnect(context, vpnService) 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/EduVPNApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | */ 17 | 18 | package nl.eduvpn.app; 19 | 20 | import android.content.Context; 21 | import android.os.StrictMode; 22 | 23 | import de.blinkt.openvpn.core.ICSOpenVPNApplication; 24 | import nl.eduvpn.app.inject.EduVPNComponent; 25 | 26 | /** 27 | * Application object which keeps track of the app lifecycle. 28 | * Created by Daniel Zolnai on 2016-09-14. 29 | */ 30 | public class EduVPNApplication extends ICSOpenVPNApplication { 31 | 32 | private EduVPNComponent _component; 33 | 34 | @Override 35 | public void onCreate() { 36 | super.onCreate(); 37 | // Set up the injector 38 | _component = EduVPNComponent.Initializer.init(this); 39 | 40 | // The base class sets a strict VM policy for debug builds, which do not work well with OkHttp 41 | // (see this issue: https://github.com/square/okhttp/issues/3537) 42 | // For now, the best solution seems to be disabling strict mode 43 | StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder().build(); 44 | StrictMode.setVmPolicy(policy); 45 | 46 | } 47 | 48 | public EduVPNComponent component() { 49 | return _component; 50 | } 51 | 52 | public static EduVPNApplication get(Context context) { 53 | return (EduVPNApplication)context.getApplicationContext(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/LicenseActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | * 17 | */ 18 | 19 | package nl.eduvpn.app 20 | 21 | import android.content.Intent 22 | import android.net.Uri 23 | import android.os.Bundle 24 | import android.view.MenuItem 25 | import androidx.core.view.isVisible 26 | import nl.eduvpn.app.base.BaseActivity 27 | import nl.eduvpn.app.databinding.ActivityLicensesBinding 28 | 29 | class LicenseActivity : BaseActivity() { 30 | 31 | override val layout = R.layout.activity_licenses 32 | 33 | override fun onCreate(savedInstanceState: Bundle?) { 34 | super.onCreate(savedInstanceState) 35 | setSupportActionBar(binding.toolbar.toolbar) 36 | supportActionBar?.setDisplayHomeAsUpEnabled(true) 37 | binding.webView.loadUrl("file:///android_asset/licenses.html"); 38 | binding.toolbar.settingsButton.isVisible = false 39 | binding.toolbar.helpButton.setOnClickListener { 40 | startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(BuildConfig.HELP_URI))) 41 | } 42 | } 43 | 44 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 45 | return if (item.itemId == android.R.id.home) { 46 | onBackPressedDispatcher.onBackPressed() 47 | true 48 | } else { 49 | super.onOptionsItemSelected(item) 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/OpenVpnLogsActivity.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app 2 | 3 | import android.os.Bundle 4 | import android.view.MenuItem 5 | import androidx.activity.viewModels 6 | import androidx.core.view.isVisible 7 | import de.blinkt.openvpn.fragments.LogFragment 8 | import nl.eduvpn.app.base.BaseActivity 9 | import nl.eduvpn.app.databinding.ActivityApiLogsBinding 10 | import nl.eduvpn.app.databinding.ActivityOpenvpnLogsBinding 11 | import nl.eduvpn.app.viewmodel.ApiLogsViewModel 12 | import nl.eduvpn.app.viewmodel.ViewModelFactory 13 | import javax.inject.Inject 14 | 15 | class OpenVpnLogsActivity : BaseActivity() { 16 | 17 | override val layout = R.layout.activity_openvpn_logs 18 | 19 | @Inject 20 | protected lateinit var viewModelFactory: ViewModelFactory 21 | 22 | override fun onCreate(savedInstanceState: Bundle?) { 23 | super.onCreate(savedInstanceState) 24 | EduVPNApplication.get(this).component().inject(this) 25 | setSupportActionBar(binding.toolbar.toolbar) 26 | supportActionBar?.setDisplayHomeAsUpEnabled(true) 27 | binding.toolbar.settingsButton.isVisible = false 28 | supportFragmentManager.beginTransaction() 29 | .add(binding.fragmentContainer.id, LogFragment()) 30 | .commit() 31 | } 32 | 33 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 34 | return if (item.itemId == android.R.id.home) { 35 | onBackPressedDispatcher.onBackPressed() 36 | true 37 | } else { 38 | super.onOptionsItemSelected(item) 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/adapter/ProfileAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | */ 17 | 18 | package nl.eduvpn.app.adapter 19 | 20 | import android.view.LayoutInflater 21 | import android.view.ViewGroup 22 | import androidx.recyclerview.widget.DiffUtil 23 | import androidx.recyclerview.widget.ListAdapter 24 | import nl.eduvpn.app.adapter.viewholder.ProfileViewHolder 25 | import nl.eduvpn.app.databinding.ListItemProfileBinding 26 | import nl.eduvpn.app.entity.Instance 27 | import nl.eduvpn.app.entity.Profile 28 | 29 | /** 30 | * Adapter for the profile list. 31 | * Created by Daniel Zolnai on 2016-10-11. 32 | */ 33 | class ProfileAdapter(private val instance: Instance) : ListAdapter(object : DiffUtil.ItemCallback() { 34 | override fun areItemsTheSame(oldItem: Profile, newItem: Profile): Boolean { 35 | return oldItem.profileId == newItem.profileId 36 | } 37 | 38 | override fun areContentsTheSame(oldItem: Profile, newItem: Profile): Boolean { 39 | return oldItem == newItem 40 | } 41 | }) { 42 | 43 | 44 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProfileViewHolder { 45 | return ProfileViewHolder(ListItemProfileBinding.inflate(LayoutInflater.from(parent.context), parent, false)) 46 | } 47 | 48 | public override fun getItem(position: Int): Profile { 49 | return super.getItem(position) 50 | } 51 | 52 | override fun onBindViewHolder(holder: ProfileViewHolder, position: Int) { 53 | val profile = getItem(position) 54 | holder.bind(instance, profile) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/adapter/viewholder/ProfileViewHolder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | */ 17 | 18 | package nl.eduvpn.app.adapter.viewholder 19 | 20 | 21 | import android.text.TextUtils 22 | import androidx.recyclerview.widget.RecyclerView 23 | import com.squareup.picasso.Picasso 24 | import nl.eduvpn.app.R 25 | import nl.eduvpn.app.databinding.ListItemProfileBinding 26 | import nl.eduvpn.app.entity.Instance 27 | import nl.eduvpn.app.entity.Profile 28 | import nl.eduvpn.app.utils.FormattingUtils 29 | 30 | /** 31 | * View holder for the provider instance list. 32 | * Created by Daniel Zolnai on 2016-10-07. 33 | */ 34 | class ProfileViewHolder(private val binding: ListItemProfileBinding) : RecyclerView.ViewHolder(binding.root) { 35 | 36 | fun bind(instance: Instance, profile: Profile) { 37 | binding.profileName.text = profile.displayName.bestTranslation 38 | binding.profileProvider.text = FormattingUtils.formatDisplayName(instance) 39 | if (!TextUtils.isEmpty(instance.logoUri)) { 40 | Picasso.get() 41 | .load(instance.logoUri) 42 | .fit() 43 | .into(binding.profileIcon) 44 | } else { 45 | binding.profileIcon.setImageResource(R.drawable.ic_vpn_profile) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/base/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | * 17 | */ 18 | 19 | package nl.eduvpn.app.base 20 | 21 | import android.os.Bundle 22 | import androidx.annotation.LayoutRes 23 | import androidx.appcompat.app.AppCompatActivity 24 | import androidx.databinding.DataBindingUtil 25 | import androidx.databinding.ViewDataBinding 26 | 27 | abstract class BaseActivity : AppCompatActivity() { 28 | 29 | protected lateinit var binding: B 30 | 31 | @get:LayoutRes 32 | protected abstract val layout: Int 33 | 34 | override fun onCreate(savedInstanceState: Bundle?) { 35 | super.onCreate(savedInstanceState) 36 | binding = DataBindingUtil.setContentView(this, layout) 37 | binding.lifecycleOwner = this 38 | } 39 | 40 | 41 | } -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/base/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | * 17 | */ 18 | 19 | package nl.eduvpn.app.base 20 | 21 | import android.os.Bundle 22 | import android.view.LayoutInflater 23 | import android.view.View 24 | import android.view.ViewGroup 25 | import androidx.annotation.LayoutRes 26 | import androidx.databinding.DataBindingUtil 27 | import androidx.databinding.ViewDataBinding 28 | import androidx.fragment.app.Fragment 29 | import nl.eduvpn.app.viewmodel.ViewModelFactory 30 | import javax.inject.Inject 31 | 32 | abstract class BaseFragment : Fragment() { 33 | 34 | protected lateinit var binding: B 35 | 36 | @Inject 37 | protected lateinit var viewModelFactory : ViewModelFactory 38 | 39 | @get:LayoutRes 40 | protected abstract val layout: Int 41 | 42 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 43 | binding = DataBindingUtil.inflate(inflater, layout, container, false).also { 44 | it.lifecycleOwner = this.viewLifecycleOwner 45 | } 46 | return binding.root 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/AuthorizationType.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | */ 17 | 18 | package nl.eduvpn.app.entity 19 | 20 | import kotlinx.serialization.SerialName 21 | import kotlinx.serialization.Serializable 22 | 23 | /** 24 | * The type of the VPN which the user will connect to. 25 | * Created by Daniel Zolnai on 2017-07-31. 26 | */ 27 | @Serializable 28 | enum class AuthorizationType { 29 | 30 | @SerialName("institute_access") 31 | Local, 32 | 33 | @SerialName("secure_internet") 34 | Distributed, 35 | 36 | @SerialName("organization") 37 | Organization 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/CertExpiryTimes.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.entity 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class CertExpiryTimes( 8 | @SerialName("start_time") 9 | val startTime: Long? = null, 10 | @SerialName("end_time") 11 | val endTime: Long? = null, 12 | @SerialName("button_time") 13 | val buttonTime: Long? = null, 14 | @SerialName("countdown_time") 15 | val countdownTime: Long? = null, 16 | @SerialName("notification_times") 17 | val notificationTimes: List = emptyList(), 18 | ) -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/CookieAndProfileMapData.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.entity 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class CookieAndProfileMapData( 8 | val data: ProfileWithoutIdMap, 9 | val cookie: Int 10 | ) 11 | 12 | @Serializable 13 | data class ProfileWithoutIdMap( 14 | internal val map: Map? = null, 15 | @SerialName("current") 16 | internal val currentProfileId: String? 17 | ) { 18 | fun getProfileList(): List { 19 | return map?.map { 20 | Profile( 21 | profileId = it.key, 22 | displayName = it.value.displayName, 23 | ) 24 | } ?: emptyList() 25 | } 26 | 27 | val currentProfile: Profile? = getProfileList().firstOrNull { it.profileId == currentProfileId } 28 | } 29 | 30 | @Serializable 31 | data class ProfileWithoutId( 32 | @SerialName("display_name") 33 | val displayName: TranslatableString, 34 | ) -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/CookieAndStringData.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.entity 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class CookieAndStringData( 7 | val data: String, 8 | val cookie: Int 9 | ) 10 | 11 | @Serializable 12 | data class CookieAndStringArrayData( 13 | val data: List, 14 | val cookie: Int 15 | ) -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/CurrentServer.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.entity 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | import org.eduvpn.common.ServerType 6 | 7 | @Serializable 8 | data class CurrentServer( 9 | @SerialName("custom_server") 10 | val customServer: CurrentServerInfo? = null, 11 | @SerialName("institute_access_server") 12 | val instituteAccessServer: CurrentServerInfo? = null, 13 | @SerialName("secure_internet_server") 14 | val secureInternetServer: CurrentServerInfo? = null, 15 | @SerialName("server_type") 16 | val serverType: Int? 17 | ) { 18 | 19 | private val info : CurrentServerInfo? = customServer ?: instituteAccessServer ?: secureInternetServer 20 | fun getUniqueId(): String? { 21 | return info?.identifier 22 | } 23 | 24 | fun getDisplayName(): TranslatableString? { 25 | return info?.displayName 26 | } 27 | 28 | fun getProfiles(): List? { 29 | return info?.profiles?.getProfileList() 30 | } 31 | 32 | val currentProfile: Profile? = info?.profiles?.currentProfile 33 | 34 | fun asInstance() : Instance? { 35 | if (info == null) { 36 | return null 37 | } 38 | val authorizationType = when (serverType) { 39 | ServerType.Custom.nativeValue -> AuthorizationType.Organization 40 | ServerType.SecureInternet.nativeValue -> AuthorizationType.Distributed 41 | ServerType.InstituteAccess.nativeValue -> AuthorizationType.Local 42 | else -> return null 43 | } 44 | return Instance( 45 | baseURI = getUniqueId() ?: return null, 46 | displayName = getDisplayName() ?: TranslatableString(), 47 | authorizationType = authorizationType, 48 | supportContact = info.supportContacts 49 | ) 50 | } 51 | } 52 | 53 | @Serializable 54 | data class CurrentServerInfo ( 55 | val identifier: String, 56 | 57 | @SerialName("display_name") 58 | val displayName: TranslatableString, 59 | 60 | val profiles: ProfileWithoutIdMap? = null, 61 | 62 | @SerialName("support_contacts") 63 | val supportContacts: List = emptyList() 64 | ) 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/Instance.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | */ 17 | package nl.eduvpn.app.entity 18 | 19 | import kotlinx.serialization.SerialName 20 | import kotlinx.serialization.Serializable 21 | 22 | /** 23 | * A configuration for an instance. 24 | * Created by Daniel Zolnai on 2016-10-07. 25 | */ 26 | @Serializable 27 | data class Instance( 28 | 29 | @SerialName("base_url") 30 | val baseURI: String, 31 | 32 | @SerialName("display_name") 33 | val displayName: TranslatableString = TranslatableString(), 34 | 35 | @SerialName("keyword_list") 36 | val keywords: TranslatableString? = TranslatableString(), 37 | 38 | @SerialName("logo") 39 | val logoUri: String? = null, 40 | 41 | @SerialName("server_type") 42 | val authorizationType: AuthorizationType = AuthorizationType.Local, 43 | 44 | @SerialName("country_code") 45 | val countryCode: String? = null, 46 | 47 | @SerialName("is_custom") 48 | val isCustom: Boolean = false, 49 | 50 | @SerialName("authentication_url_template") 51 | val authenticationUrlTemplate: String? = null, 52 | 53 | @SerialName("support_contact") 54 | val supportContact: List = emptyList() 55 | ) { 56 | 57 | val sanitizedBaseURI: String 58 | get() = if (baseURI.endsWith("/")) { 59 | baseURI.substring(0, baseURI.length - 1) 60 | } else baseURI 61 | 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/Organization.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | * 17 | */ 18 | 19 | package nl.eduvpn.app.entity 20 | 21 | import kotlinx.serialization.SerialName 22 | import kotlinx.serialization.Serializable 23 | 24 | @Serializable 25 | data class Organization( 26 | @SerialName("org_id") 27 | val orgId: String, 28 | @SerialName("display_name") 29 | val displayName: TranslatableString = TranslatableString(), 30 | @SerialName("keyword_list") 31 | val keywordList: TranslatableString = TranslatableString(), 32 | ) -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/OrganizationList.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | * 17 | */ 18 | 19 | package nl.eduvpn.app.entity 20 | 21 | import kotlinx.serialization.SerialName 22 | import kotlinx.serialization.Serializable 23 | 24 | /** 25 | * A versioned list of organizations 26 | */ 27 | @Serializable 28 | data class OrganizationList( 29 | @SerialName("organization_list") 30 | val organizationList: List? = null 31 | ) -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/Profile.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.entity 2 | 3 | import android.os.Parcelable 4 | import kotlinx.parcelize.Parcelize 5 | import kotlinx.serialization.SerialName 6 | import kotlinx.serialization.Serializable 7 | 8 | @Serializable 9 | @Parcelize 10 | data class Profile ( 11 | 12 | @SerialName("profile_id") 13 | val profileId: String, 14 | 15 | @SerialName("display_name") 16 | val displayName: TranslatableString, 17 | ) : Parcelable 18 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/SerializedVpnConfig.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.entity 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | import org.eduvpn.common.Protocol 6 | 7 | @Serializable 8 | data class SerializedVpnConfig( 9 | val config: String, 10 | val protocol: Int, 11 | @SerialName("default_gateway") 12 | val defaultGateway: Boolean, 13 | @SerialName("should_failover") 14 | val shouldFailover: Boolean = false, 15 | val proxy: ProxySettings? = null 16 | ) 17 | 18 | @Serializable 19 | data class ProxySettings( 20 | @SerialName("source_port") 21 | val sourcePort: Int, 22 | val listen: String, 23 | val peer: String 24 | ) -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/ServerList.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | * 17 | */ 18 | 19 | package nl.eduvpn.app.entity 20 | 21 | import kotlinx.serialization.SerialName 22 | import kotlinx.serialization.Serializable 23 | 24 | /** 25 | * A versioned list of organizations 26 | */ 27 | @Serializable 28 | data class ServerList( 29 | @SerialName("server_list") 30 | val serverList: List? = null 31 | ) 32 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/VPNConfig.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.entity 2 | 3 | import com.wireguard.config.Config 4 | import de.blinkt.openvpn.VpnProfile 5 | 6 | sealed class VPNConfig { 7 | 8 | data class OpenVPN(val profile: VpnProfile) : VPNConfig() 9 | 10 | data class WireGuard(val config: Config) : VPNConfig() 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/exception/CommonException.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.entity.exception 2 | 3 | import kotlinx.serialization.decodeFromString 4 | import kotlinx.serialization.json.Json 5 | 6 | data class CommonException(override val message: String?) : Exception(message) { 7 | 8 | private val exceptionMessage: ExceptionMessage? get() { 9 | if (message == null) { 10 | return null 11 | } 12 | return try { 13 | json.decodeFromString(message) 14 | } catch (ex: Exception) { 15 | null 16 | } 17 | } 18 | 19 | fun translatedMessage() : String { 20 | if (message == null) { 21 | return toString() 22 | } 23 | return exceptionMessage?.message?.bestTranslation ?: message 24 | } 25 | 26 | fun isMiscError(): Boolean { 27 | return exceptionMessage?.misc == true 28 | } 29 | 30 | companion object { 31 | private val json = Json { ignoreUnknownKeys = true } 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/exception/EduVPNException.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.entity.exception 2 | 3 | import androidx.annotation.StringRes 4 | 5 | /** 6 | * Exception with translatable message. 7 | * 8 | * @param formatArgs Arguments for [resourceIdMessage] 9 | */ 10 | class EduVPNException( 11 | @StringRes val resourceIdTitle: Int, 12 | @StringRes val resourceIdMessage: Int, 13 | vararg formatArgs: Any? 14 | ) : Exception() { 15 | val formatArgs = formatArgs 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/entity/exception/ExceptionMessage.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.entity.exception 2 | 3 | import kotlinx.serialization.Serializable 4 | import nl.eduvpn.app.entity.TranslatableString 5 | 6 | @Serializable 7 | data class ExceptionMessage( 8 | val message: TranslatableString? = null, 9 | val misc: Boolean? = false 10 | ) 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/inject/EduVPNComponent.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | */ 17 | package nl.eduvpn.app.inject 18 | 19 | import dagger.Component 20 | import nl.eduvpn.app.ApiLogsActivity 21 | import nl.eduvpn.app.CertExpiredBroadcastReceiver 22 | import nl.eduvpn.app.DisconnectVPNBroadcastReceiver 23 | import nl.eduvpn.app.EduVPNApplication 24 | import nl.eduvpn.app.MainActivity 25 | import nl.eduvpn.app.OpenVpnLogsActivity 26 | import nl.eduvpn.app.fragment.* 27 | import javax.inject.Singleton 28 | 29 | /** 30 | * The Dagger component which executes the injections. 31 | * Created by Daniel Zolnai on 2016-10-07. 32 | */ 33 | @Singleton 34 | @Component(modules = [ApplicationModule::class]) 35 | interface EduVPNComponent { 36 | object Initializer { 37 | @JvmStatic 38 | fun init(application: EduVPNApplication?): EduVPNComponent { // Don't worry if you see an error here, DaggerEduVPNComponent is generated while building. 39 | return DaggerEduVPNComponent.builder() 40 | .applicationModule(ApplicationModule(application!!)).build() 41 | } 42 | } 43 | 44 | fun inject(organizationSelectionFragment: OrganizationSelectionFragment) 45 | fun inject(mainActivity: MainActivity) 46 | fun inject(apiLogsActivity: ApiLogsActivity) 47 | fun inject(apiLogsActivity: OpenVpnLogsActivity) 48 | fun inject(connectionStatusFragment: ConnectionStatusFragment) 49 | fun inject(homeFragment: ProfileSelectionFragment) 50 | fun inject(settingsFragment: SettingsFragment) 51 | fun inject(serverSelectionFragment: ServerSelectionFragment) 52 | fun inject(addServerFragment: AddServerFragment) 53 | fun inject(certExpiredBroadcastReceiver: CertExpiredBroadcastReceiver) 54 | fun inject(disconnectVPNBroadcastReceiver: DisconnectVPNBroadcastReceiver) 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/inject/ViewModelKey.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | * 17 | */ 18 | 19 | package nl.eduvpn.app.inject 20 | 21 | import androidx.lifecycle.ViewModel 22 | import dagger.MapKey 23 | import kotlin.reflect.KClass 24 | 25 | @MapKey 26 | @MustBeDocumented 27 | @Retention(AnnotationRetention.RUNTIME) 28 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) 29 | annotation class ViewModelKey(val value: KClass) -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/inject/ViewModelModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | * 17 | */ 18 | 19 | package nl.eduvpn.app.inject 20 | 21 | import android.view.View 22 | import androidx.lifecycle.ViewModel 23 | import dagger.Binds 24 | import dagger.Module 25 | import dagger.multibindings.IntoMap 26 | import nl.eduvpn.app.viewmodel.* 27 | 28 | @Module 29 | interface ViewModelModule { 30 | 31 | @Binds 32 | @IntoMap 33 | @ViewModelKey(OrganizationSelectionViewModel::class) 34 | fun bindOrganizationSelectionViewModel(organizationSelectionViewModel: OrganizationSelectionViewModel): ViewModel 35 | 36 | @Binds 37 | @IntoMap 38 | @ViewModelKey(ServerSelectionViewModel::class) 39 | fun bindServerSelectionViewModel(serverSelectionViewModel: ServerSelectionViewModel): ViewModel 40 | 41 | @Binds 42 | @IntoMap 43 | @ViewModelKey(ConnectionStatusViewModel::class) 44 | fun bindConnectionStatusViewModel(connectionStatusViewModel: ConnectionStatusViewModel): ViewModel 45 | 46 | @Binds 47 | @IntoMap 48 | @ViewModelKey(ProfileSelectionViewModel::class) 49 | fun bindProfileSelectionViewModel(profileSelectionViewModel: ProfileSelectionViewModel): ViewModel 50 | 51 | @Binds 52 | @IntoMap 53 | @ViewModelKey(AddServerViewModel::class) 54 | fun bindAddServerViewModel(addServerViewModel: AddServerViewModel): ViewModel 55 | 56 | @Binds 57 | @IntoMap 58 | @ViewModelKey(MainViewModel::class) 59 | fun bindMainViewModel(mainViewModel: MainViewModel): ViewModel 60 | 61 | @Binds 62 | @IntoMap 63 | @ViewModelKey(SettingsViewModel::class) 64 | fun bindSettingsViewModel(settingsViewModel: SettingsViewModel): ViewModel 65 | 66 | @Binds 67 | @IntoMap 68 | @ViewModelKey(ApiLogsViewModel::class) 69 | fun bindApiLogsViewModel(apiLogsViewModel: ApiLogsViewModel): ViewModel 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/livedata/ByteCount.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.livedata 2 | 3 | data class ByteCount(val bytesIn: Long, val bytesOut: Long) 4 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/livedata/ConnectionTimeLiveData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | */ 17 | 18 | package nl.eduvpn.app.livedata 19 | 20 | import androidx.lifecycle.LiveData 21 | import androidx.lifecycle.MediatorLiveData 22 | import nl.eduvpn.app.service.VPNService 23 | 24 | /** 25 | * Amount of seconds connected to the VPN. 26 | */ 27 | object ConnectionTimeLiveData { 28 | 29 | fun create( 30 | vpnStatusLiveData: LiveData, 31 | timer: LiveData 32 | ): LiveData { 33 | var connectionTime = 0L 34 | 35 | val connectionTimeLiveData = MediatorLiveData() 36 | 37 | val update = { 38 | connectionTimeLiveData.value = (System.currentTimeMillis() - connectionTime) / 1000L 39 | } 40 | 41 | // we do not want to miss connected / disconnected events when the user puts the app in the 42 | // background, so observeForever 43 | vpnStatusLiveData.observeForever { vpnStatus -> 44 | if (vpnStatus == VPNService.VPNStatus.CONNECTED) { 45 | connectionTime = System.currentTimeMillis() 46 | connectionTimeLiveData.value = 0 47 | try { 48 | // the timer will be automatically stopped onPause and will be restarted onResume 49 | connectionTimeLiveData.addSource(timer) { update() } 50 | } catch (ex: IllegalArgumentException) { 51 | // timer already added as source 52 | } 53 | } else if (vpnStatus == VPNService.VPNStatus.DISCONNECTED) { 54 | connectionTimeLiveData.removeSource(timer) 55 | connectionTimeLiveData.value = -1 56 | } 57 | } 58 | 59 | return connectionTimeLiveData 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/livedata/IPs.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.livedata 2 | 3 | data class IPs(val clientIpv4: String?, val clientIpv6: String?, val tunnelData: TunnelData?) 4 | data class TunnelData(val tunnelIp: String?, val mtu: Int?) -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/livedata/UnlessDisconnectedLiveData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | */ 17 | 18 | package nl.eduvpn.app.livedata 19 | 20 | import androidx.lifecycle.LiveData 21 | import androidx.lifecycle.MediatorLiveData 22 | import nl.eduvpn.app.service.VPNService 23 | 24 | /** 25 | * Live data unless VPN disconnected. 26 | */ 27 | object UnlessDisconnectedLiveData { 28 | fun create( 29 | liveData: LiveData, 30 | vpnStatusLiveData: LiveData 31 | ): LiveData { 32 | val mediator = MediatorLiveData() 33 | mediator.addSource(liveData) { value -> 34 | mediator.value = if (vpnStatusLiveData.value == VPNService.VPNStatus.DISCONNECTED) { 35 | null 36 | } else { 37 | value 38 | } 39 | } 40 | mediator.addSource(vpnStatusLiveData) { vpnStatus -> 41 | if (vpnStatus == VPNService.VPNStatus.DISCONNECTED) { 42 | mediator.value = null 43 | } 44 | } 45 | return mediator 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/livedata/openvpn/ByteCountLiveData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | */ 17 | 18 | package nl.eduvpn.app.livedata.openvpn 19 | 20 | import androidx.lifecycle.LiveData 21 | import de.blinkt.openvpn.core.VpnStatus 22 | import nl.eduvpn.app.livedata.ByteCount 23 | 24 | class ByteCountLiveData : LiveData() { 25 | 26 | private val byteCountListener: VpnStatus.ByteCountListener = 27 | VpnStatus.ByteCountListener { inBytes, outBytes, _, _ -> 28 | postValue(ByteCount(inBytes, outBytes)) 29 | } 30 | 31 | override fun onActive() { 32 | VpnStatus.addByteCountListener(byteCountListener) 33 | } 34 | 35 | override fun onInactive() { 36 | VpnStatus.removeByteCountListener(byteCountListener) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/service/OrganizationService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | */ 17 | package nl.eduvpn.app.service 18 | 19 | import kotlinx.coroutines.Dispatchers 20 | import kotlinx.coroutines.withContext 21 | import nl.eduvpn.app.entity.OrganizationList 22 | import nl.eduvpn.app.entity.ServerList 23 | 24 | /** 25 | * Service which provides the configurations for organization related data model. 26 | * Created by Daniel Zolnai on 2016-10-07. 27 | */ 28 | class OrganizationService( 29 | private val serializerService: SerializerService, 30 | private val backendService: BackendService 31 | ) { 32 | 33 | suspend fun fetchServerList(searchFilter: String) : Result = withContext(Dispatchers.IO) { 34 | try { 35 | val serverListString = backendService.discoverServers(searchFilter) 36 | val result = serializerService.deserializeServerList(serverListString) 37 | return@withContext Result.success(result) 38 | } catch (throwable: Throwable) { 39 | return@withContext Result.failure(throwable) 40 | } 41 | } 42 | 43 | suspend fun fetchOrganizations(searchFilter: String): OrganizationList = withContext(Dispatchers.IO) { 44 | val organizationListString = backendService.discoverOrganizations(searchFilter) 45 | serializerService.deserializeOrganizationList(organizationListString) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/service/VPNService.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.service 2 | 3 | import android.app.Notification 4 | import androidx.lifecycle.LiveData 5 | import kotlinx.coroutines.flow.Flow 6 | import nl.eduvpn.app.livedata.ByteCount 7 | import nl.eduvpn.app.livedata.IPs 8 | import org.eduvpn.common.Protocol 9 | 10 | abstract class VPNService : LiveData() { 11 | 12 | enum class VPNStatus { 13 | DISCONNECTED, CONNECTING, CONNECTED, PAUSED, FAILED 14 | } 15 | 16 | abstract val byteCountFlow: Flow 17 | 18 | abstract val ipFlow: Flow 19 | 20 | /** 21 | * User should call this after showing a notification. 22 | * 23 | * @param id The identifier for this notification as per 24 | * {@link NotificationManager#notify(int, Notification) 25 | * NotificationManager.notify(int, Notification)}; 26 | * @param notification The Notification to be displayed. 27 | */ 28 | abstract fun startForeground(id: Int, notification: Notification) 29 | 30 | /** 31 | * Disconnects the current VPN connection. 32 | */ 33 | abstract fun disconnect() 34 | 35 | /** 36 | * Returns the error string. 37 | * 38 | * @return The description of the error. 39 | */ 40 | abstract fun getErrorString(): String? 41 | 42 | /** 43 | * @return The current status of the VPN. 44 | */ 45 | abstract fun getStatus(): VPNStatus 46 | 47 | /** 48 | * Type of the VPN protocol this service implements. 49 | */ 50 | abstract fun getProtocol(): Protocol 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/utils/Listener.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.utils 2 | 3 | interface Listener { 4 | /** 5 | * @param o the object calling `update` 6 | * @param arg an optional argument 7 | * method. 8 | */ 9 | fun update(o: Any, arg: Any?) 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/utils/WireGuardTunnel.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.utils 2 | 3 | import com.wireguard.android.backend.Tunnel 4 | 5 | class WireGuardTunnel( 6 | private val name: String, 7 | private val onStateChangeFunction: (newState: Tunnel.State) -> Unit 8 | ) : Tunnel { 9 | 10 | override fun getName() = name 11 | 12 | var state: Tunnel.State = Tunnel.State.DOWN 13 | private set 14 | 15 | override fun onStateChange(newState: Tunnel.State) { 16 | state = newState 17 | onStateChangeFunction(newState) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/utils/serializer/DateSerializer.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.utils.serializer 2 | 3 | import kotlinx.serialization.KSerializer 4 | import kotlinx.serialization.descriptors.PrimitiveKind 5 | import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor 6 | import kotlinx.serialization.descriptors.SerialDescriptor 7 | import kotlinx.serialization.encoding.Decoder 8 | import kotlinx.serialization.encoding.Encoder 9 | import java.util.* 10 | 11 | object DateSerializer : KSerializer { 12 | 13 | override val descriptor: SerialDescriptor = 14 | PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG) 15 | 16 | override fun serialize(encoder: Encoder, value: Date) { 17 | encoder.encodeLong(value.time) 18 | } 19 | 20 | override fun deserialize(decoder: Decoder): Date { 21 | return Date(decoder.decodeLong()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/utils/serializer/TranslatableStringSerializer.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.utils.serializer 2 | 3 | import kotlinx.serialization.ExperimentalSerializationApi 4 | import kotlinx.serialization.KSerializer 5 | import kotlinx.serialization.SerializationException 6 | import kotlinx.serialization.descriptors.SerialDescriptor 7 | import kotlinx.serialization.encoding.Decoder 8 | import kotlinx.serialization.encoding.Encoder 9 | import kotlinx.serialization.json.JsonElement 10 | import kotlinx.serialization.json.JsonObject 11 | import kotlinx.serialization.json.JsonPrimitive 12 | import nl.eduvpn.app.entity.TranslatableString 13 | 14 | object TranslatableStringSerializer : KSerializer { 15 | 16 | @OptIn(ExperimentalSerializationApi::class) 17 | override val descriptor: SerialDescriptor = 18 | SerialDescriptor("TranslatableString", JsonObject.serializer().descriptor) 19 | 20 | override fun serialize(encoder: Encoder, value: TranslatableString) { 21 | val jsonObject = JsonObject(value.translations.mapValues { (_, v) -> JsonPrimitive(v) }) 22 | encoder.encodeSerializableValue( 23 | JsonObject.serializer(), 24 | jsonObject 25 | ) 26 | } 27 | 28 | override fun deserialize(decoder: Decoder): TranslatableString { 29 | return when (val jsonElement = decoder.decodeSerializableValue(JsonElement.serializer())) { 30 | // Plain string was previously used to store displayName in Instance and in Profile. If 31 | // this is removed from the deserializer, a migration is necessary. 32 | is JsonPrimitive -> if (jsonElement.isString) TranslatableString(jsonElement.content) else null 33 | is JsonObject -> TranslatableString(jsonElement.filterValues { v -> v is JsonPrimitive && v.isString } 34 | .mapValues { m -> 35 | val translation = m.value as JsonPrimitive 36 | translation.content 37 | }) 38 | else -> null 39 | } ?: throw SerializationException("Invalid translatable string") 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/viewmodel/AddServerViewModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | * 17 | */ 18 | 19 | package nl.eduvpn.app.viewmodel 20 | 21 | import android.content.Context 22 | import androidx.lifecycle.MutableLiveData 23 | import androidx.lifecycle.map 24 | import nl.eduvpn.app.service.* 25 | import javax.inject.Inject 26 | 27 | class AddServerViewModel @Inject constructor( 28 | preferencesService: PreferencesService, 29 | context: Context, 30 | historyService: HistoryService, 31 | backendService: BackendService, 32 | vpnConnectionService: VPNConnectionService, 33 | ) : BaseConnectionViewModel( 34 | context, 35 | backendService, 36 | historyService, 37 | preferencesService, 38 | vpnConnectionService, 39 | ) { 40 | 41 | val serverUrl = MutableLiveData("") 42 | 43 | val addButtonEnabled = serverUrl.map { url -> 44 | url != null && url.contains(".") && url.length > 3 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/viewmodel/ApiLogsViewModel.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.viewmodel 2 | 3 | import androidx.lifecycle.AndroidViewModel 4 | import androidx.lifecycle.ViewModel 5 | import nl.eduvpn.app.service.BackendService 6 | import nl.eduvpn.app.service.HistoryService 7 | import nl.eduvpn.app.service.PreferencesService 8 | import javax.inject.Inject 9 | 10 | class ApiLogsViewModel @Inject constructor( 11 | private val backendService: BackendService 12 | ) : ViewModel() { 13 | fun getLogFileContents() : String { 14 | return backendService.getLogFile()!!.readLines().joinToString("\n") 15 | } 16 | } -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/viewmodel/ConnectionState.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | * 17 | */ 18 | 19 | package nl.eduvpn.app.viewmodel 20 | 21 | import androidx.annotation.StringRes 22 | import nl.eduvpn.app.R 23 | 24 | enum class ConnectionState(@StringRes val displayString: Int?) { 25 | Ready(null), 26 | FetchingOrganizations(R.string.fetching_organization_servers), 27 | FetchingServerList(R.string.fetching_server_list), 28 | DiscoveringApi(R.string.api_discovery_message), 29 | FetchingProfiles(R.string.loading_available_profiles), 30 | Authorizing(R.string.loading_browser_for_authorization), 31 | ProfileDownloadingKeyPair(R.string.vpn_profile_creating_keypair) 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/viewmodel/ProfileSelectionViewModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | * 17 | */ 18 | 19 | package nl.eduvpn.app.viewmodel 20 | 21 | import android.content.Context 22 | import nl.eduvpn.app.service.* 23 | import javax.inject.Inject 24 | 25 | class ProfileSelectionViewModel @Inject constructor( 26 | context: Context, 27 | historyService: HistoryService, 28 | preferencesService: PreferencesService, 29 | backendService: BackendService, 30 | vpnConnectionService: VPNConnectionService, 31 | ) : BaseConnectionViewModel( 32 | context, 33 | backendService, 34 | historyService, 35 | preferencesService, 36 | vpnConnectionService, 37 | ) 38 | -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/viewmodel/SettingsViewModel.kt: -------------------------------------------------------------------------------- 1 | package nl.eduvpn.app.viewmodel 2 | 3 | import androidx.lifecycle.AndroidViewModel 4 | import androidx.lifecycle.ViewModel 5 | import androidx.lifecycle.viewModelScope 6 | import kotlinx.coroutines.Dispatchers 7 | import kotlinx.coroutines.launch 8 | import nl.eduvpn.app.service.BackendService 9 | import nl.eduvpn.app.service.HistoryService 10 | import javax.inject.Inject 11 | 12 | class SettingsViewModel @Inject constructor( 13 | private val historyService: HistoryService, 14 | private val backendService: BackendService 15 | ) : ViewModel() { 16 | 17 | val apiLogFile get() = backendService.getLogFile() 18 | 19 | val hasAddedServers get() = historyService.addedServers?.hasServers() == true 20 | 21 | fun removeOrganizationData() { 22 | viewModelScope.launch(Dispatchers.IO) { 23 | historyService.removeOrganizationData() 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/nl/eduvpn/app/viewmodel/ViewModelFactory.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of eduVPN. 3 | * 4 | * eduVPN is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * eduVPN is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with eduVPN. If not, see . 16 | * 17 | */ 18 | 19 | package nl.eduvpn.app.viewmodel 20 | 21 | import androidx.lifecycle.ViewModel 22 | import androidx.lifecycle.ViewModelProvider 23 | import javax.inject.Inject 24 | import javax.inject.Provider 25 | 26 | /** 27 | * Factory for [ViewModel]'s 28 | */ 29 | class ViewModelFactory @Inject constructor( 30 | private val viewModelsMap: Map, @JvmSuppressWildcards Provider> 31 | ) : ViewModelProvider.Factory { 32 | override fun create(modelClass: Class): T { 33 | val creator = viewModelsMap[modelClass] 34 | ?: viewModelsMap.entries.firstOrNull { 35 | modelClass.isAssignableFrom(it.key) 36 | }?.value ?: throw IllegalArgumentException("Unknown ViewModel class $modelClass") 37 | 38 | return try { 39 | @Suppress("UNCHECKED_CAST") 40 | creator.get() as T 41 | } catch (e: Exception) { 42 | throw RuntimeException(e) 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/fade_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/anim/fade_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 37 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/anim/progress_indeterminate_horizontal_rect1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/anim/progress_indeterminate_horizontal_rect2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/color/bg_big_button.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/drawable-hdpi/logo_black.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/drawable-mdpi/logo_black.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/drawable-xhdpi/logo_black.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/external_provider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/drawable-xxhdpi/external_provider.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_shield_access_white_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/drawable-xxhdpi/icon_shield_access_white_full.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_shield_internet_white_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/drawable-xxhdpi/icon_shield_internet_white_full.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/drawable-xxhdpi/logo_black.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/maintenance_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/drawable-xxhdpi/maintenance_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/surfnet_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/drawable-xxhdpi/surfnet_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/access_type_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_progress_indeterminate_layers.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 25 | 29 | 33 | 37 | 41 | 42 | 46 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_progressbar_indeterminate.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 21 | 24 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/delete_icon.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dialog_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dialog_button_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 10 | 11 | 12 | 13 | 14 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_drop_down.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_chevron_right.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_connection_status_connecting.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 28 | 32 | 36 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_help.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_institute.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_secure_internet.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_server.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 18 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 28 | 32 | 36 | 40 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_vpn_profile.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_warning.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/loading_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/scrollbar_thumb.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/switch_thumb.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/switch_track.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/font/open_sans_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/font/open_sans_bold.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/open_sans_bold_italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/font/open_sans_bold_italic.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/open_sans_extra_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/font/open_sans_extra_bold.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/open_sans_extra_bold_italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/font/open_sans_extra_bold_italic.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/open_sans_italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/font/open_sans_italic.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/open_sans_light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/font/open_sans_light.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/open_sans_light_italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/font/open_sans_light_italic.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/open_sans_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/font/open_sans_regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/open_sans_semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/font/open_sans_semibold.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/open_sans_semibold_italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eduvpn/android/0b885b079d8c729b90342e4eabe354ab08a5d918/app/src/main/res/font/open_sans_semibold_italic.ttf -------------------------------------------------------------------------------- /app/src/main/res/interpolator/progress_indeterminate_horizontal_rect1_scalex.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/interpolator/progress_indeterminate_horizontal_rect1_translatex.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/interpolator/progress_indeterminate_horizontal_rect2_scalex.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/interpolator/progress_indeterminate_horizontal_rect2_translatex.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_api_logs.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 26 | 27 | 33 | 34 | 41 | 42 | 43 | 44 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_licenses.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 26 | 27 | 33 | 34 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 17 | 18 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_openvpn_logs.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 26 | 27 | 32 | 33 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 17 | 18 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_error.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 23 | 24 | 36 | 37 | 43 | 44 |