From 7bda4ab3f855f8523f8cd1ea747674f7dd2c920a Mon Sep 17 00:00:00 2001 From: Mykola Dzyuba Date: Sat, 3 Jan 2015 00:36:47 -0800 Subject: [PATCH 1/5] Added a test example for Android Studio. --- .../android-studio/Cukeulator/.gitignore | 6 + .../android-studio/Cukeulator/README.md | 60 ++++++ .../android-studio/Cukeulator/app/.gitignore | 1 + .../Cukeulator/app/build.gradle | 40 ++++ .../Cukeulator/app/libs/.gitignore | 1 + .../Cukeulator/app/proguard-rules.pro | 17 ++ .../assets/features/extra/calculate.feature | 20 ++ .../features/operations/addition.feature | 31 +++ .../features/operations/division.feature | 31 +++ .../operations/multiplication.feature | 31 +++ .../features/operations/subtraction.feature | 31 +++ .../test/CalculatorActivitySteps.java | 110 +++++++++++ .../cukeulator/test/SomeDependency.java | 5 + .../cucumber/cukeulator/test/Utils.java | 49 +++++ .../app/src/main/AndroidManifest.xml | 26 +++ .../cukeulator/CalculatorActivity.java | 152 ++++++++++++++ .../main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 6468 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 3664 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 9291 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 16093 bytes .../main/res/layout/activity_calculator.xml | 187 ++++++++++++++++++ .../app/src/main/res/menu/menu_main.xml | 5 + .../app/src/main/res/values-v21/styles.xml | 5 + .../app/src/main/res/values-w820dp/dimens.xml | 6 + .../app/src/main/res/values/dimens.xml | 5 + .../app/src/main/res/values/strings.xml | 9 + .../app/src/main/res/values/styles.xml | 8 + .../android-studio/Cukeulator/build.gradle | 19 ++ .../Cukeulator/gradle.properties | 18 ++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + .../android/android-studio/Cukeulator/gradlew | 164 +++++++++++++++ .../android-studio/Cukeulator/gradlew.bat | 90 +++++++++ .../android-studio/Cukeulator/settings.gradle | 1 + 34 files changed, 1134 insertions(+) create mode 100644 examples/android/android-studio/Cukeulator/.gitignore create mode 100644 examples/android/android-studio/Cukeulator/README.md create mode 100644 examples/android/android-studio/Cukeulator/app/.gitignore create mode 100644 examples/android/android-studio/Cukeulator/app/build.gradle create mode 100644 examples/android/android-studio/Cukeulator/app/libs/.gitignore create mode 100644 examples/android/android-studio/Cukeulator/app/proguard-rules.pro create mode 100644 examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/extra/calculate.feature create mode 100644 examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/addition.feature create mode 100644 examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/division.feature create mode 100644 examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/multiplication.feature create mode 100644 examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/subtraction.feature create mode 100644 examples/android/android-studio/Cukeulator/app/src/androidTest/java/cukeulator/android/example/cucumber/cukeulator/test/CalculatorActivitySteps.java create mode 100644 examples/android/android-studio/Cukeulator/app/src/androidTest/java/cukeulator/android/example/cucumber/cukeulator/test/SomeDependency.java create mode 100644 examples/android/android-studio/Cukeulator/app/src/androidTest/java/cukeulator/android/example/cucumber/cukeulator/test/Utils.java create mode 100644 examples/android/android-studio/Cukeulator/app/src/main/AndroidManifest.xml create mode 100644 examples/android/android-studio/Cukeulator/app/src/main/java/cukeulator/android/example/cucumber/cukeulator/CalculatorActivity.java create mode 100755 examples/android/android-studio/Cukeulator/app/src/main/res/drawable-hdpi/ic_launcher.png create mode 100755 examples/android/android-studio/Cukeulator/app/src/main/res/drawable-mdpi/ic_launcher.png create mode 100755 examples/android/android-studio/Cukeulator/app/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100755 examples/android/android-studio/Cukeulator/app/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 examples/android/android-studio/Cukeulator/app/src/main/res/layout/activity_calculator.xml create mode 100644 examples/android/android-studio/Cukeulator/app/src/main/res/menu/menu_main.xml create mode 100644 examples/android/android-studio/Cukeulator/app/src/main/res/values-v21/styles.xml create mode 100644 examples/android/android-studio/Cukeulator/app/src/main/res/values-w820dp/dimens.xml create mode 100644 examples/android/android-studio/Cukeulator/app/src/main/res/values/dimens.xml create mode 100644 examples/android/android-studio/Cukeulator/app/src/main/res/values/strings.xml create mode 100644 examples/android/android-studio/Cukeulator/app/src/main/res/values/styles.xml create mode 100644 examples/android/android-studio/Cukeulator/build.gradle create mode 100644 examples/android/android-studio/Cukeulator/gradle.properties create mode 100644 examples/android/android-studio/Cukeulator/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/android/android-studio/Cukeulator/gradle/wrapper/gradle-wrapper.properties create mode 100755 examples/android/android-studio/Cukeulator/gradlew create mode 100644 examples/android/android-studio/Cukeulator/gradlew.bat create mode 100644 examples/android/android-studio/Cukeulator/settings.gradle diff --git a/examples/android/android-studio/Cukeulator/.gitignore b/examples/android/android-studio/Cukeulator/.gitignore new file mode 100644 index 0000000000..afbdab33e9 --- /dev/null +++ b/examples/android/android-studio/Cukeulator/.gitignore @@ -0,0 +1,6 @@ +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build diff --git a/examples/android/android-studio/Cukeulator/README.md b/examples/android/android-studio/Cukeulator/README.md new file mode 100644 index 0000000000..1b06022795 --- /dev/null +++ b/examples/android/android-studio/Cukeulator/README.md @@ -0,0 +1,60 @@ +## Cukeulator Example Test +This is the example test-project for the Cukeulator app for Android Studio (Beta) 0.8.14. + +### Setup +Features must be placed in `assets/features/`. Subdirectories are allowed. + +The `app/libs` should contain `cucumber-android-*.jar`. Please build it following [cucumber-jvm/android] +(https://github.com/cucumber/cucumber-jvm/tree/master/android) instructions and copy to `app/libs` folder. + +The rest of the dependencies are added automatically in `app/build.gradle`. + + +### Using gradle + +To build the test apk: + +``` +cd cucumber-jvm/examples/android/android-studio/Cukeulator +./gradlew --parallel :app:assembleDebugTest +``` + +The build generates an apk in app/build/outputs/apk/app-debug.apk. + +To install the apk on a device: + +``` +adb install -r app/build/outputs/apk/app-debug.apk +``` + +To verify that the test is installed, run: + +``` +adb shell pm list instrumentation +``` + +The command output should display; + +``` +instrumentation:cukeulator.android.example.cucumber.cukeulator.test/cucumber.api.android.CucumberInstrumentation (target=cukeulator.android.example.cucumber.cukeulator) +``` + +To run the test: + +``` +adb shell am instrument -w cukeulator.android.example.cucumber.cukeulator.test/cucumber.api.android.CucumberInstrumentation +``` + +### Using an Android Studio IDE +1. Import the example to Android Studio: `File > Import Project`. +2. Make sure you have the cucumber-android jar dependencies in `app/libs/`. +3. Create a test run confiruation: + 1. Run > Edit Configurations + 2. Click `+` button and select Android Tests + 3. Specify test name: `CalculatorTest` + 4. Select module: `app` + 5. Enter a Specific instrumentation runner: `cucumber.api.android.CucumberInstrumentation` + 6. Click Ok + +### Output +Filter for the logcat tag `cucumber-android` in [DDMS](https://developer.android.com/tools/debugging/ddms.html). diff --git a/examples/android/android-studio/Cukeulator/app/.gitignore b/examples/android/android-studio/Cukeulator/app/.gitignore new file mode 100644 index 0000000000..796b96d1c4 --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/examples/android/android-studio/Cukeulator/app/build.gradle b/examples/android/android-studio/Cukeulator/app/build.gradle new file mode 100644 index 0000000000..88e0488d7c --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/build.gradle @@ -0,0 +1,40 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.1" + + defaultConfig { + applicationId "cukeulator.android.example.cucumber.cukeulator" + minSdkVersion 19 + targetSdkVersion 21 + versionCode 1 + versionName "1.0" + + testApplicationId "cukeulator.android.example.cucumber.cukeulator.test" + testInstrumentationRunner "cucumber.api.android.CucumberInstrumentation" + } + sourceSets { + androidTest { + assets.srcDirs = ['src/androidTest/assets'] + } + } + buildTypes { + release { + runProguard false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + androidTestCompile fileTree(dir: 'libs', include: ['*.jar']) + androidTestCompile 'info.cukes:cucumber-core:1.2.0' + androidTestCompile 'info.cukes:cucumber-html:0.2.3' + androidTestCompile 'info.cukes:cucumber-java:1.2.0' + androidTestCompile 'info.cukes:cucumber-junit:1.2.0' + androidTestCompile 'info.cukes:cucumber-jvm-deps:1.0.3' + androidTestCompile 'info.cukes:cucumber-picocontainer:1.2.0' + androidTestCompile 'info.cukes:gherkin:2.12.2' + androidTestCompile 'junit:junit:4.12' +} diff --git a/examples/android/android-studio/Cukeulator/app/libs/.gitignore b/examples/android/android-studio/Cukeulator/app/libs/.gitignore new file mode 100644 index 0000000000..d392f0e82c --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/libs/.gitignore @@ -0,0 +1 @@ +*.jar diff --git a/examples/android/android-studio/Cukeulator/app/proguard-rules.pro b/examples/android/android-studio/Cukeulator/app/proguard-rules.pro new file mode 100644 index 0000000000..178b5337c7 --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/mdzyuba/Code/android/adt-bundle-mac-x86_64-20140702/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/extra/calculate.feature b/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/extra/calculate.feature new file mode 100644 index 0000000000..d60de48387 --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/extra/calculate.feature @@ -0,0 +1,20 @@ +Feature: Calculate a result + Perform an arithmetic operation on two numbers using a mathematical operator + """The purpose of this feature is to illustrate how existing step-definitions + can be efficiently reused.""" + + Scenario Outline: Enter a digit, an operator and another digit + Given I have a CalculatorActivity + When I press + And I press + And I press + And I press = + Then I should see on the display + + Examples: + | num1 | num2 | op | result | + | 9 | 8 | + | 17.0 | + | 7 | 6 | – | 1.0 | + | 5 | 4 | x | 20.0 | + | 3 | 2 | / | 1.5 | + | 1 | 0 | / | Infinity | diff --git a/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/addition.feature b/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/addition.feature new file mode 100644 index 0000000000..13d5fb52c1 --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/addition.feature @@ -0,0 +1,31 @@ +Feature: Add two numbers + Calculate the sum of two numbers which consist of one or more digits + + Scenario Outline: Enter one digit per number and press = + Given I have a CalculatorActivity + When I press + And I press + + And I press + And I press = + Then I should see on the display + + Examples: + | num1 | num2 | sum | + | 0 | 0 | 0.0 | + | 0 | 1 | 1.0 | + | 1 | 1 | 2.0 | + + Scenario Outline: Enter two digits per number and press = + Given I have a CalculatorActivity + When I press + When I press + And I press + + And I press + And I press + And I press = + Then I should see on the display + + Examples: + | num1 | num2 | num3 | num4 | sum | + | 0 | 0 | 2 | 0 | 20.0 | + | 9 | 8 | 7 | 6 | 174.0 | diff --git a/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/division.feature b/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/division.feature new file mode 100644 index 0000000000..752a882be5 --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/division.feature @@ -0,0 +1,31 @@ +Feature: Divide two numbers + Calculate the quotient of two numbers which consist of one or more digits + + Scenario Outline: Enter one digit per number and press = + Given I have a CalculatorActivity + When I press + And I press / + And I press + And I press = + Then I should see on the display + + Examples: + | num1 | num2 | quotient | + | 0 | 0 | NaN | + | 1 | 0 | Infinity | + | 1 | 2 | 0.5 | + + Scenario Outline: Enter two digits per number and press = + Given I have a CalculatorActivity + When I press + When I press + And I press / + And I press + And I press + And I press = + Then I should see on the display + + Examples: + | num1 | num2 | num3 | num4 | quotient | + | 2 | 2 | 2 | 2 | 1.0 | + | 2 | 0 | 1 | 0 | 2.0 | diff --git a/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/multiplication.feature b/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/multiplication.feature new file mode 100644 index 0000000000..ca976f3795 --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/multiplication.feature @@ -0,0 +1,31 @@ +Feature: Multiply two numbers + Calculate the product of two numbers which consist of one or more digits + + Scenario Outline: Enter one digit per number and press = + Given I have a CalculatorActivity + When I press + And I press x + And I press + And I press = + Then I should see on the display + + Examples: + | num1 | num2 | product | + | 0 | 0 | 0.0 | + | 0 | 1 | 0.0 | + | 1 | 2 | 2.0 | + + Scenario Outline: Enter two digits per number and press = + Given I have a CalculatorActivity + When I press + When I press + And I press x + And I press + And I press + And I press = + Then I should see on the display + + Examples: + | num1 | num2 | num3 | num4 | product | + | 2 | 2 | 2 | 2 | 484.0 | + | 2 | 0 | 1 | 0 | 200.0 | diff --git a/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/subtraction.feature b/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/subtraction.feature new file mode 100644 index 0000000000..dcb084e111 --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/src/androidTest/assets/features/operations/subtraction.feature @@ -0,0 +1,31 @@ +Feature: Subtract two numbers + Calculate the difference of two numbers which consist of one or more digits + + Scenario Outline: Enter one digit per number and press = + Given I have a CalculatorActivity + When I press + And I press – + And I press + And I press = + Then I should see on the display + + Examples: + | num1 | num2 | delta | + | 0 | 0 | 0.0 | + | 0 | 1 | -1.0 | + | 1 | 2 | -1.0 | + + Scenario Outline: Enter two digits per number and press = + Given I have a CalculatorActivity + When I press + When I press + And I press – + And I press + And I press + And I press = + Then I should see on the display + + Examples: + | num1 | num2 | num3 | num4 | delta | + | 2 | 2 | 2 | 2 | 0.0 | + | 2 | 0 | 1 | 0 | 10.0 | diff --git a/examples/android/android-studio/Cukeulator/app/src/androidTest/java/cukeulator/android/example/cucumber/cukeulator/test/CalculatorActivitySteps.java b/examples/android/android-studio/Cukeulator/app/src/androidTest/java/cukeulator/android/example/cucumber/cukeulator/test/CalculatorActivitySteps.java new file mode 100644 index 0000000000..b11a78b38a --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/src/androidTest/java/cukeulator/android/example/cucumber/cukeulator/test/CalculatorActivitySteps.java @@ -0,0 +1,110 @@ +package cukeulator.android.example.cucumber.cukeulator.test; + +import android.test.ActivityInstrumentationTestCase2; +import android.widget.TextView; +import cucumber.api.CucumberOptions; +import cucumber.api.java.en.Given; +import cucumber.api.java.en.Then; +import cucumber.api.java.en.When; +import cukeulator.android.example.cucumber.cukeulator.CalculatorActivity; +import cukeulator.android.example.cucumber.cukeulator.R; + +import static cukeulator.android.example.cucumber.cukeulator.test.Utils.clickOnView; + +/** + * We extend ActivityInstrumentationTestCase2 in order to have access to methods like getActivity + * and getInstrumentation. Depending on what methods we are going to need, we can put our + * step definitions inside classes extending any of the following Android test classes: + *

