From d8c2c41a674cd43bbb05d9f5f9011b02a7892040 Mon Sep 17 00:00:00 2001 From: M66B Date: Tue, 4 Sep 2018 18:51:09 +0000 Subject: [PATCH] Refactoring --- .../eu/faircode/email/ActivityBilling.java | 214 ++++++++++++++++++ .../eu/faircode/email/ActivityCompose.java | 2 +- .../java/eu/faircode/email/ActivityView.java | 164 +------------- 3 files changed, 216 insertions(+), 164 deletions(-) create mode 100644 app/src/main/java/eu/faircode/email/ActivityBilling.java diff --git a/app/src/main/java/eu/faircode/email/ActivityBilling.java b/app/src/main/java/eu/faircode/email/ActivityBilling.java new file mode 100644 index 0000000000..1171447ab2 --- /dev/null +++ b/app/src/main/java/eu/faircode/email/ActivityBilling.java @@ -0,0 +1,214 @@ +package eu.faircode.email; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.provider.Settings; +import android.util.Log; +import android.view.View; +import android.widget.Toast; + +import com.android.billingclient.api.BillingClient; +import com.android.billingclient.api.BillingClientStateListener; +import com.android.billingclient.api.BillingFlowParams; +import com.android.billingclient.api.Purchase; +import com.android.billingclient.api.PurchasesUpdatedListener; +import com.google.android.material.snackbar.Snackbar; + +import java.security.NoSuchAlgorithmException; +import java.util.List; + +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +abstract class ActivityBilling extends ActivityBase implements PurchasesUpdatedListener { + private BillingClient billingClient = null; + + static final String ACTION_PURCHASE = BuildConfig.APPLICATION_ID + ".ACTION_PURCHASE"; + static final String ACTION_ACTIVATE_PRO = BuildConfig.APPLICATION_ID + ".ACTIVATE_PRO"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (Helper.isPlayStoreInstall(this)) { + billingClient = BillingClient.newBuilder(this).setListener(this).build(); + billingClient.startConnection(billingClientStateListener); + } + } + + @Override + protected void onResume() { + super.onResume(); + + LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this); + IntentFilter iff = new IntentFilter(); + iff.addAction(ACTION_PURCHASE); + iff.addAction(ACTION_ACTIVATE_PRO); + lbm.registerReceiver(receiver, iff); + + if (billingClient != null && billingClient.isReady()) + queryPurchases(); + } + + @Override + protected void onPause() { + super.onPause(); + LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this); + lbm.unregisterReceiver(receiver); + } + + @Override + protected void onDestroy() { + if (billingClient != null) + billingClient.endConnection(); + super.onDestroy(); + } + + protected Intent getIntentPro() { + if (Helper.isPlayStoreInstall(this)) + return null; + + try { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse("https://email.faircode.eu/pro/?challenge=" + getChallenge())); + return intent; + } catch (NoSuchAlgorithmException ex) { + Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); + return null; + } + } + + private String getChallenge() throws NoSuchAlgorithmException { + String android_id = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID); + return Helper.sha256(android_id); + } + + private String getResponse() throws NoSuchAlgorithmException { + return Helper.sha256(BuildConfig.APPLICATION_ID + getChallenge()); + } + + BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (ACTION_PURCHASE.equals(intent.getAction())) + onPurchase(intent); + else if (ACTION_ACTIVATE_PRO.equals(intent.getAction())) + onActivatePro(intent); + } + }; + + private View getView() { + return findViewById(android.R.id.content); + } + + private void onPurchase(Intent intent) { + if (Helper.isPlayStoreInstall(this)) { + BillingFlowParams flowParams = BillingFlowParams.newBuilder() + .setSku(BuildConfig.APPLICATION_ID + ".pro") + .setType(BillingClient.SkuType.INAPP) + .build(); + int responseCode = billingClient.launchBillingFlow(this, flowParams); + String text = Helper.getBillingResponseText(responseCode); + Log.i(Helper.TAG, "IAB launch billing flow response=" + text); + if (responseCode != BillingClient.BillingResponse.OK) + Snackbar.make(getView(), text, Snackbar.LENGTH_LONG).show(); + } else + startActivity(getIntentPro()); + } + + private void onActivatePro(Intent intent) { + try { + Uri data = intent.getParcelableExtra("uri"); + String challenge = getChallenge(); + String response = data.getQueryParameter("response"); + Log.i(Helper.TAG, "Challenge=" + challenge); + Log.i(Helper.TAG, "Response=" + response); + String expected = getResponse(); + if (expected.equals(response)) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + prefs.edit().putBoolean("pro", true).apply(); + Log.i(Helper.TAG, "Response valid"); + Snackbar.make(getView(), R.string.title_pro_valid, Snackbar.LENGTH_LONG).show(); + } else { + Log.i(Helper.TAG, "Response invalid"); + Snackbar.make(getView(), R.string.title_pro_invalid, Snackbar.LENGTH_LONG).show(); + } + + intent.setData(null); + setIntent(intent); + } catch (NoSuchAlgorithmException ex) { + Log.e(Helper.TAG, Log.getStackTraceString(ex)); + Toast.makeText(this, ex.getMessage(), Toast.LENGTH_LONG).show(); + } + } + + private BillingClientStateListener billingClientStateListener = new BillingClientStateListener() { + private int backoff = 4; // seconds + + @Override + public void onBillingSetupFinished(@BillingClient.BillingResponse int responseCode) { + String text = Helper.getBillingResponseText(responseCode); + Log.i(Helper.TAG, "IAB connected response=" + text); + if (responseCode == BillingClient.BillingResponse.OK) { + backoff = 4; + queryPurchases(); + } else + Snackbar.make(getView(), text, Snackbar.LENGTH_LONG).show(); + } + + @Override + public void onBillingServiceDisconnected() { + backoff *= 2; + Log.i(Helper.TAG, "IAB disconnected retry in " + backoff + " s"); + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + if (!billingClient.isReady()) + billingClient.startConnection(billingClientStateListener); + } + }, backoff * 1000L); + } + }; + + @Override + public void onPurchasesUpdated(int responseCode, @android.support.annotation.Nullable List purchases) { + String text = Helper.getBillingResponseText(responseCode); + Log.i(Helper.TAG, "IAB purchases updated response=" + text); + if (responseCode == BillingClient.BillingResponse.OK) + checkPurchases(purchases); + else + Snackbar.make(getView(), text, Snackbar.LENGTH_LONG).show(); + } + + private void queryPurchases() { + Purchase.PurchasesResult result = billingClient.queryPurchases(BillingClient.SkuType.INAPP); + String text = Helper.getBillingResponseText(result.getResponseCode()); + Log.i(Helper.TAG, "IAB query purchases response=" + text); + if (result.getResponseCode() == BillingClient.BillingResponse.OK) + checkPurchases(result.getPurchasesList()); + else + Snackbar.make(getView(), text, Snackbar.LENGTH_LONG).show(); + } + + private void checkPurchases(List purchases) { + if (purchases != null) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + SharedPreferences.Editor editor = prefs.edit(); + editor.remove("pro"); + for (Purchase purchase : purchases) { + Log.i(Helper.TAG, "IAB SKU=" + purchase.getSku()); + if ((BuildConfig.APPLICATION_ID + ".pro").equals(purchase.getSku())) { + editor.putBoolean("pro", true); + Log.i(Helper.TAG, "IAB pro features activated"); + } + } + editor.apply(); + } + } +} diff --git a/app/src/main/java/eu/faircode/email/ActivityCompose.java b/app/src/main/java/eu/faircode/email/ActivityCompose.java index 5b8c0125e8..b3d218591c 100644 --- a/app/src/main/java/eu/faircode/email/ActivityCompose.java +++ b/app/src/main/java/eu/faircode/email/ActivityCompose.java @@ -31,7 +31,7 @@ import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import androidx.lifecycle.Lifecycle; -public class ActivityCompose extends ActivityBase implements FragmentManager.OnBackStackChangedListener { +public class ActivityCompose extends ActivityBilling implements FragmentManager.OnBackStackChangedListener { static final int REQUEST_CONTACT_TO = 1; static final int REQUEST_CONTACT_CC = 2; static final int REQUEST_CONTACT_BCC = 3; diff --git a/app/src/main/java/eu/faircode/email/ActivityView.java b/app/src/main/java/eu/faircode/email/ActivityView.java index 422cdc32dc..987e00ac9d 100644 --- a/app/src/main/java/eu/faircode/email/ActivityView.java +++ b/app/src/main/java/eu/faircode/email/ActivityView.java @@ -24,15 +24,12 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.content.res.Configuration; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.Handler; import android.os.ParcelFileDescriptor; import android.preference.PreferenceManager; -import android.provider.Settings; import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; @@ -45,19 +42,11 @@ import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; -import com.android.billingclient.api.BillingClient; -import com.android.billingclient.api.BillingClientStateListener; -import com.android.billingclient.api.BillingFlowParams; -import com.android.billingclient.api.Purchase; -import com.android.billingclient.api.PurchasesUpdatedListener; -import com.google.android.material.snackbar.Snackbar; - import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; -import java.security.NoSuchAlgorithmException; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; @@ -78,12 +67,11 @@ import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Observer; import androidx.localbroadcastmanager.content.LocalBroadcastManager; -public class ActivityView extends ActivityBase implements FragmentManager.OnBackStackChangedListener, PurchasesUpdatedListener { +public class ActivityView extends ActivityBilling implements FragmentManager.OnBackStackChangedListener { private View view; private DrawerLayout drawerLayout; private ListView drawerList; private ActionBarDrawerToggle drawerToggle; - private BillingClient billingClient = null; private boolean newIntent = false; private long attachment = -1; @@ -101,8 +89,6 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack static final String ACTION_EDIT_FOLDER = BuildConfig.APPLICATION_ID + ".EDIT_FOLDER"; static final String ACTION_EDIT_ANSWER = BuildConfig.APPLICATION_ID + ".EDIT_ANSWER"; static final String ACTION_STORE_ATTACHMENT = BuildConfig.APPLICATION_ID + ".STORE_ATTACHMENT"; - static final String ACTION_PURCHASE = BuildConfig.APPLICATION_ID + ".ACTION_PURCHASE"; - static final String ACTION_ACTIVATE_PRO = BuildConfig.APPLICATION_ID + ".ACTIVATE_PRO"; @Override protected void onCreate(Bundle savedInstanceState) { @@ -325,11 +311,6 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack } }.load(this, new Bundle()); - if (Helper.isPlayStoreInstall(this)) { - billingClient = BillingClient.newBuilder(this).setListener(this).build(); - billingClient.startConnection(billingClientStateListener); - } - checkIntent(getIntent()); } @@ -366,17 +347,12 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack iff.addAction(ACTION_EDIT_FOLDER); iff.addAction(ACTION_EDIT_ANSWER); iff.addAction(ACTION_STORE_ATTACHMENT); - iff.addAction(ACTION_PURCHASE); - iff.addAction(ACTION_ACTIVATE_PRO); lbm.registerReceiver(receiver, iff); if (newIntent) { newIntent = false; getSupportFragmentManager().popBackStack("unified", 0); } - - if (billingClient != null && billingClient.isReady()) - queryPurchases(); } @Override @@ -392,13 +368,6 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack drawerToggle.onConfigurationChanged(newConfig); } - @Override - protected void onDestroy() { - if (billingClient != null) - billingClient.endConnection(); - super.onDestroy(); - } - @Override public void onBackPressed() { if (drawerLayout.isDrawerOpen(drawerList)) @@ -434,15 +403,6 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack } } - private String getChallenge() throws NoSuchAlgorithmException { - String android_id = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID); - return Helper.sha256(android_id); - } - - private String getResponse() throws NoSuchAlgorithmException { - return Helper.sha256(BuildConfig.APPLICATION_ID + getChallenge()); - } - private void checkIntent(Intent intent) { Log.i(Helper.TAG, "View intent=" + intent + " action=" + intent.getAction()); String action = intent.getAction(); @@ -493,20 +453,6 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack return intent; } - private Intent getIntentPro() { - if (Helper.isPlayStoreInstall(this)) - return null; - - try { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse("https://email.faircode.eu/pro/?challenge=" + getChallenge())); - return intent; - } catch (NoSuchAlgorithmException ex) { - Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); - return null; - } - } - private Intent getIntentOtherApps() { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("https://play.google.com/store/apps/dev?id=8420080860664580239")); @@ -643,10 +589,6 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack onEditAnswer(intent); else if (ACTION_STORE_ATTACHMENT.equals(intent.getAction())) onStoreAttachment(intent); - else if (ACTION_PURCHASE.equals(intent.getAction())) - onPurchase(intent); - else if (ACTION_ACTIVATE_PRO.equals(intent.getAction())) - onActivatePro(intent); } }; @@ -724,46 +666,6 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack startActivityForResult(create, REQUEST_ATTACHMENT); } - private void onPurchase(Intent intent) { - if (Helper.isPlayStoreInstall(this)) { - BillingFlowParams flowParams = BillingFlowParams.newBuilder() - .setSku(BuildConfig.APPLICATION_ID + ".pro") - .setType(BillingClient.SkuType.INAPP) - .build(); - int responseCode = billingClient.launchBillingFlow(ActivityView.this, flowParams); - String text = Helper.getBillingResponseText(responseCode); - Log.i(Helper.TAG, "IAB launch billing flow response=" + text); - if (responseCode != BillingClient.BillingResponse.OK) - Snackbar.make(view, text, Snackbar.LENGTH_LONG).show(); - } else - startActivity(getIntentPro()); - } - - private void onActivatePro(Intent intent) { - try { - Uri data = intent.getParcelableExtra("uri"); - String challenge = getChallenge(); - String response = data.getQueryParameter("response"); - Log.i(Helper.TAG, "Challenge=" + challenge); - Log.i(Helper.TAG, "Response=" + response); - String expected = getResponse(); - if (expected.equals(response)) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ActivityView.this); - prefs.edit().putBoolean("pro", true).apply(); - Log.i(Helper.TAG, "Response valid"); - Snackbar.make(view, R.string.title_pro_valid, Snackbar.LENGTH_LONG).show(); - } else { - Log.i(Helper.TAG, "Response invalid"); - Snackbar.make(view, R.string.title_pro_invalid, Snackbar.LENGTH_LONG).show(); - } - - intent.setData(null); - setIntent(intent); - } catch (NoSuchAlgorithmException ex) { - Log.e(Helper.TAG, Log.getStackTraceString(ex)); - Toast.makeText(ActivityView.this, ex.getMessage(), Toast.LENGTH_LONG).show(); - } - } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { @@ -831,68 +733,4 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack }.load(this, args); } } - - private BillingClientStateListener billingClientStateListener = new BillingClientStateListener() { - private int backoff = 4; // seconds - - @Override - public void onBillingSetupFinished(@BillingClient.BillingResponse int responseCode) { - String text = Helper.getBillingResponseText(responseCode); - Log.i(Helper.TAG, "IAB connected response=" + text); - if (responseCode == BillingClient.BillingResponse.OK) { - backoff = 4; - queryPurchases(); - } else - Snackbar.make(view, text, Snackbar.LENGTH_LONG).show(); - } - - @Override - public void onBillingServiceDisconnected() { - backoff *= 2; - Log.i(Helper.TAG, "IAB disconnected retry in " + backoff + " s"); - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - if (!billingClient.isReady()) - billingClient.startConnection(billingClientStateListener); - } - }, backoff * 1000L); - } - }; - - @Override - public void onPurchasesUpdated(int responseCode, @android.support.annotation.Nullable List purchases) { - String text = Helper.getBillingResponseText(responseCode); - Log.i(Helper.TAG, "IAB purchases updated response=" + text); - if (responseCode == BillingClient.BillingResponse.OK) - checkPurchases(purchases); - else - Snackbar.make(view, text, Snackbar.LENGTH_LONG).show(); - } - - private void queryPurchases() { - Purchase.PurchasesResult result = billingClient.queryPurchases(BillingClient.SkuType.INAPP); - String text = Helper.getBillingResponseText(result.getResponseCode()); - Log.i(Helper.TAG, "IAB query purchases response=" + text); - if (result.getResponseCode() == BillingClient.BillingResponse.OK) - checkPurchases(result.getPurchasesList()); - else - Snackbar.make(view, text, Snackbar.LENGTH_LONG).show(); - } - - private void checkPurchases(List purchases) { - if (purchases != null) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - SharedPreferences.Editor editor = prefs.edit(); - editor.remove("pro"); - for (Purchase purchase : purchases) { - Log.i(Helper.TAG, "IAB SKU=" + purchase.getSku()); - if ((BuildConfig.APPLICATION_ID + ".pro").equals(purchase.getSku())) { - editor.putBoolean("pro", true); - Log.i(Helper.TAG, "IAB pro features activated"); - } - } - editor.apply(); - } - } }