diff --git a/app/src/main/java/eu/faircode/netguard/ActivityMain.java b/app/src/main/java/eu/faircode/netguard/ActivityMain.java index 7756e0cd..8c40238a 100644 --- a/app/src/main/java/eu/faircode/netguard/ActivityMain.java +++ b/app/src/main/java/eu/faircode/netguard/ActivityMain.java @@ -60,6 +60,7 @@ import java.util.List; public class ActivityMain extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = "NetGuard.Main"; + private boolean pro = false; private boolean running = false; private SwipeRefreshLayout swipeRefresh; private RuleAdapter adapter = null; @@ -248,6 +249,14 @@ public class ActivityMain extends AppCompatActivity implements SharedPreferences // Fill application list updateApplicationList(getIntent().getStringExtra(EXTRA_SEARCH)); + + // Check if donated + new Thread(new Runnable() { + @Override + public void run() { + pro = new IAB(ActivityMain.this).hasPro(); + } + }).start(); } @Override @@ -510,7 +519,20 @@ public class ActivityMain extends AppCompatActivity implements SharedPreferences public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - switch (item.getItemId()) { + + int id = item.getItemId(); + + if (!pro && + (id == R.id.menu_app_user || + id == R.id.menu_app_system || + id == R.id.menu_app_nointernet || + id == R.id.menu_app_disabled) && + item.isChecked()) { + Toast.makeText(this, getString(R.string.msg_pro), Toast.LENGTH_SHORT).show(); + return true; + } + + switch (id) { case R.id.menu_app_user: item.setChecked(!item.isChecked()); prefs.edit().putBoolean("show_user", item.isChecked()).apply(); @@ -532,7 +554,9 @@ public class ActivityMain extends AppCompatActivity implements SharedPreferences return true; case R.id.menu_settings: - startActivity(new Intent(this, ActivitySettings.class)); + Intent settings = new Intent(this, ActivitySettings.class); + settings.putExtra(ActivitySettings.EXTRA_PRO, pro); + startActivity(settings); return true; case R.id.menu_invite: @@ -681,7 +705,7 @@ public class ActivityMain extends AppCompatActivity implements SharedPreferences // Connect to billing if (Util.hasValidFingerprint(this)) - iab.bind(); + iab.bind(null); } diff --git a/app/src/main/java/eu/faircode/netguard/ActivitySettings.java b/app/src/main/java/eu/faircode/netguard/ActivitySettings.java index 1d4e1c64..db73c31b 100644 --- a/app/src/main/java/eu/faircode/netguard/ActivitySettings.java +++ b/app/src/main/java/eu/faircode/netguard/ActivitySettings.java @@ -73,8 +73,11 @@ import javax.xml.parsers.SAXParserFactory; public class ActivitySettings extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = "NetGuard.Settings"; + private boolean pro = false; private boolean phone_state = false; + public static final String EXTRA_PRO = "Pro"; + private static final int REQUEST_EXPORT = 1; private static final int REQUEST_IMPORT = 2; private static final int REQUEST_METERED = 3; @@ -88,6 +91,8 @@ public class ActivitySettings extends AppCompatActivity implements SharedPrefere super.onCreate(savedInstanceState); + pro = getIntent().getBooleanExtra(EXTRA_PRO, false); + getFragmentManager().beginTransaction().replace(android.R.id.content, new FragmentSettings()).commit(); getSupportActionBar().setTitle(R.string.menu_settings); } @@ -140,7 +145,10 @@ public class ActivitySettings extends AppCompatActivity implements SharedPrefere pref_export.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { - startActivityForResult(getIntentCreateDocument(), ActivitySettings.REQUEST_EXPORT); + if (pro) + startActivityForResult(getIntentCreateDocument(), ActivitySettings.REQUEST_EXPORT); + else + Toast.makeText(ActivitySettings.this, getString(R.string.msg_pro), Toast.LENGTH_SHORT).show(); return true; } }); @@ -151,7 +159,10 @@ public class ActivitySettings extends AppCompatActivity implements SharedPrefere pref_import.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { - startActivityForResult(getIntentOpenDocument(), ActivitySettings.REQUEST_IMPORT); + if (pro) + startActivityForResult(getIntentOpenDocument(), ActivitySettings.REQUEST_IMPORT); + else + Toast.makeText(ActivitySettings.this, getString(R.string.msg_pro), Toast.LENGTH_SHORT).show(); return true; } }); @@ -292,26 +303,34 @@ public class ActivitySettings extends AppCompatActivity implements SharedPrefere } else SinkholeService.reload("other", "setting changed", this); - } else if ("show_stats".equals(name)) { - if (!Util.isPlayStoreInstall(this)) - SinkholeService.reloadStats("setting changed", this); + } else if ("manage_system".equals(name)) { + SharedPreferences.Editor editor = prefs.edit(); + if (prefs.getBoolean(name, false)) { + editor.putBoolean("show_system", true); + editor.putBoolean("show_user", true); + } else { + editor.putBoolean("show_user", true); + editor.putBoolean("show_system", false); + } + editor.apply(); + SinkholeService.reload(null, "setting changed", this); - } else if ("stats_base".equals(name)) { - if (!Util.isPlayStoreInstall(this)) - getPreferenceScreen().findPreference(name).setTitle(getString(R.string.setting_stats_base, prefs.getString(name, "5"))); - - } else if ("stats_frequency".equals(name)) { - if (!Util.isPlayStoreInstall(this)) - getPreferenceScreen().findPreference(name).setTitle(getString(R.string.setting_stats_frequency, prefs.getString(name, "1000"))); - - } else if ("stats_samples".equals(name)) { - if (!Util.isPlayStoreInstall(this)) - getPreferenceScreen().findPreference(name).setTitle(getString(R.string.setting_stats_samples, prefs.getString(name, "90"))); - - } else if ("auto_enable".equals(name)) + } else if ("auto_enable".equals(name)) { + if (!pro) { + prefs.edit().putString(name, "0").apply(); + Toast.makeText(ActivitySettings.this, getString(R.string.msg_pro), Toast.LENGTH_SHORT).show(); + } getPreferenceScreen().findPreference(name).setTitle(getString(R.string.setting_auto, prefs.getString(name, "0"))); - else if ("wifi_homes".equals(name)) { + } else if ("dark_theme".equals(name)) { + if (!pro) { + prefs.edit().putBoolean(name, false); + ((SwitchPreference) getPreferenceScreen().findPreference(name)).setChecked(false); + Toast.makeText(ActivitySettings.this, getString(R.string.msg_pro), Toast.LENGTH_SHORT).show(); + } + recreate(); + + } else if ("wifi_homes".equals(name)) { MultiSelectListPreference pref_wifi_homes = (MultiSelectListPreference) getPreferenceScreen().findPreference(name); Set ssid = prefs.getStringSet(name, new HashSet()); if (ssid.size() > 0) @@ -343,24 +362,32 @@ public class ActivitySettings extends AppCompatActivity implements SharedPrefere } else SinkholeService.reload("other", "setting changed", this); - } else if ("manage_system".equals(name)) { - SharedPreferences.Editor editor = prefs.edit(); - if (prefs.getBoolean(name, false)) { - editor.putBoolean("show_system", true); - editor.putBoolean("show_user", true); - } else { - editor.putBoolean("show_user", true); - editor.putBoolean("show_system", false); + } else if ("show_stats".equals(name)) { + if (pro) + SinkholeService.reloadStats("setting changed", this); + else { + prefs.edit().putBoolean(name, false); + ((SwitchPreference) getPreferenceScreen().findPreference(name)).setChecked(false); + Toast.makeText(ActivitySettings.this, getString(R.string.msg_pro), Toast.LENGTH_SHORT).show(); } - editor.apply(); - SinkholeService.reload(null, "setting changed", this); - } else if ("dark_theme".equals(name)) - recreate(); + } else if ("stats_base".equals(name)) { + if (!Util.isPlayStoreInstall(this)) + getPreferenceScreen().findPreference(name).setTitle(getString(R.string.setting_stats_base, prefs.getString(name, "5"))); + + } else if ("stats_frequency".equals(name)) { + if (!Util.isPlayStoreInstall(this)) + getPreferenceScreen().findPreference(name).setTitle(getString(R.string.setting_stats_frequency, prefs.getString(name, "1000"))); + + } else if ("stats_samples".equals(name)) { + if (!Util.isPlayStoreInstall(this)) + getPreferenceScreen().findPreference(name).setTitle(getString(R.string.setting_stats_samples, prefs.getString(name, "90"))); + } } @Override - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + public void onRequestPermissionsResult(int requestCode, String[] permissions, + int[] grantResults) { PreferenceScreen screen = getPreferenceScreen(); if (requestCode == REQUEST_METERED) diff --git a/app/src/main/java/eu/faircode/netguard/IAB.java b/app/src/main/java/eu/faircode/netguard/IAB.java index 28af3197..75db9216 100644 --- a/app/src/main/java/eu/faircode/netguard/IAB.java +++ b/app/src/main/java/eu/faircode/netguard/IAB.java @@ -25,6 +25,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.SharedPreferences; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; @@ -37,26 +38,35 @@ import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; +import java.util.Date; +import java.util.concurrent.CountDownLatch; public class IAB implements ServiceConnection { private static final String TAG = "Netguard.IAB"; private Context context; + private Event event; private boolean available = false; private IInAppBillingService service = null; private static final int IAB_VERSION = 3; // adb shell pm clear com.android.vending // adb shell am start -n eu.faircode.netguard/eu.faircode.netguard.ActivityMain + private static final String SKU_PRO = "pro"; private static final String SKU_DONATE = "donation"; // private static final String SKU_DONATE = "android.test.purchased"; public static final String ACTION_IAB = "eu.faircode.netguard.IAB"; + public interface Event { + void bound(); + } + public IAB(Context context) { this.context = context; } - public void bind() { + public void bind(Event event) { + this.event = event; try { Log.i(TAG, "Bind"); Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND"); @@ -87,20 +97,23 @@ public class IAB implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder binder) { Log.i(TAG, "Connected"); - try { - service = IInAppBillingService.Stub.asInterface(binder); + service = IInAppBillingService.Stub.asInterface(binder); - if (isPurchased(SKU_DONATE)) { - Intent intent = new Intent(ACTION_IAB); - intent.putExtra("RESULT_CODE", Activity.RESULT_OK); - LocalBroadcastManager.getInstance(context).sendBroadcast(intent); - } else - available = (service != null && isAvailable(SKU_DONATE)); + if (this.event == null) + try { + if (isPurchased(SKU_DONATE)) { + Intent intent = new Intent(ACTION_IAB); + intent.putExtra("RESULT_CODE", Activity.RESULT_OK); + LocalBroadcastManager.getInstance(context).sendBroadcast(intent); + } else + available = (service != null && isAvailable(SKU_DONATE)); - } catch (Throwable ex) { - Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex)); - Util.sendCrashReport(ex, context); - } + } catch (Throwable ex) { + Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex)); + Util.sendCrashReport(ex, context); + } + else + event.bound(); } @Override @@ -146,6 +159,61 @@ public class IAB implements ServiceConnection { } } + public boolean hasPro() { + boolean pro = false; + final CountDownLatch latch = new CountDownLatch(1); + + if (Util.isDebuggable(context)) + return true; + + bind(new Event() { + @Override + public void bound() { + try { + SharedPreferences prefs = context.getSharedPreferences("IAB", Context.MODE_PRIVATE); + boolean pro = false; + long now = new Date().getTime(); + long refreshed = prefs.getLong("refreshed", 0); + + if (!prefs.getBoolean("pro", false) || refreshed < now - 3 * 24 * 3600 * 1000L) { + Log.i(TAG, "Refreshing pro"); + try { + pro = isPurchased(SKU_PRO); + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean("pro", pro); + editor.putLong("refreshed", now); + editor.apply(); + Log.i(TAG, "Refreshed pro=" + pro); + } catch (RemoteException ignored) { + if (refreshed >= now - 5 * 24 * 3600 * 1000L) { + pro = prefs.getBoolean("pro", false); + Log.i(TAG, "Grace pro=" + pro); + } else { + SharedPreferences.Editor editor = prefs.edit(); + editor.remove("pro"); + editor.remove("refreshed"); + editor.apply(); + Log.i(TAG, "Cache expired"); + } + } + } else { + pro = prefs.getBoolean("pro", false); + Log.i(TAG, "Cached pro=" + pro); + } + } finally { + try { + latch.await(); + } catch (InterruptedException ignored) { + } + } + } + }); + + latch.countDown(); + return pro; + } + + private boolean isPurchased(String sku) throws RemoteException { try { // Get purchases diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4a699654..4e1eb907 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -80,6 +80,7 @@ Since NetGuard has no internet permission, you know your internet traffic is not ± %1$.3f▲ %2$.3f▼ MB/day %7.3f KB/s %7.3f MB/s + This is a pro feature Allow Wi-Fi when screen is on Allow mobile when screen is on