Added IAB testing

pull/199/head
M66B 4 years ago
parent 8fa9664939
commit c008ca8ed0

@ -122,6 +122,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
private SwitchCompat swAuthNtlm;
private SwitchCompat swAuthSasl;
private SwitchCompat swExactAlarms;
private SwitchCompat swTestIab;
private TextView tvProcessors;
private TextView tvMemoryClass;
private TextView tvMemoryUsage;
@ -147,7 +148,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
"protocol", "debug", "log_level",
"use_modseq", "perform_expunge",
"auth_plain", "auth_login", "auth_ntlm", "auth_sasl",
"exact_alarms"
"exact_alarms", "test_iab"
};
private final static String[] RESET_QUESTIONS = new String[]{
@ -229,6 +230,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
swAuthNtlm = view.findViewById(R.id.swAuthNtlm);
swAuthSasl = view.findViewById(R.id.swAuthSasl);
swExactAlarms = view.findViewById(R.id.swExactAlarms);
swTestIab = view.findViewById(R.id.swTestIab);
tvProcessors = view.findViewById(R.id.tvProcessors);
tvMemoryClass = view.findViewById(R.id.tvMemoryClass);
tvMemoryUsage = view.findViewById(R.id.tvMemoryUsage);
@ -605,6 +607,13 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
}
});
swTestIab.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("test_iab", checked).apply();
}
});
btnGC.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -821,6 +830,8 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
setLastCleanup(prefs.getLong("last_cleanup", -1));
swTestIab.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE);
PreferenceManager.getDefaultSharedPreferences(getContext()).registerOnSharedPreferenceChangeListener(this);
return view;
@ -991,6 +1002,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
swAuthNtlm.setChecked(prefs.getBoolean("auth_ntlm", true));
swAuthSasl.setChecked(prefs.getBoolean("auth_sasl", true));
swExactAlarms.setChecked(prefs.getBoolean("exact_alarms", false));
swTestIab.setChecked(prefs.getBoolean("test_iab", false));
tvProcessors.setText(getString(R.string.title_advanced_processors, Runtime.getRuntime().availableProcessors()));

