diff options
Diffstat (limited to 'app/src/main')
8 files changed, 176 insertions, 35 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f4a0c34..f43a428 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,8 +17,8 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.connectbot" - android:versionName="1.8.5" - android:versionCode="375" + android:versionName="1.8.6" + android:versionCode="376" android:installLocation="auto"> <uses-sdk /> diff --git a/app/src/main/java/org/connectbot/ConsoleActivity.java b/app/src/main/java/org/connectbot/ConsoleActivity.java index 0e7a693..6a6aa32 100644 --- a/app/src/main/java/org/connectbot/ConsoleActivity.java +++ b/app/src/main/java/org/connectbot/ConsoleActivity.java @@ -103,6 +103,7 @@ public class ConsoleActivity extends AppCompatActivity implements BridgeDisconne private static final int KEYBOARD_DISPLAY_TIME = 3000; private static final int KEYBOARD_REPEAT_INITIAL = 500; private static final int KEYBOARD_REPEAT = 100; + private static final String STATE_SELECTED_URI = "selectedUri"; protected ViewPager pager = null; protected TabLayout tabs = null; @@ -470,7 +471,11 @@ public class ConsoleActivity extends AppCompatActivity implements BridgeDisconne setVolumeControlStream(AudioManager.STREAM_MUSIC); // handle requested console from incoming intent - requested = getIntent().getData(); + if (icicle == null) { + requested = getIntent().getData(); + } else { + requested = Uri.parse(icicle.getString(STATE_SELECTED_URI)); + } inflater = LayoutInflater.from(this); @@ -1190,6 +1195,18 @@ public class ConsoleActivity extends AppCompatActivity implements BridgeDisconne unbindService(connection); } + @Override + public void onSaveInstanceState(Bundle savedInstanceState) { + // Maintain selected host if connected. + if (adapter.getCurrentTerminalView() != null + && !adapter.getCurrentTerminalView().bridge.isDisconnected()) { + Uri uri = adapter.getCurrentTerminalView().bridge.host.getUri(); + savedInstanceState.putString(STATE_SELECTED_URI, uri.toString()); + } + + super.onSaveInstanceState(savedInstanceState); + } + private void startCopyMode() { // mark as copying and reset any previous bounds TerminalView terminalView = (TerminalView) adapter.getCurrentTerminalView(); @@ -1375,7 +1392,7 @@ public class ConsoleActivity extends AppCompatActivity implements BridgeDisconne // and add our terminal view control, using index to place behind overlay final TerminalView terminal = new TerminalView(container.getContext(), bridge); - terminal.setId(R.id.console_flip); + terminal.setId(R.id.terminal_view); view.addView(terminal, 0); // Tag the view with its bridge so it can be retrieved later. @@ -1400,7 +1417,7 @@ public class ConsoleActivity extends AppCompatActivity implements BridgeDisconne } View view = (View) object; - TerminalView terminal = (TerminalView) view.findViewById(R.id.console_flip); + TerminalView terminal = (TerminalView) view.findViewById(R.id.terminal_view); HostBean host = terminal.bridge.host; int itemIndex = POSITION_NONE; @@ -1453,7 +1470,7 @@ public class ConsoleActivity extends AppCompatActivity implements BridgeDisconne public TerminalView getCurrentTerminalView() { View currentView = pager.findViewWithTag(getBridgeAtPosition(pager.getCurrentItem())); if (currentView == null) return null; - return (TerminalView) currentView.findViewById(R.id.console_flip); + return (TerminalView) currentView.findViewById(R.id.terminal_view); } } } diff --git a/app/src/main/java/org/connectbot/HostListActivity.java b/app/src/main/java/org/connectbot/HostListActivity.java index 2d8e882..1fe634e 100644 --- a/app/src/main/java/org/connectbot/HostListActivity.java +++ b/app/src/main/java/org/connectbot/HostListActivity.java @@ -20,6 +20,7 @@ package org.connectbot; import java.util.List; import org.connectbot.bean.HostBean; +import org.connectbot.service.OnHostStatusChangedListener; import org.connectbot.service.TerminalBridge; import org.connectbot.service.TerminalManager; import org.connectbot.transport.TransportFactory; @@ -32,17 +33,15 @@ import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.Intent.ShortcutIconResource; import android.content.ServiceConnection; import android.content.SharedPreferences; -import android.content.Intent.ShortcutIconResource; import android.content.SharedPreferences.Editor; import android.content.res.ColorStateList; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.Handler; import android.os.IBinder; -import android.os.Message; import android.preference.PreferenceManager; import android.text.format.DateUtils; import android.util.Log; @@ -51,19 +50,20 @@ import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; import android.view.MenuItem.OnMenuItemClickListener; +import android.view.View; import android.view.View.OnKeyListener; +import android.view.ViewGroup; import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; +import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.Spinner; import android.widget.TextView; -import android.widget.AdapterView.OnItemClickListener; -public class HostListActivity extends ListActivity { +public class HostListActivity extends ListActivity implements OnHostStatusChangedListener { public final static String TAG = "CB.HostListActivity"; public static final String DISCONNECT_ACTION = "org.connectbot.action.DISCONNECT"; @@ -96,13 +96,6 @@ public class HostListActivity extends ListActivity { */ private boolean closeOnDisconnectAll = true; - protected Handler updateHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - HostListActivity.this.updateList(); - } - }; - private ServiceConnection connection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { bound = ((TerminalManager.TerminalBinder) service).getService(); @@ -110,12 +103,16 @@ public class HostListActivity extends ListActivity { // update our listview binder to find the service HostListActivity.this.updateList(); + bound.registerOnHostStatusChangedListener(HostListActivity.this); + if (waitingForDisconnectAll) { disconnectAll(); } } public void onServiceDisconnected(ComponentName className) { + bound.unregisterOnHostStatusChangedListener(HostListActivity.this); + bound = null; HostListActivity.this.updateList(); } @@ -161,9 +158,6 @@ public class HostListActivity extends ListActivity { closeOnDisconnectAll = waitingForDisconnectAll && closeOnDisconnectAll; } - /* (non-Javadoc) - * @see android.app.Activity#onNewIntent(android.content.Intent) - */ @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); @@ -370,7 +364,6 @@ public class HostListActivity extends ListActivity { connect.setOnMenuItemClickListener(new OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { bridge.dispatchDisconnect(true); - updateHandler.sendEmptyMessage(-1); return true; } }); @@ -410,7 +403,7 @@ public class HostListActivity extends ListActivity { bridge.dispatchDisconnect(true); hostdb.deleteHost(host); - updateHandler.sendEmptyMessage(-1); + updateList(); } }) .setNegativeButton(R.string.delete_neg, null).create().show(); @@ -433,7 +426,6 @@ public class HostListActivity extends ListActivity { .setPositiveButton(R.string.disconnect_all_pos, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { bound.disconnectAll(true, false); - updateHandler.sendEmptyMessage(-1); waitingForDisconnectAll = false; // Clear the intent so that the activity can be relaunched without closing. @@ -511,8 +503,14 @@ public class HostListActivity extends ListActivity { this.setListAdapter(adapter); } - class HostAdapter extends ArrayAdapter<HostBean> { - private List<HostBean> hosts; + @Override + public void onHostStatusChanged() { + updateList(); + } + + static class HostAdapter extends BaseAdapter { + private final LayoutInflater inflater; + private final List<HostBean> hosts; private final TerminalManager manager; private final ColorStateList red, green, blue; @@ -525,8 +523,7 @@ public class HostListActivity extends ListActivity { } public HostAdapter(Context context, List<HostBean> hosts, TerminalManager manager) { - super(context, R.layout.item_host, hosts); - + this.inflater = LayoutInflater.from(context); this.hosts = hosts; this.manager = manager; @@ -539,7 +536,7 @@ public class HostListActivity extends ListActivity { * Check if we're connected to a terminal with the given host. */ private int getConnectedState(HostBean host) { - // always disconnected if we dont have backend service + // always disconnected if we don't have backend service if (this.manager == null) return STATE_UNKNOWN; @@ -553,6 +550,32 @@ public class HostListActivity extends ListActivity { } @Override + public int getCount() { + return hosts.size(); + } + + @Override + public Object getItem(int position) { + return hosts.get(position); + } + + /** + * Use the database's IDs for the host. + */ + @Override + public long getItemId(int position) { + return hosts.get(position).getId(); + } + + /** + * Since we're using the database's IDs, they're unchanging. + */ + @Override + public boolean hasStableIds() { + return true; + } + + @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; @@ -566,8 +589,9 @@ public class HostListActivity extends ListActivity { holder.icon = (ImageView) convertView.findViewById(android.R.id.icon); convertView.setTag(holder); - } else + } else { holder = (ViewHolder) convertView.getTag(); + } HostBean host = hosts.get(position); if (host == null) { @@ -609,8 +633,8 @@ public class HostListActivity extends ListActivity { holder.caption.setTextColor(chosen); } else { // selected, so revert back to default black text - holder.nickname.setTextAppearance(context, android.R.attr.textAppearanceLarge); - holder.caption.setTextAppearance(context, android.R.attr.textAppearanceSmall); + holder.nickname.setTextAppearance(context, android.R.style.TextAppearance_Large); + holder.caption.setTextAppearance(context, android.R.style.TextAppearance_Small); } CharSequence nice = context.getString(R.string.bind_never); diff --git a/app/src/main/java/org/connectbot/service/OnHostStatusChangedListener.java b/app/src/main/java/org/connectbot/service/OnHostStatusChangedListener.java new file mode 100644 index 0000000..0d6ced7 --- /dev/null +++ b/app/src/main/java/org/connectbot/service/OnHostStatusChangedListener.java @@ -0,0 +1,26 @@ +/* + * 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.service; + +/** + * Used to notify interested parties when a {@link TerminalBridge} has changed materially + * changed status (e.g., connected, disconnected, name changed, etc). + */ +public interface OnHostStatusChangedListener { + public void onHostStatusChanged(); +} diff --git a/app/src/main/java/org/connectbot/service/TerminalManager.java b/app/src/main/java/org/connectbot/service/TerminalManager.java index a15dff0..5416ddb 100644 --- a/app/src/main/java/org/connectbot/service/TerminalManager.java +++ b/app/src/main/java/org/connectbot/service/TerminalManager.java @@ -81,6 +81,8 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen public BridgeDisconnectedListener disconnectListener = null; + private final ArrayList<OnHostStatusChangedListener> hostStatusChangedListeners = new ArrayList<>(); + public Map<String, KeyHolder> loadedKeypairs = new HashMap<String, KeyHolder>(); public Resources res; @@ -252,6 +254,8 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen // also update database with new connected time touchHost(host); + notifyHostStatusChanged(); + return bridge; } @@ -354,6 +358,8 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen disconnected.add(bridge.host); } + notifyHostStatusChanged(); + if (shouldHideRunningNotification) { ConnectionNotifier.getInstance().hideRunningNotification(this); } @@ -719,4 +725,28 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen mPendingReconnect.clear(); } } + + /** + * Register a {@code listener} that wants to know when a host's status materially changes. + * @see #hostStatusChangedListeners + */ + public void registerOnHostStatusChangedListener(OnHostStatusChangedListener listener) { + if (!hostStatusChangedListeners.contains(listener)) { + hostStatusChangedListeners.add(listener); + } + } + + /** + * Unregister a {@code listener} that wants to know when a host's status materially changes. + * @see #hostStatusChangedListeners + */ + public void unregisterOnHostStatusChangedListener(OnHostStatusChangedListener listener) { + hostStatusChangedListeners.remove(listener); + } + + private void notifyHostStatusChanged() { + for (OnHostStatusChangedListener listener : hostStatusChangedListeners) { + listener.onHostStatusChanged(); + } + } } diff --git a/app/src/main/java/org/connectbot/util/HostDatabase.java b/app/src/main/java/org/connectbot/util/HostDatabase.java index d8cdf09..f721aeb 100644 --- a/app/src/main/java/org/connectbot/util/HostDatabase.java +++ b/app/src/main/java/org/connectbot/util/HostDatabase.java @@ -32,6 +32,7 @@ import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; +import android.support.annotation.VisibleForTesting; import android.util.Log; import com.trilead.ssh2.KnownHosts; @@ -155,6 +156,10 @@ public class HostDatabase extends RobustSQLiteOpenHelper { public void onCreate(SQLiteDatabase db) { super.onCreate(db); + createTables(db); + } + + private void createTables(SQLiteDatabase db) { db.execSQL("CREATE TABLE " + TABLE_HOSTS + " (_id INTEGER PRIMARY KEY, " + FIELD_HOST_NICKNAME + " TEXT, " @@ -203,6 +208,17 @@ public class HostDatabase extends RobustSQLiteOpenHelper { db.execSQL(CREATE_TABLE_COLOR_DEFAULTS_INDEX); } + @VisibleForTesting + public void resetDatabase() { + SQLiteDatabase db = getWritableDatabase(); + db.execSQL("DROP TABLE IF EXISTS " + TABLE_HOSTS); + db.execSQL("DROP TABLE IF EXISTS " + TABLE_PORTFORWARDS); + db.execSQL("DROP TABLE IF EXISTS " + TABLE_COLORS); + db.execSQL("DROP TABLE IF EXISTS " + TABLE_COLOR_DEFAULTS); + createTables(db); + db.close(); + } + @Override public void onRobustUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) throws SQLiteException { // Versions of the database before the Android Market release will be diff --git a/app/src/main/jni/com_google_ase_Exec.cpp b/app/src/main/jni/com_google_ase_Exec.cpp index b2fa39f..a9d1aba 100644 --- a/app/src/main/jni/com_google_ase_Exec.cpp +++ b/app/src/main/jni/com_google_ase_Exec.cpp @@ -90,7 +90,12 @@ static int create_subprocess( } fcntl(ptm, F_SETFD, FD_CLOEXEC); - if(grantpt(ptm) || unlockpt(ptm) || + if( +#if !defined(ANDROID) + /* this actually doesn't do anything on Android */ + grantpt(ptm) || +#endif + unlockpt(ptm) || ptsname_r(ptm, devname, sizeof(devname))){ LOG("[ trouble with /dev/ptmx - %s ]\n", strerror(errno)); return -1; diff --git a/app/src/main/res/values/viewpager.xml b/app/src/main/res/values/viewpager.xml new file mode 100644 index 0000000..cc73c50 --- /dev/null +++ b/app/src/main/res/values/viewpager.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<resources> + <!-- This is so that ConsoleActivity has something to refer to when + setting the ID of the TerminalView instances in the ViewPager. --> + <item name="terminal_view" type="id"/> +</resources> |