Skip to content

Commit 74e4bba

Browse files
committed
Reapply "Merge branch 'release/5.218.0'"
This reverts commit 145d037.
1 parent fc04001 commit 74e4bba

File tree

4,170 files changed

+854583
-1982
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

4,170 files changed

+854583
-1982
lines changed

.bundle/config

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
BUNDLE_PATH: "/Users/runner/work/Android/Android/vendor/bundle"
3+
BUNDLE_DEPLOYMENT: "true"
4+
BUNDLE_JOBS: "4"
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Release - Create and Push Tag
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
app-version:
7+
description: 'App Version for Release'
8+
required: true
9+
default: 'PLACEHOLDER'
10+
11+
env:
12+
ASANA_PAT: ${{ secrets.GH_ASANA_SECRET }}
13+
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
create-tag:
20+
name: Create and Push git tag for version
21+
runs-on: macos-latest
22+
23+
steps:
24+
- name: Checkout repository
25+
uses: actions/checkout@v4
26+
with:
27+
submodules: recursive
28+
29+
- name: Set up ruby env
30+
uses: ruby/setup-ruby@v1
31+
with:
32+
ruby-version: 2.7.2
33+
bundler-cache: true
34+
35+
- name: Use fastlane lane to create and push tagged release
36+
id: create_git_tag
37+
run: |
38+
bundle exec fastlane android tag_and_push_release_version app_version:${{ github.event.inputs.app-version }}
39+
40+
- name: Create Asana task when workflow failed
41+
if: ${{ failure() }}
42+
id: create-failure-task
43+
uses: duckduckgo/[email protected]
44+
with:
45+
asana-pat: ${{ secrets.GH_ASANA_SECRET }}
46+
asana-project: ${{ vars.GH_ANDROID_APP_PROJECT_ID }}
47+
asana-section: ${{ vars.GH_ANDROID_APP_INCOMING_SECTION_ID }}
48+
asana-task-name: GH Workflow Failure - Tag Android Release
49+
asana-task-description: Tag Android Release has failed. See https://github.com/duckduckgo/Android/actions/runs/${{ github.run_id }}
50+
action: 'create-asana-task'

.github/workflows/release_create_task.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Create Android App Release Task
1+
name: Release - Create Release Task in Asana
22