@ -62,7 +62,7 @@ public class FragmentPro extends FragmentBase implements SharedPreferences.OnSha
private TextView tvPriceHint;
private TextView tvFamilyHint;
private TextView tvRestoreHint;
private Button btnCheck;
private Button btnConsume;
private static final int HIDE_BANNER = 3; // weeks
@ -90,12 +90,13 @@ public class FragmentPro extends FragmentBase implements SharedPreferences.OnSha
tvFamilyHint = view.findViewById(R.id.tvFamilyHint);
tvRestoreHint = view.findViewById(R.id.tvRestoreHint);
btnCheck = view.findViewById(R.id.btnCheck);
btnConsume = view.findViewById(R.id.btnConsume);
btnBackup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(getContext(), ActivitySetup.class).putExtra("navigate", true));
startActivity(new Intent(getContext(), ActivitySetup.class)
.putExtra("navigate", true));
}
});
btnBackup.setVisibility(View.GONE);
@ -129,8 +130,8 @@ public class FragmentPro extends FragmentBase implements SharedPreferences.OnSha
btnPurchase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
public void onClick(View v) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(v.getContext());
lbm.sendBroadcast(new Intent(ActivityBilling.ACTION_PURCHASE));
}
});
@ -161,11 +162,11 @@ public class FragmentPro extends FragmentBase implements SharedPreferences.OnSha
}
});
btnCheck.setOnClickListener(new View.OnClickListener() {
btnConsume.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityBilling.ACTION_PURCHASE_CHECK));
public void onClick(View v) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(v.getContext());
lbm.sendBroadcast(new Intent(ActivityBilling.ACTION_PURCHASE_CONSUME));
}
});
@ -175,8 +176,8 @@ public class FragmentPro extends FragmentBase implements SharedPreferences.OnSha
btnPurchase.setEnabled(!Helper.isPlayStoreInstall());
tvPrice.setText(null);
tvRestoreHint.setVisibility(Helper.isPlayStoreInstall() || BuildConfig.DEBUG ? View.VISIBLE : View.GONE);
btnCheck.setEnabled(false);
btnCheck.setVisibility(Helper.isPlayStoreInstall() && debug ? View.VISIBLE : View.GONE);
btnConsume.setEnabled(false);
btnConsume.setVisibility(ActivityBilling.isTesting(getContext()) ? View.VISIBLE : View.GONE);
return view;
}
@ -188,12 +189,10 @@ public class FragmentPro extends FragmentBase implements SharedPreferences.OnSha
addBillingListener(new ActivityBilling.IBillingListener() {
@Override
public void onConnected() {
btnCheck.setEnabled(true);
}
@Override
public void onDisconnected() {
btnCheck.setEnabled(false);
}
@Override
@ -213,10 +212,11 @@ public class FragmentPro extends FragmentBase implements SharedPreferences.OnSha
}
@Override
public void onPurchased(String sku) {
public void onPurchased(String sku, boolean purchased) {
if (ActivityBilling.getSkuPro().equals(sku)) {
btnPurchase.setEnabled(false);
btnPurchase.setEnabled(!purchased);
tvPending.setVisibility(View.GONE);
btnConsume.setEnabled(purchased);
}
}

@ -678,6 +678,17 @@
app:layout_constraintTop_toBottomOf="@id/swAuthSasl"
app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swTestIab"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_advanced_test_iab"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swExactAlarms"
app:switchPadding="12dp" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvProcessors"
android:layout_width="0dp"
@ -687,7 +698,7 @@
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swExactAlarms" />
app:layout_constraintTop_toBottomOf="@id/swTestIab" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvMemoryClass"

@ -169,12 +169,12 @@
app:layout_constraintTop_toBottomOf="@id/tvFamilyHint" />
<Button
android:id="@+id/btnCheck"
android:id="@+id/btnConsume"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_check"
android:text="Consume"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvRestoreHint" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -568,6 +568,7 @@
<string name="title_advanced_auth_ntlm" translatable="false">NTLM</string>
<string name="title_advanced_auth_sasl" translatable="false">SASL</string>
<string name="title_advanced_exact_alarms" translatable="false">Use exact timers</string>
<string name="title_advanced_test_iab" translatable="false">Test IAB</string>
<string name="title_advanced_processors" translatable="false">Processors: %1$d</string>
<string name="title_advanced_memory_class" translatable="false">Memory class: %1$s/%2$s Total: %3$s</string>
<string name="title_advanced_memory_usage" translatable="false">Memory usage: %1$s/%2$s Native: %3$s</string>

@ -31,7 +31,6 @@ import android.os.Handler;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Base64;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -53,8 +52,6 @@ import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.ConsumeParams;
import com.android.billingclient.api.ConsumeResponseListener;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchaseHistoryRecord;
import com.android.billingclient.api.PurchaseHistoryResponseListener;
import com.android.billingclient.api.PurchasesUpdatedListener;
import com.android.billingclient.api.SkuDetails;
import com.android.billingclient.api.SkuDetailsParams;
@ -75,9 +72,10 @@ public class ActivityBilling extends ActivityBase implements PurchasesUpdatedLis
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_PURCHASE_CONSUME = BuildConfig.APPLICATION_ID + ".ACTION_PURCHASE_CONSUME";
static final String ACTION_PURCHASE_ERROR = BuildConfig.APPLICATION_ID + ".ACTION_PURCHASE_ERROR";
private static final String SKU_TEST = "android.test.purchased";
private final static long MAX_SKU_CACHE_DURATION = 24 * 3600 * 1000L; // milliseconds
private final static long MAX_SKU_NOACK_DURATION = 24 * 3600 * 1000L; // milliseconds
@ -102,7 +100,7 @@ public class ActivityBilling extends ActivityBase implements PurchasesUpdatedLis
getSupportFragmentManager().addOnBackStackChangedListener(this);
}
if (Helper.isPlayStoreInstall()) {
if (Helper.isPlayStoreInstall() || isTesting(this)) {
Log.i("IAB start");
billingClient = BillingClient.newBuilder(this)
.enablePendingPurchases()
@ -125,7 +123,7 @@ public class ActivityBilling extends ActivityBase implements PurchasesUpdatedLis
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
IntentFilter iff = new IntentFilter();
iff.addAction(ACTION_PURCHASE);
iff.addAction(ACTION_PURCHASE_CHECK);
iff.addAction(ACTION_PURCHASE_CONSUME);
iff.addAction(ACTION_PURCHASE_ERROR);
lbm.registerReceiver(receiver, iff);
@ -152,11 +150,16 @@ public class ActivityBilling extends ActivityBase implements PurchasesUpdatedLis
@NonNull
static String getSkuPro() {
if (BuildConfig.DEBUG)
return "android.test.purchased";
return SKU_TEST;
else
return BuildConfig.APPLICATION_ID + ".pro";
}
static boolean isTesting(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return (BuildConfig.DEBUG && prefs.getBoolean("test_iab", false));
}
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);
@ -206,8 +209,8 @@ public class ActivityBilling extends ActivityBase implements PurchasesUpdatedLis
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
if (ACTION_PURCHASE.equals(intent.getAction()))
onPurchase(intent);
else if (ACTION_PURCHASE_CHECK.equals(intent.getAction()))
onPurchaseCheck(intent);
else if (ACTION_PURCHASE_CONSUME.equals(intent.getAction()))
onPurchaseConsume(intent);
else if (ACTION_PURCHASE_ERROR.equals(intent.getAction()))
onPurchaseError(intent);
}
@ -215,7 +218,7 @@ public class ActivityBilling extends ActivityBase implements PurchasesUpdatedLis
};
private void onPurchase(Intent intent) {
if (Helper.isPlayStoreInstall()) {
if (Helper.isPlayStoreInstall() || isTesting(this)) {
String sku = getSkuPro();
Log.i("IAB purchase SKU=" + sku);
@ -255,21 +258,13 @@ public class ActivityBilling extends ActivityBase implements PurchasesUpdatedLis
}
}
private void onPurchaseCheck(Intent intent) {
billingClient.queryPurchaseHistoryAsync(BillingClient.SkuType.INAPP, new PurchaseHistoryResponseListener() {
@Override
public void onPurchaseHistoryResponse(@NonNull BillingResult result, List<PurchaseHistoryRecord> records) {
if (result.getResponseCode() == BillingClient.BillingResponseCode.OK) {
for (PurchaseHistoryRecord record : records)
Log.i("IAB history=" + record.toString());
queryPurchases();
ToastEx.makeText(ActivityBilling.this, R.string.title_setup_done, Toast.LENGTH_LONG).show();
} else
reportError(result, "IAB history");
}
});
private void onPurchaseConsume(Intent intent) {
Purchase.PurchasesResult result = billingClient.queryPurchases(BillingClient.SkuType.INAPP);
if (result.getResponseCode() == BillingClient.BillingResponseCode.OK) {
for (Purchase purchase : result.getPurchasesList())
consumePurchase(purchase);
} else
reportError(result.getBillingResult(), "IAB onPurchaseConsume");
}
private void onPurchaseError(Intent intent) {
@ -342,7 +337,7 @@ public class ActivityBilling extends ActivityBase implements PurchasesUpdatedLis
void onPurchasePending(String sku);
void onPurchased(String sku);
void onPurchased(String sku, boolean purchased);
void onError(String message);
}
@ -396,14 +391,9 @@ public class ActivityBilling extends ActivityBase implements PurchasesUpdatedLis
" time=" + new Date(time));
Log.i("IAB json=" + purchase.getOriginalJson());
//if (new Date().getTime() - purchase.getPurchaseTime() > 3 * 60 * 1000L) {
// consumePurchase(purchase);
// continue;
//}
for (IBillingListener listener : listeners)
if (isPurchaseValid(purchase))
listener.onPurchased(purchase.getSku());
listener.onPurchased(purchase.getSku(), true);
else
listener.onPurchasePending(purchase.getSku());
@ -414,7 +404,8 @@ public class ActivityBilling extends ActivityBase implements PurchasesUpdatedLis
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(publicKey);
sig.update(purchase.getOriginalJson().getBytes());
if (sig.verify(Base64.decode(purchase.getSignature(), Base64.DEFAULT))) {
if (SKU_TEST.equals(purchase.getSku()) ||
sig.verify(Base64.decode(purchase.getSignature(), Base64.DEFAULT))) {
Log.i("IAB valid signature");
if (getSkuPro().equals(purchase.getSku())) {
if (isPurchaseValid(purchase)) {
@ -466,14 +457,17 @@ public class ActivityBilling extends ActivityBase implements PurchasesUpdatedLis
}
private void consumePurchase(final Purchase purchase) {
Log.i("IAB SKU=" + purchase.getSku() + " consuming");
Log.i("IAB consuming SKU=" + purchase.getSku());
ConsumeParams params = ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingClient.consumeAsync(params, new ConsumeResponseListener() {
@Override
public void onConsumeResponse(@NonNull BillingResult result, @NonNull String purchaseToken) {
if (result.getResponseCode() != BillingClient.BillingResponseCode.OK)
if (result.getResponseCode() == BillingClient.BillingResponseCode.OK) {
for (IBillingListener listener : listeners)
listener.onPurchased(purchase.getSku(), false);
} else
reportError(result, "IAB consumed SKU=" + purchase.getSku());
}
});
@ -496,7 +490,7 @@ public class ActivityBilling extends ActivityBase implements PurchasesUpdatedLis
editor.apply();
for (IBillingListener listener : listeners)
listener.onPurchased(purchase.getSku());
listener.onPurchased(purchase.getSku(), true);
WidgetUnified.updateData(ActivityBilling.this);
} else {
@ -521,6 +515,7 @@ public class ActivityBilling extends ActivityBase implements PurchasesUpdatedLis
private boolean isPurchaseValid(Purchase purchase) {
return (isPurchased(purchase) &&
(purchase.isAcknowledged() ||
SKU_TEST.equals(purchase.getSku()) ||
purchase.getPurchaseTime() + MAX_SKU_NOACK_DURATION > new Date().getTime()));
}

Loading…
Cancel
Save