Browse Source

Refactoring

main
M66B 5 years ago
parent
commit
d8c2c41a67
3 changed files with 216 additions and 164 deletions
  1. +214
    -0
      app/src/main/java/eu/faircode/email/ActivityBilling.java
  2. +1
    -1
      app/src/main/java/eu/faircode/email/ActivityCompose.java
  3. +1
    -163
      app/src/main/java/eu/faircode/email/ActivityView.java

+ 214
- 0
app/src/main/java/eu/faircode/email/ActivityBilling.java View File

@ -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<Purchase> 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<Purchase> 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();
}
}
}

+ 1
- 1
app/src/main/java/eu/faircode/email/ActivityCompose.java View File

@ -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;


+ 1
- 163
app/src/main/java/eu/faircode/email/ActivityView.java View File

@ -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<Purchase> 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<Purchase> 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();
}
}
}

Loading…
Cancel
Save