Commit 5f6a2173 authored by Roumen Petrov's avatar Roumen Petrov
Browse files

rewrite activity WindowList to use classes from support library and switch...

rewrite activity WindowList to use classes from support library and switch WindowListActionBarAdapter to use its functionality
parent 09747d01
......@@ -137,6 +137,15 @@
<data android:mimeType="text/*"/>
</intent-filter>
</activity>
<activity
android:name="com.termoneplus.WindowListActivity"
android:label="@string/window_list"
android:parentActivityName="jackpal.androidterm.Term"
android:theme="@style/AppTheme.NoActionBar">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="jackpal.androidterm.Term"/>
</activity>
<activity
android:name="com.termoneplus.shortcuts.FileSelection"
android:configChanges="orientation|keyboardHidden"
......
......@@ -24,7 +24,6 @@
import android.widget.Spinner;
import jackpal.androidterm.R;
import jackpal.androidterm.WindowListAdapter;
import jackpal.androidterm.util.SessionList;
......
/*
* Copyright (C) 2018 Roumen Petrov. All rights reserved.
*
* 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.termoneplus;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import jackpal.androidterm.R;
import jackpal.androidterm.Term;
import jackpal.androidterm.TermDebug;
import jackpal.androidterm.TermService;
import jackpal.androidterm.util.SessionList;
public class WindowListActivity extends AppCompatActivity
implements WindowListFragment.OnItemSelectedListener {
private final ServiceConnection service_connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
TermService.TSBinder binder = (TermService.TSBinder) service;
TermService term_service = binder.getService();
SessionList sessions = term_service.getSessions();
setSessions(sessions);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_windowlist);
setResult(RESULT_CANCELED);
{
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
{
ActionBar actionBar = getSupportActionBar();
if (actionBar != null)
actionBar.setDisplayHomeAsUpEnabled(true);
}
{
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onPositionSelected(-1);
}
});
}
}
@Override
protected void onResume() {
super.onResume();
Intent TSIntent = new Intent(this, TermService.class);
if (!bindService(TSIntent, service_connection, BIND_AUTO_CREATE)) {
Log.e(TermDebug.LOG_TAG, "bind to service failed!");
}
}
@Override
protected void onPause() {
super.onPause();
setSessions(null);
unbindService(service_connection);
}
@Override
public void onPositionSelected(int position) {
Intent data = new Intent();
data.putExtra(Term.EXTRA_WINDOW_ID, position);
setResult(RESULT_OK, data);
finish();
}
private void setSessions(SessionList sessions) {
FragmentManager manager = getSupportFragmentManager();
WindowListFragment fragment = (WindowListFragment) manager.findFragmentById(R.id.windowlist);
WindowListAdapter adapter = (WindowListAdapter) fragment.getListAdapter();
adapter.setSessions(sessions);
}
}
/*
* Copyright (C) 2018 Roumen Petrov. All rights reserved.
*
* 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.termoneplus;
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import jackpal.androidterm.R;
import jackpal.androidterm.emulatorview.TermSession;
import jackpal.androidterm.emulatorview.UpdateCallback;
import jackpal.androidterm.util.SessionList;
public class WindowListAdapter extends BaseAdapter implements UpdateCallback {
protected final LayoutInflater inflater;
private final Context context;
private SessionList sessions;
public WindowListAdapter(Context context) {
this.context = context;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void setSessions(SessionList sessions) {
if ((sessions == null) && (this.sessions != null)) {
this.sessions.removeCallback(this);
this.sessions.removeTitleChangedListener(this);
}
// Set to null to avoid extra notification in onUpdate event
this.sessions = null;
if (sessions != null) {
sessions.addCallback(this);
sessions.addTitleChangedListener(this);
}
this.sessions = sessions;
notifyDataSetChanged();
}
@Override
public int getCount() {
return sessions == null ? 0 : sessions.size();
}
@Override
public TermSession getItem(int position) {
return sessions.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@SuppressLint("InflateParams")
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
// NOTE for Adapters parent will apply default layout parameters unless ...!
convertView = inflater.inflate(R.layout.content_windowlist, null);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.title);
holder.close = (WindowListFragment.CloseButton) convertView.findViewById(R.id.close);
holder.close.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = (Integer) view.getTag();
sessions.remove(position);
notifyDataSetChanged();
}
}
);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.title.setText(getItemTitle(position));
holder.close.setTag(position);
return convertView;
}
public void onUpdate() {
if (sessions == null) return;
notifyDataSetChanged();
}
protected String getItemTitle(int position) {
String title = null;
{
TermSession item = sessions.get(position);
if (item != null) title = item.getTitle();
}
if (TextUtils.isEmpty(title)) {
title = context.getString(R.string.window_title, position + 1);
}
return title;
}
private class ViewHolder {
public TextView title;
public WindowListFragment.CloseButton close;
}
}
/*
* Copyright (C) 2018 Roumen Petrov. All rights reserved.
*
* 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.termoneplus;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.ListFragment;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import jackpal.androidterm.R;
public class WindowListFragment extends ListFragment implements AdapterView.OnItemClickListener {
private OnItemSelectedListener listener;
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
listener = (OnItemSelectedListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement OnItemSelectedListener");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_windowlist, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
WindowListAdapter adapter = new WindowListAdapter(getActivity());
setListAdapter(adapter);
getListView().setOnItemClickListener(this);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (listener != null) listener.onPositionSelected(position);
}
public interface OnItemSelectedListener {
void onPositionSelected(int position);
}
public static class CloseButton extends AppCompatImageView {
public CloseButton(Context context) {
super(context);
}
public CloseButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CloseButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
// Avoid child elements to share pressed state with their parent.
// NOTE parent android:clickable attribute set to false is not same!
// As result parent could be pressed and Fragment receives onItemClick event.
public void setPressed(boolean pressed) {
if (pressed && ((View) getParent()).isPressed()) return;
super.setPressed(pressed);
}
}
}
/*
* Copyright (C) 2007 The Android Open Source Project
* Copyright (C) 2017 Roumen Petrov. All rights reserved.
* Copyright (C) 2017-2018 Roumen Petrov. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -17,6 +17,7 @@
package jackpal.androidterm;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
......@@ -35,6 +36,8 @@
import android.os.IBinder;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
......@@ -57,6 +60,8 @@
import android.widget.Toast;
import com.termoneplus.TermActionBar;
import com.termoneplus.WindowListActivity;
import com.termoneplus.WindowListAdapter;
import com.termoneplus.utils.WrapOpenURL;
import java.io.IOException;
......@@ -555,7 +560,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
} else if (id == R.id.menu_close_window) {
confirmCloseWindow();
} else if (id == R.id.menu_window_list) {
startActivityForResult(new Intent(this, WindowList.class), REQUEST_CHOOSE_WINDOW);
startActivityForResult(new Intent(this, WindowListActivity.class), REQUEST_CHOOSE_WINDOW);
} else if (id == R.id.menu_reset) {
doResetTerminal();
Toast toast = Toast.makeText(this, R.string.reset_toast_notification, Toast.LENGTH_LONG);
......@@ -973,24 +978,28 @@ private void synchronizeActionBar() {
}
private class WindowListActionBarAdapter extends WindowListAdapter implements UpdateCallback {
// From android.R.style in API 13
private static final int TextAppearance_Holo_Widget_ActionBar_Title = 0x01030112;
public WindowListActionBarAdapter(SessionList sessions) {
super(sessions);
super(Term.this);
setSessions(sessions);
}
@SuppressLint("InflateParams")
@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView label = new TextView(Term.this);
String title = getSessionTitle(position, getString(R.string.window_title, position + 1));
label.setText(title);
if (AndroidCompat.SDK >= 13) {
label.setTextAppearance(Term.this, TextAppearance_Holo_Widget_ActionBar_Title);
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.actionbar_windowlist, null);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.title);
convertView.setTag(holder);
} else {
label.setTextAppearance(Term.this, android.R.style.TextAppearance_Medium);
holder = (ViewHolder) convertView.getTag();
}
return label;
holder.title.setText(getItemTitle(position));
return convertView;
}
@Override
......@@ -1002,6 +1011,10 @@ public void onUpdate() {
notifyDataSetChanged();
synchronizeActionBar();
}
private class ViewHolder {
public TextView title;
}
}
private class EmulatorViewGestureListener extends SimpleOnGestureListener {
......
......@@ -49,7 +49,7 @@ public class TermService extends Service implements TermSession.FinishCallback
private SessionList mTermSessions;
public class TSBinder extends Binder {
TermService getService() {
public TermService getService() {
Log.i("TermService", "Activity binding to service");
return TermService.this;
}
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2018 Roumen Petrov. All rights reserved.
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.
-->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textAppearance="?android:attr/textAppearanceMedium">
</TextView>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2018 Roumen Petrov. All rights reserved.
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.
-->
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.termoneplus.WindowListActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="96dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<fragment
android:id="@+id/windowlist"
android:name="com.termoneplus.WindowListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="@layout/fragment_windowlist"/>
</RelativeLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end|right"
android:layout_margin="@dimen/fab_margin"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="@string/new_window"
android:textAppearance="?android:attr/textAppearanceMedium"
tools:layout_marginRight="@dimen/fab_margin"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@android:drawable/ic_menu_add"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2018 Roumen Petrov. All rights reserved.
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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingEnd="@dimen/activity_horizontal_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingStart="@dimen/activity_horizontal_margin">
<TextView