33
on:
44
workflow_dispatch:
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Release - Android App Production Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
app-version:
7+
description: 'App Version for Release'
8+
required: true
9+
default: 'PLACEHOLDER'
10+
11+
env:
12+
ASANA_PAT: ${{ secrets.GH_ASANA_SECRET }}
13+
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
create_release_task:
20+
uses: ./.github/workflows/release_create_task.yml
21+
with:
22+
app-version: ${{ github.event.inputs.app-version }}
23+
24+
create_release_tag:
25+
needs: create_release_task
26+
uses: ./.github/workflows/release_create_tag.yml
27+
with:
28+
app-version: ${{ github.event.inputs.app-version }}
29+
30+
launch_release_tests:
31+
needs: create_release_tag
32+
uses: ./.github/workflows/release_tests.yml
33+
with:
34+
app-version: ${{ github.event.inputs.app-version }}
35+
36+
report_workflow_failed:
37+
if: ${{ failure() }}
38+
uses: ./.github/workflows/release_report_error.yml
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Report Workflow Failed
2+
3+
on:
4+
workflow_dispatch:
5+
6+
env:
7+
ASANA_PAT: ${{ secrets.GH_ASANA_SECRET }}
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
report-release-error:
15+
name: Create Asana Task
16+
runs-on: ubuntu-20.04
17+
18+
steps:
19+
- name: Create Asana task when workflow failed
20+
uses: honeycombio/gha-create-asana-task@main
21+
with:
22+
asana-secret: ${{ secrets.GH_ASANA_SECRET }}
23+
asana-workspace-id: ${{ secrets.GH_ASANA_WORKSPACE_ID }}
24+
asana-project-id: ${{ secrets.GH_ASANA_AOR_PROJECT_ID }}
25+
asana-section-id: ${{ secrets.GH_ASANA_INCOMING_ID }}
26+
asana-task-name: GH Workflow Failure - Production Release
27+
asana-task-description: The end to end workflow has failed. See https://github.com/duckduckgo/Android/actions/runs/${{ github.run_id }}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
name: Run Release Tests in Maestro
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
app-version:
7+
description: 'App Version for Release'
8+
required: true
9+
default: 'PLACEHOLDER'
10+
11+
env:
12+
ASANA_PAT: ${{ secrets.GH_ASANA_SECRET }}
13+
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
run-release-tests:
20+
name: Run Release tests of tag version in Maestro
21+
runs-on: ubuntu-20.04
22+
23+
steps:
24+
- name: Checkout repository
25+
uses: actions/checkout@v4
26+
with:
27+
submodules: recursive
28+
ref: ${{ github.event.inputs.app-version }}
29+
30+
- name: Set up JDK 17
31+
uses: actions/setup-java@v4
32+
with:
33+
java-version: '17'
34+
distribution: 'adopt'
35+
36+
- name: Create folder
37+
if: always()
38+
run: mkdir apk
39+
40+
- name: Decode keys
41+
uses: davidSchuppa/base64Secret-toFile-action@v2
42+
with:
43+
secret: ${{ secrets.FAKE_RELEASE_PROPERTIES }}
44+
fileName: ddg_android_build.properties
45+
destination-path: $HOME/jenkins_static/com.duckduckgo.mobile.android/
46+
47+
- name: Decode key file
48+
uses: davidSchuppa/base64Secret-toFile-action@v2
49+
with:
50+
secret: ${{ secrets.FAKE_RELEASE_KEY }}
51+
fileName: android
52+
destination-path: $HOME/jenkins_static/com.duckduckgo.mobile.android/
53+
54+
- name: Setup Gradle
55+
uses: gradle/actions/setup-gradle@v3
56+
57+
- name: Assemble release APK
58+
run: ./gradlew assemblePlayRelease -Pforce-default-variant
59+
60+
- name: Move APK to new folder
61+
if: always()
62+
run: find . -name "*.apk" -exec mv '{}' apk/release.apk \;
63+
64+
- name: Release tests flows
65+
uses: mobile-dev-inc/[email protected]
66+
with:
67+
api-key: ${{ secrets.MOBILE_DEV_API_KEY }}
68+
name: ${{ github.sha }}
69+
app-file: apk/release.apk
70+
android-api-level: 30
71+
workspace: .maestro
72+
include-tags: releaseTest
73+
74+
- name: Create Asana task when workflow failed
75+
if: ${{ failure() }}
76+
id: create-failure-task
77+
uses: duckduckgo/[email protected]
78+
with:
79+
asana-pat: ${{ secrets.GH_ASANA_SECRET }}
80+
asana-project: ${{ vars.GH_ANDROID_APP_PROJECT_ID }}
81+
asana-section: ${{ vars.GH_ANDROID_APP_INCOMING_SECTION_ID }}
82+
asana-task-name: GH Workflow Failure - Tag Android Release
83+
asana-task-description: Tag Android Release has failed. See https://github.com/duckduckgo/Android/actions/runs/${{ github.run_id }}
84+
action: 'create-asana-task'

