Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ads hotfix #910

Merged
merged 8 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .run/main.dart.run.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="main.dart" type="FlutterRunConfigurationType" factoryName="Flutter">
<option name="additionalArgs" value="--dart-define=INTERSTITIAL_AD_UNIT_ID=ca-app-pub-2685698271254859/9922829329 --dart-define=DD_APPLICATION_ID=f8eabf3c-5db3-4f7e-8e6a-5a72433b46d2 --dart-define=DD_CLIENT_TOKEN=puba617ab01333a95a25a9d3709f04e1654" />
<option name="attachArgs" value="--profile" />
<option name="buildFlavor" value="prod" />
<option name="filePath" value="$PROJECT_DIR$/lib/main.dart" />
<method v="2" />
Expand Down
29 changes: 21 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -293,19 +293,26 @@ vault-secret-%:
printf "$$SECRET"

vault-secret-base64:
@SECRET=$(shell cd $(LANTERN_CLOUD) && bin/vault kv get -field=$(VAULT_FIELD) $(VAULT_PATH)); \
@set -e; \
trap 'echo "An error occurred while fetching the vault secret. Exiting..." >&2; exit 1' ERR; \
SECRET=$$(cd $(LANTERN_CLOUD) && bin/vault kv get -field=$(VAULT_FIELD) $(VAULT_PATH)); \
if [ -z "$$SECRET" ]; then echo "Error: Secret is empty or not set for VAULT_FIELD=$(VAULT_FIELD) and VAULT_PATH=$(VAULT_PATH)."; exit 1; fi; \
echo "Retrieved secret: $$SECRET" 1>&2; \
printf "$$VAULT_FIELD=$$SECRET" | ${BASE64}

dart-defines-debug:
@DART_DEFINES=$(shell make vault-secret-base64 VAULT_FIELD=INTERSTITIAL_AD_UNIT_ID VAULT_PATH=secret/googleAds); \
DART_DEFINES+=$(shell printf ',' && make vault-secret-base64 VAULT_FIELD=DD_APPLICATION_ID VAULT_PATH=secret/apps/datadog/android); \
DART_DEFINES+=$(shell printf ',' && make vault-secret-base64 VAULT_FIELD=DD_CLIENT_TOKEN VAULT_PATH=secret/apps/datadog/android); \
@set -e; \
trap 'echo "An error occurred while setting DART_DEFINES. Exiting..." >&2; exit 1' ERR; \
DART_DEFINES=$$(make vault-secret-base64 VAULT_FIELD=INTERSTITIAL_AD_UNIT_ID VAULT_PATH=secret/googleAds); \
DART_DEFINES+=$$(printf ',' && make vault-secret-base64 VAULT_FIELD=DD_APPLICATION_ID VAULT_PATH=secret/apps/datadog/android); \
DART_DEFINES+=$$(printf ',' && make vault-secret-base64 VAULT_FIELD=DD_CLIENT_TOKEN VAULT_PATH=secret/apps/datadog/android); \
DART_DEFINES+=",$(CIBASE)"; \
echo "$$DART_DEFINES"

do-android-debug: $(MOBILE_SOURCES) $(MOBILE_ANDROID_LIB)
@ln -fs $(MOBILE_DIR)/gradle.properties . && \
@set -e; \
trap 'echo "An error occurred during the android debug build process. Exiting..." >&2; exit 1' ERR; \
ln -fs $(MOBILE_DIR)/gradle.properties . && \
DART_DEFINES=`make dart-defines-debug` && \
CI="$$CI" && $(GRADLE) -Pdart-defines="$$DART_DEFINES" -PlanternVersion=$(DEBUG_VERSION) -PddClientToken=$$DD_CLIENT_TOKEN -PddApplicationID=$$DD_APPLICATION_ID \
-PproServerUrl=$(PRO_SERVER_URL) -PpaymentProvider=$(PAYMENT_PROVIDER) -Pcountry=$(COUNTRY) \
Expand All @@ -323,16 +330,22 @@ $(MOBILE_DEBUG_APK): $(MOBILE_SOURCES) $(GO_SOURCES)
cp $(MOBILE_ANDROID_DEBUG) $(MOBILE_DEBUG_APK)

env-secret-%:
@SECRET=$(shell echo "$(${*})"); \
@set -e; \
trap 'echo "An error occurred while fetching the environment secret for ${*}. Exiting..." >&2; exit 1' ERR; \
SECRET=$(shell echo "$(${*})"); \
printf ${*}=$$SECRET | ${BASE64}

