diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 0d832da5..bb0b1d76 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -2,7 +2,11 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index ca746379..aa89dc92 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -37,6 +37,30 @@ + + + + diff --git a/.idea/runConfigurations/C__.xml b/.idea/runConfigurations/C__.xml index 28e9c4f5..dc16b715 100644 --- a/.idea/runConfigurations/C__.xml +++ b/.idea/runConfigurations/C__.xml @@ -6,7 +6,7 @@ \ No newline at end of file diff --git a/android-app-core/android-app-core.iml b/android-app-core/android-app-core.iml index 7a8b4b93..e6ac0687 100644 --- a/android-app-core/android-app-core.iml +++ b/android-app-core/android-app-core.iml @@ -84,10 +84,10 @@ - + - + @@ -98,8 +98,8 @@ - + diff --git a/android-app-core/build.gradle b/android-app-core/build.gradle index 2cf84a17..f1986fc9 100644 --- a/android-app-core/build.gradle +++ b/android-app-core/build.gradle @@ -48,13 +48,13 @@ dependencies { compile 'org.solovyev.android:android-common-menus:1.1.18@aar' compile 'org.solovyev.android:android-common-core:1.1.18@aar' compile 'org.solovyev.android:android-common-preferences:1.1.18@aar' - compile 'org.solovyev.android:android-common-app:1.1.18@aar' compile('org.solovyev:jscl:1.0.8') { exclude(module: 'xercesImpl') } compile 'com.actionbarsherlock:actionbarsherlock:4.4.0@aar' - compile 'com.google.android.admob:admob:6.4.1-r11.0.0' compile 'com.android.support:support-v4:21.0.3' + compile 'org.solovyev.android:checkout:0.6.0@aar' + compile 'com.google.android.gms:play-services:6.5.87@aar' //testCompile group: 'org.robolectric', name: 'robolectric', version: '2.1.1' } diff --git a/android-app-core/src/main/AndroidManifest.xml b/android-app-core/src/main/AndroidManifest.xml index a755358f..7ee835bb 100644 --- a/android-app-core/src/main/AndroidManifest.xml +++ b/android-app-core/src/main/AndroidManifest.xml @@ -8,4 +8,8 @@ android:minSdkVersion="4" android:targetSdkVersion="17"/> + + \ No newline at end of file diff --git a/android-app-core/src/main/java/org/solovyev/android/calculator/App.java b/android-app-core/src/main/java/org/solovyev/android/calculator/App.java new file mode 100644 index 00000000..2842253f --- /dev/null +++ b/android-app-core/src/main/java/org/solovyev/android/calculator/App.java @@ -0,0 +1,166 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.android.calculator; + +import android.app.Application; +import org.solovyev.android.UiThreadExecutor; +import org.solovyev.common.listeners.JEvent; +import org.solovyev.common.listeners.JEventListener; +import org.solovyev.common.listeners.JEventListeners; +import org.solovyev.common.listeners.Listeners; +import org.solovyev.common.threads.DelayedExecutor; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * User: serso + * Date: 12/1/12 + * Time: 3:58 PM + */ + +/** + * This class aggregates several useful in any Android application interfaces and provides access to {@link android.app.Application} object from a static context. + * NOTE: use this class only if you don't use and dependency injection library (if you use any you can directly set interfaces through it).
+ *

+ * Before first usage this class must be initialized by calling {@link App#init(android.app.Application)} method (for example, from {@link android.app.Application#onCreate()}) + */ +public final class App { + + /* + ********************************************************************** + * + * FIELDS + * + ********************************************************************** + */ + + @Nonnull + private static volatile Application application; + + @Nonnull + private static volatile ServiceLocator locator; + + @Nonnull + private static volatile DelayedExecutor uiThreadExecutor; + + @Nonnull + private static volatile JEventListeners, JEvent> eventBus; + + private static volatile boolean initialized; + + private App() { + throw new AssertionError(); + } + + /* + ********************************************************************** + * + * METHODS + * + ********************************************************************** + */ + + public static void init(@Nonnull A application) { + init(application, new UiThreadExecutor(), Listeners.newEventBus(), application); + } + + public static void init(@Nonnull Application application, @Nullable ServiceLocator serviceLocator) { + init(application, new UiThreadExecutor(), Listeners.newEventBus(), serviceLocator); + } + + public static void init(@Nonnull Application application, + @Nonnull UiThreadExecutor uiThreadExecutor, + @Nonnull JEventListeners, JEvent> eventBus, + @Nullable ServiceLocator serviceLocator) { + if (!initialized) { + App.application = application; + App.uiThreadExecutor = uiThreadExecutor; + App.eventBus = eventBus; + if (serviceLocator != null) { + App.locator = serviceLocator; + } else { + // empty service locator + App.locator = new ServiceLocator() { + }; + } + + App.initialized = true; + } else { + throw new IllegalStateException("Already initialized!"); + } + } + + private static void checkInit() { + if (!initialized) { + throw new IllegalStateException("App should be initialized!"); + } + } + + /** + * @return if App has already been initialized, false otherwise + */ + public static boolean isInitialized() { + return initialized; + } + + /** + * @param real type of application + * @return application instance which was provided in {@link App#init(android.app.Application)} method + */ + @Nonnull + public static A getApplication() { + checkInit(); + return (A) application; + } + + /** + * @param real type of service locator + * @return instance of service locator user in application + */ + @Nonnull + public static L getLocator() { + checkInit(); + return (L) locator; + } + + /** + * Method returns executor which runs on Main Application's thread. It's safe to do all UI work on this executor + * + * @return UI thread executor + */ + @Nonnull + public static DelayedExecutor getUiThreadExecutor() { + checkInit(); + return uiThreadExecutor; + } + + /** + * @return application's event bus + */ + @Nonnull + public static JEventListeners, JEvent> getEventBus() { + checkInit(); + return eventBus; + } +} diff --git a/android-app-core/src/main/java/org/solovyev/android/calculator/ServiceLocator.java b/android-app-core/src/main/java/org/solovyev/android/calculator/ServiceLocator.java new file mode 100644 index 00000000..24a5598d --- /dev/null +++ b/android-app-core/src/main/java/org/solovyev/android/calculator/ServiceLocator.java @@ -0,0 +1,7 @@ +package org.solovyev.android.calculator; + +/** + * Marker interface for service locator + */ +public interface ServiceLocator { +} diff --git a/android-app-core/src/main/java/org/solovyev/android/calculator/model/AndroidMathEntityDao.java b/android-app-core/src/main/java/org/solovyev/android/calculator/model/AndroidMathEntityDao.java index 3cad19e7..a34a72a8 100644 --- a/android-app-core/src/main/java/org/solovyev/android/calculator/model/AndroidMathEntityDao.java +++ b/android-app-core/src/main/java/org/solovyev/android/calculator/model/AndroidMathEntityDao.java @@ -27,17 +27,15 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; import android.preference.PreferenceManager; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - import org.simpleframework.xml.Serializer; import org.simpleframework.xml.core.Persister; -import org.solovyev.android.App; +import org.solovyev.android.calculator.App; import org.solovyev.android.calculator.MathEntityDao; import org.solovyev.android.calculator.MathEntityPersistenceContainer; import org.solovyev.android.calculator.MathPersistenceEntity; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.StringWriter; /** diff --git a/android-app-core/src/main/res/values/admob.xml b/android-app-core/src/main/res/values/admob.xml new file mode 100644 index 00000000..54259e37 --- /dev/null +++ b/android-app-core/src/main/res/values/admob.xml @@ -0,0 +1,4 @@ + + + ca-app-pub-2228934497384784/2916398892 + \ No newline at end of file diff --git a/android-app-onscreen/android-app-onscreen.iml b/android-app-onscreen/android-app-onscreen.iml index 97c0c905..08921145 100644 --- a/android-app-onscreen/android-app-onscreen.iml +++ b/android-app-onscreen/android-app-onscreen.iml @@ -84,10 +84,8 @@ - - @@ -98,8 +96,8 @@ - + diff --git a/android-app-onscreen/build.gradle b/android-app-onscreen/build.gradle index d33bc15a..db911552 100644 --- a/android-app-onscreen/build.gradle +++ b/android-app-onscreen/build.gradle @@ -48,12 +48,10 @@ dependencies { compile 'org.solovyev.android:android-common-menus:1.1.18@aar' compile 'org.solovyev.android:android-common-core:1.1.18@aar' compile 'org.solovyev.android:android-common-preferences:1.1.18@aar' - compile 'org.solovyev.android:android-common-app:1.1.18@aar' compile('org.solovyev:jscl:1.0.8') { exclude(module: 'xercesImpl') } compile 'com.actionbarsherlock:actionbarsherlock:4.4.0@aar' - compile 'com.google.android.admob:admob:6.4.1-r11.0.0' compile 'com.android.support:support-v4:21.0.3' //testCompile group: 'org.robolectric', name: 'robolectric', version: '2.1.1' } diff --git a/android-app-onscreen/src/main/java/org/solovyev/android/calculator/onscreen/CalculatorOnscreenStartActivity.java b/android-app-onscreen/src/main/java/org/solovyev/android/calculator/onscreen/CalculatorOnscreenStartActivity.java index beb3e87a..3b032723 100644 --- a/android-app-onscreen/src/main/java/org/solovyev/android/calculator/onscreen/CalculatorOnscreenStartActivity.java +++ b/android-app-onscreen/src/main/java/org/solovyev/android/calculator/onscreen/CalculatorOnscreenStartActivity.java @@ -23,22 +23,7 @@ package org.solovyev.android.calculator.onscreen; import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; import android.os.Bundle; -import android.preference.PreferenceManager; - -import javax.annotation.Nonnull; - -import org.solovyev.android.Android; -import org.solovyev.android.App; -import org.solovyev.android.calculator.AbstractFixableError; -import org.solovyev.android.calculator.CalculatorPreferences; -import org.solovyev.android.calculator.FixableMessage; -import org.solovyev.android.calculator.FixableMessagesDialog; -import org.solovyev.common.msg.MessageType; - -import java.util.Arrays; public class CalculatorOnscreenStartActivity extends Activity { diff --git a/android-app-tests/android-app-tests.iml b/android-app-tests/android-app-tests.iml index acf62b1f..45a3417a 100644 --- a/android-app-tests/android-app-tests.iml +++ b/android-app-tests/android-app-tests.iml @@ -71,42 +71,40 @@ - - + + + + + + + - - - - - - - + - - - - - + + + + \ No newline at end of file diff --git a/android-app-widget/android-app-widget.iml b/android-app-widget/android-app-widget.iml index a9a4eee6..e5ff8511 100644 --- a/android-app-widget/android-app-widget.iml +++ b/android-app-widget/android-app-widget.iml @@ -84,10 +84,8 @@ - - @@ -98,8 +96,8 @@ - + diff --git a/android-app-widget/build.gradle b/android-app-widget/build.gradle index 93395b30..0700ca52 100644 --- a/android-app-widget/build.gradle +++ b/android-app-widget/build.gradle @@ -48,12 +48,10 @@ dependencies { compile 'org.solovyev.android:android-common-menus:1.1.18@aar' compile 'org.solovyev.android:android-common-core:1.1.18@aar' compile 'org.solovyev.android:android-common-preferences:1.1.18@aar' - compile 'org.solovyev.android:android-common-app:1.1.18@aar' compile('org.solovyev:jscl:1.0.8') { exclude(module: 'xercesImpl') } compile 'com.actionbarsherlock:actionbarsherlock:4.4.0@aar' - compile 'com.google.android.admob:admob:6.4.1-r11.0.0' compile 'com.android.support:support-v4:21.0.3' //testCompile group: 'org.robolectric', name: 'robolectric', version: '2.1.1' } diff --git a/android-app/android-app.iml b/android-app/android-app.iml index 397bc169..b8850e67 100644 --- a/android-app/android-app.iml +++ b/android-app/android-app.iml @@ -86,10 +86,9 @@ - + - @@ -97,7 +96,6 @@ - diff --git a/android-app/build.gradle b/android-app/build.gradle index 3937d838..7225c2a9 100644 --- a/android-app/build.gradle +++ b/android-app/build.gradle @@ -51,8 +51,6 @@ dependencies { compile ('ch.acra:acra:4.5.0') { exclude group: 'org.json' } - compile 'org.solovyev.android:android-common-ads:1.1.18@aar' - compile 'org.solovyev.android:android-common-billing:1.1.18@aar' compile 'org.solovyev.android:android-common-sherlock:1.1.18@aar' compile 'org.solovyev.android:android-common-lists:1.1.18@aar' compile 'org.solovyev.android:android-common-wizard:1.1.18@aar' @@ -60,6 +58,7 @@ dependencies { compile 'org.solovyev.android:android-common-other:1.1.18@aar' compile 'org.solovyev.android:android-common-db:1.1.18@aar' compile 'org.solovyev.android:android-common-security:1.1.18@aar' + compile 'org.solovyev.android:checkout:0.6.0@aar' compile project(':android-app-core') compile project(':android-app-widget') compile project(':android-app-onscreen') diff --git a/android-app/src/main/AndroidManifest.xml b/android-app/src/main/AndroidManifest.xml index d4a3b57b..6935051a 100644 --- a/android-app/src/main/AndroidManifest.xml +++ b/android-app/src/main/AndroidManifest.xml @@ -20,7 +20,11 @@ - + + + @@ -42,7 +46,7 @@ - + @@ -85,7 +89,7 @@ - + @@ -167,18 +171,12 @@ - + - - - - - - - - - - + diff --git a/android-app/src/main/java/org/solovyev/android/calculator/AdView.java b/android-app/src/main/java/org/solovyev/android/calculator/AdView.java new file mode 100644 index 00000000..1cabb3d3 --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/AdView.java @@ -0,0 +1,90 @@ +package org.solovyev.android.calculator; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.FrameLayout; +import com.google.android.gms.ads.AdListener; +import com.google.android.gms.ads.AdRequest; + +import javax.annotation.Nullable; + +public class AdView extends FrameLayout { + + @Nullable + private com.google.android.gms.ads.AdView admobView; + + public AdView(Context context) { + super(context); + } + + public AdView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public AdView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public void destroy() { + if (admobView != null) { + admobView.destroy(); + } + } + + public void pause() { + if (admobView != null) { + admobView.pause(); + } + } + + public void resume() { + if (admobView != null) { + admobView.resume(); + } + } + + public void show() { + if (admobView != null) { + return; + } + + setVisibility(VISIBLE); + + LayoutInflater.from(getContext()).inflate(R.layout.admob, this); + admobView = (com.google.android.gms.ads.AdView) findViewById(R.id.admob); + admobView.setVisibility(View.VISIBLE); + admobView.setAdListener(new AdListener() { + @Override + public void onAdFailedToLoad(int errorCode) { + hide(); + } + + @Override + public void onAdLoaded() { + } + }); + + final AdRequest.Builder b = new AdRequest.Builder(); + b.addTestDevice(AdRequest.DEVICE_ID_EMULATOR); + if (BuildConfig.DEBUG) { + // LG Nexus 5 + b.addTestDevice("B80E676D60CE6FDBE1B84A55464E3FE1"); + } + admobView.loadAd(b.build()); + } + + public void hide() { + if(admobView == null) { + return; + } + + setVisibility(GONE); + + admobView.setVisibility(View.GONE); + admobView.pause(); + admobView.destroy(); + admobView = null; + } +} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java index 3ed7a4ac..475c9aa8 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java @@ -32,13 +32,9 @@ import android.preference.PreferenceManager; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; - import com.actionbarsherlock.app.SherlockFragmentActivity; - import jscl.math.Generic; - import org.solovyev.android.Android; -import org.solovyev.android.App; import org.solovyev.android.calculator.about.CalculatorAboutActivity; import org.solovyev.android.calculator.function.FunctionEditDialogFragment; import org.solovyev.android.calculator.history.CalculatorHistoryActivity; @@ -46,14 +42,13 @@ import org.solovyev.android.calculator.math.edit.*; import org.solovyev.android.calculator.matrix.CalculatorMatrixActivity; import org.solovyev.android.calculator.plot.CalculatorPlotActivity; import org.solovyev.android.calculator.plot.CalculatorPlotter; -import org.solovyev.android.calculator.preferences.CalculatorPreferencesActivity; +import org.solovyev.android.calculator.preferences.PreferencesActivity; import org.solovyev.common.msg.Message; import org.solovyev.common.msg.MessageType; import org.solovyev.common.text.Strings; import javax.annotation.Nonnull; import javax.annotation.Nullable; - import java.util.List; /** @@ -81,7 +76,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener } public static void showSettings(@Nonnull final Context context, boolean detached) { - final Intent intent = new Intent(context, CalculatorPreferencesActivity.class); + final Intent intent = new Intent(context, PreferencesActivity.class); Android.addIntentFlags(intent, detached, context); context.startActivity(intent); } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java index 2147abee..7a9d295c 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java @@ -29,16 +29,10 @@ import android.graphics.Typeface; import android.os.Handler; import android.preference.PreferenceManager; import android.util.Log; -import net.robotmedia.billing.BillingController; -import net.robotmedia.billing.helper.DefaultBillingObserver; -import net.robotmedia.billing.model.BillingDB; import org.acra.ACRA; import org.acra.ReportingInteractionMode; import org.acra.annotation.ReportsCrashes; import org.solovyev.android.Android; -import org.solovyev.android.App; -import org.solovyev.android.ServiceLocator; -import org.solovyev.android.ads.AdsController; import org.solovyev.android.calculator.history.AndroidCalculatorHistory; import org.solovyev.android.calculator.model.AndroidCalculatorEngine; import org.solovyev.android.calculator.onscreen.CalculatorOnscreenStartActivity; @@ -46,12 +40,15 @@ import org.solovyev.android.calculator.plot.AndroidCalculatorPlotter; import org.solovyev.android.calculator.plot.CalculatorPlotterImpl; import org.solovyev.android.calculator.view.EditorTextProcessor; import org.solovyev.android.calculator.wizard.CalculatorWizards; +import org.solovyev.android.checkout.*; import org.solovyev.android.wizard.Wizards; import org.solovyev.common.msg.MessageType; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; /** * User: serso @@ -74,12 +71,14 @@ public class CalculatorApplication extends android.app.Application implements Sh ********************************************************************** */ + @Nonnull + static final String MAIL = "se.solovyev@gmail.com"; + private static final String TAG = "Calculator++ Application"; public static final String AD_FREE_PRODUCT_ID = "ad_free"; public static final String AD_FREE_P_KEY = "org.solovyev.android.calculator_ad_free"; - - public static final String ADMOB_USER_ID = "a14f02cf9c80cbc"; + public static final String ADMOB = "ca-app-pub-2228934497384784/2916398892"; @Nonnull private static CalculatorApplication instance; @@ -109,6 +108,25 @@ public class CalculatorApplication extends android.app.Application implements Sh @Nonnull private Typeface typeFace; + @Nonnull + private final Billing billing = new Billing(this, new Billing.DefaultConfiguration() { + @Nonnull + @Override + public String getPublicKey() { + return CalculatorSecurity.getPK(); + } + + @Nullable + @Override + public Inventory getFallbackInventory(@Nonnull Checkout checkout, @Nonnull Executor onLoadExecutor) { + if (RobotmediaDatabase.exists(billing.getContext())) { + return new RobotmediaInventory(checkout, onLoadExecutor); + } else { + return null; + } + } + }); + /* ********************************************************************** * @@ -137,7 +155,9 @@ public class CalculatorApplication extends android.app.Application implements Sh @Override public void onCreate() { - ACRA.init(this); + if (!BuildConfig.DEBUG) { + ACRA.init(this); + } if (!App.isInitialized()) { App.init(this); @@ -178,32 +198,11 @@ public class CalculatorApplication extends android.app.Application implements Sh Locator.getInstance().getCalculator().init(); - BillingDB.init(CalculatorApplication.this); + billing.connect(); - if (withAds) { - AdsController.getInstance().init(this, ADMOB_USER_ID, AD_FREE_PRODUCT_ID, new BillingController.IConfiguration() { - - @Override - public byte[] getObfuscationSalt() { - return new byte[]{81, -114, 32, -127, -32, -104, -40, -15, -47, 57, -13, -41, -33, 67, -114, 7, -11, 53, 126, 82}; - } - - @Override - public String getPublicKey() { - return CalculatorSecurity.getPK(); - } - }); - } - - BillingController.registerObserver(new DefaultBillingObserver(this, null)); - - // init billing controller new Thread(new Runnable() { @Override public void run() { - BillingController.checkBillingSupported(CalculatorApplication.this); - AdsController.getInstance().isAdFree(CalculatorApplication.this); - try { // prepare engine Locator.getInstance().getEngine().getMathEngine0().evaluate("1+1"); @@ -261,6 +260,11 @@ public class CalculatorApplication extends android.app.Application implements Sh return typeFace; } + @Nonnull + public Billing getBilling() { + return billing; + } + /* ********************************************************************** * diff --git a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorFragmentHelperImpl.java b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorFragmentHelperImpl.java index addf70bd..c80ef466 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorFragmentHelperImpl.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorFragmentHelperImpl.java @@ -23,17 +23,17 @@ package org.solovyev.android.calculator; import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; - -import com.google.ads.AdView; +import org.solovyev.android.checkout.*; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.solovyev.android.ads.AdsController; +import static java.util.Arrays.asList; /** * User: serso @@ -42,6 +42,8 @@ import org.solovyev.android.ads.AdsController; */ public class CalculatorFragmentHelperImpl extends AbstractCalculatorHelper implements CalculatorFragmentHelper { + private ActivityCheckout checkout; + @Nullable private AdView adView; @@ -51,6 +53,9 @@ public class CalculatorFragmentHelperImpl extends AbstractCalculatorHelper imple private boolean listenersOnCreate = true; + @Nullable + private Boolean adFree = null; + public CalculatorFragmentHelperImpl(int layoutId) { this.layoutId = layoutId; } @@ -84,26 +89,57 @@ public class CalculatorFragmentHelperImpl extends AbstractCalculatorHelper imple @Override public void onCreate(@Nonnull Fragment fragment) { - super.onCreate(fragment.getActivity()); + final FragmentActivity activity = fragment.getActivity(); + super.onCreate(activity); + checkout = Checkout.forActivity(activity, CalculatorApplication.getInstance().getBilling(), Products.create().add(ProductTypes.IN_APP, asList("ad_free"))); if (listenersOnCreate) { if (fragment instanceof CalculatorEventListener) { Locator.getInstance().getCalculator().addCalculatorEventListener((CalculatorEventListener) fragment); } } + + checkout.start(); } @Override public void onResume(@Nonnull Fragment fragment) { + if (adView != null) { + adView.resume(); + } if (!listenersOnCreate) { if (fragment instanceof CalculatorEventListener) { Locator.getInstance().getCalculator().addCalculatorEventListener((CalculatorEventListener) fragment); } } + + checkout.loadInventory().whenLoaded(new Inventory.Listener() { + @Override + public void onLoaded(@Nonnull Inventory.Products products) { + adFree = products.get(ProductTypes.IN_APP).isPurchased("ad_free"); + updateAdViewState(); + } + }); + } + + private void updateAdViewState() { + if(adFree == null || adView == null) { + return; + } + + if (adFree) { + adView.hide(); + } else { + adView.show(); + } } @Override public void onPause(@Nonnull Fragment fragment) { + adFree = null; + if (adView != null) { + adView.pause(); + } if (!listenersOnCreate) { if (fragment instanceof CalculatorEventListener) { Locator.getInstance().getCalculator().removeCalculatorEventListener((CalculatorEventListener) fragment); @@ -113,16 +149,15 @@ public class CalculatorFragmentHelperImpl extends AbstractCalculatorHelper imple @Override public void onViewCreated(@Nonnull Fragment fragment, @Nonnull View root) { - final ViewGroup adParentView = (ViewGroup) root.findViewById(R.id.ad_parent_view); + adView = (AdView) root.findViewById(R.id.ad); final ViewGroup mainFragmentLayout = (ViewGroup) root.findViewById(R.id.main_fragment_layout); if (fragment instanceof CalculatorDisplayFragment || fragment instanceof CalculatorEditorFragment || fragment instanceof CalculatorKeyboardFragment) { // no ads in those fragments } else { - if (adParentView != null) { - adView = AdsController.getInstance().inflateAd(fragment.getActivity(), adParentView, R.id.ad_parent_view); + if (adView != null) { + updateAdViewState(); } else if (mainFragmentLayout != null) { - adView = AdsController.getInstance().inflateAd(fragment.getActivity(), mainFragmentLayout, R.id.main_fragment_layout); } } @@ -135,7 +170,10 @@ public class CalculatorFragmentHelperImpl extends AbstractCalculatorHelper imple @Override public void onDestroy(@Nonnull Fragment fragment) { - super.onDestroy(fragment.getActivity()); + if (adView != null) { + adView.destroy(); + adView = null; + } if (listenersOnCreate) { if (fragment instanceof CalculatorEventListener) { @@ -143,9 +181,9 @@ public class CalculatorFragmentHelperImpl extends AbstractCalculatorHelper imple } } - if (this.adView != null) { - this.adView.destroy(); - } + checkout.stop(); + + super.onDestroy(fragment.getActivity()); } @Nonnull diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/AbstractCalculatorPlotFragment.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/AbstractCalculatorPlotFragment.java index b0a8a5bb..344e8d2c 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/AbstractCalculatorPlotFragment.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/AbstractCalculatorPlotFragment.java @@ -417,7 +417,7 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment preferences(R.id.menu_plot_settings) { @Override public void onClick(@Nonnull MenuItem data, @Nonnull Context context) { - context.startActivity(new Intent(context, CalculatorPlotPreferenceActivity.class)); + context.startActivity(new Intent(context, PlotPreferenceActivity.class)); } }; diff --git a/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotPreferenceActivity.java b/android-app/src/main/java/org/solovyev/android/calculator/plot/PlotPreferenceActivity.java similarity index 84% rename from android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotPreferenceActivity.java rename to android-app/src/main/java/org/solovyev/android/calculator/plot/PlotPreferenceActivity.java index ced327d3..f72b94fb 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotPreferenceActivity.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/plot/PlotPreferenceActivity.java @@ -23,17 +23,10 @@ package org.solovyev.android.calculator.plot; import android.os.Bundle; - -import com.actionbarsherlock.app.SherlockPreferenceActivity; - import org.solovyev.android.calculator.R; +import org.solovyev.android.calculator.preferences.BasePreferencesActivity; -/** - * User: serso - * Date: 10/4/12 - * Time: 9:01 PM - */ -public class CalculatorPlotPreferenceActivity extends SherlockPreferenceActivity { +public class PlotPreferenceActivity extends BasePreferencesActivity { @Override protected void onCreate(Bundle savedInstanceState) { diff --git a/android-app/src/main/java/org/solovyev/android/calculator/preferences/BasePreferencesActivity.java b/android-app/src/main/java/org/solovyev/android/calculator/preferences/BasePreferencesActivity.java new file mode 100644 index 00000000..c1fafefa --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/preferences/BasePreferencesActivity.java @@ -0,0 +1,92 @@ +package org.solovyev.android.calculator.preferences; + +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import com.actionbarsherlock.app.SherlockPreferenceActivity; +import org.solovyev.android.calculator.AdView; +import org.solovyev.android.calculator.CalculatorApplication; +import org.solovyev.android.calculator.R; +import org.solovyev.android.checkout.*; + +import javax.annotation.Nonnull; + +import static java.util.Arrays.asList; + +public abstract class BasePreferencesActivity extends SherlockPreferenceActivity { + + private final ActivityCheckout checkout = Checkout.forActivity(this, CalculatorApplication.getInstance().getBilling(), Products.create().add(ProductTypes.IN_APP, asList("ad_free"))); + private Inventory inventory; + private AdView adView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + checkout.start(); + inventory = checkout.loadInventory(); + } + + + private class InventoryListener implements Inventory.Listener { + @Override + public void onLoaded(@Nonnull Inventory.Products products) { + final Inventory.Product product = products.get(ProductTypes.IN_APP); + final boolean adFree = product.isPurchased("ad_free"); + onShowAd(!adFree); + } + } + + protected void onShowAd(boolean show) { + if (show) { + if (adView != null) { + return; + } + adView = (AdView) LayoutInflater.from(this).inflate(R.layout.ad, null); + adView.show(); + getListView().addHeaderView(adView); + } else { + if (adView == null) { + return; + } + getListView().removeHeaderView(adView); + adView.hide(); + adView = null; + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (checkout.onActivityResult(requestCode, resultCode, data)) { + return; + } + + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + protected void onResume() { + super.onResume(); + if (adView != null) { + adView.resume(); + } + inventory.whenLoaded(new InventoryListener()); + } + + @Override + protected void onPause() { + if (adView != null) { + adView.pause(); + } + super.onPause(); + } + + @Override + protected void onDestroy() { + if (adView != null) { + adView.destroy(); + } + checkout.stop(); + super.onDestroy(); + } +} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/preferences/CalculatorPreferencesActivity.java b/android-app/src/main/java/org/solovyev/android/calculator/preferences/CalculatorPreferencesActivity.java deleted file mode 100644 index d206f8ec..00000000 --- a/android-app/src/main/java/org/solovyev/android/calculator/preferences/CalculatorPreferencesActivity.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright 2013 serso aka se.solovyev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Contact details - * - * Email: se.solovyev@gmail.com - * Site: http://se.solovyev.org - */ - -package org.solovyev.android.calculator.preferences; - -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.preference.Preference; -import android.preference.PreferenceManager; -import android.util.Log; -import android.widget.Toast; -import com.actionbarsherlock.app.SherlockPreferenceActivity; -import net.robotmedia.billing.BillingController; -import net.robotmedia.billing.IBillingObserver; -import net.robotmedia.billing.ResponseCode; -import net.robotmedia.billing.helper.AbstractBillingObserver; -import net.robotmedia.billing.model.Transaction; -import org.solovyev.android.Activities; -import org.solovyev.android.App; -import org.solovyev.android.ads.AdsController; -import org.solovyev.android.calculator.*; -import org.solovyev.android.calculator.model.AndroidCalculatorEngine; -import org.solovyev.android.calculator.wizard.CalculatorWizards; -import org.solovyev.android.msg.AndroidMessage; -import org.solovyev.android.view.VibratorContainer; -import org.solovyev.android.wizard.WizardUi; -import org.solovyev.common.msg.Message; -import org.solovyev.common.msg.MessageType; - -import javax.annotation.Nonnull; - -import static org.solovyev.android.calculator.wizard.CalculatorWizards.DEFAULT_WIZARD_FLOW; -import static org.solovyev.android.wizard.WizardUi.startWizard; - -/** - * User: serso - * Date: 7/16/11 - * Time: 6:37 PM - */ -public class CalculatorPreferencesActivity extends SherlockPreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener, IBillingObserver { - - public static final String PREFERENCE_CLEAR_BILLING_INFO = "clear_billing_info"; - public static final String PREFERENCE_RESTART_WIZARD = "restart_wizard"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - //noinspection deprecation - addPreferencesFromResource(R.xml.preferences); - //noinspection deprecation - addPreferencesFromResource(R.xml.preferences_calculations); - addPreferencesFromResource(R.xml.preferences_appearance); - addPreferencesFromResource(R.xml.preferences_plot); - addPreferencesFromResource(R.xml.preferences_other); - addPreferencesFromResource(R.xml.preferences_onscreen); - - final Preference restartWizardPreference = findPreference(PREFERENCE_RESTART_WIZARD); - restartWizardPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - startWizard(CalculatorApplication.getInstance().getWizards(), DEFAULT_WIZARD_FLOW, CalculatorPreferencesActivity.this); - return true; - } - }); - - final Preference adFreePreference = findPreference(CalculatorApplication.AD_FREE_P_KEY); - adFreePreference.setEnabled(false); - - // observer must be set before net.robotmedia.billing.BillingController.checkBillingSupported() - BillingController.registerObserver(this); - - BillingController.checkBillingSupported(CalculatorPreferencesActivity.this); - - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - preferences.registerOnSharedPreferenceChangeListener(this); - onSharedPreferenceChanged(preferences, AndroidCalculatorEngine.Preferences.roundResult.getKey()); - onSharedPreferenceChanged(preferences, VibratorContainer.Preferences.hapticFeedbackEnabled.getKey()); - - final Preference clearBillingInfoPreference = findPreference(PREFERENCE_CLEAR_BILLING_INFO); - if (clearBillingInfoPreference != null) { - clearBillingInfoPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - - Toast.makeText(CalculatorPreferencesActivity.this, R.string.c_calc_clearing, Toast.LENGTH_SHORT).show(); - - removeBillingInformation(CalculatorPreferencesActivity.this, PreferenceManager.getDefaultSharedPreferences(CalculatorPreferencesActivity.this)); - - return true; - } - }); - } - } - - public static void removeBillingInformation(@Nonnull Context context, @Nonnull SharedPreferences preferences) { - final SharedPreferences.Editor editor = preferences.edit(); - editor.putBoolean(AbstractBillingObserver.KEY_TRANSACTIONS_RESTORED, false); - editor.commit(); - - BillingController.dropBillingData(context); - } - - private void setAdFreeAction() { - final Preference adFreePreference = findPreference(CalculatorApplication.AD_FREE_P_KEY); - - if (!AdsController.getInstance().isAdFree(this)) { - Log.d(CalculatorPreferencesActivity.class.getName(), "Ad free is not purchased - enable preference!"); - - adFreePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - public boolean onPreferenceClick(Preference preference) { - final Context context = CalculatorPreferencesActivity.this; - context.startActivity(new Intent(context, CalculatorPurchaseDialogActivity.class)); - return true; - } - }); - adFreePreference.setEnabled(true); - } else { - Log.d(CalculatorPreferencesActivity.class.getName(), "Ad free is not purchased - disable preference!"); - adFreePreference.setEnabled(false); - } - } - - @Override - protected void onDestroy() { - BillingController.unregisterObserver(this); - PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this); - super.onDestroy(); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { - if (AndroidCalculatorEngine.Preferences.roundResult.getKey().equals(key)) { - findPreference(AndroidCalculatorEngine.Preferences.precision.getKey()).setEnabled(preferences.getBoolean(key, AndroidCalculatorEngine.Preferences.roundResult.getDefaultValue())); - } else if (VibratorContainer.Preferences.hapticFeedbackEnabled.getKey().equals(key)) { - findPreference(VibratorContainer.Preferences.hapticFeedbackDuration.getKey()).setEnabled(VibratorContainer.Preferences.hapticFeedbackEnabled.getPreference(preferences)); - } - } - - @Override - public void onCheckBillingSupportedResponse(boolean supported) { - if (supported) { - setAdFreeAction(); - } else { - final Preference adFreePreference = findPreference(CalculatorApplication.AD_FREE_P_KEY); - adFreePreference.setEnabled(false); - Log.d(CalculatorPreferencesActivity.class.getName(), "Billing is not supported!"); - } - } - - @Override - public void onPurchaseIntentOK(@Nonnull String productId, @Nonnull PendingIntent purchaseIntent) { - // do nothing - } - - @Override - public void onPurchaseIntentFailure(@Nonnull String productId, @Nonnull ResponseCode responseCode) { - // do nothing - } - - @Override - public void onPurchaseStateChanged(@Nonnull String itemId, @Nonnull Transaction.PurchaseState state) { - if (CalculatorApplication.AD_FREE_PRODUCT_ID.equals(itemId)) { - final Preference adFreePreference = findPreference(CalculatorApplication.AD_FREE_P_KEY); - if (adFreePreference != null) { - switch (state) { - case PURCHASED: - adFreePreference.setEnabled(false); - // restart activity to disable ads - Activities.restartActivity(this); - break; - case CANCELLED: - adFreePreference.setEnabled(true); - break; - case REFUNDED: - adFreePreference.setEnabled(true); - break; - } - } else { - } - } - } - - @Override - public void onRequestPurchaseResponse(@Nonnull String itemId, @Nonnull ResponseCode response) { - final Preference adFreePreference = findPreference(CalculatorApplication.AD_FREE_P_KEY); - if (adFreePreference != null) { - if (response == ResponseCode.RESULT_OK) { - adFreePreference.setEnabled(false); - - final Message message = new AndroidMessage(R.string.cpp_purchase_thank_you_text, MessageType.info, App.getApplication()); - Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_message_dialog, MessageDialogData.newInstance(message, null)); - } - } - } - - @Override - public void onTransactionsRestored() { - // do nothing - } - - @Override - public void onErrorRestoreTransactions(@Nonnull ResponseCode responseCode) { - // do nothing - } -} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/preferences/CalculatorPurchaseDialogActivity.java b/android-app/src/main/java/org/solovyev/android/calculator/preferences/CalculatorPurchaseDialogActivity.java index 60ffdbde..5a9b204f 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/preferences/CalculatorPurchaseDialogActivity.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/preferences/CalculatorPurchaseDialogActivity.java @@ -23,28 +23,22 @@ package org.solovyev.android.calculator.preferences; import android.app.Activity; -import android.app.AlertDialog; +import android.content.Intent; import android.os.Bundle; import android.text.method.ScrollingMovementMethod; -import android.util.Log; import android.view.View; import android.widget.TextView; -import android.widget.Toast; - import com.actionbarsherlock.app.SherlockFragmentActivity; - -import net.robotmedia.billing.BillingController; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import org.solovyev.android.ads.AdsController; import org.solovyev.android.calculator.CalculatorApplication; import org.solovyev.android.calculator.CalculatorFragment; import org.solovyev.android.calculator.CalculatorFragmentType; import org.solovyev.android.calculator.R; +import org.solovyev.android.checkout.*; import org.solovyev.android.fragments.FragmentUtils; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * User: serso * Date: 1/20/13 @@ -52,6 +46,22 @@ import org.solovyev.android.fragments.FragmentUtils; */ public class CalculatorPurchaseDialogActivity extends SherlockFragmentActivity { + @Nonnull + private final ActivityCheckout checkout = Checkout.forActivity(this, CalculatorApplication.getInstance().getBilling(), Products.create().add("ad_free")); + + @Nonnull + private final RequestListener purchaseListener = new RequestListener() { + @Override + public void onSuccess(@Nonnull Purchase purchase) { + finish(); + } + + @Override + public void onError(int i, @Nonnull Exception e) { + finish(); + } + }; + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -59,6 +69,9 @@ public class CalculatorPurchaseDialogActivity extends SherlockFragmentActivity { setContentView(R.layout.cpp_dialog); FragmentUtils.createFragment(this, PurchaseDialogFragment.class, R.id.dialog_layout, "purchase-dialog"); + + checkout.start(); + checkout.createPurchaseFlow(purchaseListener); } public static class PurchaseDialogFragment extends CalculatorFragment { @@ -75,36 +88,35 @@ public class CalculatorPurchaseDialogActivity extends SherlockFragmentActivity { root.findViewById(R.id.cpp_continue_button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - final Activity activity = getActivity(); - if (activity != null) { - // check billing availability - if (BillingController.checkBillingSupported(activity) != BillingController.BillingStatus.SUPPORTED) { - Log.d(CalculatorPreferencesActivity.class.getName(), "Billing is not supported - warn user!"); - // warn about not supported billing - new AlertDialog.Builder(activity).setTitle(R.string.c_error).setMessage(R.string.c_billing_error).create().show(); - } else { - Log.d(CalculatorPreferencesActivity.class.getName(), "Billing is supported - continue!"); - if (!AdsController.getInstance().isAdFree(activity)) { - Log.d(CalculatorPreferencesActivity.class.getName(), "Item not purchased - try to purchase!"); - - // not purchased => purchasing - Toast.makeText(activity, R.string.c_calc_purchasing, Toast.LENGTH_SHORT).show(); - - // show purchase window for user - BillingController.requestPurchase(activity, CalculatorApplication.AD_FREE_PRODUCT_ID, true); - } else { - // and show message to user - Toast.makeText(activity, R.string.c_calc_already_purchased, Toast.LENGTH_SHORT).show(); - } - } - - activity.finish(); + ((CalculatorPurchaseDialogActivity) activity).purchase(); } } }); } } + + private void purchase() { + checkout.whenReady(new Checkout.ListenerAdapter() { + @Override + public void onReady(@Nonnull BillingRequests requests) { + requests.purchase(ProductTypes.IN_APP, "ad_free", null, checkout.getPurchaseFlow()); + } + }); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + checkout.onActivityResult(requestCode, resultCode, data); + } + + @Override + protected void onDestroy() { + checkout.destroyPurchaseFlow(); + checkout.stop(); + super.onDestroy(); + } } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesActivity.java b/android-app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesActivity.java new file mode 100644 index 00000000..6e52e7c2 --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesActivity.java @@ -0,0 +1,151 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.android.calculator.preferences; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.PreferenceManager; +import android.util.SparseArray; +import org.solovyev.android.calculator.CalculatorApplication; +import org.solovyev.android.calculator.R; + +import javax.annotation.Nonnull; + +import static org.solovyev.android.calculator.CalculatorApplication.AD_FREE_P_KEY; +import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Preferences.precision; +import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Preferences.roundResult; +import static org.solovyev.android.calculator.wizard.CalculatorWizards.DEFAULT_WIZARD_FLOW; +import static org.solovyev.android.view.VibratorContainer.Preferences.hapticFeedbackDuration; +import static org.solovyev.android.view.VibratorContainer.Preferences.hapticFeedbackEnabled; +import static org.solovyev.android.wizard.WizardUi.startWizard; + +@SuppressWarnings("deprecation") +public class PreferencesActivity extends BasePreferencesActivity implements SharedPreferences.OnSharedPreferenceChangeListener { + + @Nonnull + private static final SparseArray preferences = new SparseArray(); + + static { + preferences.append(R.xml.preferences, "screen-main"); + preferences.append(R.xml.preferences_calculations, "screen-calculations"); + preferences.append(R.xml.preferences_appearance, "screen-appearance"); + preferences.append(R.xml.preferences_plot, "screen-plot"); + preferences.append(R.xml.preferences_other, "screen-other"); + preferences.append(R.xml.preferences_onscreen, "screen-onscreen"); + } + + private Preference adFreePreference; + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final Intent intent = getIntent(); + final int preference = intent.getIntExtra("preference", R.xml.preferences); + final String title = intent.getStringExtra("preference-title"); + setPreference(preference, preferences.get(preference)); + if (preference == R.xml.preferences) { + for (int i = 0; i < preferences.size(); i++) { + final int xml = preferences.keyAt(i); + final String name = preferences.valueAt(i); + setPreferenceIntent(xml, name); + } + final Preference restartWizardPreference = findPreference("restart_wizard"); + restartWizardPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + startWizard(CalculatorApplication.getInstance().getWizards(), DEFAULT_WIZARD_FLOW, PreferencesActivity.this); + return true; + } + }); + + adFreePreference = findPreference(AD_FREE_P_KEY); + adFreePreference.setEnabled(false); + adFreePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + startActivity(new Intent(getApplicationContext(), CalculatorPurchaseDialogActivity.class)); + return true; + } + }); + } + if (title != null) { + setTitle(title); + } + + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + preferences.registerOnSharedPreferenceChangeListener(this); + onSharedPreferenceChanged(preferences, roundResult.getKey()); + onSharedPreferenceChanged(preferences, hapticFeedbackEnabled.getKey()); + } + + private void setPreference(int xml, @Nonnull String name) { + addPreferencesFromResource(xml); + } + + private void setPreferenceIntent(int xml, @Nonnull String name) { + final Preference preference = findPreference(name); + if (preference != null) { + final Intent intent = new Intent(getApplicationContext(), PreferencesActivity.class); + intent.putExtra("preference", xml); + intent.putExtra("preference-title", preference.getTitle()); + preference.setIntent(intent); + } + } + + @Override + protected void onDestroy() { + PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this); + super.onDestroy(); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { + if (roundResult.getKey().equals(key)) { + final Preference preference = findPreference(precision.getKey()); + if (preference != null) { + preference.setEnabled(preferences.getBoolean(key, roundResult.getDefaultValue())); + } + } else if (hapticFeedbackEnabled.getKey().equals(key)) { + final Preference preference = findPreference(hapticFeedbackDuration.getKey()); + if (preference != null) { + preference.setEnabled(hapticFeedbackEnabled.getPreference(preferences)); + } + } + } + + @Override + protected void onShowAd(boolean show) { + super.onShowAd(show); + if (adFreePreference != null) { + adFreePreference.setEnabled(show); + } + } +} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorWizardStep.java b/android-app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorWizardStep.java index dfb89e3d..955468b0 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorWizardStep.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorWizardStep.java @@ -25,7 +25,7 @@ package org.solovyev.android.calculator.wizard; import android.content.res.Configuration; import android.os.Bundle; import android.support.v4.app.Fragment; -import org.solovyev.android.App; +import org.solovyev.android.calculator.App; import org.solovyev.android.Views; import org.solovyev.android.calculator.CalculatorPreferences; import org.solovyev.android.calculator.R; diff --git a/android-app/src/main/res/layout/ad.xml b/android-app/src/main/res/layout/ad.xml index 8c38f244..f59ae650 100644 --- a/android-app/src/main/res/layout/ad.xml +++ b/android-app/src/main/res/layout/ad.xml @@ -22,7 +22,9 @@ ~ Site: http://se.solovyev.org --> - + diff --git a/android-app/src/main/res/layout/admob.xml b/android-app/src/main/res/layout/admob.xml new file mode 100644 index 00000000..bf8c0a09 --- /dev/null +++ b/android-app/src/main/res/layout/admob.xml @@ -0,0 +1,33 @@ + + + + + diff --git a/android-app/src/main/res/xml/preferences.xml b/android-app/src/main/res/xml/preferences.xml index 34d216d6..8cdb40f8 100644 --- a/android-app/src/main/res/xml/preferences.xml +++ b/android-app/src/main/res/xml/preferences.xml @@ -22,18 +22,33 @@ ~ Site: http://se.solovyev.org --> - + - - + a:key="@string/p_calc_ad_free_key" + a:title="@string/c_calc_ad_free_title" + a:summary="@string/c_calc_ad_free_summary" + a:defaultValue="false" /> + a:title="@string/cpp_restart_wizard" /> + + + + + + \ No newline at end of file diff --git a/android-app/src/main/res/xml/preferences_appearance.xml b/android-app/src/main/res/xml/preferences_appearance.xml index 2d9b82ad..e4cb95b0 100644 --- a/android-app/src/main/res/xml/preferences_appearance.xml +++ b/android-app/src/main/res/xml/preferences_appearance.xml @@ -25,10 +25,6 @@ - - - - - - \ No newline at end of file diff --git a/android-app/src/main/res/xml/preferences_calculations.xml b/android-app/src/main/res/xml/preferences_calculations.xml index 02e4bdc3..5fb819e6 100644 --- a/android-app/src/main/res/xml/preferences_calculations.xml +++ b/android-app/src/main/res/xml/preferences_calculations.xml @@ -25,10 +25,6 @@ - - - - - - \ No newline at end of file diff --git a/android-app/src/main/res/xml/preferences_onscreen.xml b/android-app/src/main/res/xml/preferences_onscreen.xml index 25b362ca..c7aeeee0 100644 --- a/android-app/src/main/res/xml/preferences_onscreen.xml +++ b/android-app/src/main/res/xml/preferences_onscreen.xml @@ -24,11 +24,7 @@ - - - - - @@ -38,6 +34,4 @@ a:title="@string/prefs_onscreen_show_app_icon_title" a:summary="@string/prefs_onscreen_show_app_icon_summary"/> - - \ No newline at end of file diff --git a/android-app/src/main/res/xml/preferences_other.xml b/android-app/src/main/res/xml/preferences_other.xml index c7fd99b8..9fb1699e 100644 --- a/android-app/src/main/res/xml/preferences_other.xml +++ b/android-app/src/main/res/xml/preferences_other.xml @@ -24,10 +24,6 @@ - - - - - - \ No newline at end of file diff --git a/android-app/src/main/res/xml/preferences_plot.xml b/android-app/src/main/res/xml/preferences_plot.xml index 9166bf4c..199e0f5d 100644 --- a/android-app/src/main/res/xml/preferences_plot.xml +++ b/android-app/src/main/res/xml/preferences_plot.xml @@ -24,15 +24,9 @@ - - - - - - \ No newline at end of file diff --git a/build.gradle b/build.gradle index e5f910cd..878e67ea 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ public String android_build_tools_version() { } public String android_min_sdk_version() { - return 7 + return 9 } buildscript { @@ -35,6 +35,9 @@ allprojects { maven { url "$androidHome/extras/android/m2repository/" } + maven { + url "$androidHome/extras/google/m2repository/" + } def userHome = System.getenv("HOME") maven {