Browse Source

remove ActivityBilling

main
Distopico Vegan 6 years ago
parent
commit
b9591a26aa
7 changed files with 23 additions and 323 deletions
  1. +0
    -230
      app/src/main/java/eu/faircode/email/ActivityBilling.java
  2. +1
    -1
      app/src/main/java/eu/faircode/email/ActivityCompose.java
  3. +1
    -1
      app/src/main/java/eu/faircode/email/ActivitySetup.java
  4. +1
    -5
      app/src/main/java/eu/faircode/email/ActivityView.java
  5. +18
    -26
      app/src/main/java/eu/faircode/email/AdapterMessage.java
  6. +0
    -60
      app/src/main/res/layout/fragment_pro.xml
  7. +2
    -0
      app/src/main/res/values/strings.xml

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

@ -1,230 +0,0 @@
package org.dystopia.email;
/*
This file is part of FairEmail.
FairEmail 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.
FairEmail 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 FairEmail. If not, see <http://www.gnu.org/licenses/>.
Copyright 2018 by Marcel Bokhorst (M66B)
*/
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 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
Helper.view(this, 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();
}
} catch (NoSuchAlgorithmException ex) {
Log.e(Helper.TAG, Log.getStackTraceString(ex));
Helper.unexpectedError(this, ex);
}
}
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();
if (prefs.getBoolean("play_store", true))
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.fragment.app.FragmentTransaction;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
public class ActivityCompose extends ActivityBilling implements FragmentManager.OnBackStackChangedListener {
public class ActivityCompose extends ActivityBase implements FragmentManager.OnBackStackChangedListener {
static final int REQUEST_CONTACT_TO = 1; static final int REQUEST_CONTACT_TO = 1;
static final int REQUEST_CONTACT_CC = 2; static final int REQUEST_CONTACT_CC = 2;
static final int REQUEST_CONTACT_BCC = 3; static final int REQUEST_CONTACT_BCC = 3;


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

@ -34,7 +34,7 @@ import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.localbroadcastmanager.content.LocalBroadcastManager;
public class ActivitySetup extends ActivityBilling implements FragmentManager.OnBackStackChangedListener {
public class ActivitySetup extends ActivityBase implements FragmentManager.OnBackStackChangedListener {
private boolean hasAccount; private boolean hasAccount;
static final int REQUEST_PERMISSION = 1; static final int REQUEST_PERMISSION = 1;


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

@ -90,7 +90,7 @@ import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProviders;
import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.localbroadcastmanager.content.LocalBroadcastManager;
public class ActivityView extends ActivityBilling implements FragmentManager.OnBackStackChangedListener {
public class ActivityView extends ActivityBase implements FragmentManager.OnBackStackChangedListener {
private View view; private View view;
private DrawerLayout drawerLayout; private DrawerLayout drawerLayout;
private ListView drawerList; private ListView drawerList;
@ -231,10 +231,6 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
if (getIntentFAQ().resolveActivity(getPackageManager()) != null) if (getIntentFAQ().resolveActivity(getPackageManager()) != null)
drawerArray.add(new DrawerItem(ActivityView.this, R.layout.item_drawer, R.drawable.baseline_question_answer_24, R.string.menu_faq)); drawerArray.add(new DrawerItem(ActivityView.this, R.layout.item_drawer, R.drawable.baseline_question_answer_24, R.string.menu_faq));
Intent pro = getIntentPro();
if (pro == null || pro.resolveActivity(getPackageManager()) != null)
drawerArray.add(new DrawerItem(ActivityView.this, R.layout.item_drawer, R.drawable.baseline_monetization_on_24, R.string.menu_pro));
if (Helper.getIntentPrivacy().resolveActivity(getPackageManager()) != null) if (Helper.getIntentPrivacy().resolveActivity(getPackageManager()) != null)
drawerArray.add(new DrawerItem(ActivityView.this, R.layout.item_drawer, R.drawable.baseline_account_box_24, R.string.menu_privacy)); drawerArray.add(new DrawerItem(ActivityView.this, R.layout.item_drawer, R.drawable.baseline_account_box_24, R.string.menu_privacy));


+ 18
- 26
app/src/main/java/eu/faircode/email/AdapterMessage.java View File

@ -749,34 +749,26 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
return true; return true;
} }
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));
} else {
View view = LayoutInflater.from(context).inflate(R.layout.dialog_link, null);
final EditText etLink = view.findViewById(R.id.etLink);
etLink.setText(url);
new DialogBuilderLifecycle(context, owner)
.setView(view)
.setPositiveButton(R.string.title_yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Uri uri = Uri.parse(etLink.getText().toString());
if (!"http".equals(uri.getScheme()) && !"https".equals(uri.getScheme())) {
Toast.makeText(context, context.getString(R.string.title_no_viewer, uri.toString()), Toast.LENGTH_LONG).show();
return;
}
View view = LayoutInflater.from(context).inflate(R.layout.dialog_link, null);
final EditText etLink = view.findViewById(R.id.etLink);
etLink.setText(url);
new DialogBuilderLifecycle(context, owner)
.setView(view)
.setPositiveButton(R.string.title_yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Uri uri = Uri.parse(etLink.getText().toString());
Helper.view(context, uri);
if (!"http".equals(uri.getScheme()) && !"https".equals(uri.getScheme())) {
Toast.makeText(context, context.getString(R.string.title_no_viewer, uri.toString()), Toast.LENGTH_LONG).show();
return;
} }
})
.setNegativeButton(R.string.title_no, null)
.show();
}
Helper.view(context, uri);
}
})
.setNegativeButton(R.string.title_no, null)
.show();
} }
return true; return true;


+ 0
- 60
app/src/main/res/layout/fragment_pro.xml View File

@ -1,60 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp">
<TextView
android:id="@+id/tvActivated"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title_pro_activated"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@string/title_pro_list"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvActivated" />
<Button
android:id="@+id/btnPurchase"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@string/title_pro_purchase"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvList" />
<TextView
android:id="@+id/tvHint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@string/title_pro_hint"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnPurchase" />
<TextView
android:id="@+id/tvPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_pro_price"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvHint" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

+ 2
- 0
app/src/main/res/values/strings.xml View File

@ -4,6 +4,8 @@
<string name="app_copyright">Copyright &#x24B8; 2018 by M. Bokhorst</string> <string name="app_copyright">Copyright &#x24B8; 2018 by M. Bokhorst</string>
<string name="app_eula" translatable="false">THIS SOFTWARE IS PROVIDED BY THE AUTHOR \'\'AS IS\'\' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</string> <string name="app_eula" translatable="false">THIS SOFTWARE IS PROVIDED BY THE AUTHOR \'\'AS IS\'\' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</string>
<string name="title_pro_support">TEST....</string>
<string name="channel_service">Service</string> <string name="channel_service">Service</string>
<string name="channel_notification">Notifications</string> <string name="channel_notification">Notifications</string>
<string name="channel_error">Errors</string> <string name="channel_error">Errors</string>


Loading…
Cancel
Save