Refactoring

This commit is contained in:
M66B 2019-08-13 10:27:17 +02:00
parent 17b11065d8
commit ca480d054d
26 changed files with 183 additions and 235 deletions

View File

@ -207,6 +207,12 @@
</intent-filter>
</activity>
<activity
android:name=".ActivityBilling"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:launchMode="singleInstance" />
<service
android:name=".ServiceSynchronize"
android:foregroundServiceType="dataSync" />

View File

@ -19,6 +19,7 @@ package eu.faircode.email;
Copyright 2018-2019 by Marcel Bokhorst (M66B)
*/
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -33,6 +34,8 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
@ -67,21 +70,35 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
abstract class ActivityBilling extends ActivityBase implements PurchasesUpdatedListener {
public class ActivityBilling extends ActivityBase implements PurchasesUpdatedListener, FragmentManager.OnBackStackChangedListener {
private BillingClient billingClient = null;
private Map<String, SkuDetails> skuDetails = new HashMap<>();
private List<IBillingListener> listeners = new ArrayList<>();
static final String ACTION_PURCHASE = BuildConfig.APPLICATION_ID + ".ACTION_PURCHASE";
static final String ACTION_PURCHASE_CHECK = BuildConfig.APPLICATION_ID + ".ACTION_PURCHASE_CHECK";
static final String ACTION_ACTIVATE_PRO = BuildConfig.APPLICATION_ID + ".ACTIVATE_PRO";
final static long MAX_SKU_CACHE_DURATION = 24 * 3600 * 1000L; // milliseconds
@Override
@SuppressLint("MissingSuperCall")
protected void onCreate(Bundle savedInstanceState) {
onCreate(savedInstanceState, true);
}
protected void onCreate(Bundle savedInstanceState, boolean standalone) {
super.onCreate(savedInstanceState);
if (standalone) {
setContentView(R.layout.activity_billing);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content_frame, new FragmentPro()).addToBackStack("pro");
fragmentTransaction.commit();
getSupportFragmentManager().addOnBackStackChangedListener(this);
}
if (Helper.isPlayStoreInstall(this)) {
Log.i("IAB start");
billingClient = BillingClient.newBuilder(this)
@ -92,6 +109,13 @@ abstract class ActivityBilling extends ActivityBase implements PurchasesUpdatedL
}
}
@Override
public void onBackStackChanged() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count == 0)
finish();
}
@Override
protected void onResume() {
super.onResume();
@ -100,7 +124,6 @@ abstract class ActivityBilling extends ActivityBase implements PurchasesUpdatedL
IntentFilter iff = new IntentFilter();
iff.addAction(ACTION_PURCHASE);
iff.addAction(ACTION_PURCHASE_CHECK);
iff.addAction(ACTION_ACTIVATE_PRO);
lbm.registerReceiver(receiver, iff);
if (billingClient != null && billingClient.isReady())
@ -110,6 +133,7 @@ abstract class ActivityBilling extends ActivityBase implements PurchasesUpdatedL
@Override
protected void onPause() {
super.onPause();
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
lbm.unregisterReceiver(receiver);
}
@ -118,6 +142,7 @@ abstract class ActivityBilling extends ActivityBase implements PurchasesUpdatedL
protected void onDestroy() {
if (billingClient != null)
billingClient.endConnection();
super.onDestroy();
}
@ -129,27 +154,42 @@ abstract class ActivityBilling extends ActivityBase implements PurchasesUpdatedL
return BuildConfig.APPLICATION_ID + ".pro";
}
protected Intent getIntentPro() {
if (Helper.isPlayStoreInstall(this))
return null;
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(BuildConfig.PRO_FEATURES_URI + "?challenge=" + getChallenge()));
return intent;
} catch (NoSuchAlgorithmException ex) {
Log.e(ex);
return null;
}
}
private String getChallenge() throws NoSuchAlgorithmException {
String android_id = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
private static String getChallenge(Context context) throws NoSuchAlgorithmException {
String android_id = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
return Helper.sha256(android_id);
}
private String getResponse() throws NoSuchAlgorithmException {
return Helper.sha256(BuildConfig.APPLICATION_ID + getChallenge());
private static String getResponse(Context context) throws NoSuchAlgorithmException {
return Helper.sha256(BuildConfig.APPLICATION_ID + getChallenge(context));
}
static boolean activatePro(Context context, Uri data) throws NoSuchAlgorithmException {
String challenge = getChallenge(context);
String response = data.getQueryParameter("response");
Log.i("IAB challenge=" + challenge);
Log.i("IAB response=" + response);
String expected = getResponse(context);
if (expected.equals(response)) {
Log.i("IAB response valid");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit()
.putBoolean("pro", true)
.putBoolean("play_store", false)
.apply();
WidgetUnified.update(context);
return true;
} else {
Log.i("IAB response invalid");
return false;
}
}
static boolean isPro(Context context) {
if (false && BuildConfig.DEBUG)
return true;
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("pro", false);
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
@ -160,8 +200,6 @@ abstract class ActivityBilling extends ActivityBase implements PurchasesUpdatedL
onPurchase(intent);
else if (ACTION_PURCHASE_CHECK.equals(intent.getAction()))
onPurchaseCheck(intent);
else if (ACTION_ACTIVATE_PRO.equals(intent.getAction()))
onActivatePro(intent);
}
}
};
@ -179,7 +217,14 @@ abstract class ActivityBilling extends ActivityBase implements PurchasesUpdatedL
if (result.getResponseCode() != BillingClient.BillingResponseCode.OK)
notifyError(text);
} else
Helper.view(this, getIntentPro());
try {
Intent view = new Intent(Intent.ACTION_VIEW);
view.setData(Uri.parse(BuildConfig.PRO_FEATURES_URI + "?challenge=" + getChallenge(this)));
Helper.view(this, view);
} catch (NoSuchAlgorithmException ex) {
Log.e(ex);
Helper.unexpectedError(getSupportFragmentManager(), ex);
}
}
private void onPurchaseCheck(Intent intent) {
@ -200,35 +245,6 @@ abstract class ActivityBilling extends ActivityBase implements PurchasesUpdatedL
});
}
private void onActivatePro(Intent intent) {
try {
Uri data = intent.getParcelableExtra("uri");
String challenge = getChallenge();
String response = data.getQueryParameter("response");
Log.i("IAB challenge=" + challenge);
Log.i("IAB response=" + response);
String expected = getResponse();
if (expected.equals(response)) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.edit()
.putBoolean("pro", true)
.putBoolean("play_store", false)
.apply();
Log.i("IAB response valid");
ToastEx.makeText(this, R.string.title_pro_valid, Toast.LENGTH_LONG).show();
WidgetUnified.update(this);
} else {
Log.i("IAB response invalid");
ToastEx.makeText(this, R.string.title_pro_invalid, Toast.LENGTH_LONG).show();
}
} catch (NoSuchAlgorithmException ex) {
Log.e(ex);
Helper.unexpectedError(getSupportFragmentManager(), ex);
}
}
private BillingClientStateListener billingClientStateListener = new BillingClientStateListener() {
private int backoff = 4; // seconds
@ -303,10 +319,8 @@ abstract class ActivityBilling extends ActivityBase implements PurchasesUpdatedL
if (billingClient.isReady()) {
listener.onConnected();
queryPurchases();
} else {
} else
listener.onDisconnected();
billingClient.startConnection(billingClientStateListener);
}
owner.getLifecycle().addObserver(new LifecycleObserver() {
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)

View File

@ -19,10 +19,7 @@ package eu.faircode.email;
Copyright 2018-2019 by Marcel Bokhorst (M66B)
*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.MailTo;
import android.net.Uri;
import android.os.Bundle;
@ -34,7 +31,6 @@ import androidx.core.app.TaskStackBuilder;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Lifecycle;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
@ -44,11 +40,9 @@ import java.util.ArrayList;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
public class ActivityCompose extends ActivityBilling implements FragmentManager.OnBackStackChangedListener {
public class ActivityCompose extends ActivityBase implements FragmentManager.OnBackStackChangedListener {
static final int PI_REPLY = 1;
static final String ACTION_SHOW_PRO = BuildConfig.APPLICATION_ID + ".SHOW_PRO";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -214,39 +208,4 @@ public class ActivityCompose extends ActivityBilling implements FragmentManager.
return false;
}
}
@Override
protected void onResume() {
super.onResume();
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
IntentFilter iff = new IntentFilter();
iff.addAction(ACTION_SHOW_PRO);
lbm.registerReceiver(receiver, iff);
}
@Override
protected void onPause() {
super.onPause();
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
lbm.unregisterReceiver(receiver);
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
if (ACTION_SHOW_PRO.equals(intent.getAction()))
onShowPro(intent);
}
}
};
private void onShowPro(Intent intent) {
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED))
getSupportFragmentManager().popBackStack("pro", FragmentManager.POP_BACK_STACK_INCLUSIVE);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content_frame, new FragmentPro()).addToBackStack("pro");
fragmentTransaction.commit();
}
}

