diff --git a/res/values-ru/text_about.xml b/res/values-ru/text_about.xml index da8b1886..4ffb1f8a 100644 --- a/res/values-ru/text_about.xml +++ b/res/values-ru/text_about.xml @@ -144,7 +144,7 @@ так как приложение стало довольно большим и сложным.\n Если вы хотите поддержать проект и избавиться от рекламы, вы можете купить специальную опцию в настройках приложения,\n если вы не хотите или не можете этого сделать - вы всё равно можете отблагодарить автора программы по почте: se.solovyev@gmail.com, высоко оценить приложение на андроид.маркете\n - или помочь в переводе приложения на свой роной язык. + или помочь в переводе приложения на свой родной язык. \ No newline at end of file diff --git a/src/main/java/org/solovyev/android/AndroidUtils.java b/src/main/java/org/solovyev/android/AndroidUtils.java index 8dca9fea..2822c921 100644 --- a/src/main/java/org/solovyev/android/AndroidUtils.java +++ b/src/main/java/org/solovyev/android/AndroidUtils.java @@ -10,6 +10,8 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.os.Build; +import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -35,33 +37,51 @@ public final class AndroidUtils { } public static void centerAndWrapTabsFor(@NotNull TabHost tabHost) { - int tabCount = tabHost.getTabWidget().getTabCount(); - for (int i = 0; i < tabCount; i++) { - final View view = tabHost.getTabWidget().getChildTabViewAt(i); - if (view != null) { - if (view.getLayoutParams().height > 0) { - // reduce height of the tab - view.getLayoutParams().height *= 0.8; - } + if (allowCenterAndWrappingTabs()) { + int tabCount = tabHost.getTabWidget().getTabCount(); + for (int i = 0; i < tabCount; i++) { + final View view = tabHost.getTabWidget().getChildTabViewAt(i); + if (view != null) { + if (view.getLayoutParams().height > 0) { + // reduce height of the tab + view.getLayoutParams().height *= 0.8; + } - // get title text view - final View textView = view.findViewById(android.R.id.title); - if (textView instanceof TextView) { - // just in case check the type + // get title text view + final View textView = view.findViewById(android.R.id.title); + if (textView instanceof TextView) { + // just in case check the type - // center text - ((TextView) textView).setGravity(Gravity.CENTER); - // wrap text - ((TextView) textView).setSingleLine(false); + // center text + ((TextView) textView).setGravity(Gravity.CENTER); + // wrap text + ((TextView) textView).setSingleLine(false); - // explicitly set layout parameters - textView.getLayoutParams().height = ViewGroup.LayoutParams.FILL_PARENT; - textView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT; + // explicitly set layout parameters + textView.getLayoutParams().height = ViewGroup.LayoutParams.FILL_PARENT; + textView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT; + } } } } } + private static boolean allowCenterAndWrappingTabs() { + boolean result = true; + + String deviceModel = Build.MODEL; + if (deviceModel != null) { + deviceModel = deviceModel.toUpperCase(); + if (deviceModel.contains("M1") || deviceModel.contains("MIONE") || deviceModel.contains("MI-ONE")) { + // Xiaomi Phone MiOne => do not allow to center and wrap tabs + result = false; + Log.i(AndroidUtils.class.getName(), "Device model doesn't support center and wrap of tabs: " + Build.MODEL); + } + } + + return result; + } + public static void addTab(@NotNull Context context, @NotNull TabHost tabHost, @NotNull String tabId, diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java index 22902526..b36b92b1 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java @@ -26,6 +26,8 @@ import android.widget.TextView; import com.google.ads.AdView; import jscl.AngleUnit; import jscl.NumeralBase; +import net.robotmedia.billing.BillingController; +import net.robotmedia.billing.IBillingObserver; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.solovyev.android.AndroidUtils; @@ -53,6 +55,9 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh private static final int HVGA_WIDTH_PIXELS = 320; + @Nullable + private IBillingObserver billingObserver; + public static class Preferences { @NotNull private static final String APP_VERSION_P_KEY = "application.version"; @@ -377,6 +382,10 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh private synchronized void firstTimeInit(@NotNull SharedPreferences preferences) { if (!initialized) { + billingObserver = new CalculatorBillingObserver(this); + BillingController.registerObserver(billingObserver); + BillingController.checkBillingSupported(this); + final int savedVersion = Preferences.appVersion.getPreference(preferences); final int appVersion = AndroidUtils.getAppVersionCode(this, CalculatorActivity.class.getPackage().getName()); @@ -627,6 +636,11 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh if ( adView != null ) { adView.destroy(); } + + if (billingObserver != null) { + BillingController.unregisterObserver(billingObserver); + } + super.onDestroy(); } diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java b/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java index 8496ab2a..87813353 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java @@ -36,20 +36,24 @@ public class CalculatorApplication extends android.app.Application { return instance; } - public static boolean isAdFreeApprox(@NotNull Context context) { + private static boolean isAdFreePurchased(@NotNull Context context) { return BillingController.isPurchased(context.getApplicationContext(), AD_FREE_PRODUCT_ID); } + private static boolean transactionsRestored = false; + public static boolean isAdFree(@NotNull Context context) { // check if user already bought this product - boolean purchased = isAdFreeApprox(context); - if (!purchased) { + boolean purchased = isAdFreePurchased(context); + if (!purchased && !transactionsRestored) { // we must to restore all transactions done by user to guarantee that product was purchased or not BillingController.restoreTransactions(context); + transactionsRestored = true; + // todo serso: may be call net.robotmedia.billing.BillingController.restoreTransactions() always before first check and get rid of second check // check the billing one more time - purchased = isAdFreeApprox(context); + purchased = isAdFreePurchased(context); } return purchased; } @@ -62,9 +66,8 @@ public class CalculatorApplication extends android.app.Application { @Nullable public static AdView inflateAd(@NotNull Activity activity, int parentViewId) { AdView result = null; - if ( !isAdFreeApprox(activity) ) { + if ( !isAdFree(activity) ) { Log.d(activity.getClass().getName(), "Application is not ad free - inflating ad!"); - //final List keywords = Arrays.asList("math", "mathematics", "finance", "physics", "dynamics"); final List keywords = Collections.emptyList(); result = AndroidUtils.createAndInflateAdView(activity, ADMOB_USER_ID, parentViewId, keywords); } else { @@ -78,6 +81,7 @@ public class CalculatorApplication extends android.app.Application { public void onCreate() { super.onCreate(); + //BillingController.setDebug(true); BillingController.setConfiguration(new BillingController.IConfiguration() { @Override @@ -90,7 +94,5 @@ public class CalculatorApplication extends android.app.Application { return CalculatorSecurity.getPK(); } }); - - BillingController.checkBillingSupported(this); } } diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorBillingObserver.java b/src/main/java/org/solovyev/android/calculator/CalculatorBillingObserver.java new file mode 100644 index 00000000..28433a13 --- /dev/null +++ b/src/main/java/org/solovyev/android/calculator/CalculatorBillingObserver.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2009-2012. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.calculator; + +import android.app.Activity; +import net.robotmedia.billing.BillingRequest; +import net.robotmedia.billing.helper.AbstractBillingObserver; +import net.robotmedia.billing.model.Transaction; +import org.jetbrains.annotations.NotNull; + +/** + * User: serso + * Date: 1/5/12 + * Time: 4:51 PM + */ +public class CalculatorBillingObserver extends AbstractBillingObserver { + + public CalculatorBillingObserver(@NotNull Activity activity) { + super(activity); + } + + @Override + public void onBillingChecked(boolean supported) { + // do nothing + } + + @Override + public void onPurchaseStateChanged(String itemId, Transaction.PurchaseState state) { + // do nothing + } + + @Override + public void onRequestPurchaseResponse(String itemId, BillingRequest.ResponseCode response) { + // do nothing + } +} diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorPreferencesActivity.java b/src/main/java/org/solovyev/android/calculator/CalculatorPreferencesActivity.java index 90349308..434f52ad 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorPreferencesActivity.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorPreferencesActivity.java @@ -6,11 +6,16 @@ package org.solovyev.android.calculator; import android.app.AlertDialog; +import android.app.PendingIntent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceActivity; +import android.util.Log; import net.robotmedia.billing.BillingController; +import net.robotmedia.billing.BillingRequest; +import net.robotmedia.billing.IBillingObserver; +import net.robotmedia.billing.model.Transaction; import org.solovyev.android.calculator.model.CalculatorEngine; import org.solovyev.android.view.widgets.VibratorContainer; @@ -19,7 +24,7 @@ import org.solovyev.android.view.widgets.VibratorContainer; * Date: 7/16/11 * Time: 6:37 PM */ -public class CalculatorPreferencesActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener { +public class CalculatorPreferencesActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener, IBillingObserver { @Override protected void onCreate(Bundle savedInstanceState) { @@ -35,10 +40,13 @@ public class CalculatorPreferencesActivity extends PreferenceActivity implements // check billing availability if (BillingController.checkBillingSupported(CalculatorPreferencesActivity.this) != BillingController.BillingStatus.SUPPORTED) { + Log.d(CalculatorPreferencesActivity.class.getName(), "Billing is not supported - warn user!"); // warn about not supported billing new AlertDialog.Builder(CalculatorPreferencesActivity.this).setTitle(R.string.c_error).setMessage(R.string.c_billing_error).create().show(); } else { + Log.d(CalculatorPreferencesActivity.class.getName(), "Billing is supported - continue!"); if (!CalculatorApplication.isAdFree(CalculatorPreferencesActivity.this)) { + Log.d(CalculatorPreferencesActivity.class.getName(), "Item not purchased - try to purchase!"); // not purchased => show purchase window for user BillingController.requestPurchase(CalculatorPreferencesActivity.this, CalculatorApplication.AD_FREE_PRODUCT_ID, true); } @@ -51,18 +59,67 @@ public class CalculatorPreferencesActivity extends PreferenceActivity implements addFreePreference.setEnabled(false); } + BillingController.registerObserver(this); + final SharedPreferences preferences = getPreferenceManager().getSharedPreferences(); preferences.registerOnSharedPreferenceChangeListener(this); onSharedPreferenceChanged(preferences, CalculatorEngine.Preferences.roundResult.getKey()); onSharedPreferenceChanged(preferences, VibratorContainer.HAPTIC_FEEDBACK_P_KEY); } + @Override + protected void onDestroy() { + BillingController.unregisterObserver(this); + super.onDestroy(); + } + @Override public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { if (CalculatorEngine.Preferences.roundResult.getKey().equals(key)) { - findPreference(CalculatorEngine.Preferences.roundResult.getKey()).setEnabled(preferences.getBoolean(key, CalculatorEngine.Preferences.roundResult.getDefaultValue())); + findPreference(CalculatorEngine.Preferences.precision.getKey()).setEnabled(preferences.getBoolean(key, CalculatorEngine.Preferences.roundResult.getDefaultValue())); } else if (VibratorContainer.HAPTIC_FEEDBACK_P_KEY.equals(key)) { findPreference(VibratorContainer.HAPTIC_FEEDBACK_DURATION_P_KEY).setEnabled(preferences.getBoolean(key, VibratorContainer.HAPTIC_FEEDBACK_DEFAULT)); } } + + @Override + public void onBillingChecked(boolean supported) { + // do nothing + } + + @Override + public void onPurchaseIntent(String itemId, PendingIntent purchaseIntent) { + // do nothing + } + + @Override + public void onPurchaseStateChanged(String itemId, Transaction.PurchaseState state) { + if (CalculatorApplication.AD_FREE_PRODUCT_ID.equals(itemId)) { + final Preference addFreePreference = findPreference(CalculatorApplication.AD_FREE_P_KEY); + if (addFreePreference != null) { + switch (state) { + case PURCHASED: + addFreePreference.setEnabled(false); + break; + case CANCELLED: + addFreePreference.setEnabled(true); + break; + case REFUNDED: + addFreePreference.setEnabled(true); + break; + } + } else { + } + } + } + + @Override + public void onRequestPurchaseResponse(String itemId, BillingRequest.ResponseCode response) { + // do nothing + } + + @Override + public void onTransactionsRestored() { + // do nothing + } } diff --git a/src/misc/lib/AndroidBillingLibrary.jar b/src/misc/lib/AndroidBillingLibrary.jar index ac2ebcd4..b2ebc0ea 100644 Binary files a/src/misc/lib/AndroidBillingLibrary.jar and b/src/misc/lib/AndroidBillingLibrary.jar differ diff --git a/src/misc/res/logoFULL_banner.png b/src/misc/res/logoFULL_banner.png new file mode 100644 index 00000000..ebc0d680 Binary files /dev/null and b/src/misc/res/logoFULL_banner.png differ