Does anyone recognize this pattern and know of a tidy solution?
I've got a view that can be in certain states. Let's call them Neutral, Success, Error, InProgress. In the view I've got multiple elements (Buttons, TextViews and a ProgressBar) that should either be visible/enabled depending on the state the view is in.
Currently I've got methods that represent the states that do the necessary .setEnabled() and .setVisibility() calls. With 4 states and a couple of elements this becomes messy quite fast.
I also feel that the State Pattern is not necessarily a good solution but is something that personally springs to mind.
I would love to hear what any of you think is a simple and tidy solution.
Sample code:
void setIsRegistering() {
isRegistering = true;
isRegistered = false;
progressBar.setVisibility(View.VISIBLE);
successText.setVisibility(View.GONE);
errorText.setVisibility(View.GONE);
setupFooterButton.setEnabled(false);
setupFooterButton.setText("Adding browser");
}
void setIsRegistered() {
isRegistering = false;
isRegistered = true;
progressBar.setVisibility(View.INVISIBLE);
successText.setVisibility(View.VISIBLE);
errorText.setVisibility(View.GONE);
setupFooterButton.setEnabled(true);
setupFooterButton.setText("Next");
}
void setIsNotRegistered() {
isRegistering = false;
isRegistered = false;
progressBar.setVisibility(View.INVISIBLE);
successText.setVisibility(View.INVISIBLE);
errorText.setVisibility(View.GONE);
setupFooterButton.setEnabled(true);
setupFooterButton.setText("Add browser");
}`
You can use a ViewAnimator for this: (http://developer.android.com/reference/android/widget/ViewAnimator.html)
You can then call viewAnimator.setDisplayedChild() to set the selected item.
setDisplayedChild() takes an integer, so I typically create an enum to hold the states I want:
enum ViewStates {
NEUTRAL, SUCCESS, ERROR
}
setDisplayedChild(ViewStates.Neutral.ordinal());
Or if that's too verbose:
enum ViewStates {
NEUTRAL, SUCCESS, ERROR
public static int neutral = NEUTRAL.ordinal();
public static int success = SUCCESS.ordinal();
public static int error = ERROR.ordinal();
}
setDisplayedChild(neutral);
Related
The default behavior for a ListView when calling smoothScrollToPosition on it, it to move with linear speed to the specified position.
Digging into ListView's and AbsListView's code, I can see that this behavior takes place because AbsListView uses a PositionScroller object (implementing AbsPositionScroller) that in turn uses a FlingRunnable object on which the method startScroll gets called with linear = true (which ends up having its OverScroller object use a LinearInterpolator).
I want to modify this behavior, and have it use for example the Scroller.ViscousFluidInterpolator class that the OverScroller class would use by default, but I'm not finding a way to do it.
I see that AbsListView defines a AbsPosScroller interface (that himself implements with a PositionScroller class), that I could try to implement with my own class to have it end up using the ViscousFluidInterpolator, but for some reason this interface is private to the package android.widget...
Am I missing something, or does it look like this has been written in a way that prevents it to have a behavior like that one be customized? Why would they bother writing up a AbsPosScroller interface in first place?
Any leads on how could I get the behavior I want without having to write my entire ListView class from scratch?
While I still don't know why would they write these components in a way that their behavior can't be customized easily when it would've been pretty easy to do it, I came up with an alternative implementation of smoothScrollToPosition (awesomeScrollToPosition in the code below) that does what I needed.
This solution makes use of an OverScroller object (that internally uses the ViscousInterpolator unless a different one is specified) to provide the effect I was looking for, for scrolling to elements within the visible page (the solution to achieve scrolling across pages is more convoluted, but this works for the problem I needed to solve).
I basically implemented a Runnable class private to my own ListView subclass (MyListView) that deals with the scrolling animation, re-posting itself to the UI thread for as long as the animation needs to run, using scrollingListBy in every frame (this method is only available since KitKat [19] though).
public class MyListView extends ListView {
private MyScroller mScroller;
/* MyListView constructors here */
public void awesomeScrollToPosition(int position, int duration) {
if (getChildCount() == 0) {
// Can't scroll without children (visible list items)
return;
}
if (mScroller == null) {
mScroller = new MyScroller();
}
if (mScroller.isRunning()) {
mScroller.stop();
}
int firstPos = getFirstVisiblePosition();
int lastPos = getLastVisiblePosition();
if (!(firstPos <= position && position <= lastPos)) {
// Can't scroll to an item outside of the visible range this easily
return;
}
int targetPosition = position - firstPos;
int targetTop = getChildAt(targetPosition).getTop();
mScroller.start(targetTop, duration);
}
private class MyScroller implements Runnable {
OverScroller mScroller;
boolean mRunning;
int mLastY;
MyScroller() {
mScroller = new OverScroller(getContext());
mRunning = false;
}
void start(int y, int duration) {
// start scrolling
mLastY = 0;
mScroller.startScroll(0, 0, 0, y, duration);
mRunning = true;
postOnAnimation(this);
}
boolean isRunning() {
return mRunning;
}
#Override
public void run() {
boolean more = mScroller.computeScrollOffset();
final int currentY = mScroller.getCurrY();
// actual scrolling
scrollListBy(currentY - mLastY);
if (more) {
mLastY = currentY;
// schedule next run
postOnAnimation(this);
} else {
stop();
}
}
public void stop() {
mRunning = false;
removeCallbacks(this);
}
}
}
In my test, after one action, there are two possible views which can appear and both of them are correct. How can I check if one of the view is displayed. For a single view I can check with is Displayed(). But that would fail if other view is visible instead. I want to pass the test if any one of those two views are displayed.
onMyButton.perform(click());
onMyPageOne.check(matches(isDisplayed())); //view 1
or
onMyPageTwo.check(matches(isDisplayed())); //view 2
After, perform click on MyButton, any one of the view (1 or 2) is expected to appear but not both. It is not fixed that which one would be displayed.
How can I check if any one of them is displayed?
It's possible to catch the exceptions raised by Espresso like this:
If you want to test if a view is in hierarchy:
try {
onView(withText("Button")).perform(click());
// View is in hierarchy
} catch (NoMatchingViewException e) {
// View is not in hierarchy
}
This exception will be thrown if the view is not in the hierarchy.
Sometimes the view can be in the hierarchy, but we need to test if it is displayed, so there is another exception for assertions, like this:
try {
onView(withText("Button")).check(matches(isDisplayed()));
// View is displayed
} catch (AssertionFailedError e) {
// View not displayed
}
There are two cases here that you could be trying to cover. The first is if you are checking if the view "is displayed on the screen to the user" in which case you would use isDisplayed()
onView(matcher).check(matches(isDisplayed()));
or the negation
onView(matcher).check(matches(not(isDisplayed())));
The other case is if you are checking if the view is visible but not necessarily displayed on the screen (ie. an item in a scrollview). For this you can use withEffectiveVisibility(Visibility)
onView(matcher).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
You can use Matchers.anyOf to check if any of the two views are displayed:
onView(
anyOf(withId(R.id.view_1), withId(R.id.view_2))
).check(matches(isDisplayed()));
For the ones looking to check the visibility status for a view; here are some utility functions I use.
fun ViewInteraction.isGone() = getViewAssertion(ViewMatchers.Visibility.GONE)
fun ViewInteraction.isVisible() = getViewAssertion(ViewMatchers.Visibility.VISIBLE)
fun ViewInteraction.isInvisible() = getViewAssertion(ViewMatchers.Visibility.INVISIBLE)
private fun getViewAssertion(visibility: ViewMatchers.Visibility): ViewAssertion? {
return ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(visibility))
}
And can be used as follows
onView(withId(R.id.progressBar)).isVisible()
onView(withId(R.id.progressBar)).isGone()
I researched Espresso a bit, and I found this # Espresso Samples.
Search text "Asserting that a view is not displayed". It says "The above approach works if the view is still part of the hierarchy." So I think your code should work but you need to use ViewAssertions also. Using your code, perhaps do this:
if (ViewAssertions.doesNotExist()) == null) {
return;
}
onMyPageOne.check(matches(isDisplayed()));
Another technique is check for UI existence. Search for text "Asserting that a view is not present".
Using your code, my best suggestion is:
onMyPageOne.check(doesNotExist());
Note: This calls doesNotExist method.
Their sample code is: onView(withId(R.id.bottom_left)).check(doesNotExist());
Utility class which allows to check if view is visible, gone or invisible:
public class ExtraAssertions {
public static ViewAssertion isVisible() {
return new ViewAssertion() {
public void check(View view, NoMatchingViewException noView) {
assertThat(view, new VisibilityMatcher(View.VISIBLE));
}
};
}
public static ViewAssertion isGone() {
return new ViewAssertion() {
public void check(View view, NoMatchingViewException noView) {
assertThat(view, new VisibilityMatcher(View.GONE));
}
};
}
public static ViewAssertion isInvisible() {
return new ViewAssertion() {
public void check(View view, NoMatchingViewException noView) {
assertThat(view, new VisibilityMatcher(View.INVISIBLE));
}
};
}
private static class VisibilityMatcher extends BaseMatcher<View> {
private int visibility;
public VisibilityMatcher(int visibility) {
this.visibility = visibility;
}
#Override public void describeTo(Description description) {
String visibilityName;
if (visibility == View.GONE) visibilityName = "GONE";
else if (visibility == View.VISIBLE) visibilityName = "VISIBLE";
else visibilityName = "INVISIBLE";
description.appendText("View visibility must has equals " + visibilityName);
}
#Override public boolean matches(Object o) {
if (o == null) {
if (visibility == View.GONE || visibility == View.INVISIBLE) return true;
else if (visibility == View.VISIBLE) return false;
}
if (!(o instanceof View))
throw new IllegalArgumentException("Object must be instance of View. Object is instance of " + o);
return ((View) o).getVisibility() == visibility;
}
}
}
And usage could look like this:
onView(withId(R.id.text_message)).check(isVisible());
Another view assertion which could help to check extra visibility properties of a view and its parents: it checks visibility, isAttachedToWindow, alpha:
class IsVisible : ViewAssertion {
override fun check(view: View, noViewFoundException: NoMatchingViewException?) {
ViewMatchers.assertThat(
"View is not visible. " +
"visibility: ${view.visibility}, " +
"isAttachedToWindow: ${view.isAttachedToWindow}, " +
"alpha: ${view.alpha}",
true, `is`(isViewTreeVisible(view)))
}
private fun isViewTreeVisible(view: View?): Boolean {
return if (view != null) {
val viewVisible = view.isAttachedToWindow && view.visibility == View.VISIBLE && view.alpha == 1.0f
if (view.parent !is View) viewVisible
else viewVisible && isViewTreeVisible(view.parent as View)
} else {
true
}
}
}
The problem is that all assertoin() and check() methods return Assertion that stops test flow if failed.
One simple way to check for a View or its subclass like a Button is to use method
getVisibility from View class. I must caution that visibility attribute is not clearly defined in the GUI world. A view may be considered visible but may be overlapped with another view, for one example, making it hidden.
Another way but more accurate (I have not tried) is to check for the rectangular bounds of the View. Not so simple.
Is that clear enough? cannot give you specific examples since you did not post code.
final AtomicBoolean view1Displayed = new AtomicBoolean(true);
Espresso.onView(ViewMatchers.withId(viewId1)).inRoot(RootMatchers.withDecorView(Matchers.is(intentsTestRule.getActivity().getWindow().getDecorView()))).withFailureHandler(new FailureHandler() {
#Override
public void handle(Throwable error, Matcher<View> viewMatcher) {
view1Displayed.set(false);
}
}).check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
if (view1Displayed.get()) {
try {
Espresso.onView(ViewMatchers.withId(viewId2)).inRoot(RootMatchers.withDecorView(Matchers.is(intentsTestRule.getActivity().getWindow().getDecorView()))).check(ViewAssertions.matches(Matchers.not(ViewMatchers.isDisplayed())));
} catch (NoMatchingViewException ignore) {
}
} else {
Espresso.onView(ViewMatchers.withId(viewId2)).inRoot(RootMatchers.withDecorView(Matchers.is(intentsTestRule.getActivity().getWindow().getDecorView()))).check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
}
When I face this situation I generally split into multiple tests. One test sets the conditions for view #1 to be displayed and the other test sets the conditions for view #2 to be displayed.
But let's say that you can't really control the conditions. For example, what if it depends on a random number or it depends on a third-party resource such as a calculation on a server? In that case, I usually solve the problem mocking. That way I can control the conditions so I know exactly which view to expect. I use Dependency Injection to set the mock I need for each test.
I'm trying to create a crafting recipe with bukkit and I want the recipe to ONLY accept a leather helmet with the name "Better Helmet". right now I have this:
public static ItemStack lvl2Head = new ItemStack(Material.LEATHER_HELMET, 1);
{
//removed unnessecary information
lvl2HeadMeta.setDisplayName("Better Helmet 2");
}
public void lvl1ArmorHead() {
ShapedRecipe recipe = new ShapedRecipe(lvl2Head);
recipe.shape("AAA", "ABA", "AAA");
recipe.setIngredient('A', Material.DIAMOND);
//want it to check it under here in place of "LEATHER_HELMET"
recipe.setIngredient('B', Material.LEATHER_HELMET);
this.getServer().addRecipe(recipe);
}
Is there any way I can accomplish this? I tried putting the name of the new ItemStack in place of Material.LEATHER_HELMET but it wants MaterialData not an ItemStack.
update
I'm still able to pull the item out of the crafting table using a regular leather helmet this code created with jojodmo.
Main Class:
public static ShapedRecipe lvl1ArmorHeadRecipe() {
ShapedRecipe recipe = new ShapedRecipe(lvl1Head);
recipe.shape("AAA", "ABA", "AAA");
recipe.setIngredient('A', Material.DIAMOND);
recipe.setIngredient('B', Material.LEATHER_HELMET);
return recipe;
}
public void lvl1ArmorHead(){
this.getServer().addRecipe(lvl1ArmorHeadRecipe());
}
EventHandler class:
#EventHandler
public void craft(CraftItemEvent e){
if(e.getInventory() instanceof CraftingInventory){
CraftingInventory inv = (CraftingInventory) e.getInventory();
if(inv.getSize() != 4 && e.getRecipe().equals(Main.lvl1ArmorHeadRecipe())){
org.bukkit.inventory.ItemStack helm = inv.getMatrix()[5];
if(helm.hasItemMeta()){
if(helm.getItemMeta().getDisplayName().equals("Better Helmet")){
//done.
} else{
e.setCancelled(true);
}
} else {
e.setCancelled(true);
}
}
}
}
Note: This is for Bukkit 1.7.2
I've done this before, It took me so long to figure out how to do it! The only problem is that the result still shows up if you were to use a regular leather helmet, but it just doesn't let you take the result out of the crafting table.
Here's how I did it:
public ShapedRecipie lvl1ArmorHeadRecipie(){
ShapedRecipe recipe = new ShapedRecipe(lvl2Head);
recipe.shape("AAA", "ABA", "AAA");
recipe.setIngredient('A', Material.DIAMOND);
recipe.setIngredient('B', Material.LEATHER_HELMET);
return recipie;
}
public void lvl1ArmorHead(){
this.getServer().addRecipe(lvl1ArmorHeadRecipie());
//do everything in here normally
}
Next, use this. Make sure to make the class that this is in implement Listener
#EventHandler
public void craft(CraftItemEvent e){
if(e.getInventory() instanceof CraftingInventory){
CraftingInventory inv = (CraftingInventory) e.getInventory();
if(inv.getSize() != 4 && e.getRecipe().equals(lvl1ArmorHelmetRecipe())){
ItemStack helm = inv.getMatrix()[4];//get the middle item in the bench, which is the helmet
if(helm.hasItemMeta()){//make sure the helmet has item meta
if(helm.getItemMeta().getDisplayName().equals("Better Helmet")){//make sure the helmet's display name is 'Better Helmet'
//you're done! It works! Do something like tell the player "you have crafted better armor" or something here.
return;
}
}
//the return; above would have been called if the crafting had succeeded. When it got called, the remainder of this method would not run (this part will not be run if the crafting has succeeded)
//send the player a message to make it more realistic here. For my wizardry server I use: 'One of thee items used was incorrect, and unbalanced the energy. The death block hath been destroyed'
e.setCanceled(true);
e.setResult(new ItemStack(Material.AIR));
}
}
}
Look up the PrepareItemCraftEvent, I've answered your question on the bukkit forums, look at my post: http://forums.bukkit.org/threads/resource-no-nms-make-custom-crafting-recipes-ingredients-obey-itemmeta-displayname-e-t-c.280482/
I have a Java assignment in which my professor requires me to use a LeJOS NXT to make a robot that simulates a certain animal's behaviors. I chose to develop a dragon. All the possible behaviors that I've come up so far is:
Turning around if it's too close to an obstacle.
Going to sleep when battery is low.
Pushing an object if touches.
If it's too bright, find a dark spot.
etc.
I'm now quite confused because I don't know whether to develop it sequentially in one class or to split all the dragon's behaviors into different classes. Please have a look at my explanation below.
Instead of writing everything inside one class like this:
Dragon.java
public class Dragon {
LightSensor ls = new LightSensor
public static main(String args[]) {
while (!BUTTON.Escape.IsPressed()) {
if (this.closeToObject()) {
this.turnAround();
}
// more conditions
}
}
private boolean closeToObject() {
//TODO
return false;
}
private void turnAround() {
//TODO
}
//... more methods
}
However, I want to make it appears to be more object-oriented as the course is meant to help us gain more OOP skills. So what my second option is to create action classes that extends Dragon's Behavior abstract class like this (roughly):
Dragon.java
public class Dragon {
Detect detect = new Detect(); // carry all the detection methods: distance, sound, etc.
TurnAround turnAround = new TurnAround();
public static main(String args[]) {
while (!BUTTON.Escape.IsPressed()) {
if (detect.tooCloseToObject()) {
turnAround.prepare(); // beep beep alert
turnAround.setDerection(true); // e.g. turn right
turnAround.turn();
}
}
}
}
DragonBehaviors.java
abstract class DragonBehavior {
abstract void prepare();
public void setDirection(boolean direction) {
//...
}
}
TurnAround.java
public class TurnAround extends DragonBehaviors {
String direction;
public void TurnAround() {}
public void prepare() {
// sound alert
}
public void setDirection(boolean direction) {
if (direction) this.direction = "Right";
else this.direction = "Left";
}
public void turn() {
// TODO
}
}
The code above is roughly a draft, don't focus on it. Eventually, I want to ask if my idea about the OO structure above is reasonable, otherwise it's much easier to develop the whole thing in one class, but it has nothing to do with OOP. I also have several group members to make the code finished, so I think it could be better if we share the classes to develop in an OOP way.
Which way should I go in this circumstance?
I appreciate all the comments (:
Your choice of extracting different actions into classes with common super class is IMHO reasonable. However I would make Dragon class only aware of the DragonBehavior abstract class, not the subclasses. This way you can add and remove behaviours to the dragon without actually changing it.
How? Look at Chain-of-responsibility pattern - each behaviour has its place in the chain. If behaviour decides to activate itself (i.e. perform something) it may or may not allow further behaviours to be triggered. Moreover, you can and remove behaviours (even at runtime!) and rearrange them to change the precedence (is pushing the obstacle more or less important than going to sleep?).
Is there an elegantish way in Swing to find out if there are any tooltips currently being displayed in my frame?
I'm using custom tooltips, so it would be very easy to set a flag in my createToolTip() method, but I can't see a way to find out when the tooltip is gone.
ToolTipManager has a nice flag for this, tipShowing, but of course it's private and they don't seem to offer a way to get to it. hideWindow() doesn't call out to the tooltip component (that I can tell), so I don't see a way there.
Anyone have any good ideas?
Update: I went with reflection. You can see the code here:
private boolean isToolTipVisible() {
// Going to do some nasty reflection to get at this private field. Don't try this at home!
ToolTipManager ttManager = ToolTipManager.sharedInstance();
try {
Field f = ttManager.getClass().getDeclaredField("tipShowing");
f.setAccessible(true);
boolean tipShowing = f.getBoolean(ttManager);
return tipShowing;
} catch (Exception e) {
// We'll keep silent about this for now, but obviously we don't want to hit this
// e.printStackTrace();
return false;
}
}
It appears that the isEnabled() property of the hideTipAction is directly tied to the tipShowing boolean. You could try this:
public boolean isTooltipShowing(JComponent component) {
AbstractAction hideTipAction = (AbstractAction) component.getActionMap().get("hideTip");
return hideTipAction.isEnabled();
}
You probably want to do some sanity checking for nulls, etc. But this should get you pretty close.
EDIT, to your responses:
Short of some ugly reflection code, I don't think you have much choice. You cannot subclass ToolTipManager because of the package private constructor, and the showTipWindow() and hideTipWindow() are also package private, so the Adapter pattern is out as well.
It looks like that is going to require looping over all of the components to see if they have a tooltip. I'm looking for a global value. It may be that a loop is doable, but it seems inefficient.
That's too bad. After an internal discussion, "ugly reflection" was what we came up with as well, but I was hoping someone out there had a better idea.
Since you already have your own createToolTip(), maybe you can try something like this :)
public JToolTip createToolTip() {
JToolTip tip = super.createToolTip();
tip.addAncestorListener( new AncestorListener() {
public void ancestorAdded( AncestorEvent event ) {
System.out.println( "I'm Visible!..." );
}
public void ancestorRemoved( AncestorEvent event ) {
System.out.println( "...now I'm not." );
}
public void ancestorMoved( AncestorEvent event ) {
// ignore
}
} );
return tip;
}