View File

@ -409,7 +409,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
}
private void onMenuExport() {
if (Helper.isPro(this)) {
if (ActivityBilling.isPro(this)) {
try {
askPassword(true);
} catch (Throwable ex) {
@ -417,7 +417,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
Helper.unexpectedError(getSupportFragmentManager(), ex);
}
} else
ToastEx.makeText(this, R.string.title_pro_feature, Toast.LENGTH_LONG).show();
startActivity(new Intent(this, ActivityBilling.class));
}
private void onMenuImport() {
@ -457,21 +457,20 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
private void onMenuBiometrics() {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ActivitySetup.this);
final boolean biometrics = prefs.getBoolean("biometrics", false);
final boolean pro = Helper.isPro(this);
final boolean pro = ActivityBilling.isPro(this);
Helper.authenticate(this, biometrics, new Runnable() {
@Override
public void run() {
if (pro)
if (pro) {
prefs.edit().putBoolean("biometrics", !biometrics).apply();
ToastEx.makeText(ActivitySetup.this,
pro
? biometrics
? R.string.title_setup_biometrics_disable
: R.string.title_setup_biometrics_enable
: R.string.title_pro_feature,
Toast.LENGTH_LONG).show();
ToastEx.makeText(ActivitySetup.this,
biometrics
? R.string.title_setup_biometrics_disable
: R.string.title_setup_biometrics_enable,
Toast.LENGTH_LONG).show();
} else
startActivity(new Intent(ActivitySetup.this, ActivityBilling.class));
}
}, new Runnable() {
@Override

View File

@ -19,6 +19,7 @@ package eu.faircode.email;
Copyright 2018-2019 by Marcel Bokhorst (M66B)
*/
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.app.NotificationManager;
import android.app.PendingIntent;
@ -114,14 +115,14 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
static final String ACTION_EDIT_ANSWER = BuildConfig.APPLICATION_ID + ".EDIT_ANSWER";
static final String ACTION_EDIT_RULES = BuildConfig.APPLICATION_ID + ".EDIT_RULES";
static final String ACTION_EDIT_RULE = BuildConfig.APPLICATION_ID + ".EDIT_RULE";
static final String ACTION_SHOW_PRO = BuildConfig.APPLICATION_ID + ".SHOW_PRO";
private static final long EXIT_DELAY = 2500L; // milliseconds
static final long UPDATE_INTERVAL = (BuildConfig.BETA_RELEASE ? 4 : 12) * 3600 * 1000L; // milliseconds
@Override
@SuppressLint("MissingSuperCall")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.onCreate(savedInstanceState, false);
if (savedInstanceState != null)
searching = savedInstanceState.getBoolean("fair:searching");
@ -341,14 +342,13 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
}
}).setSeparated());
if (getIntentPro() == null || getIntentPro().resolveActivity(pm) != null)
extra.add(new NavMenuItem(R.drawable.baseline_monetization_on_24, R.string.menu_pro, new Runnable() {
@Override
public void run() {
drawerLayout.closeDrawer(drawerContainer);
onShowPro(null);
}
}));
extra.add(new NavMenuItem(R.drawable.baseline_monetization_on_24, R.string.menu_pro, new Runnable() {
@Override
public void run() {
drawerLayout.closeDrawer(drawerContainer);
startActivity(new Intent(ActivityView.this, ActivityBilling.class));
}
}));
if ((getIntentInvite(this).resolveActivity(pm) != null))
extra.add(new NavMenuItem(R.drawable.baseline_people_24, R.string.menu_invite, new Runnable() {
@ -560,7 +560,6 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
iff.addAction(ACTION_EDIT_ANSWER);
iff.addAction(ACTION_EDIT_RULES);
iff.addAction(ACTION_EDIT_RULE);
iff.addAction(ACTION_SHOW_PRO);
lbm.registerReceiver(receiver, iff);
checkUpdate(false);
@ -990,8 +989,6 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
onEditRules(intent);
else if (ACTION_EDIT_RULE.equals(action))
onEditRule(intent);
else if (ACTION_SHOW_PRO.equals(action))
onShowPro(intent);
}
}
};
@ -1093,15 +1090,6 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
fragmentTransaction.commit();
}
private void onShowPro(Intent intent) {
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED))
getSupportFragmentManager().popBackStack("pro", FragmentManager.POP_BACK_STACK_INCLUSIVE);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content_frame, new FragmentPro()).addToBackStack("pro");
fragmentTransaction.commit();
}
private class UpdateInfo {
String tag_name; // version
String html_url;

View File

@ -125,7 +125,7 @@ public class AdapterAccount extends RecyclerView.Adapter<AdapterAccount.ViewHold
private void bindTo(TupleAccountEx account) {
view.setActivated(account.tbd != null);
vwColor.setBackgroundColor(account.color == null ? Color.TRANSPARENT : account.color);
vwColor.setVisibility(Helper.isPro(context) ? View.VISIBLE : View.INVISIBLE);
vwColor.setVisibility(ActivityBilling.isPro(context) ? View.VISIBLE : View.INVISIBLE);
ivSync.setImageResource(account.synchronize ? R.drawable.baseline_sync_24 : R.drawable.baseline_sync_disabled_24);

View File

@ -167,7 +167,7 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
if (listener == null) {
vwColor.setBackgroundColor(folder.accountColor == null ? Color.TRANSPARENT : folder.accountColor);
vwColor.setVisibility(account < 0 && Helper.isPro(context) ? View.VISIBLE : View.GONE);
vwColor.setVisibility(account < 0 && ActivityBilling.isPro(context) ? View.VISIBLE : View.GONE);
if (folder.sync_state == null || "requested".equals(folder.sync_state)) {
if (folder.executing > 0)
@ -600,9 +600,8 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
@RequiresApi(api = Build.VERSION_CODES.O)
private void onActionCreateChannel() {
if (!Helper.isPro(context)) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(context)) {
context.startActivity(new Intent(context, ActivityBilling.class));
return;
}

View File

@ -107,7 +107,7 @@ public class AdapterIdentity extends RecyclerView.Adapter<AdapterIdentity.ViewHo
private void bindTo(TupleIdentityEx identity) {
view.setActivated(identity.tbd != null);
vwColor.setBackgroundColor(identity.color == null ? Color.TRANSPARENT : identity.color);
vwColor.setVisibility(Helper.isPro(context) ? View.VISIBLE : View.INVISIBLE);
vwColor.setVisibility(ActivityBilling.isPro(context) ? View.VISIBLE : View.INVISIBLE);
ivSync.setImageResource(identity.synchronize ? R.drawable.baseline_sync_24 : R.drawable.baseline_sync_disabled_24);

View File

@ -82,6 +82,7 @@ import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -122,6 +123,7 @@ import org.jsoup.nodes.Element;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
@ -646,7 +648,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
// Account color
vwColor.setCardBackgroundColor(message.accountColor == null ? Color.TRANSPARENT : message.accountColor);
vwColor.setVisibility(Helper.isPro(context) ? View.VISIBLE : View.INVISIBLE);
vwColor.setVisibility(ActivityBilling.isPro(context) ? View.VISIBLE : View.INVISIBLE);
// Expander
boolean expanded = (viewType == ViewType.THREAD && properties.getValue("expanded", message.id));
@ -881,7 +883,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
int flagged = (message.count - message.unflagged);
ivFlagged.setImageResource(flagged > 0 ? R.drawable.baseline_star_24 : R.drawable.baseline_star_border_24);
ivFlagged.setImageTintList(ColorStateList.valueOf(flagged > 0
? message.color == null || !Helper.isPro(context)
? message.color == null || !ActivityBilling.isPro(context)
? colorAccent : message.color : textColorSecondary));
ivFlagged.setVisibility(flags && !message.folderReadOnly
? (message.uid == null ? View.INVISIBLE : View.VISIBLE)
@ -1319,9 +1321,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
}
private void onActionCalendar(TupleMessageEx message, int action) {
if (!Helper.isPro(context)) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(context)) {
context.startActivity(new Intent(context, ActivityBilling.class));
return;
}
@ -1709,9 +1710,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
@TargetApi(Build.VERSION_CODES.O)
private void onActionCreateChannel() {
if (!Helper.isPro(context)) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(context)) {
context.startActivity(new Intent(context, ActivityBilling.class));
return;
}
@ -2172,10 +2172,15 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
Log.i("Opening uri=" + uri);
if (BuildConfig.APPLICATION_ID.equals(uri.getHost()) && "/activate/".equals(uri.getPath())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
lbm.sendBroadcast(
new Intent(ActivityView.ACTION_ACTIVATE_PRO)
.putExtra("uri", uri));
try {
if (ActivityBilling.activatePro(context, uri))
ToastEx.makeText(context, R.string.title_pro_valid, Toast.LENGTH_LONG).show();
else
ToastEx.makeText(context, R.string.title_pro_invalid, Toast.LENGTH_LONG).show();
} catch (NoSuchAlgorithmException ex) {
Log.e(ex);
Helper.unexpectedError(parentFragment.getFragmentManager(), ex);
}
} else {
if ("cid".equals(uri.getScheme()))
return;
@ -2821,7 +2826,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
if (recipients.length == 0 &&
data.message.list_post == null &&
data.message.receipt_to == null &&
(answers == 0 && Helper.isPro(context))) {
(answers == 0 && ActivityBilling.isPro(context))) {
onMenuReply(data, "reply");
return;
}
@ -2832,7 +2837,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
popupMenu.getMenu().findItem(R.id.menu_reply_to_all).setVisible(recipients.length > 0);
popupMenu.getMenu().findItem(R.id.menu_reply_list).setVisible(data.message.list_post != null);
popupMenu.getMenu().findItem(R.id.menu_reply_receipt).setVisible(data.message.receipt_to != null);
popupMenu.getMenu().findItem(R.id.menu_reply_answer).setVisible(answers != 0 || !Helper.isPro(context));
popupMenu.getMenu().findItem(R.id.menu_reply_answer).setVisible(answers != 0 || !ActivityBilling.isPro(context));
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
@ -2908,9 +2913,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem target) {
if (!Helper.isPro(context)) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(context)) {
context.startActivity(new Intent(context, ActivityBilling.class));
return true;
}
@ -3901,9 +3905,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(getContext())) {
getContext().startActivity(new Intent(getContext(), ActivityBilling.class));
return;
}
@ -3978,9 +3981,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(getContext())) {
getContext().startActivity(new Intent(getContext(), ActivityBilling.class));
return;
}

View File

@ -101,7 +101,7 @@ public class AdapterNavFolder extends RecyclerView.Adapter<AdapterNavFolder.View
? R.drawable.baseline_folder_24
: R.drawable.baseline_folder_open_24);
if (folder.accountColor == null || !Helper.isPro(context))
if (folder.accountColor == null || !ActivityBilling.isPro(context))
ivItem.clearColorFilter();
else
ivItem.setColorFilter(folder.accountColor);

View File

@ -184,7 +184,7 @@ public class AdapterRule extends RecyclerView.Adapter<AdapterRule.ViewHolder> {
popupMenu.getMenu().add(Menu.NONE, R.string.title_rule_enabled, 1, R.string.title_rule_enabled)
.setCheckable(true).setChecked(rule.enabled);
popupMenu.getMenu().add(Menu.NONE, R.string.title_rule_execute, 2, R.string.title_rule_execute)
.setEnabled(Helper.isPro(context));
.setEnabled(ActivityBilling.isPro(context));
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override

View File

@ -1737,7 +1737,7 @@ class Core {
}
private static void runRules(Context context, Message imessage, EntityMessage message, List<EntityRule> rules) {
if (!Helper.isPro(context))
if (!ActivityBilling.isPro(context))
return;
DB db = DB.getInstance(context);
@ -1938,7 +1938,7 @@ class Core {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean badge = prefs.getBoolean("badge", true);
boolean pro = Helper.isPro(context);
boolean pro = ActivityBilling.isPro(context);
// Current
int unseen = 0;
@ -2057,7 +2057,7 @@ class Core {
if (messages == null || messages.size() == 0 || nm == null)
return notifications;
boolean pro = Helper.isPro(context);
boolean pro = ActivityBilling.isPro(context);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean biometrics = prefs.getBoolean("biometrics", false);

View File

@ -49,7 +49,6 @@ import android.widget.RadioGroup;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -762,7 +761,7 @@ public class FragmentAccount extends FragmentBase {
EntityFolder left = (EntityFolder) args.getSerializable("left");
EntityFolder right = (EntityFolder) args.getSerializable("right");
boolean pro = Helper.isPro(context);
boolean pro = ActivityBilling.isPro(context);
boolean should = args.getBoolean("should");
if (host.contains(":")) {
@ -1167,7 +1166,7 @@ public class FragmentAccount extends FragmentBase {
etName.setText(account == null ? null : account.name);
boolean pro = Helper.isPro(getContext());
boolean pro = ActivityBilling.isPro(getContext());
cbNotify.setChecked(account != null && account.notify && pro);
cbNotify.setEnabled(pro);
@ -1292,11 +1291,11 @@ public class FragmentAccount extends FragmentBase {
switch (requestCode) {
case REQUEST_COLOR:
if (resultCode == RESULT_OK && data != null) {
if (Helper.isPro(getContext())) {
if (ActivityBilling.isPro(getContext())) {
Bundle args = data.getBundleExtra("args");
setColor(args.getInt("color"));
} else
ToastEx.makeText(getContext(), R.string.title_pro_feature, Toast.LENGTH_LONG).show();
startActivity(new Intent(getContext(), ActivityBilling.class));
}
break;
case REQUEST_SAVE:

View File

@ -99,7 +99,6 @@ import androidx.core.content.FileProvider;
import androidx.cursoradapter.widget.SimpleCursorAdapter;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.Observer;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -903,9 +902,8 @@ public class FragmentCompose extends FragmentBase {
}
private void onMenuAnswer() {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityCompose.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(getContext())) {
getContext().startActivity(new Intent(getContext(), ActivityBilling.class));
return;
}
@ -1542,9 +1540,8 @@ public class FragmentCompose extends FragmentBase {
}
private void onSendAfter(long time) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityCompose.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(getContext())) {
getContext().startActivity(new Intent(getContext(), ActivityBilling.class));
return;
}
@ -2499,7 +2496,7 @@ public class FragmentCompose extends FragmentBase {
}
});
}
}else {
} else {
// Move draft to new account
if (draft.account != aid && aid >= 0) {
Log.i("Account changed");

View File

@ -31,7 +31,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.method.LinkMovementMethod;
@ -53,7 +52,6 @@ import android.widget.RadioGroup;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -594,7 +592,7 @@ public class FragmentIdentity extends FragmentBase {
if (TextUtils.isEmpty(bcc))
bcc = null;
if (color == Color.TRANSPARENT || !Helper.isPro(context))
if (color == Color.TRANSPARENT || !ActivityBilling.isPro(context))
color = null;
if (TextUtils.isEmpty(signature))
signature = null;
@ -1005,11 +1003,11 @@ public class FragmentIdentity extends FragmentBase {
switch (requestCode) {
case REQUEST_COLOR:
if (resultCode == RESULT_OK && data != null) {
if (Helper.isPro(getContext())) {
if (ActivityBilling.isPro(getContext())) {
Bundle args = data.getBundleExtra("args");
setColor(args.getInt("color"));
} else
ToastEx.makeText(getContext(), R.string.title_pro_feature, Toast.LENGTH_LONG).show();
startActivity(new Intent(getContext(), ActivityBilling.class));
}
break;
case REQUEST_SAVE:

View File

@ -372,8 +372,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
tvSupport.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
getContext().startActivity(new Intent(getContext(), ActivityBilling.class));
}
});
@ -3408,9 +3407,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
break;
case REQUEST_MESSAGES_COLOR:
if (resultCode == RESULT_OK && data != null) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(getContext())) {
getContext().startActivity(new Intent(getContext(), ActivityBilling.class));
return;
}
@ -4007,9 +4005,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
}
private void onColor(long id, int color) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(getContext())) {
getContext().startActivity(new Intent(getContext(), ActivityBilling.class));
return;
}
@ -4045,9 +4042,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
}
private void onSnooze(Bundle args) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(getContext())) {
getContext().startActivity(new Intent(getContext(), ActivityBilling.class));
return;
}
@ -4099,9 +4095,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
}
private void onSnoozeSelection(Bundle args) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(getContext())) {
getContext().startActivity(new Intent(getContext(), ActivityBilling.class));
return;
}
@ -4322,9 +4317,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
static void search(
final Context context, final LifecycleOwner owner, final FragmentManager manager,
long folder, boolean server, String query) {
if (!Helper.isPro(context)) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(context)) {
context.startActivity(new Intent(context, ActivityBilling.class));
return;
}

View File

@ -289,7 +289,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
swBadge.setChecked(prefs.getBoolean("badge", true));
boolean pro = Helper.isPro(getContext());
boolean pro = ActivityBilling.isPro(getContext());
swSubscriptions.setChecked(prefs.getBoolean("subscriptions", false) && pro);
swSubscriptions.setEnabled(pro);
swSubscribedOnly.setChecked(prefs.getBoolean("subscribed_only", false));

View File

@ -232,7 +232,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
}
private void setOptions() {
boolean pro = Helper.isPro(getContext());
boolean pro = ActivityBilling.isPro(getContext());
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
swNotifyPreview.setChecked(prefs.getBoolean("notify_preview", true));

View File

@ -264,7 +264,7 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
break;
}
boolean pro = Helper.isPro(getContext());
boolean pro = ActivityBilling.isPro(getContext());
swSchedule.setChecked(prefs.getBoolean("schedule", false) && pro);
swSchedule.setEnabled(pro);
tvScheduleStart.setText(formatHour(getContext(), prefs.getInt("schedule_start", 0)));

View File

@ -57,7 +57,6 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.Group;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -494,9 +493,8 @@ public class FragmentRule extends FragmentBase {
break;
case REQUEST_COLOR:
if (resultCode == RESULT_OK && data != null) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(getContext())) {
getContext().startActivity(new Intent(getContext(), ActivityBilling.class));
return;
}
@ -770,9 +768,8 @@ public class FragmentRule extends FragmentBase {
}
private void onActionSave() {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
if (!ActivityBilling.isPro(getContext())) {
getContext().startActivity(new Intent(getContext(), ActivityBilling.class));
return;
}

View File

@ -230,7 +230,7 @@ public class Helper {
(Helper.hasValidFingerprint(context) ? "1" : "3") +
(BuildConfig.PLAY_STORE_RELEASE ? "p" : "") +
(BuildConfig.DEBUG ? "d" : "") +
(Helper.isPro(context) ? "+" : "");
(ActivityBilling.isPro(context) ? "+" : "");
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setPackage(BuildConfig.APPLICATION_ID);
intent.setType("text/plain");
@ -812,27 +812,17 @@ public class Helper {
return BuildConfig.PLAY_STORE_RELEASE;
}
static boolean isPro(Context context) {
if (false && BuildConfig.DEBUG)
return true;
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("pro", false);
}
static void linkPro(final TextView tv) {
if (isPro(tv.getContext()) && !BuildConfig.DEBUG)
if (ActivityBilling.isPro(tv.getContext()) && !BuildConfig.DEBUG)
hide(tv);
else {
final Intent pro = new Intent(Intent.ACTION_VIEW, Uri.parse(BuildConfig.PRO_FEATURES_URI));
PackageManager pm = tv.getContext().getPackageManager();
if (pro.resolveActivity(pm) != null) {
tv.getPaint().setUnderlineText(true);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
tv.getContext().startActivity(pro);
}
});
}
tv.getPaint().setUnderlineText(true);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
tv.getContext().startActivity(new Intent(tv.getContext(), ActivityBilling.class));
}
});
}
}

