Remove Google's Ad Consent library. https://redmine.stoutner.com/issues/329
authorSoren Stoutner <soren@stoutner.com>
Fri, 21 Dec 2018 20:14:37 +0000 (13:14 -0700)
committerSoren Stoutner <soren@stoutner.com>
Fri, 21 Dec 2018 20:14:37 +0000 (13:14 -0700)
12 files changed:
.idea/dictionaries/soren.xml
app/build.gradle
app/src/free/java/com/stoutner/privacybrowser/dialogs/AdConsentDialog.java
app/src/free/java/com/stoutner/privacybrowser/helpers/AdConsentDatabaseHelper.java [new file with mode: 0644]
app/src/free/java/com/stoutner/privacybrowser/helpers/AdHelper.java
app/src/free/res/values-de/strings.xml
app/src/free/res/values-es/strings.xml
app/src/free/res/values-it/strings.xml
app/src/free/res/values-ru/strings.xml
app/src/free/res/values/strings.xml
app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java
app/src/main/java/com/stoutner/privacybrowser/helpers/BookmarksDatabaseHelper.java

index adbe0dc0583d9809e0594921e97b1fd075dbda42..f6c0e6aaaecf7a1402aba41906ded4bfed273be3 100644 (file)
@@ -28,6 +28,7 @@
       <w>buildversion</w>
       <w>buratti</w>
       <w>cardview</w>
+      <w>ceecdfd</w>
       <w>checkedtextview</w>
       <w>chromebooks</w>
       <w>chromeversion</w>
@@ -36,6 +37,7 @@
       <w>commitdiff</w>
       <w>coordinatorlayout</w>
       <w>customuseragent</w>
+      <w>daeef</w>
       <w>databaseview</w>
       <w>deeplinks</w>
       <w>didn</w>
index ac49448881b0d48b548f74563ca33d999d1ccb8b..42709506f6756ab81fa5dc740cae58ae30430c36 100644 (file)
@@ -75,7 +75,4 @@ dependencies {
 
     // Only compile Firebase ads for the free flavor.
     freeImplementation 'com.google.firebase:firebase-ads:17.1.2'
-
-    // Only compile the consent library for the free flavor.  It is used to comply with the GDPR in Europe.
-    freeImplementation 'com.google.android.ads.consent:consent-library:1.0.6'
 }
\ No newline at end of file
index 8808923a641be83c0591ba8941c00853560e24e2..94f8a91e60019bf40c10be40bb7eef602a8d9d93 100644 (file)
@@ -26,10 +26,9 @@ import android.content.DialogInterface;
 import android.os.Build;
 import android.os.Bundle;
 
-import com.google.ads.consent.ConsentInformation;
-import com.google.ads.consent.ConsentStatus;
 import com.stoutner.privacybrowser.R;
 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