dart-defines-release:
@DART_DEFINES=`make env-secret-INTERSTITIAL_AD_UNIT_ID`; \
@set -e; \
trap 'echo "An error occurred while setting DART_DEFINES for release. Exiting..." >&2; exit 1' ERR; \
@DART_DEFINES=`make env-secret-INTERSTITIAL_AD_UNIT_ID`; \
DART_DEFINES+=`printf ',' && $(CIBASE)`; \
printf $$DART_DEFINES

$(MOBILE_RELEASE_APK): $(MOBILE_SOURCES) $(GO_SOURCES) $(MOBILE_ANDROID_LIB) require-datadog-ci
echo $(MOBILE_ANDROID_LIB) && \
@set -e; \
trap 'echo "An error occurred during the android release build process. Exiting..." >&2; exit 1' ERR; \
echo $(MOBILE_ANDROID_LIB) && \
mkdir -p ~/.gradle && \
ln -fs $(MOBILE_DIR)/gradle.properties . && \
COUNTRY="$$COUNTRY" && \
Expand Down
4 changes: 2 additions & 2 deletions android/app/libs/liblantern-all.aar
Git LFS file not shown
12 changes: 11 additions & 1 deletion android/app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,14 @@

##---------------Begin: proguard configuration for Signal ----------
-keep class org.whispersystems.** { *; }
##---------------End: proguard configuration for Signal ----------
##---------------End: proguard configuration for Signal ----------

-keep class com.google.ads.** # Don't proguard AdMob classes
-dontwarn com.google.ads.
-keep public class com.google.android.gms.ads.** {
public *;
}

-keep public class com.google.ads.** {
public *;
}
59 changes: 44 additions & 15 deletions android/app/src/main/kotlin/io/lantern/model/SessionModel.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package io.lantern.model

import android.app.Activity
import android.content.Intent
import android.os.AsyncTask
import android.os.Build
import android.content.Intent
import androidx.core.content.ContextCompat
import com.google.gson.JsonObject
import com.google.protobuf.ByteString
Expand All @@ -23,7 +23,6 @@ import org.getlantern.lantern.MainActivity
import org.getlantern.lantern.R
import org.getlantern.lantern.activity.FreeKassaActivity_
import org.getlantern.lantern.activity.WebViewActivity_
import org.getlantern.mobilesdk.model.IssueReporter
import org.getlantern.lantern.datadog.Datadog
import org.getlantern.lantern.model.LanternHttpClient
import org.getlantern.lantern.model.LanternHttpClient.ProCallback
Expand All @@ -40,6 +39,7 @@ import org.getlantern.lantern.util.restartApp
import org.getlantern.lantern.util.showAlertDialog
import org.getlantern.lantern.util.showErrorDialog
import org.getlantern.mobilesdk.Logger
import org.getlantern.mobilesdk.model.IssueReporter
import org.getlantern.mobilesdk.model.SessionManager