+ * ActivityInstrumentationTestCase2 + * InstrumentationTestCase + * AndroidTestCase + *

+ * The CucumberOptions annotation is mandatory for exactly one of the classes in the test project. + * Only the first annotated class that is found will be used, others are ignored. If no class is + * annotated, an exception is thrown. + *

+ * The options need to at least specify features = "features". Features must be placed inside + * assets/features/ of the test project (or a subdirectory thereof). + */ +@CucumberOptions(features = "features") +public class CalculatorActivitySteps extends ActivityInstrumentationTestCase2 { + + public CalculatorActivitySteps(SomeDependency dependency) { + super(CalculatorActivity.class); + assertNotNull(dependency); + } + + @Given("^I have a CalculatorActivity$") + public void I_have_a_CalculatorActivity() { + assertNotNull(getActivity()); + } + + @When("^I press (\\d)$") + public void I_press_d(int d) { + CalculatorActivity activity = getActivity(); + + switch (d) { + case 0: + clickOnView(activity, R.id.btn_d_0); + break; + case 1: + clickOnView(activity, R.id.btn_d_1); + break; + case 2: + clickOnView(activity, R.id.btn_d_2); + break; + case 3: + clickOnView(activity, R.id.btn_d_3); + break; + case 4: + clickOnView(activity, R.id.btn_d_4); + break; + case 5: + clickOnView(activity, R.id.btn_d_5); + break; + case 6: + clickOnView(activity, R.id.btn_d_6); + break; + case 7: + clickOnView(activity, R.id.btn_d_7); + break; + case 8: + clickOnView(activity, R.id.btn_d_8); + break; + case 9: + clickOnView(activity, R.id.btn_d_9); + break; + } + } + + @When("^I press ([+–x\\/=])$") + public void I_press_op(char op) { + CalculatorActivity activity = getActivity(); + + switch (op) { + case '+': + clickOnView(activity, R.id.btn_op_add); + break; + case '–': + clickOnView(activity, R.id.btn_op_subtract); + break; + case 'x': + clickOnView(activity, R.id.btn_op_multiply); + break; + case '/': + clickOnView(activity, R.id.btn_op_divide); + break; + case '=': + clickOnView(activity, R.id.btn_op_equals); + break; + } + } + + @Then("^I should see (\\S+) on the display$") + public void I_should_see_s_on_the_display(String s) { + TextView display = (TextView) getActivity().findViewById(R.id.txt_calc_display); + String displayed_result = display.getText().toString(); + assertEquals(s, displayed_result); + } +} diff --git a/examples/android/android-studio/Cukeulator/app/src/androidTest/java/cukeulator/android/example/cucumber/cukeulator/test/SomeDependency.java b/examples/android/android-studio/Cukeulator/app/src/androidTest/java/cukeulator/android/example/cucumber/cukeulator/test/SomeDependency.java new file mode 100644 index 0000000000..a70ec3895c --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/src/androidTest/java/cukeulator/android/example/cucumber/cukeulator/test/SomeDependency.java @@ -0,0 +1,5 @@ +package cukeulator.android.example.cucumber.cukeulator.test; + +// Dummy class to demonstrate dependency injection +public class SomeDependency { +} diff --git a/examples/android/android-studio/Cukeulator/app/src/androidTest/java/cukeulator/android/example/cucumber/cukeulator/test/Utils.java b/examples/android/android-studio/Cukeulator/app/src/androidTest/java/cukeulator/android/example/cucumber/cukeulator/test/Utils.java new file mode 100644 index 0000000000..b0ecc4bef8 --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/src/androidTest/java/cukeulator/android/example/cucumber/cukeulator/test/Utils.java @@ -0,0 +1,49 @@ +package cukeulator.android.example.cucumber.cukeulator.test; + +import android.app.Activity; +import android.util.Log; +import android.view.View; + +public final class Utils { + private static final MultiLock lock = new MultiLock(); + + public static class MultiLock { + private int mLocks; + + public synchronized void acquire() throws InterruptedException { + if (mLocks++ >= 0) { + wait(); + } + } + + public synchronized void release() { + if (--mLocks <= 0) { + notifyAll(); + } + } + } + + private Utils() { + } + + public static void clickOnView(Activity activity, int id) { + View view = activity.findViewById(id); + if (view != null) clickOnView(activity, view); + } + + public static void clickOnView(Activity activity, final View view) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + view.callOnClick(); + lock.release(); + } + }); + try { + lock.acquire(); + } catch (InterruptedException e) { + Log.e("cucumber-android", e.toString()); + Thread.currentThread().interrupt(); + } + } +} diff --git a/examples/android/android-studio/Cukeulator/app/src/main/AndroidManifest.xml b/examples/android/android-studio/Cukeulator/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..da666c53ce --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/src/main/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + diff --git a/examples/android/android-studio/Cukeulator/app/src/main/java/cukeulator/android/example/cucumber/cukeulator/CalculatorActivity.java b/examples/android/android-studio/Cukeulator/app/src/main/java/cukeulator/android/example/cucumber/cukeulator/CalculatorActivity.java new file mode 100644 index 0000000000..51620abfed --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/src/main/java/cukeulator/android/example/cucumber/cukeulator/CalculatorActivity.java @@ -0,0 +1,152 @@ +package cukeulator.android.example.cucumber.cukeulator; + +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +public class CalculatorActivity extends Activity { + private static enum Operation {ADD, SUB, MULT, DIV, NONE} + + private TextView txtCalcDisplay; + private TextView txtCalcOperator; + private Operation operation; + private boolean decimals; + private boolean resetDisplay; + private boolean performOperation; + private double value; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_calculator); + txtCalcDisplay = (TextView) findViewById(R.id.txt_calc_display); + txtCalcOperator = (TextView) findViewById(R.id.txt_calc_operator); + operation = Operation.NONE; + } + + public void onDigitPressed(View v) { + if (resetDisplay) { + txtCalcDisplay.setText(null); + resetDisplay = false; + } + txtCalcOperator.setText(null); + + if (decimals || !only0IsDisplayed()) txtCalcDisplay.append(((Button) v).getText()); + + if (operation != Operation.NONE) performOperation = true; + } + + public void onOperatorPressed(View v) { + if (performOperation) { + performOperation(); + performOperation = false; + } + switch (v.getId()) { + case R.id.btn_op_divide: + operation = Operation.DIV; + txtCalcOperator.setText("/"); + break; + case R.id.btn_op_multiply: + operation = Operation.MULT; + txtCalcOperator.setText("x"); + break; + case R.id.btn_op_subtract: + operation = Operation.SUB; + txtCalcOperator.setText("–"); + break; + case R.id.btn_op_add: + operation = Operation.ADD; + txtCalcOperator.setText("+"); + break; + case R.id.btn_op_equals: + break; + default: + throw new RuntimeException("Unsupported operation."); + } + resetDisplay = true; + value = getDisplayValue(); + } + + public void onSpecialPressed(View v) { + switch (v.getId()) { + case R.id.btn_spec_sqroot: { + double value = getDisplayValue(); + double sqrt = Math.sqrt(value); + txtCalcDisplay.setText(Double.toString(sqrt)); + break; + } + case R.id.btn_spec_pi: { + resetDisplay = false; + txtCalcOperator.setText(null); + txtCalcDisplay.setText(Double.toString(Math.PI)); + if (operation != Operation.NONE) performOperation = true; + return; + } + case R.id.btn_spec_percent: { + double value = getDisplayValue(); + double percent = value / 100.0F; + txtCalcDisplay.setText(Double.toString(percent)); + break; + } + case R.id.btn_spec_comma: { + if (!decimals) { + String text = displayIsEmpty() ? "0." : "."; + txtCalcDisplay.append(text); + decimals = true; + } + break; + } + case R.id.btn_spec_clear: { + value = 0; + decimals = false; + operation = Operation.NONE; + txtCalcDisplay.setText(null); + txtCalcOperator.setText(null); + break; + } + } + resetDisplay = false; + performOperation = false; + } + + private void performOperation() { + double display = getDisplayValue(); + + switch (operation) { + case DIV: + value = value / display; + break; + case MULT: + value = value * display; + break; + case SUB: + value = value - display; + break; + case ADD: + value = value + display; + break; + case NONE: + return; + default: + throw new RuntimeException("Unsupported operation."); + } + txtCalcOperator.setText(null); + txtCalcDisplay.setText(Double.toString(value)); + } + + private boolean only0IsDisplayed() { + CharSequence text = txtCalcDisplay.getText(); + return text.length() == 1 && text.charAt(0) == '0'; + } + + private boolean displayIsEmpty() { + return txtCalcDisplay.getText().length() == 0; + } + + private double getDisplayValue() { + String display = txtCalcDisplay.getText().toString(); + return display.isEmpty() ? 0.0F : Double.parseDouble(display); + } +} diff --git a/examples/android/android-studio/Cukeulator/app/src/main/res/drawable-hdpi/ic_launcher.png b/examples/android/android-studio/Cukeulator/app/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100755 index 0000000000000000000000000000000000000000..019f515cadfec581021dcbb023d4d7dcd4a699b2 GIT binary patch literal 6468 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 t))002ovPDHLkV1f$oPu>6k literal 0 HcmV?d00001 diff --git a/examples/android/android-studio/Cukeulator/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/examples/android/android-studio/Cukeulator/app/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100755 index 0000000000000000000000000000000000000000..1814a2578e7575ee9edf598ade0211cf0e2f4212 GIT binary patch literal 16093 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 literal 0 HcmV?d00001 diff --git a/examples/android/android-studio/Cukeulator/app/src/main/res/layout/activity_calculator.xml b/examples/android/android-studio/Cukeulator/app/src/main/res/layout/activity_calculator.xml new file mode 100644 index 0000000000..99566881f1 --- /dev/null +++ b/examples/android/android-studio/Cukeulator/app/src/main/res/layout/activity_calculator.xml @@ -0,0 +1,187 @@ + + + + + + + + + + +