View File

@ -459,7 +459,7 @@ public class Log {
Helper.hasValidFingerprint(context) ? "1" : "3",
BuildConfig.PLAY_STORE_RELEASE ? "p" : "",
BuildConfig.DEBUG ? "d" : "",
Helper.isPro(context) ? "+" : ""));
ActivityBilling.isPro(context) ? "+" : ""));
sb.append(String.format("Android: %s (SDK %d)\r\n", Build.VERSION.RELEASE, Build.VERSION.SDK_INT));
sb.append("\r\n");

View File

@ -60,7 +60,7 @@ public class ServiceExternal extends Service {
if (intent == null)
return START_NOT_STICKY;
if (!Helper.isPro(this))
if (!ActivityBilling.isPro(this))
return START_NOT_STICKY;
final Boolean enabled;

View File

@ -1488,7 +1488,7 @@ public class ServiceSynchronize extends ServiceBase {
am.cancel(piAlarm);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (!prefs.getBoolean("schedule", false) || !Helper.isPro(context))
if (!prefs.getBoolean("schedule", false) || !ActivityBilling.isPro(context))
return;
int minuteStart = prefs.getInt("schedule_start", 0);

View File

@ -43,7 +43,7 @@ public class WidgetUnified extends AppWidgetProvider {
static void update(Context context) {
Log.i("Widget unified update");
if (Helper.isPro(context)) {
if (ActivityBilling.isPro(context)) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, WidgetUnified.class));
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.lv);
@ -56,7 +56,7 @@ public class WidgetUnified extends AppWidgetProvider {
view.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(context, ActivityView.REQUEST_UNIFIED, view, PendingIntent.FLAG_UPDATE_CURRENT);
boolean pro = Helper.isPro(context);
boolean pro = ActivityBilling.isPro(context);
for (int id : appWidgetIds) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_unified);

View File

@ -0,0 +1,6 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ActivityBilling" />