+import com.stoutner.privacybrowser.helpers.AdConsentDatabaseHelper;
 import com.stoutner.privacybrowser.helpers.AdHelper;
 
 public class AdConsentDialog extends DialogFragment {
@@ -47,19 +46,20 @@ public class AdConsentDialog extends DialogFragment {
             dialogBuilder.setIcon(R.drawable.block_ads_enabled_light);
         }
 
+        // Initialize the bookmarks database helper.  The `0` specifies a database version, but that is ignored and set instead using a constant in `AdConsentDatabaseHelper`.
+        // `getContext()` can be used instead of `getActivity.getApplicationContext()` on the minimum API >= 23.
+        AdConsentDatabaseHelper adConsentDatabaseHelper = new AdConsentDatabaseHelper(getActivity().getApplicationContext(), null, null, 0);
+
         // Set the title.
         dialogBuilder.setTitle(R.string.ad_consent);
 
         // Set the text.
         dialogBuilder.setMessage(R.string.ad_consent_text);
 
-        // Get a handle for the consent information.
-        ConsentInformation consentInformation = ConsentInformation.getInstance(getActivity().getApplicationContext());
-
         // Configure the close button.
         dialogBuilder.setNegativeButton(R.string.close_browser, (DialogInterface dialog, int which) -> {
-            // Set the consent status to Unknown.
-            consentInformation.setConsentStatus(ConsentStatus.UNKNOWN);
+            // Update the ad consent database.
+            adConsentDatabaseHelper.updateAdConsent(false);
 
             // Close the browser.  `finishAndRemoveTask` also removes Privacy Browser from the recent app list.
             if (Build.VERSION.SDK_INT >= 21) {
@@ -74,13 +74,10 @@ public class AdConsentDialog extends DialogFragment {
 
         // Configure the accept button.
         dialogBuilder.setPositiveButton(R.string.accept_ads, (DialogInterface dialog, int which) -> {
-            // Set the consent status to Non-Personalized.
-            consentInformation.setConsentStatus(ConsentStatus.NON_PERSONALIZED);
+            // Update the ad consent database.
+            adConsentDatabaseHelper.updateAdConsent(true);
 
-            // Indicate the user is under age, which disables personalized advertising and remarketing.  https://developers.google.com/admob/android/eu-consent
-            consentInformation.setTagForUnderAgeOfConsent(true);
-
-            // Load an ad.
+            // Load an ad.  `getContext()` can be used instead of `getActivity.getApplicationContext()` on the minimum API >= 23.
             AdHelper.loadAd(getActivity().findViewById(R.id.adview), getActivity().getApplicationContext(), getString(R.string.ad_unit_id));
         });
 
@@ -91,8 +88,12 @@ public class AdConsentDialog extends DialogFragment {
     // Close Privacy Browser Free if the dialog is cancelled without selecting a button (by tapping on the background).
     @Override
     public void onCancel(DialogInterface dialogInterface) {
-        // Set the consent status to Unknown.
-        ConsentInformation.getInstance(getActivity().getApplicationContext()).setConsentStatus(ConsentStatus.UNKNOWN);
+        // Initialize the bookmarks database helper.  The `0` specifies a database version, but that is ignored and set instead using a constant in `AdConsentDatabaseHelper`.
+        // `getContext()` can be used instead of `getActivity.getApplicationContext()` on the minimum API >= 23.
+        AdConsentDatabaseHelper adConsentDatabaseHelper = new AdConsentDatabaseHelper(getActivity().getApplicationContext(), null, null, 0);
+
+        // Update the ad consent database.
+        adConsentDatabaseHelper.updateAdConsent(false);
 
         // Close the browser.  `finishAndRemoveTask` also removes Privacy Browser from the recent app list.
         if (Build.VERSION.SDK_INT >= 21) {
diff --git a/app/src/free/java/com/stoutner/privacybrowser/helpers/AdConsentDatabaseHelper.java b/app/src/free/java/com/stoutner/privacybrowser/helpers/AdConsentDatabaseHelper.java
new file mode 100644 (file)
index 0000000..bbe480c
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2018 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser 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.
+ *
+ * Privacy Browser 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 Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.stoutner.privacybrowser.helpers;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+public class AdConsentDatabaseHelper extends SQLiteOpenHelper {
+    private static final int SCHEMA_VERSION = 1;
+    private static final String AD_CONSENT_DATABASE = "ad_consent.db";
+    private static final String AD_CONSENT_TABLE = "ad_consent";
+
+    private static final String _ID = "_id";
+    private static final String AD_CONSENT = "ad_consent";
+
+    private static final String CREATE_AD_CONSENT_TABLE = "CREATE TABLE " + AD_CONSENT_TABLE + " (" +
+            _ID + " INTEGER PRIMARY KEY, " +
+            AD_CONSENT + " BOOLEAN)";
+
+    // Initialize the database.  The lint warnings for the unused parameters are suppressed.
+    public AdConsentDatabaseHelper(Context context, @SuppressWarnings("UnusedParameters") String name, SQLiteDatabase.CursorFactory cursorFactory, @SuppressWarnings("UnusedParameters") int version) {
+        super(context, AD_CONSENT_DATABASE, cursorFactory, SCHEMA_VERSION);
+    }
+
+    @Override
+    public void onCreate(SQLiteDatabase adConsentDatabase) {
+        // Create the ad consent database.
+        adConsentDatabase.execSQL(CREATE_AD_CONSENT_TABLE);
+
+        // Create an ad consent ContentValues.
+        ContentValues adConsentContentValues = new ContentValues();
+
+        // Populate the ad consent content values.
+        adConsentContentValues.put(AD_CONSENT, false);
+
+        // Insert a new row.  The second argument is `null`, which makes it so that a completely null row cannot be created.
+        adConsentDatabase.insert(AD_CONSENT_TABLE, null, adConsentContentValues);
+    }
+
+    @Override
+    public void onUpgrade(SQLiteDatabase adConsentDatabase, int oldVersion, int newVersion) {
+        // Code for upgrading the database will be added here if the schema version ever increases above 1.
+    }
+
+    // Check to see if ad consent has been granted.
+    public boolean isGranted() {
+        // Get a readable database handle.
+        SQLiteDatabase adConsentDatabase = this.getReadableDatabase();
+
+        // Get the ad consent cursor.
+        Cursor adConsentCursor = adConsentDatabase.rawQuery("SELECT * FROM " + AD_CONSENT_TABLE, null);
+
+        // Move to the first entry.
+        adConsentCursor.moveToFirst();
+
+        // Get the ad consent boolean.
+        boolean adConsent = (adConsentCursor.getInt(adConsentCursor.getColumnIndex(AD_CONSENT)) == 1);
+
+        // Close the cursor.
+        adConsentCursor.close();
+
+        // Close the database.
+        adConsentDatabase.close();
+
+        // Return the ad consent boolean.
+        return adConsent;
+    }
+
+    // Update the ad consent.
+    public void updateAdConsent(boolean adConsent) {
+        // Get a writable database handle.
+        SQLiteDatabase adConsentDatabase = this.getWritableDatabase();
+
+        // Create an ad consent integer.
+        int adConsentInt;
+
+        // Set the ad consent integer according to the boolean.
+        if (adConsent) {
+            adConsentInt = 1;
+        } else {
+            adConsentInt = 0;
+        }
+
+        // Update the ad consent in the database.
+        adConsentDatabase.execSQL("UPDATE " + AD_CONSENT_TABLE + " SET " + AD_CONSENT + " = " + adConsentInt);
+
+        // Close the database.
+        adConsentDatabase.close();
+    }
+}
\ No newline at end of file
index d1638c7386582faab50cf7c40ba83ddd86e57686..7de4e522dec4a6655c6c7e4237e231600115929a 100644 (file)
@@ -26,9 +26,6 @@ import android.os.Bundle;
 import android.view.View;
 import android.widget.RelativeLayout;
 
-import com.google.ads.consent.ConsentInfoUpdateListener;
-import com.google.ads.consent.ConsentInformation;
-import com.google.ads.consent.ConsentStatus;
 import com.google.ads.mediation.admob.AdMobAdapter;
 import com.google.android.gms.ads.AdRequest;
 import com.google.android.gms.ads.AdSize;
@@ -45,36 +42,21 @@ public class AdHelper {
             // Initialize mobile ads.
             MobileAds.initialize(applicationContext, googleAppId);
 
-            // Store the publisher ID in a string array.
-            String[] publisherIds = {"pub-5962503714887045"};
-
-            // Check to see if consent is needed in Europe to comply with the GDPR.
-            ConsentInformation consentInformation = ConsentInformation.getInstance(applicationContext);
-            consentInformation.requestConsentInfoUpdate(publisherIds, new ConsentInfoUpdateListener() {
-                @Override
-                public void onConsentInfoUpdated(ConsentStatus consentStatus) {
-                    if (consentStatus == ConsentStatus.UNKNOWN) {  // The user has not yet consented to ads.
-                        // Display the ad consent dialog.
-                        DialogFragment adConsentDialogFragment = new AdConsentDialog();
-                        adConsentDialogFragment.show(fragmentManager, "Ad Consent");
-                    } else {  // The user has consented to ads.
-                        // Indicate the user is under age, which disables personalized advertising and remarketing.  https://developers.google.com/admob/android/eu-consent
-                        consentInformation.setTagForUnderAgeOfConsent(true);
-
-                        // Load an ad.
-                        loadAd(view, applicationContext, adUnitId);
-                    }
-                }
-
-                @Override
-                public void onFailedToUpdateConsentInfo(String reason) {  // The user is not in Europe.
-                    // Indicate the user is under age, which disables personalized advertising and remarketing.  https://developers.google.com/admob/android/eu-consent
-                    consentInformation.setTagForUnderAgeOfConsent(true);
-
-                    // Load an ad.
-                    loadAd(view, applicationContext, adUnitId);
-                }
-            });
+            // Initialize the bookmarks database helper.  The `0` specifies a database version, but that is ignored and set instead using a constant in `AdConsentDatabaseHelper`.
+            AdConsentDatabaseHelper adConsentDatabaseHelper = new AdConsentDatabaseHelper(applicationContext, null, null, 0);
+
+            // Check to see if consent has been granted.
+            boolean adConsentGranted = adConsentDatabaseHelper.isGranted();
+
+            // Display the ad consent dialog if needed.
+            if (!adConsentGranted) {  // Ad consent has not been granted.
+                // Display the ad consent dialog.
+                DialogFragment adConsentDialogFragment = new AdConsentDialog();
+                adConsentDialogFragment.show(fragmentManager, "Ad Consent");
+            } else {  // Ad consent has been granted.
+                // Load an ad.
+                loadAd(view, applicationContext, adUnitId);
+            }
 
             // Set the initialized variable to true so this section doesn't run again.
             initialized = true;
@@ -105,16 +87,14 @@ public class AdHelper {
         // Display the new AdView.
         adViewParentLayout.addView(adView);
 
-        // Only request non-personalized ads.
+        // Only request non-personalized ads.  https://developers.google.com/ad-manager/mobile-ads-sdk/android/eu-consent#forward_consent_to_the_google_mobile_ads_sdk
         Bundle adSettingsBundle = new Bundle();
         adSettingsBundle.putString("npa", "1");
 
-        // Request a new ad.
+        // Build the ad request.
         AdRequest adRequest = new AdRequest.Builder().addNetworkExtrasBundle(AdMobAdapter.class, adSettingsBundle).build();
-        // Pixel test ads.
-        // AdRequest adRequest = new AdRequest.Builder().addTestDevice("20DAEEF7662E2238C99A509BE5D78A26").addNetworkExtrasBundle(AdMobAdapter.class, adSettingsBundle).build();
-        // Pixel 2 XL test ads.
-        // AdRequest adRequest = new AdRequest.Builder().addTestDevice("137D42984218CEECDFD11927BB7D6416").addNetworkExtrasBundle(AdMobAdapter.class, adSettingsBundle).build();
+
+        // Make it so.
         adView.loadAd(adRequest);
     }
 
index 5e6b2504753262ab5769f26914798c3a79d63c2e..06f6535a1b9af571f930c8b0a9d77af1a36e0551 100644 (file)
@@ -26,7 +26,7 @@
 
     <!-- Ad Consent. -->
     <string name="ad_consent_text">Privacy Browser Free blendet einen Werbebanner unten am Bildschirm ein.
-        Diese Werbungen kommen von Googles üblich genutzten Anbietern und sind anonymisiert und nicht verfolgend eingestellt. \n\nDie Standardversion von Privacy Browser beinhaltet keine Werbung.</string>
+        Diese Werbungen kommen von Googles üblich genutzten Anbietern und sind anonymisiert. \n\nDie Standardversion von Privacy Browser beinhaltet keine Werbung.</string>
     <string name="close_browser">Browser schließen</string>
     <string name="accept_ads">Werbung zustimmen</string>
 </resources>
\ No newline at end of file
index fb83ddd0e94c20866e1f34db1f153ab4d08b24df..e06c7ee9c07f156ba3aeb7152bada1b820300951 100644 (file)
@@ -26,7 +26,7 @@
 
     <!-- Ad Consent. -->
     <string name="ad_consent_text">Navegador Privado Gratuíto muestra un anuncio de banner en la parte inferior de la pantalla.
-        Estos anuncios proceden del conjunto de proveedores habituales de Google y están configurados para que no sean personalizados ni de seguimiento.
+        Estos anuncios proceden del conjunto de proveedores habituales de Google y están configurados para que no sean personalizados.
         \n\nLa versión estándar de Navegador Privado no contiene anuncios.</string>
     <string name="close_browser">Cerrar el navegador</string>
     <string name="accept_ads">Aceptar anuncios</string>
index 1cd0c659fadd2025be20b488f7f84f056f68408c..12cd684400407ef5648a40a19ee5a885d3ce6091 100644 (file)
@@ -26,7 +26,7 @@
 
     <!-- Ad Consent. -->
     <string name="ad_consent_text">Privacy Browser Free mostra un banner pubblicitario nella parte inferiore dello schermo.
-        Questi annunci provengono dai provider normalmente utilizzati da Google e sono configurati in modo da non essere personalizzati e da non tracciare l\'utente.
+        Questi annunci provengono dai provider normalmente utilizzati da Google e sono configurati in modo da non essere personalizzati.
         \n\nLa versione standard di Privacy Browser non contiene annunci.</string>
     <string name="close_browser">Chiudi il Browser</string>
     <string name="accept_ads">Accetta gli Annunci</string>
index 868fa078620ceb0c41d5b4d9b025a16555fc5a83..5b87709e0a3092d6b64ff1071ad83459ce9b99c6 100644 (file)
@@ -24,7 +24,7 @@
 
     <!-- Ad Consent. -->
     <string name="ad_consent_text">Privacy Browser Free отображает рекламный баннер в нижней части экрана.
-        Реклама поступает от широко используемых Google поставщиков и настроена так, чтобы исключить персонализацию и возможность отслеживания.
+        Реклама поступает от широко используемых Google поставщиков и настроена так, чтобы исключить персонализацию.
         \n\nСтандартная версия Privacy Browser не содержит рекламы.</string>
     <string name="close_browser">Закрыть браузер</string>
     <string name="accept_ads">Разрешить рекламу</string>
index af5d2675bb5f93cee810bc9c386dd1d59e460b8f..29bec4c2eb60941564a6ec715208491d15e309b8 100644 (file)
   You should have received a copy of the GNU General Public License
   along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>. -->
 
-<resources>
+<!-- `tools:ignore="MissingTranslation"` allows release APKs to be built if translation strings are missing.  The missing strings will fall back to English. -->
+<resources
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="MissingTranslation" >
+
     <!-- Providers. -->
     <string name="file_provider" translatable="false">com.stoutner.privacybrowser.fileprovider.free</string>
 
@@ -35,7 +39,7 @@
 
     <!-- Ad Consent. -->
     <string name="ad_consent_text">Privacy Browser Free displays a banner ad on the bottom of the screen.
-        These ads come from Google’s set of commonly used providers and are configured to be non-personalized and non-tracking.
+        These ads come from Google’s set of commonly used providers and are configured to be non-personalized.
         \n\nThe standard version of Privacy Browser does not contain ads.</string>
     <string name="close_browser">Close Browser</string>
     <string name="accept_ads">Accept Ads</string>
index 3d92e076e370a669d49b927146abe662f56c3d8e..b54888e2b03fe8521a752d578698ccb1da8e9d89 100644 (file)
@@ -844,8 +844,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         final MenuItem navigationHistoryMenuItem = navigationMenu.getItem(3);
         final MenuItem navigationRequestsMenuItem = navigationMenu.getItem(4);
 
-        // Initialize the bookmarks database helper.  `this` specifies the context.  The two `nulls` do not specify the database name or a `CursorFactory`.
-        // The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`.
+        // Initialize the bookmarks database helper.  The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`.
         bookmarksDatabaseHelper = new BookmarksDatabaseHelper(this, null, null, 0);
 
         // Initialize `currentBookmarksFolder`.  `""` is the home folder in the database.
index ac70f2c8a6de2e4be4638ef7aa9e90b75bff1f7f..7eb584b52763b5f0fde25ae4390f443a27de740c 100644 (file)
@@ -125,8 +125,8 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper {
         // Get a readable database handle.
         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
 
-        // Prepare the SQL statement to get the `Cursor` for `databaseId`
-        final String GET_ONE_BOOKMARK = "SELECT * FROM " + BOOKMARKS_TABLE +
+        // Prepare the SQL statement to get the cursor for the database ID.
+        String GET_ONE_BOOKMARK = "SELECT * FROM " + BOOKMARKS_TABLE +
                 " WHERE " + _ID + " = " + databaseId;
 
         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.  We can't close the `Cursor` because we need to use it in the parent activity.
@@ -138,14 +138,14 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper {
         // Get a readable database handle.
         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
 
-        // Prepare the SQL statement to get the `Cursor` for the folder.
-        final String GET_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE +
+        // Prepare the SQL statement to get the cursor for the folder.
+        String GET_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE +
                 " WHERE " + _ID + " = " + databaseId;
 
-        // Get `folderCursor`.  The second argument is `null` because there are no `selectionArgs`.
+        // Get a folder cursor.
         Cursor folderCursor = bookmarksDatabase.rawQuery(GET_FOLDER, null);
 
-        // Get `folderName`.
+        // Get the folder name.
         folderCursor.moveToFirst();
         String folderName = folderCursor.getString(folderCursor.getColumnIndex(BOOKMARK_NAME));
 
@@ -250,7 +250,7 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper {
                 " WHERE " + IS_FOLDER + " = " + 1 +
                 " AND " + BOOKMARK_NAME + " = " + currentFolder;
 
-        // The second argument is `null` because there are no `selectionArgs`.
+        // Get the bookmark cursor and move to the first entry.
         Cursor bookmarkCursor = bookmarksDatabase.rawQuery(GET_PARENT_FOLDER, null);
         bookmarkCursor.moveToFirst();