aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/org/connectbot
diff options
context:
space:
mode:
authorKyle Horimoto <khorimoto@gmail.com>2015-09-18 12:22:29 -0700
committerKyle Horimoto <khorimoto@gmail.com>2015-09-25 11:23:36 -0700
commita9700a076d09989a5c6ae77888096e1ad5e4ffbf (patch)
treeaf73f204ad679a6988bd3e97e831aaa5a8a537ba /app/src/main/java/org/connectbot
parentd88325b798d01a4584f551ea14ff072453ce603a (diff)
downloadconnectbot-a9700a076d09989a5c6ae77888096e1ad5e4ffbf.tar.gz
connectbot-a9700a076d09989a5c6ae77888096e1ad5e4ffbf.tar.bz2
connectbot-a9700a076d09989a5c6ae77888096e1ad5e4ffbf.zip
Add EditHostActivity.
Diffstat (limited to 'app/src/main/java/org/connectbot')
-rw-r--r--app/src/main/java/org/connectbot/EditHostActivity.java43
-rw-r--r--app/src/main/java/org/connectbot/HostEditorFragment.java339
-rw-r--r--app/src/main/java/org/connectbot/bean/HostBean.java61
3 files changed, 443 insertions, 0 deletions
diff --git a/app/src/main/java/org/connectbot/EditHostActivity.java b/app/src/main/java/org/connectbot/EditHostActivity.java
new file mode 100644
index 0000000..6c7da11
--- /dev/null
+++ b/app/src/main/java/org/connectbot/EditHostActivity.java
@@ -0,0 +1,43 @@
+/*
+ * ConnectBot: simple, powerful, open-source SSH client for Android
+ * Copyright 2015 Kenny Root, Jeffrey Sharkey
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.connectbot;
+
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+
+import org.connectbot.bean.HostBean;
+
+public class EditHostActivity extends AppCompatActivity implements HostEditorFragment.Listener {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_edit_host);
+
+ if (savedInstanceState == null) {
+ HostEditorFragment editor = HostEditorFragment.newInstance(null);
+ getSupportFragmentManager().beginTransaction()
+ .add(R.id.fragment_container, editor).commit();
+ }
+ }
+
+ @Override
+ public void onHostUpdated(HostBean host) {
+
+ }
+}
diff --git a/app/src/main/java/org/connectbot/HostEditorFragment.java b/app/src/main/java/org/connectbot/HostEditorFragment.java
new file mode 100644
index 0000000..ea9d65f
--- /dev/null
+++ b/app/src/main/java/org/connectbot/HostEditorFragment.java
@@ -0,0 +1,339 @@
+/*
+ * ConnectBot: simple, powerful, open-source SSH client for Android
+ * Copyright 2015 Kenny Root, Jeffrey Sharkey
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.connectbot;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.support.design.widget.TextInputLayout;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.Spinner;
+
+import org.connectbot.bean.HostBean;
+import org.connectbot.transport.SSH;
+import org.connectbot.transport.Telnet;
+import org.connectbot.transport.TransportFactory;
+import org.connectbot.util.HostDatabase;
+
+public class HostEditorFragment extends Fragment {
+
+ private static final String ARG_EXISTING_HOST = "existingHost";
+ private static final String ARG_IS_EXPANDED = "isExpanded";
+ private static final String ARG_QUICKCONNECT_STRING = "quickConnectString";
+
+ // The host being edited.
+ private HostBean mHost;
+
+ // Whether the host is being created for the first time (as opposed to an existing one being
+ // edited).
+ private boolean mIsCreating;
+
+ // The listener for changes to this host.
+ private Listener mListener;
+
+ // Whether the URI parts subsection is expanded.
+ private boolean mIsUriEditorExpanded = false;
+
+ // Whether a URI text edit is in progress. When the quick-connect field is being edited, changes
+ // automatically propagate to the URI part fields; likewise, when the URI part fields are
+ // edited, changes are propagated to the quick-connect field. This boolean safeguards against
+ // infinite loops which can be caused by one field changing the other field, which changes the
+ // first field, etc.
+ private boolean mUriFieldEditInProgress = false;
+
+ private Spinner mTransportSpinner;
+ private TextInputLayout mQuickConnectContainer;
+ private EditText mQuickConnectField;
+ private ImageButton mExpandCollapseButton;
+ private View mUriPartsContainer;
+ private View mUsernameContainer;
+ private EditText mUsernameField;
+ private View mHostnameContainer;
+ private EditText mHostnameField;
+ private View mPortContainer;
+ private EditText mPortField;
+
+ public static HostEditorFragment newInstance(HostBean existingHost) {
+ HostEditorFragment fragment = new HostEditorFragment();
+ Bundle args = new Bundle();
+ if (existingHost != null) {
+ args.putParcelable(ARG_EXISTING_HOST, existingHost.getValues());
+ }
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ public HostEditorFragment() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Bundle bundle = savedInstanceState == null ? getArguments() : savedInstanceState;
+
+ Parcelable existingHostParcelable = bundle.getParcelable(ARG_EXISTING_HOST);
+ mIsCreating = existingHostParcelable == null;
+ if (existingHostParcelable != null) {
+ mHost = HostBean.fromContentValues((ContentValues) existingHostParcelable);
+ } else {
+ mHost = new HostBean();
+ }
+
+ mIsUriEditorExpanded = bundle.getBoolean(ARG_IS_EXPANDED);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.fragment_host_editor, container, false);
+
+ mTransportSpinner = (Spinner) view.findViewById(R.id.transport_selector);
+ ArrayAdapter<String> transportSelection = new ArrayAdapter<>(
+ getActivity(),
+ android.R.layout.simple_spinner_item,
+ TransportFactory.getTransportNames());
+ transportSelection.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mTransportSpinner.setAdapter(transportSelection);
+ mTransportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ String protocol = (String) mTransportSpinner.getSelectedItem();
+ if (protocol == null) {
+ // During initialization, protocol can be null before the list of dropdown items
+ // has been generated. Return early in that case.
+ return;
+ }
+
+ mHost.setProtocol(protocol);
+ mHost.setPort(TransportFactory.getTransport(protocol).getDefaultPort());
+
+ mQuickConnectContainer.setHint(
+ TransportFactory.getFormatHint(protocol, getActivity()));
+
+ // Different protocols have different field types, so show only the fields needed.
+ if (SSH.getProtocolName().equals(protocol)) {
+ mUsernameContainer.setVisibility(View.VISIBLE);
+ mHostnameContainer.setVisibility(View.VISIBLE);
+ mPortContainer.setVisibility(View.VISIBLE);
+ mExpandCollapseButton.setVisibility(View.VISIBLE);
+ } else if (Telnet.getProtocolName().equals(protocol)) {
+ mUsernameContainer.setVisibility(View.GONE);
+ mHostnameContainer.setVisibility(View.VISIBLE);
+ mPortContainer.setVisibility(View.VISIBLE);
+ mExpandCollapseButton.setVisibility(View.VISIBLE);
+ } else {
+ // Local protocol has only one field, so no need to show the URI parts
+ // container.
+ setUriPartsContainerExpanded(false);
+ mExpandCollapseButton.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ mQuickConnectContainer =
+ (TextInputLayout) view.findViewById(R.id.quickconnect_field_container);
+
+ mQuickConnectField = (EditText) view.findViewById(R.id.quickconnect_field);
+ String oldQuickConnect = savedInstanceState == null ?
+ null : savedInstanceState.getString(ARG_QUICKCONNECT_STRING);
+ mQuickConnectField.setText(oldQuickConnect == null ? mHost.toString() : oldQuickConnect);
+ mQuickConnectField.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (mTransportSpinner.getSelectedItem() == null) {
+ // During initialization, protocol can be null before the list of dropdown items
+ // has been generated. Return early in that case.
+ return;
+ }
+
+ if (!mUriFieldEditInProgress) {
+ applyQuickConnectString(
+ s.toString(), (String) mTransportSpinner.getSelectedItem());
+
+ mUriFieldEditInProgress = true;
+ mUsernameField.setText(mHost.getUsername());
+ mHostnameField.setText(mHost.getHostname());
+ mPortField.setText(Integer.toString(mHost.getPort()));
+ mUriFieldEditInProgress = false;
+ }
+ }
+ });
+
+ mExpandCollapseButton = (ImageButton) view.findViewById(R.id.expand_collapse_button);
+ mExpandCollapseButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setUriPartsContainerExpanded(!mIsUriEditorExpanded);
+ }
+ });
+
+ mUriPartsContainer = view.findViewById(R.id.uri_parts_container);
+
+ mUsernameContainer = view.findViewById(R.id.username_field_container);
+ mUsernameField = (EditText) view.findViewById(R.id.username_edit_text);
+ mUsernameField.setText(mHost.getUsername());
+ mUsernameField.addTextChangedListener(new UriDataUpdater(HostDatabase.FIELD_HOST_USERNAME));
+
+ mHostnameContainer = view.findViewById(R.id.hostname_field_container);
+ mHostnameField = (EditText) view.findViewById(R.id.hostname_edit_text);
+ mHostnameField.setText(mHost.getHostname());
+ mHostnameField.addTextChangedListener(new UriDataUpdater(HostDatabase.FIELD_HOST_HOSTNAME));
+
+ mPortContainer = view.findViewById(R.id.port_field_container);
+ mPortField = (EditText) view.findViewById(R.id.port_edit_text);
+ mPortField.setText(Integer.toString(mHost.getPort()));
+ mPortField.addTextChangedListener(new UriDataUpdater(HostDatabase.FIELD_HOST_PORT));
+
+ setUriPartsContainerExpanded(mIsUriEditorExpanded);
+
+ return view;
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ try {
+ mListener = (Listener) context;
+ } catch (ClassCastException e) {
+ throw new ClassCastException(context.toString() + " must implement Listener");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mListener = null;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ super.onSaveInstanceState(savedInstanceState);
+
+ savedInstanceState.putParcelable(ARG_EXISTING_HOST, mHost.getValues());
+ savedInstanceState.putBoolean(ARG_IS_EXPANDED, mIsUriEditorExpanded);
+ savedInstanceState.putString(
+ ARG_QUICKCONNECT_STRING, mQuickConnectField.getText().toString());
+ }
+
+ private void setUriPartsContainerExpanded(boolean expanded) {
+ mIsUriEditorExpanded = expanded;
+
+ if (mIsUriEditorExpanded) {
+ mExpandCollapseButton.setImageResource(R.drawable.ic_expand_less);
+ mUriPartsContainer.setVisibility(View.VISIBLE);
+ } else {
+ mExpandCollapseButton.setImageResource(R.drawable.ic_expand_more);
+ mUriPartsContainer.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Applies the quick-connect URI entered in the field by copying its URI parts to mHost's
+ * fields.
+ * @param quickConnectString The URI entered in the quick-connect field.
+ * @param protocol The protocol for this connection.
+ */
+ private void applyQuickConnectString(String quickConnectString, String protocol) {
+ if (quickConnectString == null || protocol == null)
+ return;
+
+ Uri uri = TransportFactory.getUri(protocol, quickConnectString);
+ if (uri == null) {
+ // If the URI was invalid, null out the associated fields.
+ mHost.setProtocol(protocol);
+ mHost.setUsername(null);
+ mHost.setHostname(null);
+ mHost.setNickname(null);
+ mHost.setPort(TransportFactory.getTransport(protocol).getDefaultPort());
+ return;
+ }
+
+ HostBean host = TransportFactory.getTransport(protocol).createHost(uri);
+ mHost.setProtocol(host.getProtocol());
+ mHost.setUsername(host.getUsername());
+ mHost.setHostname(host.getHostname());
+ mHost.setNickname(host.getNickname());
+ mHost.setPort(host.getPort());
+ }
+
+ public interface Listener {
+ public void onHostUpdated(HostBean host);
+ }
+
+ private class UriDataUpdater implements TextWatcher {
+
+ private final String mFieldType;
+
+ public UriDataUpdater(String fieldType) {
+ mFieldType = fieldType;
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ String text = s.toString();
+
+ if (HostDatabase.FIELD_HOST_USERNAME.equals(mFieldType)) {
+ mHost.setUsername(text);
+ } else if (HostDatabase.FIELD_HOST_HOSTNAME.equals(mFieldType)) {
+ mHost.setHostname(text);
+ } else if (HostDatabase.FIELD_HOST_PORT.equals(mFieldType)) {
+ try {
+ mHost.setPort(Integer.parseInt(text));
+ } catch (NumberFormatException e) {
+ return;
+ }
+ } else {
+ throw new RuntimeException("Invalid field type.");
+ }
+
+ if (!mUriFieldEditInProgress) {
+ mUriFieldEditInProgress = true;
+ mQuickConnectField.setText(mHost.toString());
+ mUriFieldEditInProgress = false;
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/connectbot/bean/HostBean.java b/app/src/main/java/org/connectbot/bean/HostBean.java
index 93d7716..1fbb9be 100644
--- a/app/src/main/java/org/connectbot/bean/HostBean.java
+++ b/app/src/main/java/org/connectbot/bean/HostBean.java
@@ -17,6 +17,10 @@
package org.connectbot.bean;
+import org.connectbot.transport.Local;
+import org.connectbot.transport.SSH;
+import org.connectbot.transport.Telnet;
+import org.connectbot.transport.TransportFactory;
import org.connectbot.util.HostDatabase;
import android.content.ContentValues;
@@ -226,6 +230,29 @@ public class HostBean extends AbstractBean {
return values;
}
+ public static HostBean fromContentValues(ContentValues values) {
+ HostBean host = new HostBean();
+ host.setNickname(values.getAsString(HostDatabase.FIELD_HOST_NICKNAME));
+ host.setProtocol(values.getAsString(HostDatabase.FIELD_HOST_PROTOCOL));
+ host.setUsername(values.getAsString(HostDatabase.FIELD_HOST_USERNAME));
+ host.setHostname(values.getAsString(HostDatabase.FIELD_HOST_HOSTNAME));
+ host.setPort(values.getAsInteger(HostDatabase.FIELD_HOST_PORT));
+ host.setLastConnect(values.getAsLong(HostDatabase.FIELD_HOST_LASTCONNECT));
+ host.setColor(values.getAsString(HostDatabase.FIELD_HOST_COLOR));
+ host.setUseKeys(Boolean.valueOf(values.getAsString(HostDatabase.FIELD_HOST_USEKEYS)));
+ host.setUseAuthAgent(values.getAsString(HostDatabase.FIELD_HOST_USEAUTHAGENT));
+ host.setPostLogin(values.getAsString(HostDatabase.FIELD_HOST_POSTLOGIN));
+ host.setPubkeyId(values.getAsLong(HostDatabase.FIELD_HOST_PUBKEYID));
+ host.setWantSession(Boolean.valueOf(values.getAsString(HostDatabase.FIELD_HOST_WANTSESSION)));
+ host.setDelKey(values.getAsString(HostDatabase.FIELD_HOST_DELKEY));
+ host.setFontSize(values.getAsInteger(HostDatabase.FIELD_HOST_FONTSIZE));
+ host.setCompression(Boolean.valueOf(values.getAsString(HostDatabase.FIELD_HOST_COMPRESSION)));
+ host.setEncoding(values.getAsString(HostDatabase.FIELD_HOST_ENCODING));
+ host.setStayConnected(values.getAsBoolean(HostDatabase.FIELD_HOST_STAYCONNECTED));
+ host.setQuickDisconnect(values.getAsBoolean(HostDatabase.FIELD_HOST_QUICKDISCONNECT));
+ return host;
+ }
+
@Override
public boolean equals(Object o) {
if (o == null || !(o instanceof HostBean))
@@ -302,4 +329,38 @@ public class HostBean extends AbstractBean {
return Uri.parse(sb.toString());
}
+ /**
+ * Generates a "pretty" string to be used in the quick-connect host edit view.
+ */
+ @Override
+ public String toString() {
+ if (protocol == null)
+ return "";
+
+ int defaultPort = TransportFactory.getTransport(protocol).getDefaultPort();
+
+ if (SSH.getProtocolName().equals(protocol)) {
+ if (username == null || hostname == null ||
+ username.equals("") || hostname.equals(""))
+ return "";
+
+ if (port == defaultPort)
+ return username + "@" + hostname;
+ else
+ return username + "@" + hostname + ":" + port;
+ } else if (Telnet.getProtocolName().equals(protocol)) {
+ if (hostname == null || hostname.equals(""))
+ return "";
+ else if (port == defaultPort)
+ return hostname;
+ else
+ return hostname + ":" + port;
+ } else if (Local.getProtocolName().equals(protocol)) {
+ return nickname;
+ }
+
+ // Fail gracefully.
+ return "";
+ }
+
}