aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/src/androidTest/java/org/connectbot/ConnectbotMatchers.java97
-rw-r--r--app/src/androidTest/java/org/connectbot/StartupTest.java118
-rw-r--r--app/src/main/java/org/connectbot/ConsoleActivity.java45
-rw-r--r--app/src/main/java/org/connectbot/HostListActivity.java38
-rw-r--r--app/src/main/res/layout/item_host.xml101
-rw-r--r--app/src/main/res/values-v11/styles.xml12
-rw-r--r--app/src/main/res/values/styles.xml24
7 files changed, 289 insertions, 146 deletions
diff --git a/app/src/androidTest/java/org/connectbot/ConnectbotMatchers.java b/app/src/androidTest/java/org/connectbot/ConnectbotMatchers.java
new file mode 100644
index 0000000..85a071d
--- /dev/null
+++ b/app/src/androidTest/java/org/connectbot/ConnectbotMatchers.java
@@ -0,0 +1,97 @@
+package org.connectbot;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.test.espresso.matcher.BoundedMatcher;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.connectbot.bean.HostBean;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static org.hamcrest.CoreMatchers.allOf;
+
+public class ConnectbotMatchers {
+ /**
+ * Matches the nickname of a {@link HostBean}.
+ */
+ @NonNull
+ public static Matcher<Object> withHostNickname(final String content) {
+ return new BoundedMatcher<Object, HostBean>(HostBean.class) {
+ @Override
+ public boolean matchesSafely(HostBean host) {
+ return host.getNickname().matches(content);
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("with host nickname '" + content + "'");
+ }
+ };
+ }
+
+ /**
+ * Matches the drawable state on an ImageView that is set with setImageState.
+ */
+ @NonNull
+ public static Matcher<View> withDrawableState(final int expectedState) {
+ return new TypeSafeMatcher<View>() {
+ @Override
+ public boolean matchesSafely(View view) {
+ if (!(view instanceof ImageView)) {
+ return false;
+ }
+
+ int[] states = view.getDrawableState();
+ for (int state : states) {
+ if (state == expectedState) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("with drawable state '" + expectedState + "'");
+ }
+ };
+ }
+
+ @NonNull
+ public static Matcher<View> withTextColor(@ColorInt final int expectedColor) {
+ return new TypeSafeMatcher<View>() {
+ @Override
+ public boolean matchesSafely(View view) {
+ if (!(view instanceof TextView)) {
+ return false;
+ }
+
+ TextView tv = (TextView) view;
+ return tv.getCurrentTextColor() == expectedColor;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("with color '" + Integer.toHexString(expectedColor) + "'");
+ }
+ };
+ }
+
+ @NonNull
+ public static Matcher<View> hostDisconnected() {
+ return hasDescendant(allOf(withId(android.R.id.icon),
+ withDrawableState(android.R.attr.state_expanded)));
+ }
+
+ @NonNull
+ public static Matcher<View> hostConnected() {
+ return hasDescendant(allOf(withId(android.R.id.icon),
+ withDrawableState(android.R.attr.state_checked)));
+ }
+}
diff --git a/app/src/androidTest/java/org/connectbot/StartupTest.java b/app/src/androidTest/java/org/connectbot/StartupTest.java
index 0eb9c11..a60d00e 100644
--- a/app/src/androidTest/java/org/connectbot/StartupTest.java
+++ b/app/src/androidTest/java/org/connectbot/StartupTest.java
@@ -11,7 +11,11 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import android.content.Intent;
+import android.content.res.Resources;
+import android.support.annotation.ColorInt;
+import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
+import android.support.annotation.StringRes;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.intent.Intents;
import android.support.test.espresso.matcher.BoundedMatcher;
@@ -19,6 +23,7 @@ import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.view.View;
import android.widget.ImageView;
+import android.widget.TextView;
import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
@@ -29,6 +34,7 @@ import static android.support.test.espresso.action.ViewActions.pressBack;
import static android.support.test.espresso.action.ViewActions.pressImeActionButton;
import static android.support.test.espresso.action.ViewActions.pressMenuKey;
import static android.support.test.espresso.action.ViewActions.typeText;
+import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.intent.Intents.intended;
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
@@ -36,6 +42,10 @@ import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static org.connectbot.ConnectbotMatchers.hostConnected;
+import static org.connectbot.ConnectbotMatchers.hostDisconnected;
+import static org.connectbot.ConnectbotMatchers.withHostNickname;
+import static org.connectbot.ConnectbotMatchers.withTextColor;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
@@ -87,10 +97,60 @@ public class StartupTest {
.check(matches(hostDisconnected()));
}
+ @Test
+ public void localConnectionCanDelete() {
+ startNewLocalConnectionAndGoBack("Local");
+ onData(withHostNickname("Local")).inAdapterView(withId(android.R.id.list))
+ .perform(longClick());
+ onView(withText(R.string.list_host_delete)).perform(click());
+ onView(withText(R.string.delete_pos)).perform(click());
+ }
+
+ @Test
+ public void localConnectionCanChangeToRed() throws Exception {
+ startNewLocalConnectionAndGoBack("Local1");
+ changeColor("Local1", R.color.red, R.string.color_red);
+ }
+
+ /**
+ * Changes the color of {@code hostName} from the {@link HostListActivity} to the {@code color}
+ * from {@code R.color.[color]} with identifying {@code stringForColor} from
+ * {@code R.string.[colorname]}.
+ */
+ private void changeColor(String hostName, @ColorRes int color, @StringRes int stringForColor) {
+ // Bring up the context menu.
+ onData(withHostNickname(hostName)).inAdapterView(withId(android.R.id.list))
+ .perform(longClick());
+ onView(withText(R.string.list_host_edit)).perform(click());
+
+ // Click on the color category and select the desired one.
+ onView(withText(R.string.hostpref_color_title)).perform(click());
+ onView(withText(stringForColor)).perform(click());
+
+ // Go back to the host list.
+ onView(withText(R.string.hostpref_color_title)).perform(pressBack());
+
+ Resources res = InstrumentationRegistry.getTargetContext().getResources();
+ onData(withHostNickname(hostName)).inAdapterView(withId(android.R.id.list))
+ .check(matches(hasDescendant(allOf(withId(android.R.id.text1),
+ withTextColor(res.getColor(color))))));
+ }
+
+ private void startNewLocalConnectionAndGoBack(String name) {
+ startNewLocalConnection(name);
+ onView(withId(R.id.console_flip)).perform(closeSoftKeyboard(), pressBack());
+ onData(withHostNickname(name)).inAdapterView(withId(android.R.id.list))
+ .check(matches(isDisplayed()));
+ }
+
private void startNewLocalConnection() {
+ startNewLocalConnection("Local");
+ }
+
+ private void startNewLocalConnection(String name) {
onView(withId(R.id.transport_selection)).perform(click());
onData(allOf(is(instanceOf(String.class)), is("local"))).perform(click());
- onView(withId(R.id.front_quickconnect)).perform(typeText("Local"));
+ onView(withId(R.id.front_quickconnect)).perform(typeText(name));
Intents.init();
try {
@@ -103,60 +163,4 @@ public class StartupTest {
onView(withId(R.id.console_flip)).check(matches(
hasDescendant(allOf(isDisplayed(), withId(R.id.terminal_view)))));
}
-
- /**
- * Matches the nickname of a {@link HostBean}.
- */
- public static Matcher<Object> withHostNickname(final String content) {
- return new BoundedMatcher<Object, HostBean>(HostBean.class) {
- @Override
- public boolean matchesSafely(HostBean host) {
- return host.getNickname().matches(content);
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("with host nickname '" + content + "'");
- }
- };
- }
-
- /**
- * Matches the drawable state on an ImageView that is set with setImageState.
- */
- public static Matcher<View> withDrawableState(final int expectedState) {
- return new TypeSafeMatcher<View>() {
- @Override
- public boolean matchesSafely(View view) {
- if (!(view instanceof ImageView)) {
- return false;
- }
-
- int[] states = view.getDrawableState();
- for (int state : states) {
- if (state == expectedState) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("with drawable state '" + expectedState + "'");
- }
- };
- }
-
- @NonNull
- private Matcher<View> hostDisconnected() {
- return hasDescendant(allOf(withId(android.R.id.icon),
- withDrawableState(android.R.attr.state_expanded)));
- }
-
- @NonNull
- private Matcher<View> hostConnected() {
- return hasDescendant(allOf(withId(android.R.id.icon),
- withDrawableState(android.R.attr.state_checked)));
- }
}
diff --git a/app/src/main/java/org/connectbot/ConsoleActivity.java b/app/src/main/java/org/connectbot/ConsoleActivity.java
index 95d21d8..7ed9076 100644
--- a/app/src/main/java/org/connectbot/ConsoleActivity.java
+++ b/app/src/main/java/org/connectbot/ConsoleActivity.java
@@ -154,7 +154,7 @@ public class ConsoleActivity extends AppCompatActivity implements BridgeDisconne
private ImageView mKeyboardButton;
- private ActionBar actionBar;
+ @Nullable private ActionBar actionBar;
private boolean inActionBarMenu = false;
private boolean titleBarHide;
@@ -380,7 +380,11 @@ public class ConsoleActivity extends AppCompatActivity implements BridgeDisconne
autoHideEmulatedKeys();
terminal.bridge.tryKeyVibrate();
- if (titleBarHide) {
+ hideActionBarIfRequested();
+ }
+
+ private void hideActionBarIfRequested() {
+ if (titleBarHide && actionBar != null) {
actionBar.hide();
}
}
@@ -436,9 +440,7 @@ public class ConsoleActivity extends AppCompatActivity implements BridgeDisconne
keyboardGroup.startAnimation(keyboard_fade_out);
keyboardGroup.setVisibility(View.GONE);
- if (titleBarHide) {
- actionBar.hide();
- }
+ hideActionBarIfRequested();
keyboardGroupHider = null;
}
};
@@ -449,9 +451,7 @@ public class ConsoleActivity extends AppCompatActivity implements BridgeDisconne
if (keyboardGroupHider != null)
handler.removeCallbacks(keyboardGroupHider);
keyboardGroup.setVisibility(View.GONE);
- if (titleBarHide) {
- actionBar.hide();
- }
+ hideActionBarIfRequested();
}
@Override
@@ -488,7 +488,10 @@ public class ConsoleActivity extends AppCompatActivity implements BridgeDisconne
if (icicle == null) {
requested = getIntent().getData();
} else {
- requested = Uri.parse(icicle.getString(STATE_SELECTED_URI));
+ String uri = icicle.getString(STATE_SELECTED_URI);
+ if (uri != null) {
+ requested = Uri.parse(uri);
+ }
}
inflater = LayoutInflater.from(this);
@@ -605,18 +608,20 @@ public class ConsoleActivity extends AppCompatActivity implements BridgeDisconne
actionBar = getSupportActionBar();
- actionBar.setDisplayHomeAsUpEnabled(true);
- if (titleBarHide) {
- actionBar.hide();
- }
- actionBar.addOnMenuVisibilityListener(new ActionBar.OnMenuVisibilityListener() {
- public void onMenuVisibilityChanged(boolean isVisible) {
- inActionBarMenu = isVisible;
- if (isVisible == false) {
- hideEmulatedKeys();
- }
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ if (titleBarHide) {
+ actionBar.hide();
}
- });
+ actionBar.addOnMenuVisibilityListener(new ActionBar.OnMenuVisibilityListener() {
+ public void onMenuVisibilityChanged(boolean isVisible) {
+ inActionBarMenu = isVisible;
+ if (isVisible == false) {
+ hideEmulatedKeys();
+ }
+ }
+ });
+ }
final HorizontalScrollView keyboardScroll = (HorizontalScrollView) findViewById(R.id.keyboard_hscroll);
if (!hardKeyboard) {
diff --git a/app/src/main/java/org/connectbot/HostListActivity.java b/app/src/main/java/org/connectbot/HostListActivity.java
index 1fe634e..0e6fa3e 100644
--- a/app/src/main/java/org/connectbot/HostListActivity.java
+++ b/app/src/main/java/org/connectbot/HostListActivity.java
@@ -43,6 +43,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
+import android.support.annotation.StyleRes;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.ContextMenu;
@@ -475,6 +476,9 @@ public class HostListActivity extends ListActivity implements OnHostStatusChange
intent.setData(uri);
startActivity(intent);
+ // Clear the input box for the next entry.
+ quickconnect.setText("");
+
return true;
}
@@ -617,26 +621,26 @@ public class HostListActivity extends ListActivity implements OnHostStatusChange
break;
}
- ColorStateList chosen = null;
- if (HostDatabase.COLOR_RED.equals(host.getColor()))
- chosen = this.red;
- else if (HostDatabase.COLOR_GREEN.equals(host.getColor()))
- chosen = this.green;
- else if (HostDatabase.COLOR_BLUE.equals(host.getColor()))
- chosen = this.blue;
-
- Context context = convertView.getContext();
-
- if (chosen != null) {
- // set color normally if not selected
- holder.nickname.setTextColor(chosen);
- holder.caption.setTextColor(chosen);
+ @StyleRes final int chosenStyleFirstLine;
+ @StyleRes final int chosenStyleSecondLine;
+ if (HostDatabase.COLOR_RED.equals(host.getColor())) {
+ chosenStyleFirstLine = R.style.ListItemFirstLineText_Red;
+ chosenStyleSecondLine = R.style.ListItemSecondLineText_Red;
+ } else if (HostDatabase.COLOR_GREEN.equals(host.getColor())) {
+ chosenStyleFirstLine = R.style.ListItemFirstLineText_Green;
+ chosenStyleSecondLine = R.style.ListItemSecondLineText_Green;
+ } else if (HostDatabase.COLOR_BLUE.equals(host.getColor())) {
+ chosenStyleFirstLine = R.style.ListItemFirstLineText_Blue;
+ chosenStyleSecondLine = R.style.ListItemSecondLineText_Blue;
} else {
- // selected, so revert back to default black text
- holder.nickname.setTextAppearance(context, android.R.style.TextAppearance_Large);
- holder.caption.setTextAppearance(context, android.R.style.TextAppearance_Small);
+ chosenStyleFirstLine = R.style.ListItemFirstLineText;
+ chosenStyleSecondLine = R.style.ListItemSecondLineText;
}
+ holder.nickname.setTextAppearance(chosenStyleFirstLine);
+ holder.caption.setTextAppearance(chosenStyleSecondLine);
+
+ Context context = convertView.getContext();
CharSequence nice = context.getString(R.string.bind_never);
if (host.getLastConnect() > 0) {
nice = DateUtils.getRelativeTimeSpanString(host.getLastConnect() * 1000);
diff --git a/app/src/main/res/layout/item_host.xml b/app/src/main/res/layout/item_host.xml
index 56c3d34..8c9f9fc 100644
--- a/app/src/main/res/layout/item_host.xml
+++ b/app/src/main/res/layout/item_host.xml
@@ -17,60 +17,61 @@
-->
<RelativeLayout
- android:id="@android:id/content"
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:minHeight="72dp"
- >
+ android:id="@android:id/content"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="72dp"
+ >
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:layout_alignParentEnd="true"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:layout_marginEnd="16dp"
- android:layout_marginRight="16dp"
- android:contentDescription="@string/image_description_connected"
- android:src="@drawable/connected"
- />
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:layout_marginEnd="16dp"
+ android:layout_marginRight="16dp"
+ android:contentDescription="@string/image_description_connected"
+ android:src="@drawable/connected"
+ />
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentStart="true"
- android:layout_alignParentLeft="true"
- android:layout_alignWithParentIfMissing="true"
- android:layout_centerVertical="true"
- android:layout_marginStart="16dp"
- android:layout_marginLeft="16dp"
- android:layout_marginEnd="16dp"
- android:layout_marginRight="16dp"
- android:orientation="vertical"
- android:layout_toStartOf="@android:id/icon"
- android:layout_toLeftOf="@android:id/icon"
- >
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_alignWithParentIfMissing="true"
+ android:layout_centerVertical="true"
+ android:layout_marginEnd="16dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ android:layout_marginStart="16dp"
+ android:layout_toLeftOf="@android:id/icon"
+ android:layout_toStartOf="@android:id/icon"
+ android:orientation="vertical"
+ >
- <TextView
- android:id="@android:id/text1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="end"
- android:singleLine="true"
- android:paddingTop="20dp"
- android:textAppearance="@style/ListItemFirstLineText"
- />
+ <TextView
+ android:id="@android:id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:paddingTop="20dp"
+ android:singleLine="true"
+ android:textAppearance="@style/ListItemFirstLineText"
+ tools:text="shell.example.com"/>
- <TextView
- android:id="@android:id/text2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingBottom="20dp"
- android:textAppearance="@style/ListItemSecondLineText"
- />
+ <TextView
+ android:id="@android:id/text2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="20dp"
+ android:textAppearance="@style/ListItemSecondLineText"
+ tools:text="2 minutes ago"/>
- </LinearLayout>
+ </LinearLayout>
</RelativeLayout>
diff --git a/app/src/main/res/values-v11/styles.xml b/app/src/main/res/values-v11/styles.xml
index 9f8d6a0..8522aae 100644
--- a/app/src/main/res/values-v11/styles.xml
+++ b/app/src/main/res/values-v11/styles.xml
@@ -17,6 +17,14 @@
*/
-->
<resources>
- <style name="ListItemFirstLineText" parent="TextAppearance.AppCompat" />
- <style name="ListItemSecondLineText" parent="TextAppearance.AppCompat" />
+
+ <style name="ListItemFirstLineText" parent="TextAppearance.AppCompat">
+ <item name="android:textColor">?android:textColorPrimary</item>
+ <item name="android:textSize">16sp</item>
+ </style>
+
+ <style name="ListItemSecondLineText" parent="TextAppearance.AppCompat">
+ <item name="android:textColor">?android:textColorSecondary</item>
+ <item name="android:textSize">14sp</item>
+ </style>
</resources>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index a850d38..13a424f 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -39,4 +39,28 @@
<item name="android:textColor">?android:textColorSecondary</item>
<item name="android:textSize">14sp</item>
</style>
+
+ <style name="ListItemFirstLineText.Red" parent="ListItemFirstLineText">
+ <item name="android:textColor">@color/red</item>
+ </style>
+
+ <style name="ListItemSecondLineText.Red" parent="ListItemSecondLineText">
+ <item name="android:textColor">@color/red</item>
+ </style>
+
+ <style name="ListItemFirstLineText.Green" parent="ListItemFirstLineText">
+ <item name="android:textColor">@color/green</item>
+ </style>
+
+ <style name="ListItemSecondLineText.Green" parent="ListItemSecondLineText">
+ <item name="android:textColor">@color/green</item>
+ </style>
+
+ <style name="ListItemFirstLineText.Blue" parent="ListItemFirstLineText">
+ <item name="android:textColor">@color/blue</item>
+ </style>
+
+ <style name="ListItemSecondLineText.Blue" parent="ListItemSecondLineText">
+ <item name="android:textColor">@color/blue</item>
+ </style>
</resources>