Skip to content

Commit

Permalink
Merge branch 'release/2.4.1.0' into 'master'
Browse files Browse the repository at this point in the history
Release 2.4.1.0

See merge request ProtonVPN/android/android-app-new!183
  • Loading branch information
AlgirdasPundzius committed Nov 6, 2020
2 parents f365463 + 82d74a1 commit 24637f5
Show file tree
Hide file tree
Showing 90 changed files with 1,603 additions and 399 deletions.
74 changes: 45 additions & 29 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ buildscript {
plugins {
id 'com.android.application'
id 'com.github.triplet.play' version '2.7.2'
id 'org.jetbrains.kotlin.plugin.serialization' version '1.3.70'
id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlin_version"
}

apply plugin: 'io.gitlab.arturbosch.detekt'
Expand Down Expand Up @@ -150,7 +150,7 @@ def appId = project.hasProperty('appId') ? appId : "ch.protonvpn.android"
android {
def helpers = new Helpers()

compileSdkVersion 28
compileSdkVersion 30
// FIXME: update on CI image
ndkVersion "20.0.5594570"
useLibrary 'org.apache.http.legacy'
Expand All @@ -174,7 +174,7 @@ android {
defaultConfig {
applicationId appId
minSdkVersion 21
targetSdkVersion 28
targetSdkVersion 30
multiDexEnabled true
versionName helpers.fullVersionName
versionCode helpers.getVersionCode(0)
Expand Down Expand Up @@ -260,6 +260,12 @@ android {
main {
assets.srcDirs = ['src/main/assets', 'assets', 'ovpnlibs/assets', '../openvpn/build/ovpnassets']
}
test {
java.srcDirs += "$projectDir/src/sharedTest/java"
}
androidTest {
java.srcDirs += "$projectDir/src/sharedTest/java"
}
}
compileOptions {
targetCompatibility 1.8
Expand Down Expand Up @@ -339,6 +345,12 @@ task prepareGuestHoleServers {
}
}

tasks.withType(Test) {
testLogging {
events "passed", "skipped", "failed"
}
}

preBuild.dependsOn prepareGuestHoleServers

ext.abiCodes = ['armeabi-v7a':1, 'arm64-v8a':2, x86:3, x86_64:4]
Expand Down Expand Up @@ -502,43 +514,43 @@ apply plugin: 'checkstyle'

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
debugImplementation 'androidx.test.espresso.idling:idling-concurrent:3.3.0-rc01'
debugImplementation 'androidx.test.espresso.idling:idling-concurrent:3.3.0'
debugImplementation('com.jakewharton.espresso:okhttp3-idling-resource:1.0.0') {
exclude module: 'support-annotations'
}
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4'

detekt 'io.gitlab.arturbosch.detekt:detekt-formatting:1.9.1'
detekt 'io.gitlab.arturbosch.detekt:detekt-cli:1.9.1'
detektPlugins 'pm.algirdas.detekt:codeanalysis:0.3.2'
detektPlugins 'io.gitlab.arturbosch.detekt:detekt-formatting:1.9.1'

implementation 'com.proton:srp:1.0.0@aar'
implementation 'androidx.test.espresso:espresso-idling-resource:3.3.0-rc01'
implementation 'androidx.test.espresso:espresso-idling-resource:3.3.0'
// 3.10 of commons-lang3 causes NoClassDefFoundError on start (to be investigated)
implementation 'org.apache.commons:commons-lang3:3.9'
implementation 'commons-codec:commons-codec:1.14'
implementation 'com.qozix:tileview:2.2.7'
implementation 'com.google.android.material:material:1.1.0'
implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.10.0'
implementation 'com.jakewharton:butterknife:10.2.1'
implementation 'com.jakewharton:butterknife:10.2.3'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.github.lzyzsd:circleprogress:1.2.1'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.core:core:1.3.0'
implementation 'androidx.core:core-ktx:1.3.0'
implementation 'androidx.core:core:1.3.1'
implementation 'androidx.core:core-ktx:1.3.1'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
implementation 'com.daimajia.easing:library:2.1@aar'
implementation 'com.daimajia.easing:library:2.4@aar'
implementation 'com.squareup:otto:1.3.8'
implementation 'io.sentry:sentry-android:1.7.30'
implementation 'com.makeramen:roundedimageview:2.3.0'
implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
implementation 'com.github.shts:TriangleLabelView:1.1.2'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'com.github.VictorAlbertos:RxActivityResult:0.5.0-2.x'
implementation 'com.jakewharton.rxbinding2:rxbinding-design:2.2.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.19'
Expand All @@ -557,20 +569,24 @@ dependencies {
implementation 'com.github.douglasjunior:android-simple-tooltip:0.2.3'
implementation 'ru.egslava:MaskedEditText:1.0.5'
implementation 'com.evernote:android-state:1.4.1'
implementation 'androidx.work:work-runtime:2.3.4'
implementation 'androidx.work:work-runtime:2.4.0'
implementation 'com.github.akarnokd:rxjava2-extensions:0.20.10'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7'
implementation "com.datatheorem.android.trustkit:trustkit:1.1.2"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
implementation "com.datatheorem.android.trustkit:trustkit:1.1.3"
implementation 'com.xwray:groupie:2.7.2'
implementation 'com.xwray:groupie-databinding:2.7.2'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'org.minidns:minidns-hla:0.3.4'
implementation 'org.minidns:minidns-hla:1.0.0'
implementation 'com.github.tony19:logback-android:2.0.0'
implementation 'org.slf4j:slf4j-api:1.7.30'
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0"
implementation "androidx.preference:preference-ktx:1.1.1"

// Glide
implementation 'com.github.bumptech.glide:glide:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'

// Proton Core libs
implementation "me.proton.core:network:0.2.3"
implementation "me.proton.core:util-kotlin:0.1.5"
Expand All @@ -585,7 +601,7 @@ dependencies {
kapt "com.google.dagger:dagger-android-processor:$daggerVersion"
kapt "com.google.dagger:dagger-compiler:$daggerVersion"

kapt 'com.jakewharton:butterknife-compiler:10.2.1'
kapt 'com.jakewharton:butterknife-compiler:10.2.3'
kapt 'com.evernote:android-state-processor:1.4.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

Expand All @@ -598,33 +614,33 @@ dependencies {
testImplementation 'junit:junit:4.13'
testImplementation 'io.mockk:mockk:1.10.0'
androidTestImplementation 'io.mockk:mockk-android:1.10.0'
androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7'
androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.9'

androidTestImplementation('androidx.test.espresso:espresso-idling-resource:3.3.0-rc01') {
androidTestImplementation('androidx.test.espresso:espresso-idling-resource:3.3.0') {
exclude module: 'support-annotations'
}
androidTestImplementation 'com.azimolabs.conditionwatcher:conditionwatcher:0.2'

// Core library
androidTestImplementation 'androidx.test:core:1.2.0'
androidTestImplementation 'androidx.test:core:1.3.0'
testImplementation "androidx.arch.core:core-testing:2.1.0"
androidTestImplementation "androidx.arch.core:core-testing:2.1.0"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.9'

// AndroidJUnitRunner and JUnit Rules
androidTestImplementation 'androidx.test:runner:1.3.0-rc01'
androidTestImplementation 'androidx.test:rules:1.3.0-rc01'
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test:rules:1.3.0'

// Assertions
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.ext:truth:1.2.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.ext:truth:1.3.0'
androidTestImplementation 'com.google.truth:truth:1.0.1'

// Espresso dependencies
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-rc01'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.3.0-rc01'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.3.0-rc01'
androidTestImplementation 'androidx.test.espresso:espresso-accessibility:3.3.0-rc01'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-accessibility:3.3.0'
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
implementation project(path: ':openvpn')
}
12 changes: 12 additions & 0 deletions app/src/androidTest/java/com/protonvpn/actions/HomeRobot.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ public HomeRobot disableSecureCore() {
return this;
}

public void openDrawer() {
clickOnObjectWithContentDescription(R.string.hamburgerMenu);
}

public void checkOfferVisible(String label) {
checkIfObjectWithIdAndTextIsDisplayed(R.id.drawerNotificationItem, label);
}

public void checkOfferNotVisible(String label) {
checkIfObjectWithIdAndTextIsNotDisplayed(R.id.drawerNotificationItem, label);
}

public SettingsRobot openSettings() {
clickOnObjectWithContentDescription(R.string.hamburgerMenu);
clickOnObjectWithText("Settings");
Expand Down
26 changes: 26 additions & 0 deletions app/src/androidTest/java/com/protonvpn/di/MockApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,17 @@ import com.protonvpn.MockSwitch
import com.protonvpn.android.api.NetworkResultCallback
import com.protonvpn.android.api.ProtonApiRetroFit
import com.protonvpn.android.api.ProtonVPNRetrofit
import com.protonvpn.android.appconfig.ApiNotification
import com.protonvpn.android.appconfig.ApiNotificationTypes
import com.protonvpn.android.appconfig.ApiNotificationsResponse
import com.protonvpn.android.appconfig.AppConfigResponse
import com.protonvpn.android.appconfig.FeatureFlags
import com.protonvpn.android.components.LoaderUI
import com.protonvpn.android.models.login.GenericResponse
import com.protonvpn.android.models.login.SessionListResponse
import com.protonvpn.android.models.login.VpnInfoResponse
import com.protonvpn.android.models.vpn.ServerList
import com.protonvpn.test.shared.ApiNotificationTestHelper
import com.protonvpn.testsHelper.MockedServers
import com.protonvpn.testsHelper.TestUser
import kotlinx.coroutines.CoroutineScope
Expand All @@ -36,6 +42,12 @@ import me.proton.core.network.domain.ApiResult

class MockApi(scope: CoroutineScope, manager: ApiManager<ProtonVPNRetrofit>) : ProtonApiRetroFit(scope, manager) {

override suspend fun getAppConfig(): ApiResult<AppConfigResponse> =
ApiResult.Success(AppConfigResponse(featureFlags = FeatureFlags(
maintenanceTrackerEnabled = true,
netShieldEnabled = true,
pollApiNotifications = true)))

override suspend fun getSession(): ApiResult<SessionListResponse> =
ApiResult.Success(SessionListResponse(0, listOf()))

Expand All @@ -54,4 +66,18 @@ class MockApi(scope: CoroutineScope, manager: ApiManager<ProtonVPNRetrofit>) : P
override fun getVPNInfo(callback: NetworkResultCallback<VpnInfoResponse>) = scope.launch {
ApiResult.Success(TestUser.getBasicUser().vpnInfoResponse)
}

override suspend fun getApiNotifications(): ApiResult<ApiNotificationsResponse> =
ApiResult.Success(ApiNotificationTestHelper.mockResponse(
ApiNotificationTestHelper.mockOffer("1", Long.MIN_VALUE, Long.MIN_VALUE + 1, PAST_OFFER_LABEL),
ApiNotificationTestHelper.mockOffer("2", Long.MIN_VALUE, Long.MAX_VALUE, OFFER_LABEL),
ApiNotificationTestHelper.mockOffer("3", Long.MAX_VALUE - 1, Long.MAX_VALUE, FUTURE_OFFER_LABEL),
ApiNotification("2", Long.MIN_VALUE, Long.MAX_VALUE, ApiNotificationTypes.TYPE_OFFER + 1)
))

companion object {
const val OFFER_LABEL = "Offer"
const val PAST_OFFER_LABEL = "Past"
const val FUTURE_OFFER_LABEL = "Future"
}
}
8 changes: 7 additions & 1 deletion app/src/androidTest/java/com/protonvpn/di/MockAppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.protonvpn.android.api.GuestHole
import com.protonvpn.android.api.ProtonApiRetroFit
import com.protonvpn.android.api.ProtonVPNRetrofit
import com.protonvpn.android.api.VpnApiClient
import com.protonvpn.android.appconfig.ApiNotificationManager
import com.protonvpn.android.appconfig.AppConfig
import com.protonvpn.android.models.config.UserData
import com.protonvpn.android.models.config.VpnProtocol
Expand Down Expand Up @@ -73,7 +74,12 @@ class MockAppModule {

@Singleton
@Provides
fun provideAppConfig(api: ProtonApiRetroFit): AppConfig = AppConfig(scope, api)
fun provideAppConfig(api: ProtonApiRetroFit, userData: UserData): AppConfig = AppConfig(scope, api, userData)

@Singleton
@Provides
fun provideApiNotificationManager(appConfig: AppConfig): ApiNotificationManager =
ApiNotificationManager(scope, System::currentTimeMillis, appConfig)

@Singleton
@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.protonvpn.di

import android.content.Context
import android.content.Intent
import com.protonvpn.android.ProtonApplication
import com.protonvpn.android.api.ProtonApiRetroFit
import com.protonvpn.android.models.config.UserData
import com.protonvpn.android.ui.home.ServerListUpdater
Expand All @@ -39,7 +40,8 @@ class MockVpnStateMonitor(
networkManager: NetworkManager,
maintenanceTracker: MaintenanceTracker,
scope: CoroutineScope
) : VpnStateMonitor(userData, api, vpnBackendProvider, serverListUpdater, trafficMonitor, networkManager, maintenanceTracker, scope) {
) : VpnStateMonitor(ProtonApplication.getAppContext(), userData, api, vpnBackendProvider,
serverListUpdater, trafficMonitor, networkManager, maintenanceTracker, scope) {

override fun prepare(context: Context): Intent? = null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2018 Proton Technologies AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
*/
package com.protonvpn.tests.home

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import com.protonvpn.actions.HomeRobot
import com.protonvpn.di.MockApi
import com.protonvpn.tests.testRules.ProtonHomeActivityTestRule
import com.protonvpn.tests.testRules.SetUserPreferencesRule
import com.protonvpn.testsHelper.TestUser
import org.junit.ClassRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@LargeTest
@RunWith(AndroidJUnit4::class)
class HomeRobotTests {

private val homeRobot = HomeRobot()

@get:Rule
var testRule = ProtonHomeActivityTestRule()

@Test
fun offerShown() {
homeRobot.openDrawer()
homeRobot.checkOfferVisible(MockApi.OFFER_LABEL)
homeRobot.checkOfferNotVisible(MockApi.PAST_OFFER_LABEL)
homeRobot.checkOfferNotVisible(MockApi.FUTURE_OFFER_LABEL)
}

companion object {
@ClassRule
@JvmField
var testClassRule = SetUserPreferencesRule(TestUser.getPlusUser())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import static com.protonvpn.android.ui.onboarding.OnboardingPreferences.FLOATINGACTION_DIALOG;
import static com.protonvpn.android.ui.onboarding.OnboardingPreferences.FLOATING_BUTTON_USED;
import static com.protonvpn.android.ui.onboarding.OnboardingPreferences.MAPVIEW_DIALOG;
import static com.protonvpn.android.ui.onboarding.OnboardingPreferences.NETSHIELD_DIALOG;
import static com.protonvpn.android.ui.onboarding.OnboardingPreferences.PROFILES_DIALOG;
import static com.protonvpn.android.ui.onboarding.OnboardingPreferences.SECURECORE_DIALOG;
import static com.protonvpn.android.ui.onboarding.OnboardingPreferences.SLIDES_SHOWN;
Expand All @@ -38,6 +39,7 @@ public static void setCompletedOnboarding() {
Storage.saveBoolean(SECURECORE_DIALOG, true);
Storage.saveBoolean(FLOATINGACTION_DIALOG, true);
Storage.saveBoolean(FLOATING_BUTTON_USED, true);
Storage.saveBoolean(NETSHIELD_DIALOG, true);
Storage.saveBoolean(COUNTRY_DIALOG, true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ protected void checkIfObjectWithTextIsNotDisplayed(String text) {
onView(Matchers.allOf(withText(text))).equals(nullValue());
}

protected void checkIfObjectWithIdAndTextIsNotDisplayed(@IdRes int objectId, String text) {
onView(Matchers.allOf(withId(objectId), withText(text), isDisplayed())).equals(nullValue());
}

protected void checkIfObjectWithTextIsDisplayed(String text) {
onView(isRoot()).perform(waitText(text));
ViewInteraction object = onView(Matchers.allOf(withText(text), isDisplayed()));
Expand Down
Loading

0 comments on commit 24637f5

Please sign in to comment.