Skip to content

Commit

Permalink
Merge pull request codinguser#453 from rivaldi8/bugfix-417-calculator…
Browse files Browse the repository at this point in the history
…edittext-focus-issue

Bugfix 417: Sometimes amount text boxes in the split editor fail getting the focus
Fixes codinguser#417
  • Loading branch information
codinguser committed Dec 23, 2015
2 parents 0f10259 + 4586a62 commit 3d9ebc0
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 67 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* Copyright (c) 2012 - 2015 Ngewi Fet <ngewif@gmail.com>
*
* 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.
*/

package org.gnucash.android.test.ui;

import android.content.Intent;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;

import org.gnucash.android.R;
import org.gnucash.android.db.AccountsDbAdapter;
import org.gnucash.android.db.DatabaseHelper;
import org.gnucash.android.db.SplitsDbAdapter;
import org.gnucash.android.db.TransactionsDbAdapter;
import org.gnucash.android.model.Account;
import org.gnucash.android.model.Commodity;
import org.gnucash.android.ui.common.UxArgument;
import org.gnucash.android.ui.transaction.TransactionsActivity;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.pressBack;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.hamcrest.Matchers.not;

// TODO: Find out how to press the keys in the KeyboardView.
@RunWith(AndroidJUnit4.class)
public class CalculatorEditTextTest extends
ActivityInstrumentationTestCase2<TransactionsActivity> {
private static final String DUMMY_ACCOUNT_UID = "transactions-account";
private static final String DUMMY_ACCOUNT_NAME = "Transactions Account";

private static final String TRANSFER_ACCOUNT_NAME = "Transfer account";
private static final String TRANSFER_ACCOUNT_UID = "transfer_account";
public static final String CURRENCY_CODE = "USD";

private SQLiteDatabase mDb;
private DatabaseHelper mDbHelper;
private AccountsDbAdapter mAccountsDbAdapter;
private TransactionsDbAdapter mTransactionsDbAdapter;
private SplitsDbAdapter mSplitsDbAdapter;
private TransactionsActivity mTransactionsActivity;

public CalculatorEditTextTest() {
super(TransactionsActivity.class);
}

@Override
@Before
public void setUp() throws Exception {
super.setUp();
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
AccountsActivityTest.preventFirstRunDialogs(getInstrumentation().getTargetContext());


mDbHelper = new DatabaseHelper(getInstrumentation().getTargetContext());
try {
mDb = mDbHelper.getWritableDatabase();
} catch (SQLException e) {
Log.e(getClass().getName(), "Error getting database: " + e.getMessage());
mDb = mDbHelper.getReadableDatabase();
}
mSplitsDbAdapter = new SplitsDbAdapter(mDb);
mTransactionsDbAdapter = new TransactionsDbAdapter(mDb, mSplitsDbAdapter);
mAccountsDbAdapter = new AccountsDbAdapter(mDb, mTransactionsDbAdapter);
mAccountsDbAdapter.deleteAllRecords();

Account account = new Account(DUMMY_ACCOUNT_NAME);
account.setUID(DUMMY_ACCOUNT_UID);
account.setCommodity(Commodity.getInstance(CURRENCY_CODE));

Account account2 = new Account(TRANSFER_ACCOUNT_NAME);
account2.setUID(TRANSFER_ACCOUNT_UID);
account2.setCommodity(Commodity.getInstance(CURRENCY_CODE));

mAccountsDbAdapter.addRecord(account);
mAccountsDbAdapter.addRecord(account2);

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra(UxArgument.SELECTED_ACCOUNT_UID, DUMMY_ACCOUNT_UID);
setActivityIntent(intent);
mTransactionsActivity = getActivity();
}

/**
* Checks the calculator keyboard is showed/hided as expected.
*/
@Test
public void testShowingHidingOfCalculatorKeyboard() {
clickOnView(R.id.fab_create_transaction);

// Giving the focus to the amount field shows the keyboard
onView(withId(R.id.input_transaction_amount)).perform(click());
onView(withId(R.id.calculator_keyboard)).check(matches(isDisplayed()));

// Pressing back hides the keyboard (still with focus)
pressBack();
onView(withId(R.id.calculator_keyboard)).check(matches(not(isDisplayed())));

// Clicking the amount field already focused shows the keyboard again
clickOnView(R.id.input_transaction_amount);
onView(withId(R.id.calculator_keyboard)).check(matches(isDisplayed()));

// Changing the focus to another field hides the keyboard
clickOnView(R.id.input_transaction_name);
onView(withId(R.id.calculator_keyboard)).check(matches(not(isDisplayed())));
}

/**
* Simple wrapper for clicking on views with espresso
* @param viewId View resource ID
*/
private void clickOnView(int viewId){
onView(withId(viewId)).perform(click());
}

@Override
@After
public void tearDown() throws Exception {
mTransactionsActivity.finish();
super.tearDown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.inputmethodservice.KeyboardView;
import android.support.annotation.XmlRes;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
Expand Down Expand Up @@ -47,12 +46,12 @@

/**
* A custom EditText which supports computations and uses a custom calculator keyboard.
* <p>Afer the view is inflated, make sure to call {@link #bindListeners(KeyboardView)}
* with the view from your layout where the calculator keyboard should be displayed:</p>
* <p>After the view is inflated, make sure to call {@link #bindListeners(KeyboardView)}
* with the view from your layout where the calculator keyboard should be displayed.</p>
* @author Ngewi Fet <ngewif@gmail.com>
*/
public class CalculatorEditText extends EditText {
CalculatorKeyboard mCalculatorKeyboard;
private CalculatorKeyboard mCalculatorKeyboard;

private Commodity mCommodity = Commodity.DEFAULT_COMMODITY;
private Context mContext;
Expand All @@ -63,7 +62,6 @@ public class CalculatorEditText extends EditText {
private boolean isContentModified = false;

private int mCalculatorKeysLayout;
private KeyboardView mCalculatorKeyboardView;

public CalculatorEditText(Context context) {
super(context);
Expand Down Expand Up @@ -121,7 +119,6 @@ public void bindListeners(CalculatorKeyboard calculatorKeyboard){
mCalculatorKeyboard = calculatorKeyboard;
mContext = calculatorKeyboard.getContext();
setOnFocusChangeListener(new OnFocusChangeListener() {
// NOTE By setting the on focus listener, we can show the custom keyboard when the edit box gets focus, but also hide it when the edit box loses focus
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
Expand Down Expand Up @@ -159,14 +156,11 @@ public boolean onLongClick(View v) {
}
});

// Although it looks redundant having both onClickListener and OnTouchListener, removing
// one of them makes the standard keyboard show up in addition to the calculator one.
// Although this handler doesn't make sense, if removed, the standard keyboard
// shows up in addition to the calculator one when the EditText gets a touch event.
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (!mCalculatorKeyboard.isCustomKeyboardVisible())
mCalculatorKeyboard.showCustomKeyboard(v);

// XXX: Use dispatchTouchEvent()?
onTouchEvent(event);
return false;
Expand All @@ -177,72 +171,22 @@ public boolean onTouch(View v, MotionEvent event) {
}

/**
* Initializes listeners on the edittext
* Initializes listeners on the EditText
*/
public void bindListeners(KeyboardView keyboardView){
bindListeners(new CalculatorKeyboard(mContext, keyboardView, mCalculatorKeysLayout));
}

/**
* Returns the calculator keyboard instantiated by this edittext
* Returns the calculator keyboard instantiated by this EditText
* @return CalculatorKeyboard
*/
public CalculatorKeyboard getCalculatorKeyboard(){
return mCalculatorKeyboard;
}

/**
* Returns the view Id of the keyboard view
* @return Keyboard view
*/
public KeyboardView getCalculatorKeyboardView() {
return mCalculatorKeyboardView;
}

/**
* Set the keyboard view used for displaying the keyboard
* @param calculatorKeyboardView Calculator keyboard view
*/
public void setCalculatorKeyboardView(KeyboardView calculatorKeyboardView) {
this.mCalculatorKeyboardView = calculatorKeyboardView;
bindListeners(calculatorKeyboardView);
}

/**
* Returns the XML resource ID describing the calculator keys layout
* @return XML resource ID
*/
public int getCalculatorKeysLayout() {
return mCalculatorKeysLayout;
}

/**
* Sets the XML resource describing the layout of the calculator keys
* @param mCalculatorKeysLayout XML resource ID
*/
public void setCalculatorKeysLayout(@XmlRes int mCalculatorKeysLayout) {
this.mCalculatorKeysLayout = mCalculatorKeysLayout;
bindListeners(mCalculatorKeyboardView);
}

/**
* Sets the calculator keyboard to use for this EditText
* @param keyboard Properly intialized calculator keyobard
*/
public void setCalculatorKeyboard(CalculatorKeyboard keyboard){
this.mCalculatorKeyboard = keyboard;
}

/**
* Returns the currency used for computations
* @return ISO 4217 currency
*/
public Commodity getCommodity() {
return mCommodity;
}

/**
* Sets the commodity to use for calculations
* Sets the commodity to use for calculations.
* The commodity determines the number of decimal places used
* @param commodity ISO 4217 currency
*/
Expand All @@ -251,8 +195,8 @@ public void setCommodity(Commodity commodity) {
}

/**
* Evaluates the arithmetic expression in the editText and sets the text property
* @return Result of arithmetic evaluation which is same as text displayed in edittext
* Evaluates the arithmetic expression in the EditText and sets the text property
* @return Result of arithmetic evaluation which is same as text displayed in EditText
*/
public String evaluate(){
String amountString = getCleanString();
Expand Down Expand Up @@ -330,7 +274,7 @@ public BigDecimal getValue(){
}

/**
* Set the text to the value of {@code amount} formatted according to the locale
* Set the text to the value of {@code amount} formatted according to the locale.
* <p>The number of decimal places are determined by the currency set to the view, and the
* decimal separator is determined by the device locale. There are no thousandths separators.</p>
* @param amount BigDecimal amount
Expand Down

0 comments on commit 3d9ebc0

Please sign in to comment.