From e1991a6926189edff8177481ba4ec7e341642cd9 Mon Sep 17 00:00:00 2001 From: Yusaku Mandai Date: Sun, 18 Sep 2016 15:36:47 +0900 Subject: [PATCH 1/6] Refactor Blocks Following changes are made in this commit: * Rename classes As we discussed offline * Extract common functions among block classes Changed NumberTextHolder interface for better encapsulation * Change return value type of BlockBase#getKind The previous code uses Class class, which does not represent actual use case (e.g., ForwardSecBlock#getKind returns SequenceBlock.class). Replaced Class type with Enum. * Remove locale-dependent code on parsing numbers The previous code relies on the Locale.US no matter what locale this app runs on. This commit fixes the locale dependent code by extracting the parsing logic. * Fix the unspoken rule that using scaled values for communicating between blocks and number pickers. The previous code scaled values so that the value has no radix point, which was confusing code. Fixed by replacing the type with BigDecimal and explicitly use the raw value. In accordance with it, changed the type of "number" in ProgramDataSpec for saving without data loss * Remove code in Unit class for handling quantities, which was ugly and cannot be used widely. Changed second string ("second/s" -> just "s") --- .../drive/database/ProgramDataManager.java | 10 +- .../drive/database/ProgramDataSpec.java | 2 +- .../drive/execution/ExecutionThread.java | 1 + .../activity/ProgrammingActivityBase.java | 2 +- .../programming/visual/block/BlockBase.java | 23 +- .../visual/block/BlockFactory.java | 164 ++++++-------- .../visual/block/NumTextHolder.java | 82 ------- .../visual/block/NumberTextHolder.java | 83 +++++++ .../visual/block/NumberTextViewDelegate.java | 75 +++++++ ...{WhileForeverBlock.java => LoopBlock.java} | 8 +- .../{WhileNumBlock.java => NTimesBlock.java} | 52 ++--- .../block/repetition/RepetitionBlock.java | 11 +- .../RepetitionBlockHasNumberText.java | 74 +++++++ .../repetition/RepetitionBreakBlock.java | 8 +- .../block/repetition/RepetitionEndBlock.java | 8 +- .../repetition/RepetitionHasNumText.java | 42 ---- .../block/selection/SelectionBlock.java | 20 +- .../SelectionBlockHasNumberText.java | 75 +++++++ .../block/selection/SelectionEndBlock.java | 8 +- .../block/selection/SelectionHasNumText.java | 42 ---- .../visual/block/sequence/SequenceBlock.java | 9 +- .../sequence/SequenceBlockHasNumText.java | 43 ---- .../sequence/SequenceBlockHasNumberText.java | 83 +++++++ .../visual/layout/BlockSpaceManagerBase.java | 3 +- .../visual/layout/ExecutionSpaceManager.java | 18 +- .../layout/ProgrammingSpaceManager.java | 132 +++++------- .../drive/util/development/Unit.java | 64 ++---- .../drive/util/string/ParseUtil.java | 78 +++++++ .../drive/view/NumberSelectSeekBarView.java | 125 ++++++----- .../drive/view/NumberSelectViewBase.java | 22 +- .../view/NumberSelectWheelScrollerView.java | 202 ++++++++++-------- .../{icon_while_forever.png => icon_loop.png} | Bin .../{icon_while_num.png => icon_n_times.png} | Bin ...block_while_forever.xml => block_loop.xml} | 2 +- ...{block_while_num.xml => block_n_times.xml} | 2 +- app/src/main/res/values-ja/strings.xml | 5 +- app/src/main/res/values/strings.xml | 9 +- .../visual/activity/NxtBlockListActivity.java | 8 +- .../selection/IfNxtIsOutOfLineBlock.java | 10 +- .../block/selection/IfNxtWasTouchedBlock.java | 10 +- .../selection/IfThereWasALargeSoundBlock.java | 10 +- .../block/sequence/BackwardSecBlock.java | 47 ++-- .../block/sequence/ForwardSecBlock.java | 48 ++--- .../sequence/SetLeftMotorSpeedBlock.java | 44 ++-- .../sequence/SetRightMotorSpeedBlock.java | 44 ++-- .../visual/block/sequence/StopSecBlock.java | 46 ++-- .../block/sequence/TurnLeftSecBlock.java | 43 ++-- .../block/sequence/TurnRightSecBlock.java | 43 ++-- .../drive/util/string/ParseUtilTest.java | 49 +++++ 49 files changed, 1058 insertions(+), 931 deletions(-) delete mode 100644 app/src/main/java/com/pileproject/drive/programming/visual/block/NumTextHolder.java create mode 100644 app/src/main/java/com/pileproject/drive/programming/visual/block/NumberTextHolder.java create mode 100644 app/src/main/java/com/pileproject/drive/programming/visual/block/NumberTextViewDelegate.java rename app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/{WhileForeverBlock.java => LoopBlock.java} (83%) rename app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/{WhileNumBlock.java => NTimesBlock.java} (63%) create mode 100644 app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBlockHasNumberText.java delete mode 100644 app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionHasNumText.java create mode 100644 app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionBlockHasNumberText.java delete mode 100644 app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionHasNumText.java delete mode 100644 app/src/main/java/com/pileproject/drive/programming/visual/block/sequence/SequenceBlockHasNumText.java create mode 100644 app/src/main/java/com/pileproject/drive/programming/visual/block/sequence/SequenceBlockHasNumberText.java create mode 100644 app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java rename app/src/main/res/drawable-hdpi/{icon_while_forever.png => icon_loop.png} (100%) rename app/src/main/res/drawable-hdpi/{icon_while_num.png => icon_n_times.png} (100%) rename app/src/main/res/layout/{block_while_forever.xml => block_loop.xml} (96%) rename app/src/main/res/layout/{block_while_num.xml => block_n_times.xml} (97%) create mode 100644 app/src/test/java/com/pileproject/drive/util/string/ParseUtilTest.java diff --git a/app/src/main/java/com/pileproject/drive/database/ProgramDataManager.java b/app/src/main/java/com/pileproject/drive/database/ProgramDataManager.java index f93bbd7..d95fb65 100644 --- a/app/src/main/java/com/pileproject/drive/database/ProgramDataManager.java +++ b/app/src/main/java/com/pileproject/drive/database/ProgramDataManager.java @@ -22,7 +22,7 @@ import com.pileproject.drive.programming.visual.activity.BlockPositionComparator; import com.pileproject.drive.programming.visual.block.BlockBase; import com.pileproject.drive.programming.visual.block.BlockFactory; -import com.pileproject.drive.programming.visual.block.NumTextHolder; +import com.pileproject.drive.programming.visual.block.NumberTextHolder; import com.pileproject.drive.programming.visual.layout.BlockSpaceLayout; import com.yahoo.squidb.data.SquidCursor; import com.yahoo.squidb.sql.Query; @@ -129,8 +129,8 @@ private boolean saveProgram(String programName, String programType, BlockSpaceLa .setLeft(b.getLeft()) .setTop(b.getTop()); // get the number of TextView if the block has one - if (b instanceof NumTextHolder) { - data.setNumber(((NumTextHolder) b).getNum()); + if (b instanceof NumberTextHolder) { + data.setNumber(((NumberTextHolder) b).getValueAsString()); } // save the data @@ -202,8 +202,8 @@ private ArrayList loadBlocks(SquidCursor c) { // set data's properties b.setLeft(data.getLeft()); b.setTop(data.getTop()); - if (b instanceof NumTextHolder) { - ((NumTextHolder) b).setNum(data.getNumber()); + if (b instanceof NumberTextHolder) { + ((NumberTextHolder) b).setValueAsString(data.getNumber()); } // add the block to a list blocks.add(b); diff --git a/app/src/main/java/com/pileproject/drive/database/ProgramDataSpec.java b/app/src/main/java/com/pileproject/drive/database/ProgramDataSpec.java index 8c3dabc..b08f265 100644 --- a/app/src/main/java/com/pileproject/drive/database/ProgramDataSpec.java +++ b/app/src/main/java/com/pileproject/drive/database/ProgramDataSpec.java @@ -47,5 +47,5 @@ public class ProgramDataSpec { // the number which a number holder block has @ColumnSpec(defaultValue = "0") - int number; + String number; } \ No newline at end of file diff --git a/app/src/main/java/com/pileproject/drive/execution/ExecutionThread.java b/app/src/main/java/com/pileproject/drive/execution/ExecutionThread.java index 1708729..6122f74 100644 --- a/app/src/main/java/com/pileproject/drive/execution/ExecutionThread.java +++ b/app/src/main/java/com/pileproject/drive/execution/ExecutionThread.java @@ -25,6 +25,7 @@ import com.pileproject.drive.app.DriveApplication; import com.pileproject.drive.database.ProgramDataManager; import com.pileproject.drive.programming.visual.block.BlockBase; +import com.pileproject.drive.programming.visual.block.selection.SelectionEndBlock; /** * A Thread class to execute program. diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/activity/ProgrammingActivityBase.java b/app/src/main/java/com/pileproject/drive/programming/visual/activity/ProgrammingActivityBase.java index 96a8c3f..3676f2c 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/activity/ProgrammingActivityBase.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/activity/ProgrammingActivityBase.java @@ -148,7 +148,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { // Get results int howToMake = data.getIntExtra(getString(R.string.key_block_how_to_make), BlockFactory.SEQUENCE); String blockName = data.getStringExtra(getString(R.string.key_block_block_name)); - ArrayList blocks = BlockFactory.createBlocks(howToMake, blockName); + List blocks = BlockFactory.createBlocks(howToMake, blockName); mSpaceManager.addBlocks(blocks); } break; diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockBase.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockBase.java index 392874d..32b5555 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockBase.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockBase.java @@ -17,6 +17,8 @@ package com.pileproject.drive.programming.visual.block; import android.content.Context; +import android.support.annotation.LayoutRes; +import android.view.LayoutInflater; import android.widget.RelativeLayout; import com.pileproject.drive.execution.ExecutionCondition; @@ -29,10 +31,20 @@ * @version 1.0 18-June-2013 */ public abstract class BlockBase extends RelativeLayout { - public BlockBase(Context context) { + + public BlockBase(Context context, @LayoutRes int layoutRes) { super(context); + + LayoutInflater.from(context).inflate(layoutRes, this); } + /** + * Returns kind of this block. + * + * @return {@link BlockKind} + */ + public abstract BlockKind getKind(); + /** * Action that this block does while the execution of program. * Return delay that occurs after this action @@ -45,10 +57,7 @@ public BlockBase(Context context) { public abstract int action( MachineController controller, ExecutionCondition condition); - /** - * Return class to check a program is correct or not - * - * @return Class - */ - public abstract Class getKind(); + public enum BlockKind { + SEQUENCE, SELECTION_BEGIN, SELECTION_END, REPETITION_BEGIN, REPETITION_END, REPETITION_BREAK + } } \ No newline at end of file diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java index a4167c9..0366bba 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java @@ -17,16 +17,16 @@ package com.pileproject.drive.programming.visual.block; import android.content.Context; +import android.support.annotation.IntDef; import com.pileproject.drive.app.DriveApplication; import com.pileproject.drive.programming.visual.block.repetition.RepetitionEndBlock; import com.pileproject.drive.programming.visual.block.selection.SelectionEndBlock; import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; - -import trikita.log.Log; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; /** * Factory that creates blocks @@ -38,131 +38,93 @@ public class BlockFactory { public static final int SEQUENCE = 0; public static final int REPETITION = 1; public static final int SELECTION = 2; + @Deprecated public static final int UNDO = 3; public static final int LOAD = 4; - /** - * This class can't be created as an instance - */ private BlockFactory() { } - /** - * Return class by name - * - * @param className - * @return Class - */ @SuppressWarnings("unchecked") - private static Class getClassForName(String className) throws RuntimeException { + private static Class getClassForName(String className) throws RuntimeException { + try { return (Class) Class.forName(className); + } catch (ClassNotFoundException e) { - throw new RuntimeException(e); + + throw new RuntimeException("Invalid class name '" + className + "'", e); } } - /** - * Create blocks by reflecting - * - * @param blockName - * @return - */ - private static BlockBase create(String blockName) { + private static BlockBase create(Class blockClass) throws RuntimeException { - // Get class - Class blockClass = null; try { - blockClass = getClassForName(blockName); - } catch (RuntimeException e) { - Log.e(e.getMessage()); - } + Constructor constructor = blockClass.getConstructor(Context.class); - // Get constructor - Class[] types = {Context.class}; - Constructor constructor; - try { - constructor = blockClass.getConstructor(types); - } catch (SecurityException | NoSuchMethodException e) { - throw new RuntimeException(e); - } + return constructor.newInstance(DriveApplication.getContext()); - // Create a new instance - Object[] args = {DriveApplication.getContext()}; - BlockBase b; - try { - b = constructor.newInstance(args); - } catch (IllegalArgumentException e) { - throw new RuntimeException(e); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); + } catch (Exception e) { + // there's no way to recover. let App die. + throw new RuntimeException("Failed to instantiate " + blockClass, e); } - return b; } - /** - * Create a sequence block - * - * @param blockName - * @return - */ - private static ArrayList createSequenceBlock(String blockName) { - ArrayList blocks = new ArrayList<>(); - BlockBase b = create(blockName); - blocks.add(b); - return blocks; + private static List createSequenceBlock(Class blockClass) { + + return Collections.singletonList(create(blockClass)); } - /** - * create a repetition block and an end block - * - * @param blockName - * @return - */ - private static ArrayList createRepetitionBlock( - String blockName) { - ArrayList blocks = new ArrayList<>(); - BlockBase b = new RepetitionEndBlock(DriveApplication.getContext()); // Add - // RepetitionEndBlock - blocks.add(b); - b = create(blockName); - blocks.add(b); - return blocks; + private static List createRepetitionBlock(Class blockClass) { + + return Arrays.asList(new RepetitionEndBlock(DriveApplication.getContext()), create(blockClass)); + } + + private static List createSelectionBlock(Class blockClass) { + + return Arrays.asList(new SelectionEndBlock(DriveApplication.getContext()), create(blockClass)); } /** - * Create a selection block and an end block + * Returns one or two instances of block whose class is blockName. + * Type of block can be specified with @{howToMake}, which also determines the number + * of blocks this function returns. * - * @param blockName - * @return + * @param howToMake type of block. must be one of {@link BlockFactory#SEQUENCE}, + * {@link BlockFactory#REPETITION}, {@link BlockFactory#SELECTION}, + * {@link BlockFactory#UNDO}, {@link BlockFactory#LOAD} + * @param blockName class name of block to be created + * @return list of blocks. the first element of the list is end block + * if block type is {@link BlockFactory#SELECTION} or + * {@link BlockFactory#REPETITION}. + * + * @exception RuntimeException if blockName is not supported block class name + * or howToMake is none of the values listed above */ - private static ArrayList createSelectionBlock(String blockName) { - ArrayList blocks = new ArrayList<>(); - BlockBase b = new SelectionEndBlock(DriveApplication.getContext()); // Add RepetitionEndBlock - blocks.add(b); - b = create(blockName); - blocks.add(b); - return blocks; - } + public static List createBlocks(@HowToMake int howToMake, String blockName) { + + Class blockClass = getClassForName(blockName); + + switch (howToMake) { + case SEQUENCE: + case UNDO: + case LOAD: { + return createSequenceBlock(blockClass); + } - public static ArrayList createBlocks(int howToMake, String blockName) { - ArrayList blocks = null; - if (howToMake == SEQUENCE) { - blocks = createSequenceBlock(blockName); - } else if (howToMake == REPETITION) { - blocks = createRepetitionBlock(blockName); - } else if (howToMake == SELECTION) { - blocks = createSelectionBlock(blockName); - } else if (howToMake == UNDO || howToMake == LOAD) { - // When users undo or load their program, this app should create - // a block. It is the same way when in which app makes sequence - // block - blocks = createSequenceBlock(blockName); + case REPETITION: { + return createRepetitionBlock(blockClass); + } + + case SELECTION: { + return createSelectionBlock(blockClass); + } } - return blocks; + + throw new RuntimeException("Do not know how to make a block of " + blockName); + } + + @IntDef({SEQUENCE, REPETITION, SELECTION, UNDO, LOAD}) + public @interface HowToMake { } } diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/NumTextHolder.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/NumTextHolder.java deleted file mode 100644 index 1eb8811..0000000 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/NumTextHolder.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2011-2015 PILE Project, Inc. - * - * 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 com.pileproject.drive.programming.visual.block; - -import android.widget.TextView; - -import com.pileproject.drive.util.development.Unit; - -/** - * Interface for block has TextView - * - * @author Tatsuya Iwanari - * @version 1.0 4-June-2013 - */ -public interface NumTextHolder { - /** - * Get number as Integer from TextView - * - * @return int - * Value of textView as integer - */ - int getNum(); - - /** - * Set number to TextView - * - * @param num the number that is set to TextView - */ - void setNum(int num); - - /** - * Get TextView - * - * @return TextView - */ - TextView getTextView(); - - /** - * Get Digit of the number of this block - * - * @return Integer[] - * 0 - Integral Part, 1 - Decimal Part - */ - Integer[] getDigit(); - - /** - * Get Max Value of this block - * - * @return double - * Maximum value - */ - double getMax(); - - /** - * Get Min Value of this block - * - * @return double - * Minimum value - */ - double getMin(); - - /** - * Returns unit of the value which is contained in this text field - * - * @return - */ - Unit getUnit(); -} \ No newline at end of file diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/NumberTextHolder.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/NumberTextHolder.java new file mode 100644 index 0000000..f991a55 --- /dev/null +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/NumberTextHolder.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2011-2015 PILE Project, Inc. + * + * 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 com.pileproject.drive.programming.visual.block; + +import android.view.View; + +import com.pileproject.drive.util.development.Unit; +import com.pileproject.drive.util.math.Range; + +import java.math.BigDecimal; + +/** + * Interface for block has TextView + * + * @author Tatsuya Iwanari + * @version 1.0 4-June-2013 + */ +public interface NumberTextHolder { + /** + * Get value of the TextView + */ + BigDecimal getValue(); + + /** + * Set value to TextView + */ + void setValue(BigDecimal value); + + /** + * Represents the precision of the value this class holds in 10-base. + * Precision of a value means the length of decimal digits + * e.g., if returns 3, the value can be set at 0.001-basis + */ + int getPrecision(); + + /** + * Returns the range which users can set the value within + * @return + */ + Range getRange(); + + /** + * Returns unit of the value + */ + Unit getUnit(); + + /** + * Enable the TextView in this holder if enable is true. + * Disable the TextView in this holder if enable is false + */ + void enableTextView(boolean enabled); + + /** + * Set {@link android.view.View.OnLongClickListener} to the TextView + */ + void setOnLongClickTextViewListener(View.OnLongClickListener listener); + + /** + * Returns a string which represents the value in this view. + * The string is formatted in {@link java.util.Locale#US} ("." means the radix point) + */ + String getValueAsString(); + + /** + * Set the value as String. + * The string should be formateed as {@link java.util.Locale#US} + */ + void setValueAsString(String value); +} \ No newline at end of file diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/NumberTextViewDelegate.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/NumberTextViewDelegate.java new file mode 100644 index 0000000..96edc9b --- /dev/null +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/NumberTextViewDelegate.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011-2015 PILE Project, Inc. + * + * 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 com.pileproject.drive.programming.visual.block; + +import android.view.View; +import android.widget.TextView; + +import com.pileproject.drive.util.string.ParseUtil; + +import java.math.BigDecimal; +import java.util.Locale; + +public class NumberTextViewDelegate { + + private final TextView textView; + private final String textFormat; + private final int precision; + + private BigDecimal valueCache; + + public NumberTextViewDelegate(TextView textView, NumberTextHolder holder) { + this.precision = holder.getPrecision(); + this.textView = textView; + this.textFormat = "%." + precision + "f"; + } + + public int getActionValue() { + return getValue().movePointRight(precision).intValue(); + } + + public BigDecimal getValue() { + if (valueCache == null) { + String value = (String) textView.getText(); + valueCache = ParseUtil.bigDecimalValueOf(value); + } + + return valueCache; + } + + public void setValue(BigDecimal value) { + valueCache = value; + textView.setText(String.format(Locale.getDefault(), textFormat, value)); + } + + public String getValueAsString() { + return getValue().toString(); + } + + public void setValueAsString(String value) { + setValue(ParseUtil.bigDecimalValueOf(value, Locale.US)); + } + + public void enableTextView(boolean enabled) { + textView.setFocusable(enabled); + textView.setFocusableInTouchMode(enabled); + textView.setEnabled(enabled); + } + + public void setOnTextViewLongClickListener(View.OnLongClickListener listener) { + textView.setOnLongClickListener(listener); + } +} diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/WhileForeverBlock.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/LoopBlock.java similarity index 83% rename from app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/WhileForeverBlock.java rename to app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/LoopBlock.java index ae08248..c445792 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/WhileForeverBlock.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/LoopBlock.java @@ -17,7 +17,6 @@ package com.pileproject.drive.programming.visual.block.repetition; import android.content.Context; -import android.view.LayoutInflater; import com.pileproject.drive.R; import com.pileproject.drive.execution.ExecutionCondition; @@ -29,11 +28,10 @@ * @author Tatsuya Iwanari * @version 1.0 7-July-2013 */ -public class WhileForeverBlock extends RepetitionBlock { +public class LoopBlock extends RepetitionBlock { - public WhileForeverBlock(Context context) { - super(context); - LayoutInflater.from(context).inflate(R.layout.block_while_forever, this); + public LoopBlock(Context context) { + super(context, R.layout.block_loop); } @Override diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/WhileNumBlock.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/NTimesBlock.java similarity index 63% rename from app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/WhileNumBlock.java rename to app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/NTimesBlock.java index c6497e0..80b2e0a 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/WhileNumBlock.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/NTimesBlock.java @@ -17,14 +17,14 @@ package com.pileproject.drive.programming.visual.block.repetition; import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; import com.pileproject.drive.R; import com.pileproject.drive.execution.ExecutionCondition; import com.pileproject.drive.execution.MachineController; import com.pileproject.drive.util.development.Unit; +import com.pileproject.drive.util.math.Range; + +import java.math.BigDecimal; /** * While in selected times @@ -32,50 +32,40 @@ * @author Tatsuya Iwanari * @version 1.0 7-July-2013 */ -public class WhileNumBlock extends RepetitionHasNumText { - - public WhileNumBlock(Context context) { - super(context); +public class NTimesBlock extends RepetitionBlockHasNumberText { - View layout = LayoutInflater.from(context).inflate(R.layout.block_while_num, this); - numText = (TextView) layout.findViewById(R.id.block_numText); - } + // TODO: set from preference + private static final Range range = Range.closed(BigDecimal.ONE, new BigDecimal(5)); - @Override - public int getNum() { - return Integer.parseInt(numText.getText().toString()); - } + private static final int PRECISION = 0; - @Override - public void setNum(int num) { - numText.setText(String.valueOf(num)); - } - - @Override - public Integer[] getDigit() { - return new Integer[]{2, 0}; + public NTimesBlock(Context context) { + super(context, R.layout.block_n_times, R.id.block_numText); } @Override - public double getMax() { - return (double) 5; + public int action(MachineController controller, ExecutionCondition condition) { + int n = getValue().intValue(); + int index = condition.getProgramCount(); + for (int i = 1; i < n; i++) { + condition.pushBeginningOfLoop(index); + } + return 0; } @Override - public double getMin() { - return (double) 1; + public int getPrecision() { + return PRECISION; } @Override - public int action(MachineController controller, ExecutionCondition condition) { - int index = condition.getProgramCount(); - for (int i = 1; i < getNum(); i++) - condition.pushBeginningOfLoop(index); - return 0; + public Range getRange() { + return range; } @Override public Unit getUnit() { return Unit.NumberOfTimes; } + } diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBlock.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBlock.java index 85bc65e..78fd9c1 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBlock.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBlock.java @@ -17,6 +17,7 @@ package com.pileproject.drive.programming.visual.block.repetition; import android.content.Context; +import android.support.annotation.LayoutRes; import com.pileproject.drive.programming.visual.block.BlockBase; @@ -29,14 +30,14 @@ */ public abstract class RepetitionBlock extends BlockBase { - public static final int FOREVER_WHILE_OFFSET = -1000; + static final int FOREVER_WHILE_OFFSET = -1000; - public RepetitionBlock(Context context) { - super(context); + public RepetitionBlock(Context context, @LayoutRes int layoutRes) { + super(context, layoutRes); } @Override - public Class getKind() { - return RepetitionBlock.class; + public final BlockKind getKind() { + return BlockKind.REPETITION_BEGIN; } } \ No newline at end of file diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBlockHasNumberText.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBlockHasNumberText.java new file mode 100644 index 0000000..b553f77 --- /dev/null +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBlockHasNumberText.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011-2015 PILE Project, Inc. + * + * 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 com.pileproject.drive.programming.visual.block.repetition; + +import android.content.Context; +import android.support.annotation.IdRes; +import android.support.annotation.LayoutRes; +import android.view.View; +import android.widget.TextView; + +import com.pileproject.drive.programming.visual.block.NumberTextHolder; +import com.pileproject.drive.programming.visual.block.NumberTextViewDelegate; + +import java.math.BigDecimal; + +public abstract class RepetitionBlockHasNumberText extends RepetitionBlock implements NumberTextHolder { + + private final NumberTextViewDelegate mDelegate; + + /** + * Constructor + * + * @param context The context of activity that creates this view + */ + public RepetitionBlockHasNumberText(Context context, @LayoutRes int layoutRes, @IdRes int textViewId) { + super(context, layoutRes); + + mDelegate = new NumberTextViewDelegate((TextView) findViewById(textViewId), this); + } + + @Override + public BigDecimal getValue() { + return mDelegate.getValue(); + } + + @Override + public void setValue(BigDecimal value) { + mDelegate.setValue(value); + } + + @Override + public String getValueAsString() { + return mDelegate.getValueAsString(); + } + + @Override + public void setValueAsString(String value) { + mDelegate.setValueAsString(value); + } + + @Override + public void enableTextView(boolean enabled) { + mDelegate.enableTextView(enabled); + } + + @Override + public void setOnLongClickTextViewListener(View.OnLongClickListener listener) { + mDelegate.setOnTextViewLongClickListener(listener); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBreakBlock.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBreakBlock.java index 008dee3..90e8631 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBreakBlock.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBreakBlock.java @@ -17,7 +17,6 @@ package com.pileproject.drive.programming.visual.block.repetition; import android.content.Context; -import android.view.LayoutInflater; import com.pileproject.drive.R; import com.pileproject.drive.execution.ExecutionCondition; @@ -29,13 +28,12 @@ */ public class RepetitionBreakBlock extends BlockBase { public RepetitionBreakBlock(Context context) { - super(context); - LayoutInflater.from(context).inflate(R.layout.block_repetition_break, this); + super(context, R.layout.block_repetition_break); } @Override - public Class getKind() { - return RepetitionBreakBlock.class; + public final BlockKind getKind() { + return BlockKind.REPETITION_BREAK; } @Override diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionEndBlock.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionEndBlock.java index 2058f3b..f82f841 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionEndBlock.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionEndBlock.java @@ -17,7 +17,6 @@ package com.pileproject.drive.programming.visual.block.repetition; import android.content.Context; -import android.view.LayoutInflater; import com.pileproject.drive.R; import com.pileproject.drive.execution.ExecutionCondition; @@ -33,13 +32,12 @@ public class RepetitionEndBlock extends BlockBase { public RepetitionEndBlock(Context context) { - super(context); - LayoutInflater.from(context).inflate(R.layout.block_repetition_end, this); + super(context, R.layout.block_repetition_end); } @Override - public Class getKind() { - return RepetitionEndBlock.class; + public final BlockKind getKind() { + return BlockKind.REPETITION_END; } @Override diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionHasNumText.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionHasNumText.java deleted file mode 100644 index 58c34b6..0000000 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionHasNumText.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2011-2015 PILE Project, Inc. - * - * 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 com.pileproject.drive.programming.visual.block.repetition; - -import android.content.Context; -import android.widget.TextView; - -import com.pileproject.drive.programming.visual.block.NumTextHolder; - - -public abstract class RepetitionHasNumText extends RepetitionBlock implements NumTextHolder { - - protected TextView numText; - - /** - * Constructor - * - * @param context The context of activity that creates this view - */ - public RepetitionHasNumText(Context context) { - super(context); - } - - @Override - public TextView getTextView() { - return numText; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionBlock.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionBlock.java index d4850e7..b25dcfa 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionBlock.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionBlock.java @@ -17,7 +17,10 @@ package com.pileproject.drive.programming.visual.block.selection; import android.content.Context; +import android.support.annotation.LayoutRes; +import com.pileproject.drive.execution.ExecutionCondition; +import com.pileproject.drive.execution.MachineController; import com.pileproject.drive.programming.visual.block.BlockBase; /** @@ -28,12 +31,21 @@ */ public abstract class SelectionBlock extends BlockBase { - public SelectionBlock(Context context) { - super(context); + public SelectionBlock(Context context, @LayoutRes int layoutRes) { + super(context, layoutRes); } + protected abstract boolean evaluateCondition(MachineController controller); + @Override - public Class getKind() { - return SelectionBlock.class; + public final BlockKind getKind() { + return BlockKind.SELECTION_BEGIN; } + + @Override + public final int action(MachineController controller, ExecutionCondition condition) { + condition.pushSelectionResult(evaluateCondition(controller)); + return 0; + } + } \ No newline at end of file diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionBlockHasNumberText.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionBlockHasNumberText.java new file mode 100644 index 0000000..3cc7b75 --- /dev/null +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionBlockHasNumberText.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011-2015 PILE Project, Inc. + * + * 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 com.pileproject.drive.programming.visual.block.selection; + +import android.content.Context; +import android.support.annotation.IdRes; +import android.support.annotation.LayoutRes; +import android.view.View; +import android.widget.TextView; + +import com.pileproject.drive.programming.visual.block.NumberTextHolder; +import com.pileproject.drive.programming.visual.block.NumberTextViewDelegate; + +import java.math.BigDecimal; + +/** + * SelectionBlock that has a TextView + * + * @author Tatsuya Iwanari + * @version 1.0 7-July-2013 + */ +public abstract class SelectionBlockHasNumberText extends SelectionBlock implements NumberTextHolder { + + private final NumberTextViewDelegate mDelegate; + + public SelectionBlockHasNumberText(Context context, @LayoutRes int layoutRes, @IdRes int textViewId) { + super(context, layoutRes); + + mDelegate = new NumberTextViewDelegate((TextView) findViewById(textViewId), this); + } + + @Override + public BigDecimal getValue() { + return mDelegate.getValue(); + } + + @Override + public void setValue(BigDecimal value) { + mDelegate.setValue(value); + } + + @Override + public String getValueAsString() { + return mDelegate.getValueAsString(); + } + + @Override + public void setValueAsString(String value) { + mDelegate.setValueAsString(value); + } + + @Override + public void enableTextView(boolean enabled) { + mDelegate.enableTextView(enabled); + } + + @Override + public void setOnLongClickTextViewListener(View.OnLongClickListener listener) { + mDelegate.setOnTextViewLongClickListener(listener); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionEndBlock.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionEndBlock.java index e54d1a5..8559d12 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionEndBlock.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionEndBlock.java @@ -17,7 +17,6 @@ package com.pileproject.drive.programming.visual.block.selection; import android.content.Context; -import android.view.LayoutInflater; import com.pileproject.drive.R; import com.pileproject.drive.execution.ExecutionCondition; @@ -31,13 +30,12 @@ public class SelectionEndBlock extends BlockBase { public SelectionEndBlock(Context context) { - super(context); - LayoutInflater.from(context).inflate(R.layout.block_selection_end, this); + super(context, R.layout.block_selection_end); } @Override - public Class getKind() { - return SelectionEndBlock.class; + public BlockKind getKind() { + return BlockKind.SELECTION_END; } @Override diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionHasNumText.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionHasNumText.java deleted file mode 100644 index 35ce221..0000000 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/selection/SelectionHasNumText.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2011-2015 PILE Project, Inc. - * - * 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 com.pileproject.drive.programming.visual.block.selection; - -import android.content.Context; -import android.widget.TextView; - -import com.pileproject.drive.programming.visual.block.NumTextHolder; - -/** - * SelectionBlock that has a TextView - * - * @author Tatsuya Iwanari - * @version 1.0 7-July-2013 - */ -public abstract class SelectionHasNumText extends SelectionBlock implements NumTextHolder { - - protected TextView numText; - - public SelectionHasNumText(Context context) { - super(context); - } - - @Override - public TextView getTextView() { - return numText; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/sequence/SequenceBlock.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/sequence/SequenceBlock.java index 0f57f17..5a36158 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/sequence/SequenceBlock.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/sequence/SequenceBlock.java @@ -17,6 +17,7 @@ package com.pileproject.drive.programming.visual.block.sequence; import android.content.Context; +import android.support.annotation.LayoutRes; import com.pileproject.drive.programming.visual.block.BlockBase; @@ -28,12 +29,12 @@ */ public abstract class SequenceBlock extends BlockBase { - public SequenceBlock(Context context) { - super(context); + public SequenceBlock(Context context, @LayoutRes int layoutRes) { + super(context, layoutRes); } @Override - public Class getKind() { - return SequenceBlock.class; + public final BlockKind getKind() { + return BlockKind.SEQUENCE; } } \ No newline at end of file diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/sequence/SequenceBlockHasNumText.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/sequence/SequenceBlockHasNumText.java deleted file mode 100644 index 3fafb49..0000000 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/sequence/SequenceBlockHasNumText.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2011-2015 PILE Project, Inc. - * - * 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 com.pileproject.drive.programming.visual.block.sequence; - -import android.content.Context; -import android.widget.TextView; - -import com.pileproject.drive.programming.visual.block.NumTextHolder; - - -/** - * SequenceBlock that has a TextView - * - * @author Tatsuya Iwanari - * @version 1.0 7-July-2013 - */ -public abstract class SequenceBlockHasNumText extends SequenceBlock implements NumTextHolder { - - protected TextView numText; - - public SequenceBlockHasNumText(Context context) { - super(context); - } - - @Override - public TextView getTextView() { - return numText; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/sequence/SequenceBlockHasNumberText.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/sequence/SequenceBlockHasNumberText.java new file mode 100644 index 0000000..b25e2c3 --- /dev/null +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/sequence/SequenceBlockHasNumberText.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2011-2015 PILE Project, Inc. + * + * 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 com.pileproject.drive.programming.visual.block.sequence; + +import android.content.Context; +import android.support.annotation.IdRes; +import android.support.annotation.LayoutRes; +import android.view.View; +import android.widget.TextView; + +import com.pileproject.drive.programming.visual.block.NumberTextHolder; +import com.pileproject.drive.programming.visual.block.NumberTextViewDelegate; + +import java.math.BigDecimal; + + +/** + * SequenceBlock that has a TextView + * + * @author Tatsuya Iwanari + * @version 1.0 7-July-2013 + */ +public abstract class SequenceBlockHasNumberText extends SequenceBlock implements NumberTextHolder { + + private final NumberTextViewDelegate mDelegate; + + public SequenceBlockHasNumberText(Context context, @LayoutRes int layoutRes, @IdRes int textViewId) { + super(context, layoutRes); + + mDelegate = new NumberTextViewDelegate((TextView) findViewById(textViewId), this); + } + + /** + * Returns the value for those which do not understand radix points + */ + protected int getActionValue() { + return mDelegate.getActionValue(); + } + + @Override + public BigDecimal getValue() { + return mDelegate.getValue(); + } + + @Override + public void setValue(BigDecimal value) { + mDelegate.setValue(value); + } + + @Override + public String getValueAsString() { + return mDelegate.getValueAsString(); + } + + @Override + public void setValueAsString(String value) { + mDelegate.setValueAsString(value); + } + + @Override + public void enableTextView(boolean enabled) { + mDelegate.enableTextView(enabled); + } + + @Override + public void setOnLongClickTextViewListener(View.OnLongClickListener listener) { + mDelegate.setOnTextViewLongClickListener(listener); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/layout/BlockSpaceManagerBase.java b/app/src/main/java/com/pileproject/drive/programming/visual/layout/BlockSpaceManagerBase.java index 82c0b11..9cec58a 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/layout/BlockSpaceManagerBase.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/layout/BlockSpaceManagerBase.java @@ -23,6 +23,7 @@ import com.pileproject.drive.programming.visual.block.BlockBase; import java.util.ArrayList; +import java.util.List; /** * A manager of BlockSpaceLayout. @@ -126,7 +127,7 @@ public ArrayList loadUserProgramNames() { * e.g., can move or not * @param blocks */ - public abstract void addBlocks(ArrayList blocks); + public abstract void addBlocks(List blocks); private void placeBlocks(ArrayList data) { if (data.isEmpty()) { diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/layout/ExecutionSpaceManager.java b/app/src/main/java/com/pileproject/drive/programming/visual/layout/ExecutionSpaceManager.java index 17b1994..2eb4d06 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/layout/ExecutionSpaceManager.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/layout/ExecutionSpaceManager.java @@ -18,13 +18,12 @@ import android.content.Context; import android.view.View; import android.widget.LinearLayout.LayoutParams; -import android.widget.TextView; import com.pileproject.drive.programming.visual.block.BlockBase; -import com.pileproject.drive.programming.visual.block.NumTextHolder; +import com.pileproject.drive.programming.visual.block.NumberTextHolder; import com.pileproject.drive.view.FrameView; -import java.util.ArrayList; +import java.util.List; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; @@ -40,15 +39,14 @@ public ExecutionSpaceManager(Context context, BlockSpaceLayout layout) { } @Override - public void addBlocks(ArrayList blocks) { + public void addBlocks(List blocks) { + for (BlockBase block : blocks) { - if (block instanceof NumTextHolder) { - // set views not editable - TextView numText = ((NumTextHolder) block).getTextView(); - numText.setFocusable(false); - numText.setFocusableInTouchMode(false); - numText.setEnabled(false); + + if (block instanceof NumberTextHolder) { + ((NumberTextHolder) block).enableTextView(false); } + mLayout.addView(block, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); } } diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/layout/ProgrammingSpaceManager.java b/app/src/main/java/com/pileproject/drive/programming/visual/layout/ProgrammingSpaceManager.java index 31bc81b..3d4b7f2 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/layout/ProgrammingSpaceManager.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/layout/ProgrammingSpaceManager.java @@ -19,26 +19,21 @@ import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; import android.view.MotionEvent; import android.view.View; -import android.view.View.OnLongClickListener; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.animation.AlphaAnimation; import android.view.animation.CycleInterpolator; import android.widget.LinearLayout.LayoutParams; -import android.widget.TextView; import com.pileproject.drive.R; import com.pileproject.drive.programming.visual.block.BlockBase; -import com.pileproject.drive.programming.visual.block.NumTextHolder; -import com.pileproject.drive.util.development.Unit; -import com.pileproject.drive.util.math.Range; +import com.pileproject.drive.programming.visual.block.NumberTextHolder; import com.pileproject.drive.view.NumberSelectSeekBarView; import com.pileproject.drive.view.NumberSelectViewBase; -import java.util.ArrayList; +import java.util.List; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; @@ -46,7 +41,38 @@ * A manager of BlockSpaceLayout that helps users to make programs. */ public class ProgrammingSpaceManager extends BlockSpaceManagerBase { - public final OnTouchListener mMoveBlock = new OnTouchListener() { + + private final BlockOnTouchListener mOnTouchListener = new BlockOnTouchListener(); + + public ProgrammingSpaceManager(Context context, BlockSpaceLayout layout) { + super(context, layout); + } + + private void setListeners(BlockBase block) { + // set OnTouchListener to the block + block.setOnTouchListener(mOnTouchListener); + + if (block instanceof NumberTextHolder) { + ((NumberTextHolder) block).setOnLongClickTextViewListener( + new OnTouchNumTextListener(mContext, (NumberTextHolder) block)); + } + } + + @Override + public void addBlocks(List blocks) { + // emphasize block animation + AlphaAnimation alpha = new AlphaAnimation(1, 0); + alpha.setDuration(1000); + alpha.setInterpolator(new CycleInterpolator(3)); + + for (BlockBase block : blocks) { + setListeners(block); + mLayout.addView(block, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + block.setAnimation(alpha); + } + } + + private class BlockOnTouchListener implements OnTouchListener { int currentX; // the left position of this view (x coordinate) int currentY; // the top position of this view (y coordinate) int offsetX; // the x position of user's finger @@ -115,85 +141,35 @@ private void moveViewWithinItsParent(View view, int currentX, int currentY) { view.layout(currentX, currentY, currentX + view.getWidth(), currentY + view.getHeight()); } - }; - - public ProgrammingSpaceManager(Context context, BlockSpaceLayout layout) { - super(context, layout); } - private void setListeners(BlockBase block) { - // set OnTouchListener to the block - block.setOnTouchListener(mMoveBlock); - // set OnTouchListener to TextView - if (block instanceof NumTextHolder) { - TextView numText = ((NumTextHolder) block).getTextView(); - numText.setOnLongClickListener(new OnTouchNumTextListener(block)); - } - } + private class OnTouchNumTextListener implements View.OnLongClickListener { - @Override - public void addBlocks(ArrayList blocks) { - // emphasize block animation - AlphaAnimation alpha = new AlphaAnimation(1, 0); - alpha.setDuration(1000); - alpha.setInterpolator(new CycleInterpolator(3)); + private final Context context; + private final NumberTextHolder holder; - for (BlockBase block : blocks) { - setListeners(block); - mLayout.addView(block, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); - block.setAnimation(alpha); + public OnTouchNumTextListener(Context context, NumberTextHolder parent) { + this.context = context; + this.holder = parent; } - } - @Override - public void deleteAllBlocks() { - super.deleteAllBlocks(); - } + @Override + public boolean onLongClick(View v) { - /** - * A listener to pick a value. - */ - class OnTouchNumTextListener implements OnLongClickListener { - NumTextHolder mParent; + final NumberSelectViewBase numberSelectView = new NumberSelectSeekBarView(context, + holder.getValue(), holder.getRange(), holder.getPrecision(), holder.getUnit()); - public OnTouchNumTextListener(BlockBase parent) { - mParent = (NumTextHolder) parent; - } + new AlertDialog.Builder(context) + .setTitle(R.string.programming_pleaseSelectNumbers) + .setView(numberSelectView) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + holder.setValue(numberSelectView.getValue()); + } + }) + .show(); - @Override - public boolean onLongClick(View v) { - // get the old value - final int oldNum = mParent.getNum(); - - // create a new NumberPicker and set the old value - Integer[] digit = mParent.getDigit(); - - final int numOfIntegralDigits = digit[0]; - final int numOfDecimalDigits = digit[1]; - - final Range range = Range.closed(mParent.getMin(), mParent.getMax()); - final Unit unit = mParent.getUnit(); - - final NumberSelectViewBase numberSelectView = - new NumberSelectSeekBarView(mContext, range, unit, numOfIntegralDigits, numOfDecimalDigits); - - numberSelectView.setNum(oldNum); - - // create a new AlertDialog to pick the number - AlertDialog.Builder dialog = new AlertDialog.Builder(mContext); - dialog.setTitle(R.string.programming_pleaseSelectNumbers); - dialog.setView(numberSelectView); - dialog.setPositiveButton(R.string.ok, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - double rawNum = numberSelectView.getSelectedNum(); - int newNum = (int) (rawNum * Math.pow(10, numOfDecimalDigits)); - - // set new value - mParent.setNum(newNum); - } - }); - dialog.show(); return true; } } diff --git a/app/src/main/java/com/pileproject/drive/util/development/Unit.java b/app/src/main/java/com/pileproject/drive/util/development/Unit.java index 7314a2a..4dad2cc 100644 --- a/app/src/main/java/com/pileproject/drive/util/development/Unit.java +++ b/app/src/main/java/com/pileproject/drive/util/development/Unit.java @@ -16,66 +16,46 @@ package com.pileproject.drive.util.development; -import android.content.Context; +import android.content.res.Resources; import com.pileproject.drive.R; +import com.pileproject.drive.app.DriveApplication; + +import java.math.BigDecimal; +import java.util.Locale; /** * enumeration of unit for number selecting on blocks * * @author yusaku */ -public enum Unit { - Second, - Percentage, - NumberOfTimes, - Dimensionless; +public class Unit { + + public static final Unit Second = new Unit(); + public static final Unit Percentage = new Unit(); + public static final Unit NumberOfTimes = new Unit(); - /** - * get the unit string based on the value and selected unit - * - * @return string which contains the value and its unit - */ - public static String getUnitString( - Context context, Unit unit, String format, double value) { - final String formattedValue = String.format(format, value); + private static final Resources RESOURCES = DriveApplication.getContext().getResources(); - final int quantity = getQuantityOfValueInStringFormat(formattedValue, format); + private Unit() { - switch (unit) { - case Second: - return value + " " + context.getResources().getQuantityString(R.plurals.seconds, quantity); + } - case Percentage: - return value + " " + context.getResources().getString(R.string.percent); + public String getUnitString(BigDecimal value, int precision) { - case NumberOfTimes: - return context.getResources() - .getString(R.string.blocks_repeatNum, - Integer.parseInt(formattedValue.trim())); + if (this == Second) { + String format = "%." + precision + "f"; - default: - break; + return String.format(Locale.getDefault(), format, value) + RESOURCES.getString(R.string.second); } - return ""; - } + if (this == Percentage) { + String format = "%." + precision + "f"; - /** - * returns a quantity of formattedValue - * TODO: apply this for other locale than English - * See also: http://www.unicode - * .org/cldr/charts/latest/supplemental/language_plural_rules.html - * - * @param formattedValue - * @param format - * @return - */ - private static int getQuantityOfValueInStringFormat(String formattedValue, String format) { - if (formattedValue.equals(String.format(format, 1.0))) { - return 1; + return String.format(Locale.getDefault(), format, value) + RESOURCES.getString(R.string.percent); } - return 2; + // if this == NumberOfTimes + return RESOURCES.getString(R.string.blocks_repeatNum, value.intValue()); } } diff --git a/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java b/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java new file mode 100644 index 0000000..e30aa67 --- /dev/null +++ b/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011-2015 PILE Project, Inc. + * + * 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 com.pileproject.drive.util.string; + +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; + +public class ParseUtil { + + /** + * Parse a string as double in default locale (e.g., "1,234" means 1234E-3 in France). + * + * @throws NumberFormatException throw if the string makes no sense as number. + */ + public static double doubleValueOf(String value) { + + return doubleValueOf(value, Locale.getDefault()); + } + + /** + * Parse a string as double. + * This function takes locale into account (e.g., "1,234" means 1234E-3 in France). + * + * @throws NumberFormatException throw if the string makes no sense as number. + */ + public static double doubleValueOf(String value, Locale locale) throws NumberFormatException { + + try { + + NumberFormat format = NumberFormat.getNumberInstance(locale); + Number number = format.parse(value); + + return number.doubleValue(); + } catch (ParseException e) { + + throw new NumberFormatException("String '" + value + "' cannot be parsed as double value" + + " in locale " + locale); + } + } + + public static BigDecimal bigDecimalValueOf(String value) throws NumberFormatException { + + return bigDecimalValueOf(value, Locale.getDefault()); + } + + public static BigDecimal bigDecimalValueOf(String value, Locale locale) throws NumberFormatException { + + try { + DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getInstance(locale); + decimalFormat.setParseBigDecimal(true); + + Number number = decimalFormat.parse(value); + + return (BigDecimal) number; + } catch (ParseException e) { + + throw new NumberFormatException("String '" + value + "' cannot be parsed as double value" + + " in locale " + locale); + } + } +} diff --git a/app/src/main/java/com/pileproject/drive/view/NumberSelectSeekBarView.java b/app/src/main/java/com/pileproject/drive/view/NumberSelectSeekBarView.java index f2245a1..1761827 100644 --- a/app/src/main/java/com/pileproject/drive/view/NumberSelectSeekBarView.java +++ b/app/src/main/java/com/pileproject/drive/view/NumberSelectSeekBarView.java @@ -18,13 +18,14 @@ import android.content.Context; import android.view.LayoutInflater; -import android.view.View; import android.widget.SeekBar; import android.widget.TextView; import com.pileproject.drive.R; -import com.pileproject.drive.util.math.Range; import com.pileproject.drive.util.development.Unit; +import com.pileproject.drive.util.math.Range; + +import java.math.BigDecimal; /** * A view class which is used for number selecting on blocks. @@ -32,28 +33,19 @@ */ public class NumberSelectSeekBarView extends NumberSelectViewBase { - private final int mNumberOfIntegralDigits; - private final int mNumberOfDecimalDigits; + private final Range mRange; + private final int mPrecision; + private final SeekBar mSeekBar; private final Unit mUnit; - - private double mValue; - - private SeekBar mSeekBar; - private TextView mTextView; - + private final TextView mTextView; + private BigDecimal mValue; private final SeekBar.OnSeekBarChangeListener mListener = new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekbar, int value, boolean fromUser) { - // the value should be jacked up by the apparent minimum value of SeekBar - // when the value is displayed - mValue = toDoubleExpression(value) + mRange.getLowerBound(); + mValue = fromSeekBarExpression(value, mRange, mPrecision); - final String fmt = - "%" + mNumberOfIntegralDigits + "." + mNumberOfDecimalDigits + "f"; - - // use the proper unit based on the value - mTextView.setText(Unit.getUnitString(mContext, mUnit, fmt, mValue)); + mTextView.setText(mUnit.getUnitString(mValue, mPrecision)); } @Override @@ -68,72 +60,79 @@ public void onStopTrackingTouch(SeekBar arg0) { }; /** - * @param context - * @param range - a range users can select within this range - * @param unit - a unit of the value in this view - * @param numOfIntegralDigits - number of integral digits - * @param numOfDecimalDigits - number of decimal digits + * Constructor. + * @param context context + * @param value initial value + * @param range BigDecimal range. users can select within this range + * @param precision precision of the value + * @param unit unit of the value in this view */ - public NumberSelectSeekBarView(Context context, Range range, - Unit unit, int numOfIntegralDigits, int numOfDecimalDigits) { - super(context, range); + public NumberSelectSeekBarView(Context context, BigDecimal value, Range range, + int precision, Unit unit) { + super(context); mUnit = unit; + mRange = range; + mPrecision = precision; - mNumberOfIntegralDigits = numOfIntegralDigits; - mNumberOfDecimalDigits = numOfDecimalDigits; + LayoutInflater.from(context).inflate(R.layout.view_number_select_seekbar, this); + mTextView = (TextView) findViewById(R.id.programming_numberSelectView_valueText); + mSeekBar = (SeekBar) findViewById(R.id.programming_numberSelectView_seekBar); - View layout = LayoutInflater.from(context).inflate(R.layout.view_number_select_seekbar, this); + mSeekBar.setOnSeekBarChangeListener(mListener); + mSeekBar.setMax(toSeekBarExpression(mRange.getUpperBound(), mRange, precision)); - mTextView = (TextView) layout.findViewById(R.id.programming_numberSelectView_valueText); - mSeekBar = (SeekBar) layout.findViewById(R.id.programming_numberSelectView_seekBar); + setValue(value); + } - mSeekBar.setOnSeekBarChangeListener(mListener); + private static int toSeekBarExpression(BigDecimal value, Range range, int precision) { + + if (!range.contains(value)) { + return 0; + } - int min = toIntegerExpression(mRange.getLowerBound()); - int max = toIntegerExpression(mRange.getUpperBound()); + // if value = 0.2, range = (-1.0, 1.0), precision = 1, we want to get a result 12 + // because in seekbar expression, values in the range are converted as below + // (-1.0, -0.9, ..., 0.0, ..., 0.9, 1.0) => (0, 1, ..., 10, ..., 19, 20) - mSeekBar.setMax(max - min); + // so the following operations are needed: + // -1.0 => -10 + BigDecimal lowerMoved = range.getLowerBound().movePointRight(precision); + // 0.2 => 2 + BigDecimal valueMoved = value.movePointRight(precision); + // 2 - (-10) = 12 + BigDecimal ret = valueMoved.subtract(lowerMoved); + + return ret.intValue(); } - @Override - public void setNum(int num) { - double value = toDoubleExpression(num); + private static BigDecimal fromSeekBarExpression(int value, Range range, int precision) { - if (!mRange.contains(value)) { + BigDecimal valueMoved = new BigDecimal(value).movePointLeft(precision); + BigDecimal ret = valueMoved.add(range.getLowerBound()); + + if (!range.contains(ret)) { throw new RuntimeException("The value to set SeekBar is out of range " + - "(range: " + mRange + ", value: " + value + ")"); + "(range: " + range + ", value: " + value + ")"); } - // because minimum value of SeekBar is always 0, - // the value to set SeekBar should be subtracted by its "apparent" minimum - mValue = value - mRange.getLowerBound(); - - mSeekBar.setProgress(toIntegerExpression(mValue)); + return ret; } @Override - public double getSelectedNum() { + public BigDecimal getValue() { return mValue; } - /** - * Get rid of the decimal part. - * e.g., 1.15 -> 115 - * @param value a value in double - * @return a value in integer - */ - private int toIntegerExpression(double value) { - return (int) (value * Math.pow(10.0, mNumberOfDecimalDigits)); - } + @Override + public void setValue(BigDecimal value) { - /** - * Convert an integer value to double value. - * e.g., 115 -> 1.15 - * @param value a value in integer - * @return a value in double - */ - private double toDoubleExpression(int value) { - return value / Math.pow(10.0, mNumberOfDecimalDigits); + if (!mRange.contains(value)) { + throw new RuntimeException("The value to set SeekBar is out of range " + + "(range: " + mRange + ", value: " + value + ")"); + } + + mValue = value; + mSeekBar.setProgress(toSeekBarExpression(mValue, mRange, mPrecision)); } } diff --git a/app/src/main/java/com/pileproject/drive/view/NumberSelectViewBase.java b/app/src/main/java/com/pileproject/drive/view/NumberSelectViewBase.java index 42d7fc6..d40cf8c 100644 --- a/app/src/main/java/com/pileproject/drive/view/NumberSelectViewBase.java +++ b/app/src/main/java/com/pileproject/drive/view/NumberSelectViewBase.java @@ -19,31 +19,27 @@ import android.content.Context; import android.widget.LinearLayout; -import com.pileproject.drive.util.math.Range; +import java.math.BigDecimal; /** * An abstract view class which provides an interface of a view for selecting values. */ public abstract class NumberSelectViewBase extends LinearLayout { - final protected Range mRange; - protected Context mContext; - public NumberSelectViewBase(Context context, Range range) { + public NumberSelectViewBase(Context context) { super(context); - mContext = context; - mRange = range; } - /** - * A setter of a value. - * @param num a value to be set - */ - public abstract void setNum(int num); - /** * A getter of a value. * This is used to get the real value in double. * @return the selected value */ - public abstract double getSelectedNum(); + public abstract BigDecimal getValue(); + + /** + * A setter of a value. + * @param value a value to be set + */ + public abstract void setValue(BigDecimal value); } diff --git a/app/src/main/java/com/pileproject/drive/view/NumberSelectWheelScrollerView.java b/app/src/main/java/com/pileproject/drive/view/NumberSelectWheelScrollerView.java index f064500..cd019ad 100644 --- a/app/src/main/java/com/pileproject/drive/view/NumberSelectWheelScrollerView.java +++ b/app/src/main/java/com/pileproject/drive/view/NumberSelectWheelScrollerView.java @@ -26,6 +26,7 @@ import com.pileproject.drive.R; import com.pileproject.drive.util.math.Range; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -34,76 +35,132 @@ */ public class NumberSelectWheelScrollerView extends NumberSelectViewBase { private List mNumbers; - private int mIntegralPart, mDecimalPart; + + private final Range mRange; + private final int mScaledMaximum; + private final int mScaledMinimum; + + private final int mDigitCounts; + private final int mPrecision; + + private final OnValueChangeListener listener = new OnValueChangeListener() { + + @Override + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + + picker.setValue(newVal); + + int scaledValue = getScaledValue(); + + if (scaledValue > mScaledMaximum) { + changeToMax(); + } else if (scaledValue < mScaledMinimum) { + changeToMin(); + } + } + }; /** - * @param context an application context - * @param integralPart the length of integral part - * @param decimalPart the length of decimal part + * * Constructor. + * @param context context + * @param value initial value + * @param range BigDecimal range. users can select within this range + * @param precision precision of the value + * @param digitCount number of digits this view has */ - public NumberSelectWheelScrollerView(Context context, Range range, int integralPart, int decimalPart) { - super(context, range); + public NumberSelectWheelScrollerView(Context context, BigDecimal value, Range range, int precision, int digitCount) { + super(context); + + mPrecision = precision; + mDigitCounts = digitCount; - final double min = range.getLowerBound(); - final double max = range.getUpperBound(); + mRange = range; + mScaledMaximum = mRange.getUpperBound().movePointRight(mPrecision).intValue(); + mScaledMinimum = mRange.getLowerBound().movePointRight(mPrecision).intValue(); - // choose somewhat correct lengths - mIntegralPart = (integralPart > 0) ? integralPart : 3; - mDecimalPart = (decimalPart >= 0) ? decimalPart : 0; - mNumbers = new ArrayList<>(mIntegralPart + mDecimalPart); + mNumbers = new ArrayList<>(mDigitCounts); // create LayoutParams (width = 0, height = wrap_content, weight = 1.0f) LayoutParams lp = new LayoutParams(0, FrameLayout.LayoutParams.WRAP_CONTENT); lp.weight = 1.0f; - for (int i = 0; i < mIntegralPart + mDecimalPart; i++) { - NumberPicker picker = new NumberPicker(context); - - // allow numbers 0 to 9 - picker.setMaxValue(9); - picker.setMinValue(0); - - // hide software keyboard - picker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); - picker.setOnValueChangedListener(new OnValueChangeListener() { - @Override - public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - int index = mNumbers.indexOf(picker); - picker.setValue(oldVal); // reset old values for check - - double raw = getSelectedNum(); - - // prevent overflow - if ((oldVal + 1) % 10 == newVal) { - // check the new value is larger than the maximum value or not - if (raw + Math.pow(10, mIntegralPart - (index + 1)) > max) { - changeToMax(); // change value to maximum - return; - } - } - // prevent underflow - else { - // check the new value is lower than the minimum value or not - if (raw - Math.pow(10, mIntegralPart - (index + 1)) < min) { - changeToMin(); // change value to minimum - return; - } - } - picker.setValue(newVal); - } - }); + for (int i = 0; i < mDigitCounts; i++) { + NumberPicker picker = createNumberPicker(context); + this.addView(picker, lp); mNumbers.add(picker); } - if (mDecimalPart != 0) { + if (mPrecision != 0) { // add period between integral part and decimal part TextView period = new TextView(context); period.setText(R.string.select_number_period); // period.setTextSize(R.dimen.period); lp.gravity = Gravity.CENTER; - this.addView(period, mIntegralPart, lp); + int insertIndex = mDigitCounts - mPrecision; + this.addView(period, insertIndex, lp); + } + + setValue(value); + } + + @Override + public BigDecimal getValue() { + return new BigDecimal(getScaledValue()).movePointLeft(mPrecision); + } + + @Override + public void setValue(BigDecimal value) { + setScaledValue(value.movePointRight(mPrecision).intValue()); + } + + /** + * Change the number of this view to maximum value. + */ + public void changeToMax() { + setScaledValue(mScaledMaximum); + } + + /** + * Change the number of this view to minimum value. + */ + public void changeToMin() { + setScaledValue(mScaledMinimum); + } + + private NumberPicker createNumberPicker(Context context) { + + NumberPicker picker = new NumberPicker(context); + + // allow numbers 0 to 9 + picker.setMaxValue(9); + picker.setMinValue(0); + + // hide software keyboard + picker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); + picker.setOnValueChangedListener(listener); + + return picker; + } + + private int getScaledValue() { + int scaledResult = 0; + + for (int i = 0; i < mDigitCounts; ++i) { + int digit = mNumbers.get(mDigitCounts - (i + 1)).getValue(); + + scaledResult += digit * Math.pow(10, i); + } + + return scaledResult; + } + + private void setScaledValue(int scaledValue) { + for (int i = 0; i < mDigitCounts; ++i) { + int digit = (int) Math.pow(10, mDigitCounts - (i + 1)); + mNumbers.get(i).setValue(scaledValue / digit); + scaledValue %= digit; } } @@ -111,6 +168,7 @@ public void onValueChange(NumberPicker picker, int oldVal, int newVal) { * Carry up count. * @param index the index of the target number */ + @Deprecated public void carryUp(int index) { if (index < 0) { return; @@ -130,6 +188,7 @@ public void carryUp(int index) { * Carry down count. * @param index the index of the target number */ + @Deprecated public void carryDown(int index) { if (index < 0) { return; @@ -144,47 +203,4 @@ public void carryDown(int index) { picker.setValue(picker.getValue() - 1); } } - - @Override - public double getSelectedNum() { - double result = 0; - for (int i = 0; i < mIntegralPart + mDecimalPart; i++) - result += mNumbers.get(i).getValue() * Math.pow(10, mIntegralPart - (i + 1)); - return result; - } - - @Override - public void setNum(int num) { - // set the number to NumberPicker - for (int i = 0; i < mIntegralPart + mDecimalPart; i++) { - int digit = (int) Math.pow(10, mIntegralPart + mDecimalPart - (i + 1)); - mNumbers.get(i).setValue(num / digit); - num %= digit; - } - } - - private void changeTo(double target) { - int num = (int) (target * Math.pow(10, mDecimalPart)); - for (int i = 0; i < mIntegralPart + mDecimalPart; i++) { - int digit = (int) Math.pow(10, mIntegralPart + mDecimalPart - (i + 1)); - mNumbers.get(i).setValue(num / digit); - num %= digit; - } - } - - /** - * Change the number of this view to maximum value. - */ - public void changeToMax() { - final double max = mRange.getUpperBound(); - changeTo(max); - } - - /** - * Change the number of this view to minimum value. - */ - public void changeToMin() { - final double min = mRange.getLowerBound(); - changeTo(min); - } } diff --git a/app/src/main/res/drawable-hdpi/icon_while_forever.png b/app/src/main/res/drawable-hdpi/icon_loop.png similarity index 100% rename from app/src/main/res/drawable-hdpi/icon_while_forever.png rename to app/src/main/res/drawable-hdpi/icon_loop.png diff --git a/app/src/main/res/drawable-hdpi/icon_while_num.png b/app/src/main/res/drawable-hdpi/icon_n_times.png similarity index 100% rename from app/src/main/res/drawable-hdpi/icon_while_num.png rename to app/src/main/res/drawable-hdpi/icon_n_times.png diff --git a/app/src/main/res/layout/block_while_forever.xml b/app/src/main/res/layout/block_loop.xml similarity index 96% rename from app/src/main/res/layout/block_while_forever.xml rename to app/src/main/res/layout/block_loop.xml index 805bd20..2cd5072 100644 --- a/app/src/main/res/layout/block_while_forever.xml +++ b/app/src/main/res/layout/block_loop.xml @@ -33,6 +33,6 @@ android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:contentDescription="@string/noImage" - android:src="@drawable/icon_while_forever"/> + android:src="@drawable/icon_loop"/> \ No newline at end of file diff --git a/app/src/main/res/layout/block_while_num.xml b/app/src/main/res/layout/block_n_times.xml similarity index 97% rename from app/src/main/res/layout/block_while_num.xml rename to app/src/main/res/layout/block_n_times.xml index fde8a48..7571e14 100644 --- a/app/src/main/res/layout/block_while_num.xml +++ b/app/src/main/res/layout/block_n_times.xml @@ -47,6 +47,6 @@ android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:contentDescription="@string/noImage" - android:src="@drawable/icon_while_num"/> + android:src="@drawable/icon_n_times"/> \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 83c5c86..33590ed 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -30,6 +30,7 @@ ぶんき くりかえし % + びょう エラー Bluetoothきのうをオンにしました Bluetooth きのうがオンになっていません @@ -62,8 +63,8 @@ - ずっとくりかえす - □かいくりかえす + ずっとくりかえす + □かいくりかえす くりかえしをぬける %d かい diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 84f7938..5cfa1d3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -30,6 +30,7 @@ Selection Repetition % + s Error Turned on Bluetooth Please turn on Bluetooth. @@ -62,14 +63,14 @@ - Repeat forever - Repeat □times + Repeat forever + Repeat □times Exit a loop Repeats: %d - 0.0 + 0 0 Repeat @@ -85,7 +86,7 @@ Execute Screen Connecting... - This device doesn\'t have Bluetooth function. + This device does not have Bluetooth function. Please wait for a while. Error: Failed to connect the device. Execution starts. diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/activity/NxtBlockListActivity.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/activity/NxtBlockListActivity.java index c36ce60..30ac336 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/activity/NxtBlockListActivity.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/activity/NxtBlockListActivity.java @@ -16,9 +16,9 @@ package com.pileproject.drive.programming.visual.activity; +import com.pileproject.drive.programming.visual.block.repetition.LoopBlock; +import com.pileproject.drive.programming.visual.block.repetition.NTimesBlock; import com.pileproject.drive.programming.visual.block.repetition.RepetitionBreakBlock; -import com.pileproject.drive.programming.visual.block.repetition.WhileForeverBlock; -import com.pileproject.drive.programming.visual.block.repetition.WhileNumBlock; import com.pileproject.drive.programming.visual.block.selection.IfNxtIsOutOfLineBlock; import com.pileproject.drive.programming.visual.block.selection.IfNxtWasTouchedBlock; import com.pileproject.drive.programming.visual.block.selection.IfThereWasALargeSoundBlock; @@ -43,8 +43,8 @@ protected BlockClassHolder[][] getBlockIcons() { new BlockClassHolder(SetLeftMotorSpeedBlock.class), new BlockClassHolder(SetRightMotorSpeedBlock.class), }, { - new BlockClassHolder(WhileForeverBlock.class), - new BlockClassHolder(WhileNumBlock.class), + new BlockClassHolder(LoopBlock.class), + new BlockClassHolder(NTimesBlock.class), new BlockClassHolder(RepetitionBreakBlock.class), }, { new BlockClassHolder(IfNxtIsOutOfLineBlock.class), diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/selection/IfNxtIsOutOfLineBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/selection/IfNxtIsOutOfLineBlock.java index c5a286a..958564e 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/selection/IfNxtIsOutOfLineBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/selection/IfNxtIsOutOfLineBlock.java @@ -17,10 +17,8 @@ package com.pileproject.drive.programming.visual.block.selection; import android.content.Context; -import android.view.LayoutInflater; import com.pileproject.drive.R; -import com.pileproject.drive.execution.ExecutionCondition; import com.pileproject.drive.execution.MachineController; import com.pileproject.drive.execution.NxtController; import com.pileproject.drive.preferences.BlockPreferences; @@ -38,17 +36,15 @@ public class IfNxtIsOutOfLineBlock extends SelectionBlock { private int mThreshold; public IfNxtIsOutOfLineBlock(Context context) { - super(context); - LayoutInflater.from(context).inflate(R.layout.block_if_nxt_is_out_of_line, this); + super(context, R.layout.block_if_nxt_is_out_of_line); mThreshold = BlockPreferences.get(context).getLineSensorThreshold(); } @Override - public int action(MachineController controller, ExecutionCondition condition) { + protected boolean evaluateCondition(MachineController controller) { // comment is weird. // getLightPercent returns tenfold value - condition.pushSelectionResult(((NxtController) controller).getLineSensorValue() > mThreshold * 10); - return 0; + return ((NxtController) controller).getLineSensorValue() > mThreshold * 10; } } diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/selection/IfNxtWasTouchedBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/selection/IfNxtWasTouchedBlock.java index 11d8ecc..e492d62 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/selection/IfNxtWasTouchedBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/selection/IfNxtWasTouchedBlock.java @@ -17,10 +17,8 @@ package com.pileproject.drive.programming.visual.block.selection; import android.content.Context; -import android.view.LayoutInflater; import com.pileproject.drive.R; -import com.pileproject.drive.execution.ExecutionCondition; import com.pileproject.drive.execution.MachineController; import com.pileproject.drive.execution.NxtController; @@ -33,13 +31,11 @@ public class IfNxtWasTouchedBlock extends SelectionBlock { public IfNxtWasTouchedBlock(Context context) { - super(context); - LayoutInflater.from(context).inflate(R.layout.block_if_nxt_was_touched, this); + super(context, R.layout.block_if_nxt_was_touched); } @Override - public int action(MachineController controller, ExecutionCondition condition) { - condition.pushSelectionResult(((NxtController) controller).getTouchSensorValue()); - return 0; + protected boolean evaluateCondition(MachineController controller) { + return ((NxtController) controller).getTouchSensorValue(); } } diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/selection/IfThereWasALargeSoundBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/selection/IfThereWasALargeSoundBlock.java index 723f988..a2cdbea 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/selection/IfThereWasALargeSoundBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/selection/IfThereWasALargeSoundBlock.java @@ -17,10 +17,8 @@ package com.pileproject.drive.programming.visual.block.selection; import android.content.Context; -import android.view.LayoutInflater; import com.pileproject.drive.R; -import com.pileproject.drive.execution.ExecutionCondition; import com.pileproject.drive.execution.MachineController; import com.pileproject.drive.execution.NxtController; import com.pileproject.drive.preferences.BlockPreferences; @@ -38,17 +36,15 @@ public class IfThereWasALargeSoundBlock extends SelectionBlock { private int mThreshold; public IfThereWasALargeSoundBlock(Context context) { - super(context); - LayoutInflater.from(context).inflate(R.layout.block_if_there_was_a_large_sound, this); + super(context, R.layout.block_if_there_was_a_large_sound); mThreshold = BlockPreferences.get(context).getSoundSensorThreshold(); } @Override - public int action(MachineController controller, ExecutionCondition condition) { + protected boolean evaluateCondition(MachineController controller) { // need multiply 10 because getdB returns 10 times value // the comment is messed up - condition.pushSelectionResult(((NxtController) controller).getSoundSensorValue() > mThreshold * 10); - return 0; + return ((NxtController) controller).getSoundSensorValue() > mThreshold * 10; } } diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/BackwardSecBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/BackwardSecBlock.java index 9dd9aab..8050694 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/BackwardSecBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/BackwardSecBlock.java @@ -17,17 +17,15 @@ package com.pileproject.drive.programming.visual.block.sequence; import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; import com.pileproject.drive.R; import com.pileproject.drive.execution.ExecutionCondition; import com.pileproject.drive.execution.MachineController; import com.pileproject.drive.execution.NxtController; import com.pileproject.drive.util.development.Unit; +import com.pileproject.drive.util.math.Range; -import java.util.Locale; +import java.math.BigDecimal; /** * Backward for a while @@ -35,47 +33,32 @@ * @author yusaku * @version 1.0 7-July-2013 */ -public class BackwardSecBlock extends SequenceBlockHasNumText { +public class BackwardSecBlock extends SequenceBlockHasNumberText { - public BackwardSecBlock(Context context) { - super(context); - - View layout = LayoutInflater.from(context).inflate(R.layout.block_backward_sec, this); - numText = (TextView) layout.findViewById(R.id.block_numText); - } - - @Override - public int getNum() { - double raw = Double.parseDouble(numText.getText().toString()); - return (int) (raw * 1000); - } + // TODO: set from preference + private static final Range range = Range.closed(BigDecimal.ZERO, new BigDecimal(3)); - @Override - public void setNum(int num) { - double raw = num / 1000.0; - numText.setText(String.format(Locale.ENGLISH, "%.3f", raw)); - } + // TODO: set from preference + private static final int PRECISION = 3; - @Override - public Integer[] getDigit() { - return new Integer[]{1, 3}; + public BackwardSecBlock(Context context) { + super(context, R.layout.block_backward_sec, R.id.block_numText); } @Override - public double getMax() { - return 3.0; + public int getPrecision() { + return PRECISION; } @Override - public double getMin() { - return 0.0; + public Range getRange() { + return range; } @Override - public int action( - MachineController controller, ExecutionCondition condition) { + public int action(MachineController controller, ExecutionCondition condition) { ((NxtController) controller).moveBackward(); - return getNum(); + return getActionValue(); } @Override diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/ForwardSecBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/ForwardSecBlock.java index 5114997..c390c27 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/ForwardSecBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/ForwardSecBlock.java @@ -17,17 +17,15 @@ package com.pileproject.drive.programming.visual.block.sequence; import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; import com.pileproject.drive.R; import com.pileproject.drive.execution.ExecutionCondition; import com.pileproject.drive.execution.MachineController; import com.pileproject.drive.execution.NxtController; import com.pileproject.drive.util.development.Unit; +import com.pileproject.drive.util.math.Range; -import java.util.Locale; +import java.math.BigDecimal; /** * Forward for a while @@ -35,48 +33,32 @@ * @author yusaku * @version 1.0 7-July-2013 */ -public class ForwardSecBlock extends SequenceBlockHasNumText { +public class ForwardSecBlock extends SequenceBlockHasNumberText { - public ForwardSecBlock(Context context) { - super(context); - // Create view defined as the layout XML by LayoutInflater - // Set this view to LayoutInflater#inflate() 2nd argument - View layout = LayoutInflater.from(context).inflate(R.layout.block_forward_sec, this); - numText = (TextView) layout.findViewById(R.id.block_numText); - } + // TODO: set from preference + private static final Range range = Range.closed(BigDecimal.ZERO, new BigDecimal(3)); - @Override - public int getNum() { - double raw = Double.parseDouble(numText.getText().toString()); - return (int) (raw * 1000); - } + // TODO: set from preference + private static final int PRECISION = 3; - @Override - public void setNum(int num) { - double raw = (double) num / 1000.0; - numText.setText(String.format(Locale.ENGLISH, "%.3f", raw)); - } - - @Override - public Integer[] getDigit() { - return new Integer[]{1, 3}; + public ForwardSecBlock(Context context) { + super(context, R.layout.block_forward_sec, R.id.block_numText); } @Override - public double getMax() { - return 3.0; + public int getPrecision() { + return PRECISION; } @Override - public double getMin() { - return 0.000; + public Range getRange() { + return range; } @Override - public int action( - MachineController controller, ExecutionCondition condition) { + public int action(MachineController controller, ExecutionCondition condition) { ((NxtController) controller).moveForward(); - return getNum(); + return getActionValue(); } @Override diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetLeftMotorSpeedBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetLeftMotorSpeedBlock.java index 76e8db8..d6f01f7 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetLeftMotorSpeedBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetLeftMotorSpeedBlock.java @@ -17,15 +17,15 @@ package com.pileproject.drive.programming.visual.block.sequence; import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; import com.pileproject.drive.R; import com.pileproject.drive.execution.ExecutionCondition; import com.pileproject.drive.execution.MachineController; import com.pileproject.drive.execution.NxtController; import com.pileproject.drive.util.development.Unit; +import com.pileproject.drive.util.math.Range; + +import java.math.BigDecimal; /** * Set left motor power @@ -33,43 +33,31 @@ * @author yusaku * @version 1.0 7-July-2013 */ -public class SetLeftMotorSpeedBlock extends SequenceBlockHasNumText { +public class SetLeftMotorSpeedBlock extends SequenceBlockHasNumberText { - public SetLeftMotorSpeedBlock(Context context) { - super(context); - View layout = LayoutInflater.from(context).inflate(R.layout.block_set_left_motor_speed, this); - numText = (TextView) layout.findViewById(R.id.block_numText); - } + // TODO: set from preference + private static final Range range = Range.closed(BigDecimal.ZERO, new BigDecimal(100)); - @Override - public int getNum() { - return Integer.parseInt(numText.getText().toString()); - } + // TODO: set from preference + private static final int PRECISION = 1; - @Override - public void setNum(int num) { - numText.setText(String.valueOf(num)); - } - - @Override - public Integer[] getDigit() { - return new Integer[]{3, 0}; + public SetLeftMotorSpeedBlock(Context context) { + super(context, R.layout.block_set_left_motor_speed, R.id.block_numText); } @Override - public double getMax() { - return 100; + public int getPrecision() { + return PRECISION; } @Override - public double getMin() { - return 0; + public Range getRange() { + return range; } @Override - public int action( - MachineController controller, ExecutionCondition condition) { - ((NxtController) controller).setMotorPower(NxtController.MotorKind.LeftMotor, getNum()); + public int action(MachineController controller, ExecutionCondition condition) { + ((NxtController) controller).setMotorPower(NxtController.MotorKind.LeftMotor, getValue().doubleValue()); return 0; } diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetRightMotorSpeedBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetRightMotorSpeedBlock.java index d6b7fac..dcc9c11 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetRightMotorSpeedBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetRightMotorSpeedBlock.java @@ -17,15 +17,15 @@ package com.pileproject.drive.programming.visual.block.sequence; import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; import com.pileproject.drive.R; import com.pileproject.drive.execution.ExecutionCondition; import com.pileproject.drive.execution.MachineController; import com.pileproject.drive.execution.NxtController; import com.pileproject.drive.util.development.Unit; +import com.pileproject.drive.util.math.Range; + +import java.math.BigDecimal; /** * Set right motor power @@ -33,43 +33,31 @@ * @author yusaku * @version 1.0 7-July-2013 */ -public class SetRightMotorSpeedBlock extends SequenceBlockHasNumText { +public class SetRightMotorSpeedBlock extends SequenceBlockHasNumberText { - public SetRightMotorSpeedBlock(Context context) { - super(context); - View layout = LayoutInflater.from(context).inflate(R.layout.block_set_right_motor_speed, this); - numText = (TextView) layout.findViewById(R.id.block_numText); - } - - @Override - public int getNum() { - return Integer.parseInt(numText.getText().toString()); - } + // TODO: set from preference + private static final Range range = Range.closed(BigDecimal.ZERO, new BigDecimal(100)); - @Override - public void setNum(int num) { - numText.setText(String.valueOf(num)); - } + // TODO: set from preference + private static final int PRECISION = 1; - @Override - public Integer[] getDigit() { - return new Integer[]{3, 0}; + public SetRightMotorSpeedBlock(Context context) { + super(context, R.layout.block_set_right_motor_speed, R.id.block_numText); } @Override - public double getMax() { - return 100.0; + public int getPrecision() { + return PRECISION; } @Override - public double getMin() { - return 0.0; + public Range getRange() { + return range; } @Override - public int action( - MachineController controller, ExecutionCondition condition) { - ((NxtController) controller).setMotorPower(NxtController.MotorKind.RightMotor, getNum()); + public int action(MachineController controller, ExecutionCondition condition) { + ((NxtController) controller).setMotorPower(NxtController.MotorKind.RightMotor, getValue().doubleValue()); return 0; } diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/StopSecBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/StopSecBlock.java index d8ae14a..97b44f6 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/StopSecBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/StopSecBlock.java @@ -17,16 +17,14 @@ package com.pileproject.drive.programming.visual.block.sequence; import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; import com.pileproject.drive.R; import com.pileproject.drive.execution.ExecutionCondition; import com.pileproject.drive.execution.MachineController; import com.pileproject.drive.util.development.Unit; +import com.pileproject.drive.util.math.Range; -import java.util.Locale; +import java.math.BigDecimal; /** * Stop for a while @@ -34,46 +32,32 @@ * @author yusaku * @version 1.0 7-July-2013 */ -public class StopSecBlock extends SequenceBlockHasNumText { +public class StopSecBlock extends SequenceBlockHasNumberText { - public StopSecBlock(Context context) { - super(context); - View layout = LayoutInflater.from(context).inflate(R.layout.block_stop_sec, this); - numText = (TextView) layout.findViewById(R.id.block_numText); - } + // TODO: set from preference + private static final Range range = Range.closed(BigDecimal.ZERO, new BigDecimal(3)); - @Override - public int getNum() { - double raw = Double.parseDouble(numText.getText().toString()); - return (int) (raw * 1000.0); - } + // TODO: set from preference + private static final int PRECISION = 3; - @Override - public void setNum(int num) { - double raw = num / 1000.0; - numText.setText(String.format(Locale.ENGLISH, "%.3f", raw)); - } - - @Override - public Integer[] getDigit() { - return new Integer[]{1, 3}; + public StopSecBlock(Context context) { + super(context, R.layout.block_stop_sec, R.id.block_numText); } @Override - public double getMax() { - return 3.0; + public int getPrecision() { + return PRECISION; } @Override - public double getMin() { - return 0.0; + public Range getRange() { + return range; } @Override - public int action( - MachineController controller, ExecutionCondition condition) { + public int action(MachineController controller, ExecutionCondition condition) { controller.halt(); - return getNum(); + return getActionValue(); } @Override diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnLeftSecBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnLeftSecBlock.java index 98945fc..3876dc4 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnLeftSecBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnLeftSecBlock.java @@ -17,17 +17,15 @@ package com.pileproject.drive.programming.visual.block.sequence; import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; import com.pileproject.drive.R; import com.pileproject.drive.execution.ExecutionCondition; import com.pileproject.drive.execution.MachineController; import com.pileproject.drive.execution.NxtController; import com.pileproject.drive.util.development.Unit; +import com.pileproject.drive.util.math.Range; -import java.util.Locale; +import java.math.BigDecimal; /** * Turn left for a while @@ -35,46 +33,33 @@ * @author yusaku * @version 1.0 7-July-2013 */ -public class TurnLeftSecBlock extends SequenceBlockHasNumText { +public class TurnLeftSecBlock extends SequenceBlockHasNumberText { - public TurnLeftSecBlock(Context context) { - super(context); - View layout = LayoutInflater.from(context).inflate(R.layout.block_turn_left_sec, this); - numText = (TextView) layout.findViewById(R.id.block_numText); - } + // TODO: set from preference + private static final Range range = Range.closed(BigDecimal.ZERO, new BigDecimal(3)); - @Override - public int getNum() { - double raw = Double.parseDouble(numText.getText().toString()); - return (int) (raw * 1000); - } + // TODO: set from preference + private static final int PRECISION = 3; - @Override - public void setNum(int num) { - double raw = num / 1000.0; - numText.setText(String.format(Locale.ENGLISH, "%.3f", raw)); - } - - @Override - public Integer[] getDigit() { - return new Integer[]{1, 3}; + public TurnLeftSecBlock(Context context) { + super(context, R.layout.block_turn_left_sec, R.id.block_numText); } @Override - public double getMax() { - return 3.0; + public int getPrecision() { + return PRECISION; } @Override - public double getMin() { - return 0.0; + public Range getRange() { + return range; } @Override public int action( MachineController controller, ExecutionCondition condition) { ((NxtController) controller).turnLeft(); - return getNum(); + return getActionValue(); } @Override diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnRightSecBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnRightSecBlock.java index 61f020f..3e5c33c 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnRightSecBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnRightSecBlock.java @@ -17,17 +17,15 @@ package com.pileproject.drive.programming.visual.block.sequence; import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; import com.pileproject.drive.R; import com.pileproject.drive.execution.ExecutionCondition; import com.pileproject.drive.execution.MachineController; import com.pileproject.drive.execution.NxtController; import com.pileproject.drive.util.development.Unit; +import com.pileproject.drive.util.math.Range; -import java.util.Locale; +import java.math.BigDecimal; /** * Turn right for a while @@ -35,46 +33,33 @@ * @author yusaku * @version 1.0 7-July-2013 */ -public class TurnRightSecBlock extends SequenceBlockHasNumText { +public class TurnRightSecBlock extends SequenceBlockHasNumberText { - public TurnRightSecBlock(Context context) { - super(context); - View layout = LayoutInflater.from(context).inflate(R.layout.block_turn_right_sec, this); - numText = (TextView) layout.findViewById(R.id.block_numText); - } + // TODO: set from preference + private static final Range range = Range.closed(BigDecimal.ZERO, new BigDecimal(3)); - @Override - public int getNum() { - double raw = Double.parseDouble(numText.getText().toString()); - return (int) (raw * 1000); - } + // TODO: set from preference + private static final int PRECISION = 3; - @Override - public void setNum(int num) { - double raw = num / 1000.0; - numText.setText(String.format(Locale.ENGLISH, "%.3f", raw)); - } - - @Override - public Integer[] getDigit() { - return new Integer[]{1, 3}; + public TurnRightSecBlock(Context context) { + super(context, R.layout.block_turn_right_sec, R.id.block_numText); } @Override - public double getMax() { - return 3.0; + public int getPrecision() { + return PRECISION; } @Override - public double getMin() { - return 0.0; + public Range getRange() { + return range; } @Override public int action( MachineController controller, ExecutionCondition condition) { ((NxtController) controller).turnRight(); - return getNum(); + return getActionValue(); } @Override diff --git a/app/src/test/java/com/pileproject/drive/util/string/ParseUtilTest.java b/app/src/test/java/com/pileproject/drive/util/string/ParseUtilTest.java new file mode 100644 index 0000000..0a54daf --- /dev/null +++ b/app/src/test/java/com/pileproject/drive/util/string/ParseUtilTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011-2015 PILE Project, Inc. + * + * 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 com.pileproject.drive.util.string; + +import org.junit.Test; + +import java.util.Locale; + +import static org.junit.Assert.assertEquals; + +public class ParseUtilTest { + + @Test + public void testDoubleValueOf_whenLocaleIsJapan_thenRegardsDotAsRadixPoint() throws Exception { + + assertEquals(1.234, ParseUtil.doubleValueOf("1.234", Locale.JAPAN), 0.0); + } + + @Test + public void testDoubleValueOf_whenLocaleIsEnglish_thenRegardsDotAsRadixPoint() throws Exception { + + assertEquals(1.234, ParseUtil.doubleValueOf("1.234", Locale.ENGLISH), 0.0); + } + + @Test + public void testDoubleValueOf_whenLocaleIsFrance_thenRegardsCommaAsRadixPoint() throws Exception { + + assertEquals(1.234, ParseUtil.doubleValueOf("1,234", Locale.FRANCE), 0.0); + } + + @Test(expected = NumberFormatException.class) + public void testDoubleValueOf_whenStringIsNotNumber_thenThrowsException() throws Exception { + ParseUtil.doubleValueOf("foobar"); + } +} \ No newline at end of file From eb7939bf11d900389e98673142b700e3229ae928 Mon Sep 17 00:00:00 2001 From: Yusaku Mandai Date: Thu, 29 Sep 2016 22:12:08 +0900 Subject: [PATCH 2/6] Fix PR according to the comments on #35 * remove UNDO in BlockFactory.java * move FOREVER_WHILE_OFFSET in RepetitionBlock.java to ExecutionCondition.java * add Javadocs on NumberTextDelegate * change the signature of BlockSpaceManagerBase#placeBlock (ArrayList to List) * rename OnTouchNumTextListener to OnTouchNumberTextListener * remove OnNumberTextListener#context and rename holder to mHolder * rename Unit#getUnitString to decorateValue and introduce new class NumberUtil --- .../drive/execution/ExecutionCondition.java | 34 ++++++++--- .../visual/block/BlockFactory.java | 7 +-- .../visual/block/NumberTextViewDelegate.java | 18 +++++- .../visual/block/repetition/LoopBlock.java | 3 +- .../visual/block/repetition/NTimesBlock.java | 6 +- .../block/repetition/RepetitionBlock.java | 1 - .../visual/layout/BlockSpaceManagerBase.java | 2 +- .../layout/ProgrammingSpaceManager.java | 20 +++--- .../drive/util/development/Unit.java | 38 +++++++++--- .../drive/util/string/NumberUtil.java | 61 +++++++++++++++++++ .../drive/util/string/ParseUtil.java | 18 +++++- .../drive/view/NumberSelectSeekBarView.java | 2 +- .../view/NumberSelectWheelScrollerView.java | 2 +- .../sequence/SetLeftMotorSpeedBlock.java | 2 +- .../sequence/SetRightMotorSpeedBlock.java | 2 +- .../block/sequence/TurnLeftSecBlock.java | 3 +- .../block/sequence/TurnRightSecBlock.java | 3 +- 17 files changed, 168 insertions(+), 54 deletions(-) create mode 100644 app/src/main/java/com/pileproject/drive/util/string/NumberUtil.java diff --git a/app/src/main/java/com/pileproject/drive/execution/ExecutionCondition.java b/app/src/main/java/com/pileproject/drive/execution/ExecutionCondition.java index 4a0fb8b..72c37c1 100644 --- a/app/src/main/java/com/pileproject/drive/execution/ExecutionCondition.java +++ b/app/src/main/java/com/pileproject/drive/execution/ExecutionCondition.java @@ -16,10 +16,7 @@ package com.pileproject.drive.execution; - import com.pileproject.drive.programming.visual.block.BlockBase; -import com.pileproject.drive.programming.visual.block.repetition.RepetitionEndBlock; -import com.pileproject.drive.programming.visual.block.repetition.WhileForeverBlock; import java.util.ArrayList; import java.util.Collections; @@ -31,6 +28,8 @@ * A container class that has the condition of program execution. */ public class ExecutionCondition { + private static final int FOREVER_WHILE_OFFSET = -1000; + private Stack mWhileStack; private Stack mIfStack; private int mBeginningOfCurrentLoop; @@ -147,10 +146,29 @@ public int sizeOfSelectionResult() { * Push the index of the beginning block of the current loop to a stack. * @param index the index of the beginning block */ - public void pushBeginningOfLoop(int index) { + private void pushBeginningOfLoop(int index) { mWhileStack.push(index); mBeginningOfCurrentLoop = index >= 0 ? - index : index - WhileForeverBlock.FOREVER_WHILE_OFFSET; + index : index - FOREVER_WHILE_OFFSET; + } + + /** + * Enters infinite loop. + */ + public void enterInfiniteLoop() { + int index = getProgramCount(); + pushBeginningOfLoop(index + FOREVER_WHILE_OFFSET); // push with offset + } + + /** + * Enters N-times loop. + * @param count number of times this loop repeats. + */ + public void enterNTimesLoop(int count) { + int index = getProgramCount(); + for (int i = 1; i < count; i++) { + pushBeginningOfLoop(index); + } } /** @@ -160,7 +178,7 @@ public void reachEndOfLoop() { if (mWhileStack.isEmpty()) return ; int index = mWhileStack.peek() >= 0 ? - mWhileStack.peek() : mWhileStack.peek() - WhileForeverBlock.FOREVER_WHILE_OFFSET; + mWhileStack.peek() : mWhileStack.peek() - FOREVER_WHILE_OFFSET; // the loop has already finished if (mBeginningOfCurrentLoop != index) { @@ -189,7 +207,7 @@ public void breakLoop() { // update index if (!mWhileStack.isEmpty()) { mBeginningOfCurrentLoop = mWhileStack.peek() >= 0 ? - mWhileStack.peek() : mWhileStack.peek() - WhileForeverBlock.FOREVER_WHILE_OFFSET; + mWhileStack.peek() : mWhileStack.peek() - FOREVER_WHILE_OFFSET; } else { mBeginningOfCurrentLoop = -1; } @@ -199,7 +217,7 @@ public void breakLoop() { // move to the end of the current loop for (; mBlocks.size() >= mProgramCount; ++mProgramCount) { - if (mBlocks.get(mProgramCount).getKind() == RepetitionEndBlock.class) break; + if (mBlocks.get(mProgramCount).getKind() == BlockBase.BlockKind.REPETITION_END) break; } } } diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java index 0366bba..3f49b61 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java @@ -38,8 +38,6 @@ public class BlockFactory { public static final int SEQUENCE = 0; public static final int REPETITION = 1; public static final int SELECTION = 2; - @Deprecated - public static final int UNDO = 3; public static final int LOAD = 4; private BlockFactory() { @@ -92,7 +90,7 @@ private static List createSelectionBlock(Class b * * @param howToMake type of block. must be one of {@link BlockFactory#SEQUENCE}, * {@link BlockFactory#REPETITION}, {@link BlockFactory#SELECTION}, - * {@link BlockFactory#UNDO}, {@link BlockFactory#LOAD} + * , and {@link BlockFactory#LOAD} * @param blockName class name of block to be created * @return list of blocks. the first element of the list is end block * if block type is {@link BlockFactory#SELECTION} or @@ -107,7 +105,6 @@ public static List createBlocks(@HowToMake int howToMake, String bloc switch (howToMake) { case SEQUENCE: - case UNDO: case LOAD: { return createSequenceBlock(blockClass); } @@ -124,7 +121,7 @@ public static List createBlocks(@HowToMake int howToMake, String bloc throw new RuntimeException("Do not know how to make a block of " + blockName); } - @IntDef({SEQUENCE, REPETITION, SELECTION, UNDO, LOAD}) + @IntDef({SEQUENCE, REPETITION, SELECTION, LOAD}) public @interface HowToMake { } } diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/NumberTextViewDelegate.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/NumberTextViewDelegate.java index 96edc9b..d28cb7b 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/NumberTextViewDelegate.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/NumberTextViewDelegate.java @@ -18,15 +18,28 @@ import android.view.View; import android.widget.TextView; +import com.pileproject.drive.util.string.NumberUtil; import com.pileproject.drive.util.string.ParseUtil; import java.math.BigDecimal; import java.util.Locale; +/** + * This class represents a delegate for classes with a TextView. + * Most of the methods in {@link NumberTextHolder} are implemented in this class. + * + * The list of methods in {@link NumberTextHolder} which are not implemented is: + *
    + *
  • {@link NumberTextHolder#getPrecision()}
  • + *
  • {@link NumberTextHolder#getRange()}
  • + *
  • {@link NumberTextHolder#getUnit()}
  • + *
+ * + * These methods should be implemented in concrete classes. + */ public class NumberTextViewDelegate { private final TextView textView; - private final String textFormat; private final int precision; private BigDecimal valueCache; @@ -34,7 +47,6 @@ public class NumberTextViewDelegate { public NumberTextViewDelegate(TextView textView, NumberTextHolder holder) { this.precision = holder.getPrecision(); this.textView = textView; - this.textFormat = "%." + precision + "f"; } public int getActionValue() { @@ -52,7 +64,7 @@ public BigDecimal getValue() { public void setValue(BigDecimal value) { valueCache = value; - textView.setText(String.format(Locale.getDefault(), textFormat, value)); + textView.setText(NumberUtil.toString(value, precision)); } public String getValueAsString() { diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/LoopBlock.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/LoopBlock.java index c445792..c324d10 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/LoopBlock.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/LoopBlock.java @@ -36,8 +36,7 @@ public LoopBlock(Context context) { @Override public int action(MachineController controller, ExecutionCondition condition) { - int index = condition.getProgramCount(); - condition.pushBeginningOfLoop(index + FOREVER_WHILE_OFFSET); // push with offset + condition.enterInfiniteLoop(); return 1; } } diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/NTimesBlock.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/NTimesBlock.java index 80b2e0a..2782b7a 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/NTimesBlock.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/NTimesBlock.java @@ -46,10 +46,8 @@ public NTimesBlock(Context context) { @Override public int action(MachineController controller, ExecutionCondition condition) { int n = getValue().intValue(); - int index = condition.getProgramCount(); - for (int i = 1; i < n; i++) { - condition.pushBeginningOfLoop(index); - } + condition.enterNTimesLoop(n); + return 0; } diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBlock.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBlock.java index 78fd9c1..3139b36 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBlock.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/repetition/RepetitionBlock.java @@ -30,7 +30,6 @@ */ public abstract class RepetitionBlock extends BlockBase { - static final int FOREVER_WHILE_OFFSET = -1000; public RepetitionBlock(Context context, @LayoutRes int layoutRes) { super(context, layoutRes); diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/layout/BlockSpaceManagerBase.java b/app/src/main/java/com/pileproject/drive/programming/visual/layout/BlockSpaceManagerBase.java index 9cec58a..cbef4c0 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/layout/BlockSpaceManagerBase.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/layout/BlockSpaceManagerBase.java @@ -129,7 +129,7 @@ public ArrayList loadUserProgramNames() { */ public abstract void addBlocks(List blocks); - private void placeBlocks(ArrayList data) { + private void placeBlocks(List data) { if (data.isEmpty()) { return; } diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/layout/ProgrammingSpaceManager.java b/app/src/main/java/com/pileproject/drive/programming/visual/layout/ProgrammingSpaceManager.java index 3d4b7f2..9ebf231 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/layout/ProgrammingSpaceManager.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/layout/ProgrammingSpaceManager.java @@ -54,7 +54,7 @@ private void setListeners(BlockBase block) { if (block instanceof NumberTextHolder) { ((NumberTextHolder) block).setOnLongClickTextViewListener( - new OnTouchNumTextListener(mContext, (NumberTextHolder) block)); + new OnTouchNumberTextListener((NumberTextHolder) block)); } } @@ -143,29 +143,27 @@ private void moveViewWithinItsParent(View view, int currentX, int currentY) { } } - private class OnTouchNumTextListener implements View.OnLongClickListener { + private class OnTouchNumberTextListener implements View.OnLongClickListener { - private final Context context; - private final NumberTextHolder holder; + private final NumberTextHolder mHolder; - public OnTouchNumTextListener(Context context, NumberTextHolder parent) { - this.context = context; - this.holder = parent; + public OnTouchNumberTextListener(NumberTextHolder parent) { + mHolder = parent; } @Override public boolean onLongClick(View v) { - final NumberSelectViewBase numberSelectView = new NumberSelectSeekBarView(context, - holder.getValue(), holder.getRange(), holder.getPrecision(), holder.getUnit()); + final NumberSelectViewBase numberSelectView = new NumberSelectSeekBarView(mContext, + mHolder.getValue(), mHolder.getRange(), mHolder.getPrecision(), mHolder.getUnit()); - new AlertDialog.Builder(context) + new AlertDialog.Builder(mContext) .setTitle(R.string.programming_pleaseSelectNumbers) .setView(numberSelectView) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - holder.setValue(numberSelectView.getValue()); + mHolder.setValue(numberSelectView.getValue()); } }) .show(); diff --git a/app/src/main/java/com/pileproject/drive/util/development/Unit.java b/app/src/main/java/com/pileproject/drive/util/development/Unit.java index 4dad2cc..6a9faa3 100644 --- a/app/src/main/java/com/pileproject/drive/util/development/Unit.java +++ b/app/src/main/java/com/pileproject/drive/util/development/Unit.java @@ -20,8 +20,8 @@ import com.pileproject.drive.R; import com.pileproject.drive.app.DriveApplication; +import com.pileproject.drive.util.string.NumberUtil; -import java.math.BigDecimal; import java.util.Locale; /** @@ -41,21 +41,41 @@ private Unit() { } - public String getUnitString(BigDecimal value, int precision) { + /** + * Decorates numeric value with the Unit string with precision. + * This method takes locales into account and uses default locale by calling + * {@link Locale#getDefault()}. + * + * @param value value to be decorated + * @param precision precision of the value in the return string. + * @param type parameter for value, which extends {@link Number} + * @return decorated string in default locale and with given precision. + */ + public String decorateValue(T value, int precision) { + return decorateValue(Locale.getDefault(), value, precision); + } - if (this == Second) { - String format = "%." + precision + "f"; + /** + * Decorates numeric value with the Unit string with precision. + * This method takes locales into account. + * + * @param locale the locale in which the value decorated + * @param value value to be decorated + * @param precision precision of the value in the return string. + * @param type parameter for value, which extends {@link Number} + * @return decorated string in default locale and with given precision. + */ + public String decorateValue(Locale locale, T value, int precision) { - return String.format(Locale.getDefault(), format, value) + RESOURCES.getString(R.string.second); + if (this == Second) { + return NumberUtil.toString(locale, value, precision) + RESOURCES.getString(R.string.second); } if (this == Percentage) { - String format = "%." + precision + "f"; - - return String.format(Locale.getDefault(), format, value) + RESOURCES.getString(R.string.percent); + return NumberUtil.toString(locale, value, precision) + RESOURCES.getString(R.string.percent); } // if this == NumberOfTimes - return RESOURCES.getString(R.string.blocks_repeatNum, value.intValue()); + return RESOURCES.getString(R.string.blocks_repeatNum, (Integer) value); } } diff --git a/app/src/main/java/com/pileproject/drive/util/string/NumberUtil.java b/app/src/main/java/com/pileproject/drive/util/string/NumberUtil.java new file mode 100644 index 0000000..357a494 --- /dev/null +++ b/app/src/main/java/com/pileproject/drive/util/string/NumberUtil.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2011-2015 PILE Project, Inc. + * + * 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 com.pileproject.drive.util.string; + +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Locale; + +public class NumberUtil { + + /** + * Converts numerical value to string expression. This function takes locales into account and + * uses default locale by calling {@link Locale#getDefault()}. + * With precision in the arguments you can control the number of digits in fraction + * part. + * + * @param value value to be converted as a string + * @param precision number of precision. + * @param type parameter of value, which should be extends {@link Number} + * @return string expression of value in appropriate locale and + * with precision + */ + public static String toString(T value, int precision) { + return toString(Locale.getDefault(), value, precision); + } + + /** + * Converts numerical value to string expression. This function takes locales into account. + * With precision in the arguments you can control the number of digits in fraction + * part. + * + * @param locale locale in which the value will be expressed. + * @param value value to be converted as a string + * @param precision number of precision. + * @param type parameter of value, which should be extends {@link Number} + * @return string expression of value in appropriate locale and + * with precision + */ + public static String toString(Locale locale, T value, int precision) { + DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getInstance(locale); + + decimalFormat.setMaximumFractionDigits(precision); + decimalFormat.setMinimumFractionDigits(precision); + + return decimalFormat.format(value); + } +} diff --git a/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java b/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java index e30aa67..4a19b28 100644 --- a/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java +++ b/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java @@ -25,7 +25,8 @@ public class ParseUtil { /** - * Parse a string as double in default locale (e.g., "1,234" means 1234E-3 in France). + * Parse a string as double in the context of default locale + * (e.g., "1,234" means 1234E-3 in France). * * @throws NumberFormatException throw if the string makes no sense as number. */ @@ -43,11 +44,11 @@ public static double doubleValueOf(String value) { public static double doubleValueOf(String value, Locale locale) throws NumberFormatException { try { - NumberFormat format = NumberFormat.getNumberInstance(locale); Number number = format.parse(value); return number.doubleValue(); + } catch (ParseException e) { throw new NumberFormatException("String '" + value + "' cannot be parsed as double value" + @@ -55,11 +56,23 @@ public static double doubleValueOf(String value, Locale locale) throws NumberFor } } + /** + * Parse a string as {@link BigDecimal} in the context of default locale + * (e.g., "1,234" means 1234E-3 in France). + * + * @throws NumberFormatException throw if the string makes no sense as number. + */ public static BigDecimal bigDecimalValueOf(String value) throws NumberFormatException { return bigDecimalValueOf(value, Locale.getDefault()); } + /** + * Parse a string as {@link BigDecimal}. + * This function takes locale into account (e.g., "1,234" means 1234E-3 in France). + * + * @throws NumberFormatException throw if the string makes no sense as number. + */ public static BigDecimal bigDecimalValueOf(String value, Locale locale) throws NumberFormatException { try { @@ -69,6 +82,7 @@ public static BigDecimal bigDecimalValueOf(String value, Locale locale) throws N Number number = decimalFormat.parse(value); return (BigDecimal) number; + } catch (ParseException e) { throw new NumberFormatException("String '" + value + "' cannot be parsed as double value" + diff --git a/app/src/main/java/com/pileproject/drive/view/NumberSelectSeekBarView.java b/app/src/main/java/com/pileproject/drive/view/NumberSelectSeekBarView.java index 1761827..f918e38 100644 --- a/app/src/main/java/com/pileproject/drive/view/NumberSelectSeekBarView.java +++ b/app/src/main/java/com/pileproject/drive/view/NumberSelectSeekBarView.java @@ -45,7 +45,7 @@ public class NumberSelectSeekBarView extends NumberSelectViewBase { public void onProgressChanged(SeekBar seekbar, int value, boolean fromUser) { mValue = fromSeekBarExpression(value, mRange, mPrecision); - mTextView.setText(mUnit.getUnitString(mValue, mPrecision)); + mTextView.setText(mUnit.decorateValue(mValue, mPrecision)); } @Override diff --git a/app/src/main/java/com/pileproject/drive/view/NumberSelectWheelScrollerView.java b/app/src/main/java/com/pileproject/drive/view/NumberSelectWheelScrollerView.java index cd019ad..eafdc4f 100644 --- a/app/src/main/java/com/pileproject/drive/view/NumberSelectWheelScrollerView.java +++ b/app/src/main/java/com/pileproject/drive/view/NumberSelectWheelScrollerView.java @@ -61,7 +61,7 @@ public void onValueChange(NumberPicker picker, int oldVal, int newVal) { }; /** - * * Constructor. + * Constructor. * @param context context * @param value initial value * @param range BigDecimal range. users can select within this range diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetLeftMotorSpeedBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetLeftMotorSpeedBlock.java index d6f01f7..8ab5531 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetLeftMotorSpeedBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetLeftMotorSpeedBlock.java @@ -39,7 +39,7 @@ public class SetLeftMotorSpeedBlock extends SequenceBlockHasNumberText { private static final Range range = Range.closed(BigDecimal.ZERO, new BigDecimal(100)); // TODO: set from preference - private static final int PRECISION = 1; + private static final int PRECISION = 0; public SetLeftMotorSpeedBlock(Context context) { super(context, R.layout.block_set_left_motor_speed, R.id.block_numText); diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetRightMotorSpeedBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetRightMotorSpeedBlock.java index dcc9c11..8b69a51 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetRightMotorSpeedBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/SetRightMotorSpeedBlock.java @@ -39,7 +39,7 @@ public class SetRightMotorSpeedBlock extends SequenceBlockHasNumberText { private static final Range range = Range.closed(BigDecimal.ZERO, new BigDecimal(100)); // TODO: set from preference - private static final int PRECISION = 1; + private static final int PRECISION = 0; public SetRightMotorSpeedBlock(Context context) { super(context, R.layout.block_set_right_motor_speed, R.id.block_numText); diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnLeftSecBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnLeftSecBlock.java index 3876dc4..59336c3 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnLeftSecBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnLeftSecBlock.java @@ -56,8 +56,7 @@ public Range getRange() { } @Override - public int action( - MachineController controller, ExecutionCondition condition) { + public int action(MachineController controller, ExecutionCondition condition) { ((NxtController) controller).turnLeft(); return getActionValue(); } diff --git a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnRightSecBlock.java b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnRightSecBlock.java index 3e5c33c..91ad4f0 100644 --- a/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnRightSecBlock.java +++ b/app/src/nxt/java/com/pileproject/drive/programming/visual/block/sequence/TurnRightSecBlock.java @@ -56,8 +56,7 @@ public Range getRange() { } @Override - public int action( - MachineController controller, ExecutionCondition condition) { + public int action(MachineController controller, ExecutionCondition condition) { ((NxtController) controller).turnRight(); return getActionValue(); } From f857271b48b053f8eb61dc833cbf295c85fb3332 Mon Sep 17 00:00:00 2001 From: Yusaku Mandai Date: Thu, 29 Sep 2016 22:13:59 +0900 Subject: [PATCH 3/6] Add and fix tests for the following classes: * NumberTextViewDelegate * Unit * NumberUtil * ParseUtil And cradle.build in the root directory is modified to add the dexmaker libraries which are necessary for mockito --- app/build.gradle | 5 +- .../block/NumberTextViewDelegateTest.java | 78 +++++++++++++++ .../drive/util/development/UnitTest.java | 96 +++++++++++++++++++ .../drive/util/string/NumberUtilTest.java | 45 +++++++++ .../drive/util/string/ParseUtilTest.java | 43 ++++++++- 5 files changed, 263 insertions(+), 4 deletions(-) create mode 100644 app/src/androidTest/java/com/pileproject/drive/programming/visual/block/NumberTextViewDelegateTest.java create mode 100644 app/src/androidTest/java/com/pileproject/drive/util/development/UnitTest.java create mode 100644 app/src/test/java/com/pileproject/drive/util/string/NumberUtilTest.java diff --git a/app/build.gradle b/app/build.gradle index a0c06c6..2b36161 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -80,7 +80,10 @@ dependencies { androidTestCompile 'com.android.support:support-annotations:23.4.0' // mockito - androidTestCompile 'org.mockito:mockito-core:1.9.5' + androidTestCompile 'org.mockito:mockito-core:1.10.19' + androidTestCompile "com.crittercism.dexmaker:dexmaker:1.4" + androidTestCompile "com.crittercism.dexmaker:dexmaker-dx:1.4" + androidTestCompile "com.crittercism.dexmaker:dexmaker-mockito:1.4" // our library compile 'com.pileproject:drivecommand:2.1.0' diff --git a/app/src/androidTest/java/com/pileproject/drive/programming/visual/block/NumberTextViewDelegateTest.java b/app/src/androidTest/java/com/pileproject/drive/programming/visual/block/NumberTextViewDelegateTest.java new file mode 100644 index 0000000..4332c5f --- /dev/null +++ b/app/src/androidTest/java/com/pileproject/drive/programming/visual/block/NumberTextViewDelegateTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011-2015 PILE Project, Inc. + * + * 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 com.pileproject.drive.programming.visual.block; + +import android.support.test.runner.AndroidJUnit4; +import android.widget.TextView; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +import java.math.BigDecimal; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(AndroidJUnit4.class) +public class NumberTextViewDelegateTest { + + private static final int PRECISION = 3; + + public TextView mockTextView; + + public NumberTextHolder mockNumberTextHolder; + + public NumberTextViewDelegate numberTextViewDelegate; + + @Before + public void before() { + mockTextView = Mockito.mock(TextView.class); + + mockNumberTextHolder = Mockito.mock(NumberTextHolder.class); + + doReturn(PRECISION).when(mockNumberTextHolder).getPrecision(); + + numberTextViewDelegate = new NumberTextViewDelegate(mockTextView, mockNumberTextHolder); + } + + @Test + public void whenTextViewReturnsNumber_thenGetValueSucceeds() throws Exception { + + doReturn("2.500").when(mockTextView).getText(); + assertEquals(new BigDecimal("2.5"), numberTextViewDelegate.getValue()); + } + + @Test + public void whenTextViewReturnsNumber_thenGetActionValueSucceeds() throws Exception { + + doReturn("2.500").when(mockTextView).getText(); + assertEquals(2500, numberTextViewDelegate.getActionValue()); + } + + @Test + public void whenTextViewDisabled_thenVerifyTheMethodsCalled() throws Exception { + + numberTextViewDelegate.enableTextView(false); + + verify(mockTextView).setFocusable(false); + verify(mockTextView).setFocusableInTouchMode(false); + verify(mockTextView).setEnabled(false); + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/pileproject/drive/util/development/UnitTest.java b/app/src/androidTest/java/com/pileproject/drive/util/development/UnitTest.java new file mode 100644 index 0000000..6d5967e --- /dev/null +++ b/app/src/androidTest/java/com/pileproject/drive/util/development/UnitTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2011-2015 PILE Project, Inc. + * + * 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 com.pileproject.drive.util.development; + +import android.content.res.Configuration; +import android.content.res.Resources; + +import com.pileproject.drive.app.DriveApplication; + +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; + +import java.util.Locale; + +import static junit.framework.Assert.assertEquals; + +@RunWith(Enclosed.class) +public class UnitTest { + + public static void setLocale(Locale locale) { + + Resources res = DriveApplication.getContext().getResources(); + Configuration config = res.getConfiguration(); + config.locale = locale; + res.updateConfiguration(config, res.getDisplayMetrics()); + } + + public static class InUS { + + @Before + public void before() { + setLocale(Locale.US); + } + + @Test + public void whenUnitIsSecond_thenDecoratesAsSecondString() throws Exception { + assertEquals("When value is 1.0 and unit is second", + "1.000s", Unit.Second.decorateValue(Locale.ENGLISH, 1.0, 3)); + } + + @Test + public void whenUnitIsPercent_thenDecoratesAsPercentString() throws Exception { + assertEquals("When value is 100 and unit is percentage", + "100%", Unit.Percentage.decorateValue(Locale.ENGLISH, 100, 0)); + } + + @Test + public void whenUnitIsNumberOfTimes_thenDecoratesAsNumberOfTimesString() throws Exception { + assertEquals("When the value 100 and unit is NumberOfTimes", + "Repeats: 100", Unit.NumberOfTimes.decorateValue(Locale.ENGLISH, 100, 0)); + } + } + + public static class InJP { + + @Before + public void before() { + setLocale(Locale.JAPAN); + } + + @Test + public void whenUnitIsSecond_thenDecoratesAsSecondString() throws Exception { + assertEquals("When value is 1.0 and unit is second", + "1.000びょう", Unit.Second.decorateValue(Locale.JAPAN, 1.0, 3)); + } + + @Test + public void whenUnitIsPercent_thenDecoratesAsPercentString() throws Exception { + assertEquals("When value is 100 and unit is percentage", + "100%", Unit.Percentage.decorateValue(Locale.JAPAN, 100, 0)); + } + + @Test + public void whenUnitIsNumberOfTimes_thenDecoratesAsNumberOfTimesString() throws Exception { + assertEquals("When the value 100 and unit is NumberOfTimes", + "100 かい", Unit.NumberOfTimes.decorateValue(Locale.JAPAN, 100, 0)); + } + } + +} \ No newline at end of file diff --git a/app/src/test/java/com/pileproject/drive/util/string/NumberUtilTest.java b/app/src/test/java/com/pileproject/drive/util/string/NumberUtilTest.java new file mode 100644 index 0000000..f71bc68 --- /dev/null +++ b/app/src/test/java/com/pileproject/drive/util/string/NumberUtilTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011-2015 PILE Project, Inc. + * + * 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 com.pileproject.drive.util.string; + +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.Locale; + +import static org.junit.Assert.*; + +public class NumberUtilTest { + + @Test + public void whenLocaleIsJapan_thenConvertsAsJapaneseFormat() throws Exception { + assertEquals("When the precision 3 and locale Japan", + "1.250", NumberUtil.toString(Locale.JAPAN, 1.25, 3)); + } + + @Test + public void whenLocaleIsFrance_thenConvertsAsFrenchFormat() throws Exception { + assertEquals("When the precision 3 and locale France", + "1,250", NumberUtil.toString(Locale.FRANCE, 1.25, 3)); + } + + @Test + public void whenValueTypeIsBigDecimal_thenConvertsSuccessfully() throws Exception { + assertEquals("When the precision 4 and locale Japan", + "1.2345", NumberUtil.toString(Locale.JAPAN, new BigDecimal("1.2345"), 4)); + } +} \ No newline at end of file diff --git a/app/src/test/java/com/pileproject/drive/util/string/ParseUtilTest.java b/app/src/test/java/com/pileproject/drive/util/string/ParseUtilTest.java index 0a54daf..33d4c37 100644 --- a/app/src/test/java/com/pileproject/drive/util/string/ParseUtilTest.java +++ b/app/src/test/java/com/pileproject/drive/util/string/ParseUtilTest.java @@ -18,6 +18,7 @@ import org.junit.Test; +import java.math.BigDecimal; import java.util.Locale; import static org.junit.Assert.assertEquals; @@ -27,23 +28,59 @@ public class ParseUtilTest { @Test public void testDoubleValueOf_whenLocaleIsJapan_thenRegardsDotAsRadixPoint() throws Exception { - assertEquals(1.234, ParseUtil.doubleValueOf("1.234", Locale.JAPAN), 0.0); + // there's no error when a double value represents 1.250 so let delta be 0.0 + assertEquals(1.250, ParseUtil.doubleValueOf("1.250", Locale.JAPAN), 0.0); } @Test public void testDoubleValueOf_whenLocaleIsEnglish_thenRegardsDotAsRadixPoint() throws Exception { - assertEquals(1.234, ParseUtil.doubleValueOf("1.234", Locale.ENGLISH), 0.0); + assertEquals(1.250, ParseUtil.doubleValueOf("1.250", Locale.ENGLISH), 0.0); } @Test public void testDoubleValueOf_whenLocaleIsFrance_thenRegardsCommaAsRadixPoint() throws Exception { - assertEquals(1.234, ParseUtil.doubleValueOf("1,234", Locale.FRANCE), 0.0); + assertEquals(1.250, ParseUtil.doubleValueOf("1,250", Locale.FRANCE), 0.0); + } + + @Test + public void testDoubleValueOf_whenLocaleIsJapan_thenRegardsCommaAsSeparator() throws Exception { + + assertEquals(1_250, ParseUtil.doubleValueOf("1,250", Locale.JAPAN), 0.0); } @Test(expected = NumberFormatException.class) public void testDoubleValueOf_whenStringIsNotNumber_thenThrowsException() throws Exception { ParseUtil.doubleValueOf("foobar"); } + + @Test + public void testBigDecimalValueOf_whenLocaleIsJapan_thenRegardsDotAsRadixPoint() throws Exception { + + assertEquals(new BigDecimal("1.234"), ParseUtil.bigDecimalValueOf("1.234", Locale.JAPAN)); + } + + @Test + public void testBigDecimalValueOf_whenLocaleIsEnglish_thenRegardsDotAsRadixPoint() throws Exception { + + assertEquals(new BigDecimal("1.234"), ParseUtil.bigDecimalValueOf("1.234", Locale.ENGLISH)); + } + + @Test + public void testBigDecimalValueOf_whenLocaleIsFrance_thenRegardsCommaAsRadixPoint() throws Exception { + + assertEquals(new BigDecimal("1.234"), ParseUtil.bigDecimalValueOf("1,234", Locale.FRANCE)); + } + + @Test + public void testBigDecimalValueOf_whenLocaleIsJapan_thenRegardsCommaAsSeparator() throws Exception { + + assertEquals(new BigDecimal(1_234), ParseUtil.bigDecimalValueOf("1,234", Locale.JAPAN)); + } + + @Test(expected = NumberFormatException.class) + public void testBigDecimalValueOf_whenStringIsNotNumber_thenThrowsException() throws Exception { + ParseUtil.bigDecimalValueOf("foobar"); + } } \ No newline at end of file From bed4086d66eb2f1df92e6eb2ddc311cbbe34323d Mon Sep 17 00:00:00 2001 From: Yusaku Mandai Date: Thu, 29 Sep 2016 22:15:56 +0900 Subject: [PATCH 4/6] Remove superfluous line-breaks --- .../drive/programming/visual/block/BlockFactory.java | 10 ---------- .../com/pileproject/drive/util/string/ParseUtil.java | 11 ----------- 2 files changed, 21 deletions(-) diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java index 3f49b61..63415c0 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java @@ -45,23 +45,17 @@ private BlockFactory() { @SuppressWarnings("unchecked") private static Class getClassForName(String className) throws RuntimeException { - try { return (Class) Class.forName(className); - } catch (ClassNotFoundException e) { - throw new RuntimeException("Invalid class name '" + className + "'", e); } } private static BlockBase create(Class blockClass) throws RuntimeException { - try { Constructor constructor = blockClass.getConstructor(Context.class); - return constructor.newInstance(DriveApplication.getContext()); - } catch (Exception e) { // there's no way to recover. let App die. throw new RuntimeException("Failed to instantiate " + blockClass, e); @@ -69,17 +63,14 @@ private static BlockBase create(Class blockClass) throws Ru } private static List createSequenceBlock(Class blockClass) { - return Collections.singletonList(create(blockClass)); } private static List createRepetitionBlock(Class blockClass) { - return Arrays.asList(new RepetitionEndBlock(DriveApplication.getContext()), create(blockClass)); } private static List createSelectionBlock(Class blockClass) { - return Arrays.asList(new SelectionEndBlock(DriveApplication.getContext()), create(blockClass)); } @@ -100,7 +91,6 @@ private static List createSelectionBlock(Class b * or howToMake is none of the values listed above */ public static List createBlocks(@HowToMake int howToMake, String blockName) { - Class blockClass = getClassForName(blockName); switch (howToMake) { diff --git a/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java b/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java index 4a19b28..c456c9d 100644 --- a/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java +++ b/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java @@ -31,7 +31,6 @@ public class ParseUtil { * @throws NumberFormatException throw if the string makes no sense as number. */ public static double doubleValueOf(String value) { - return doubleValueOf(value, Locale.getDefault()); } @@ -42,15 +41,11 @@ public static double doubleValueOf(String value) { * @throws NumberFormatException throw if the string makes no sense as number. */ public static double doubleValueOf(String value, Locale locale) throws NumberFormatException { - try { NumberFormat format = NumberFormat.getNumberInstance(locale); Number number = format.parse(value); - return number.doubleValue(); - } catch (ParseException e) { - throw new NumberFormatException("String '" + value + "' cannot be parsed as double value" + " in locale " + locale); } @@ -63,7 +58,6 @@ public static double doubleValueOf(String value, Locale locale) throws NumberFor * @throws NumberFormatException throw if the string makes no sense as number. */ public static BigDecimal bigDecimalValueOf(String value) throws NumberFormatException { - return bigDecimalValueOf(value, Locale.getDefault()); } @@ -74,17 +68,12 @@ public static BigDecimal bigDecimalValueOf(String value) throws NumberFormatExce * @throws NumberFormatException throw if the string makes no sense as number. */ public static BigDecimal bigDecimalValueOf(String value, Locale locale) throws NumberFormatException { - try { DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getInstance(locale); decimalFormat.setParseBigDecimal(true); - Number number = decimalFormat.parse(value); - return (BigDecimal) number; - } catch (ParseException e) { - throw new NumberFormatException("String '" + value + "' cannot be parsed as double value" + " in locale " + locale); } From 1152325ab89e047229b9f1e82e709d2206f63b5b Mon Sep 17 00:00:00 2001 From: Yusaku Mandai Date: Thu, 29 Sep 2016 22:29:00 +0900 Subject: [PATCH 5/6] Remove an extra comma --- .../drive/programming/visual/block/BlockFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java b/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java index 63415c0..77b1dbd 100644 --- a/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java +++ b/app/src/main/java/com/pileproject/drive/programming/visual/block/BlockFactory.java @@ -81,7 +81,7 @@ private static List createSelectionBlock(Class b * * @param howToMake type of block. must be one of {@link BlockFactory#SEQUENCE}, * {@link BlockFactory#REPETITION}, {@link BlockFactory#SELECTION}, - * , and {@link BlockFactory#LOAD} + * and {@link BlockFactory#LOAD} * @param blockName class name of block to be created * @return list of blocks. the first element of the list is end block * if block type is {@link BlockFactory#SELECTION} or From e5fd256a3cd70ae841245367c149328d61f1f674 Mon Sep 17 00:00:00 2001 From: Yusaku Mandai Date: Thu, 29 Sep 2016 23:29:26 +0900 Subject: [PATCH 6/6] Add constructor guards for util classes --- .../com/pileproject/drive/util/bluetooth/BluetoothUtil.java | 5 +++++ .../com/pileproject/drive/util/development/DeployUtils.java | 5 +++++ .../java/com/pileproject/drive/util/string/NumberUtil.java | 4 ++++ .../java/com/pileproject/drive/util/string/ParseUtil.java | 4 ++++ 4 files changed, 18 insertions(+) diff --git a/app/src/main/java/com/pileproject/drive/util/bluetooth/BluetoothUtil.java b/app/src/main/java/com/pileproject/drive/util/bluetooth/BluetoothUtil.java index 828be9e..276ab1f 100644 --- a/app/src/main/java/com/pileproject/drive/util/bluetooth/BluetoothUtil.java +++ b/app/src/main/java/com/pileproject/drive/util/bluetooth/BluetoothUtil.java @@ -19,6 +19,11 @@ import android.bluetooth.BluetoothAdapter; public class BluetoothUtil { + + private BluetoothUtil() { + throw new AssertionError("This class cannot be instantiated"); + } + public static boolean hasBluetoothFunction() { return BluetoothAdapter.getDefaultAdapter() != null; } diff --git a/app/src/main/java/com/pileproject/drive/util/development/DeployUtils.java b/app/src/main/java/com/pileproject/drive/util/development/DeployUtils.java index 2b8de8f..e403f5f 100644 --- a/app/src/main/java/com/pileproject/drive/util/development/DeployUtils.java +++ b/app/src/main/java/com/pileproject/drive/util/development/DeployUtils.java @@ -26,6 +26,11 @@ * A class for checking building environments, devices, etc. */ public class DeployUtils { + + private DeployUtils() { + throw new AssertionError("This class cannot be instantiated"); + } + /** * Return true if the device is emulator. */ diff --git a/app/src/main/java/com/pileproject/drive/util/string/NumberUtil.java b/app/src/main/java/com/pileproject/drive/util/string/NumberUtil.java index 357a494..41966cc 100644 --- a/app/src/main/java/com/pileproject/drive/util/string/NumberUtil.java +++ b/app/src/main/java/com/pileproject/drive/util/string/NumberUtil.java @@ -22,6 +22,10 @@ public class NumberUtil { + private NumberUtil() { + throw new AssertionError("This class cannot be instantiated"); + } + /** * Converts numerical value to string expression. This function takes locales into account and * uses default locale by calling {@link Locale#getDefault()}. diff --git a/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java b/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java index c456c9d..6ce345d 100644 --- a/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java +++ b/app/src/main/java/com/pileproject/drive/util/string/ParseUtil.java @@ -24,6 +24,10 @@ public class ParseUtil { + private ParseUtil() { + throw new AssertionError("This class cannot be instantiated"); + } + /** * Parse a string as double in the context of default locale * (e.g., "1,234" means 1234E-3 in France).