/**
Expand All @@ -66,7 +66,11 @@ class SessionModel(
const val PATH_USER_LEVEL = "userLevel"

const val PATH_SPLIT_TUNNELING = "/splitTunneling"
const val SHOULD_SHOW_CAS_ADS = "shouldShowCASAds"
const val SHOULD_SHOW_GOOGLE_ADS = "shouldShowGoogleAds"
const val PATH_APPS_DATA = "/appsData/"


}

init {
Expand All @@ -87,30 +91,43 @@ class SessionModel(
// hard disable chat
tx.put(SessionManager.CHAT_ENABLED, false)
tx.put(PATH_SDK_VERSION, Internalsdk.sdkVersion())
//By Default set it to false
tx.put(SHOULD_SHOW_GOOGLE_ADS, false)
tx.put(SHOULD_SHOW_CAS_ADS, false)
}
updateAppsData()
checkAdsAvailability()
}

fun checkAdsAvailability() {
Logger.debug(TAG, "checkAdsAvailability called")
val googleAds = shouldShowAdsBasedRegion { LanternApp.getSession().shouldShowAdsEnabled() }
Logger.debug(TAG, "checkAdsAvailability with googleAds values $googleAds enable ${LanternApp.getSession().shouldShowAdsEnabled()}")
val casAds = shouldShowAdsBasedRegion { LanternApp.getSession().shouldCASShowAdsEnabled() }
Logger.debug(TAG, "checkAdsAvailability with cas values $googleAds enable ${LanternApp.getSession().shouldCASShowAdsEnabled()}")
db.mutate { tx ->
tx.put(SHOULD_SHOW_GOOGLE_ADS, googleAds)
tx.put(SHOULD_SHOW_CAS_ADS, casAds)
}
}


override fun doOnMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"authorizeViaEmail" -> authorizeViaEmail(call.argument("emailAddress")!!, result)
"shouldShowAds" -> {
result.success(shouldShowAdsBasedRegion {
LanternApp.getSession().shouldShowAdsEnabled()
})
}
"shouldCASShowAds" -> {
result.success(shouldShowAdsBasedRegion {
LanternApp.getSession().shouldCASShowAdsEnabled()
})
}
"checkEmailExists" -> checkEmailExists(call.argument("emailAddress")!!, result)
"requestLinkCode" -> requestLinkCode(result)
"resendRecoveryCode" -> sendRecoveryCode(result)
"validateRecoveryCode" -> validateRecoveryCode(call.argument("code")!!, result)
"approveDevice" -> approveDevice(call.argument("code")!!, result)
"removeDevice" -> removeDevice(call.argument("deviceId")!!, result)
"reportIssue" -> reportIssue(call.argument("email")!!, call.argument("issue")!!, call.argument("description")!!, result)
"reportIssue" -> reportIssue(
call.argument("email")!!,
call.argument("issue")!!,
call.argument("description")!!,
result
)

"applyRefCode" -> paymentsUtil.applyRefCode(call.argument("refCode")!!, result)
"redeemResellerCode" -> paymentsUtil.redeemResellerCode(
call.argument("email")!!,
Expand Down Expand Up @@ -158,12 +175,15 @@ class SessionModel(
activity.startActivity(intent)
}
}

"trackUserAction" -> {
Datadog.trackUserClick(call.argument("message")!!)
}

"acceptTerms" -> {
LanternApp.getSession().acceptTerms()
}

"setLanguage" -> {
LanternApp.getSession().setLanguage(call.argument("lang"))
}
Expand Down Expand Up @@ -572,9 +592,18 @@ class SessionModel(
)
}

private fun reportIssue(email: String, issue: String, description: String, methodCallResult: MethodChannel.Result) {
private fun reportIssue(
email: String,
issue: String,
description: String,
methodCallResult: MethodChannel.Result
) {
if (!Utils.isNetworkAvailable(activity)) {
methodCallResult.error("errorReportingIssue", activity.getString(R.string.no_internet_connection), null)
methodCallResult.error(
"errorReportingIssue",
activity.getString(R.string.no_internet_connection),
null
)
return
}
Logger.debug(TAG, "Reporting $issue issue on behalf of $email")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ class MainActivity :
//If user come here it mean user has all permissions needed
// Also user given permission for VPN service dialog as well
LanternApp.getSession().setHasFirstSessionCompleted(true)
sessionModel.checkAdsAvailability()
updateStatus(true)
startVpnService()
}
Expand Down Expand Up @@ -606,6 +607,7 @@ class MainActivity :
// this mean user has already given
// system permissions
LanternApp.getSession().setHasFirstSessionCompleted(true)
sessionModel.checkAdsAvailability()
}

}
Expand Down
47 changes: 27 additions & 20 deletions lib/ad_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,14 @@ import 'package:clever_ads_solutions/public/AdCallback.dart';
import 'package:clever_ads_solutions/public/AdImpression.dart';
import 'package:clever_ads_solutions/public/AdTypes.dart';
import 'package:clever_ads_solutions/public/Audience.dart';
import 'package:clever_ads_solutions/public/ConsentFlow.dart';
import 'package:clever_ads_solutions/public/InitConfig.dart';
import 'package:clever_ads_solutions/public/InitializationListener.dart';
import 'package:clever_ads_solutions/public/MediationManager.dart';
import 'package:clever_ads_solutions/public/OnDismissListener.dart';
import 'package:flutter/foundation.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:lantern/common/datadog.dart';
import 'package:lantern/replica/common.dart';

import 'common/session_model.dart';

enum AdType { Google, CAS }

const privacyPolicy = 'https://lantern.io/privacy';
Expand Down Expand Up @@ -59,10 +55,9 @@ class AdHelper {
}

// Private methods to decide whether to load or show Google Ads or CAS ads based on conditions
Future<void> _decideAndLoadAds() async {
final shouldShowGoogleAds = await sessionModel.shouldShowAds();
final shouldShowCASAds = await sessionModel.shouldCASShowAds();

Future<void> _decideAndLoadAds(
{required bool shouldShowGoogleAds,
required bool shouldShowCASAds}) async {
logger.d(
'[Ads Manager] Google Ads enable $shouldShowGoogleAds: CAS Ads $shouldShowCASAds');
if (shouldShowGoogleAds) {
Expand Down Expand Up @@ -95,27 +90,32 @@ class AdHelper {

Future<void> _loadInterstitialAd() async {
//To avoid calling multiple ads request repeatedly
assert(interstitialAdUnitId!="","interstitialAdUnitId should not be null or empty");
if (_interstitialAd == null && _failedLoadAttempts < _maxFailAttempts) {
logger.i('[Ads Manager] Request: Making Google Ad request.');
await InterstitialAd.load(
adUnitId: interstitialAdUnitId,
request: const AdRequest(),
adLoadCallback: InterstitialAdLoadCallback(
onAdLoaded: (ad) {
_failedLoadAttempts = 0;
ad.fullScreenContentCallback = FullScreenContentCallback(
onAdClicked: (ad) {
logger.i('[Ads Manager] onAdClicked callback');
Datadog.trackUserTap('User tapped on interstitial ad', googleAttributes);
Datadog.trackUserTap(
'User tapped on interstitial ad', googleAttributes);
},
onAdShowedFullScreenContent: (ad) {
logger.i('[Ads Manager] Showing Ads');
Datadog.trackUserCustom('User shown interstitial ad', googleAttributes);
Datadog.trackUserCustom(
'User shown interstitial ad', googleAttributes);
},
onAdFailedToShowFullScreenContent: (ad, error) {
logger.i(
'[Ads Manager] onAdFailedToShowFullScreenContent callback');
Datadog.addError('Ad failed to show full screen content: $error',
attributes: googleAttributes);
Datadog.addError(
'Ad failed to show full screen content: $error',
attributes: googleAttributes);
//if ads fail to load let user turn on VPN
_postShowingAds();
},
Expand All @@ -131,7 +131,8 @@ class AdHelper {
onAdFailedToLoad: (err) {
_failedLoadAttempts++; // increment the count on failure
logger.i('[Ads Manager] failed to load $err');
Datadog.addError('failed to load interstitial ad: $err', attributes: googleAttributes);
Datadog.addError('failed to load interstitial ad: $err',
attributes: googleAttributes);
_postShowingAds();
},
),
Expand All @@ -143,12 +144,10 @@ class AdHelper {
if (_currentAdType == AdType.Google) {
_interstitialAd?.dispose();
_interstitialAd = null;
_failedLoadAttempts = 0; // Reset counter for Google Ads
logger.i(
'[Ads Manager] Post-show: Google Ad displayed. Resetting failed load attempts and requesting a new ad.');
_loadInterstitialAd();
} else if (_currentAdType == AdType.CAS) {
_failedCASLoadAttempts = 0; // Reset counter for CAS Ads
logger.i(
'[Ads Manager] Post-show: CAS Ad displayed. Resetting failed load attempts and requesting a new ad.');
_loadCASInterstitial();
Expand All @@ -162,8 +161,13 @@ class AdHelper {
}

// Public methods
Future<void> loadAds() async {
await _decideAndLoadAds();
Future<void> loadAds(
{required bool shouldShowGoogleAds,
required bool shouldShowCASAds}) async {
await _decideAndLoadAds(
shouldShowCASAds: shouldShowCASAds,
shouldShowGoogleAds: shouldShowGoogleAds,
);
}

Future<void> showAds() async {
Expand Down Expand Up @@ -211,14 +215,16 @@ class AdHelper {

void _onCASAdShowFailed() {
logger.e('[Ads Manager] Error: CAS Interstitial failed to display.');
Datadog.addError('Failed to display interstitial ad', attributes: casAttributes);
Datadog.addError('Failed to display interstitial ad',
attributes: casAttributes);
_failedCASLoadAttempts++;
_postShowingAds(); // Reload or decide the next action
}

void _onCASAdClosedOrComplete() {
logger.i('[Ads Manager] Completion: CAS Interstitial closed or completed.');
Datadog.trackUserCustom('Interstitial ad closed or completed', casAttributes);
Datadog.trackUserCustom(
'Interstitial ad closed or completed', casAttributes);
// Reset the counter when the ad successfully shows and closes/completes
_failedCASLoadAttempts = 0;
_postShowingAds();
Expand Down Expand Up @@ -278,7 +284,8 @@ class InterstitialListenerWrapper extends AdCallback {
onFailed.call();
logger.i(
'[CASIntegrationHelper] - InterstitialListenerWrapper onShowFailed-:$message');
Datadog.addError('Interstitial ad onShowFailed: $message', attributes: casAttributes);
Datadog.addError('Interstitial ad onShowFailed: $message',
attributes: casAttributes);
}

@override
Expand Down
Loading
Loading