Gemfile.lock

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ GEM
106106
xcodeproj (>= 1.13.0, < 2.0.0)
107107
xcpretty (~> 0.3.0)
108108
xcpretty-travis-formatter (>= 0.0.3)
109+
fastlane-plugin-firebase_app_distribution (0.9.1)
110+
google-apis-firebaseappdistribution_v1 (~> 0.3.0)
111+
google-apis-firebaseappdistribution_v1alpha (~> 0.2.0)
109112
fastlane-plugin-property_file_read (1.0.1)
110113
gh_inspector (1.1.3)
111114
google-apis-androidpublisher_v3 (0.53.0)
@@ -119,6 +122,10 @@ GEM
119122
retriable (>= 2.0, < 4.a)
120123
rexml
121124
webrick
125+
google-apis-firebaseappdistribution_v1 (0.3.0)
126+
google-apis-core (>= 0.11.0, < 2.a)
127+
google-apis-firebaseappdistribution_v1alpha (0.2.0)
128+
google-apis-core (>= 0.11.0, < 2.a)
122129
google-apis-iamcredentials_v1 (0.17.0)
123130
google-apis-core (>= 0.11.0, < 2.a)
124131
google-apis-playcustomapp_v1 (0.13.0)
@@ -213,6 +220,7 @@ PLATFORMS
213220

214221
DEPENDENCIES
215222
fastlane
223+
fastlane-plugin-firebase_app_distribution
216224
fastlane-plugin-property_file_read
217225

218226
BUNDLED WITH

anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesRemoteFeatureCodeGenerator.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
107107
)
108108
.build(),
109109
)
110+
.addParameter("callback", featureTogglesCallback.asClassName(module))
110111
.addParameter("appBuildConfig", appBuildConfig.asClassName(module))
111112
.addParameter("variantManager", variantManager.asClassName(module))
112113
.addCode(
@@ -118,6 +119,7 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
118119
.featureName(%S)
119120
.appVariantProvider({ appBuildConfig.variantName })
120121
.localeProvider({ appBuildConfig.deviceLocale })
122+
.callback(callback)
121123
// save empty variants will force the default variant to be set
122124
.forceDefaultVariantProvider({ variantManager.updateVariants(emptyList()) })
123125
.build()
@@ -1151,6 +1153,7 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
11511153
private val context = FqName("android.content.Context")
11521154
private val privacyFeaturePlugin = FqName("com.duckduckgo.privacy.config.api.PrivacyFeaturePlugin")
11531155
private val appBuildConfig = FqName("com.duckduckgo.appbuildconfig.api.AppBuildConfig")
1156+
private val featureTogglesCallback = FqName("com.duckduckgo.feature.toggles.internal.api.FeatureTogglesCallback")
11541157
private val variantManager = FqName("com.duckduckgo.experiments.api.VariantManager")
11551158
private val buildFlavorInternal = FqName("com.duckduckgo.appbuildconfig.api.BuildFlavor.INTERNAL")
11561159
private val moshi = FqName("com.squareup.moshi.Moshi")

app-tracking-protection/vpn-api/src/main/java/com/duckduckgo/mobile/android/vpn/Vpn.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,15 @@ interface Vpn {
2626
suspend fun start()
2727

2828
/**
29-
* Disable the device VPN by stopping the VPN service
29+
* Pauses the VPN tunnel.
30+
* All features that were registered to use the VPN tunnel (eg. AppTP, NetP) continue to be registered and so a subsequent
31+
* [start] call will re-enable them all
32+
*/
33+
suspend fun pause()
34+
35+
/**
36+
* Stops the VPN tunnel AND all features registered to use the VPN tunnel (eg. AppTP, NetP). A subsequent call to [start]
37+
* will not re-start the VPN because no feature would be registered.
3038
*/
3139
suspend fun stop()
3240

app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/VpnFeaturesRegistryImpl.kt

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,33 @@ import android.content.SharedPreferences
2121
import androidx.core.content.edit
2222
import com.duckduckgo.common.utils.DispatcherProvider
2323
import com.duckduckgo.data.store.api.SharedPreferencesProvider
24+
import com.duckduckgo.di.scopes.AppScope
2425
import com.duckduckgo.mobile.android.vpn.service.TrackerBlockingVpnService
26+
import com.squareup.anvil.annotations.ContributesBinding
27+
import dagger.SingleInstanceIn
2528
import java.util.UUID
29+
import javax.inject.Inject
2630
import kotlinx.coroutines.sync.Mutex
2731
import kotlinx.coroutines.withContext
2832
import logcat.logcat
2933

3034
private const val PREFS_FILENAME = "com.duckduckgo.mobile.android.vpn.feature.registry.v1"
3135
private const val IS_INITIALIZED = "IS_INITIALIZED"
3236

33-
internal class VpnFeaturesRegistryImpl(
37+
@ContributesBinding(
38+
scope = AppScope::class,
39+
boundType = VpnFeaturesRegistry::class,
40+
)
41+
@ContributesBinding(
42+
scope = AppScope::class,
43+
boundType = Vpn::class,
44+
)
45+
@SingleInstanceIn(AppScope::class)
46+
class VpnFeaturesRegistryImpl @Inject constructor(
3447
private val vpnServiceWrapper: VpnServiceWrapper,
3548
private val sharedPreferencesProvider: SharedPreferencesProvider,
3649
private val dispatcherProvider: DispatcherProvider,
37-
) : VpnFeaturesRegistry {
50+
) : VpnFeaturesRegistry, Vpn {
3851

3952
private val mutex = Mutex()
4053

@@ -103,6 +116,34 @@ internal class VpnFeaturesRegistryImpl(
103116
private fun registeredFeatures(): Map<String, Any?> {
104117
return preferences.all.filter { it.key != IS_INITIALIZED }
105118
}
119+
120+
override suspend fun start() = withContext(dispatcherProvider.io()) {
121+
vpnServiceWrapper.startService()
122+
}
123+
124+
override suspend fun pause() {
125+
vpnServiceWrapper.stopService()
126+
}
127+
128+
override suspend fun stop() {
129+
try {
130+
mutex.lock()
131+
// unregister all features
132+
getRegisteredFeatures().onEach {
133+
preferences.edit(commit = true) {
134+
remove(it.featureName)
135+
}
136+
}
137+
// stop VPN
138+
vpnServiceWrapper.stopService()
139+
} finally {
140+
mutex.unlock()
141+
}
142+
}
143+
144+
override suspend fun snooze(triggerAtMillis: Long) {
145+
vpnServiceWrapper.snoozeService(triggerAtMillis)
146+
}
106147
}
107148

108149
/**
@@ -111,10 +152,9 @@ internal class VpnFeaturesRegistryImpl(
111152
*
112153
* The class is marked as open to be able to mock it in tests.
113154
*/
114-
internal open class VpnServiceWrapper(
155+
open class VpnServiceWrapper @Inject constructor(
115156
private val context: Context,
116-
private val dispatcherProvider: DispatcherProvider,
117-
) : Vpn {
157+
) {
118158
open fun restartVpnService(forceRestart: Boolean) {
119159
TrackerBlockingVpnService.restartVpnService(context, forceRestart = forceRestart)
120160
}
@@ -127,19 +167,11 @@ internal open class VpnServiceWrapper(
127167
TrackerBlockingVpnService.startService(context)
128168
}
129169

130-
open fun isServiceRunning(): Boolean {
131-
return TrackerBlockingVpnService.isServiceRunning(context)
132-
}
133-
134-
override suspend fun start() = withContext(dispatcherProvider.io()) {
135-
startService()
136-
}
137-
138-
override suspend fun stop() = withContext(dispatcherProvider.io()) {
139-
stopService()
170+
open fun snoozeService(triggerAtMillis: Long) {
171+
TrackerBlockingVpnService.snoozeService(context, triggerAtMillis)
140172
}
141173

142-
override suspend fun snooze(triggerAtMillis: Long) {
143-
TrackerBlockingVpnService.snoozeService(context, triggerAtMillis)
174+
open fun isServiceRunning(): Boolean {
175+
return TrackerBlockingVpnService.isServiceRunning(context)
144176
}
145177
}

0 commit comments

Comments
 (0)