blob: 8f70a6644689c35c8e93a694480f389e4e61a6fe [file] [log] [blame]
/*
* Copyright (C) 2010 Google Inc.
*
* 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.googlecode.android_scripting.activity;
import android.app.ListActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.googlecode.android_scripting.Analytics;
import com.googlecode.android_scripting.Constants;
import com.googlecode.android_scripting.Log;
import com.googlecode.android_scripting.R;
import com.googlecode.android_scripting.interpreter.InterpreterProcess;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.connectbot.ConsoleActivity;
/**
* An activity that allows to monitor running scripts.
*
* @author Alexey Reznichenko (alexey.reznichenko@gmail.com)
*/
public class ScriptProcessMonitor extends ListActivity {
private final static int UPDATE_INTERVAL_SECS = 1;
private final Timer mTimer = new Timer();
private volatile ScriptingLayerService mService;
private ScriptListAdapter mUpdater;
private List<InterpreterProcess> mProcessList;
private ScriptMonitorAdapter mAdapter;
private boolean mIsConnected = false;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = ((ScriptingLayerService.LocalBinder) service).getService();
mUpdater = new ScriptListAdapter();
mTimer.scheduleAtFixedRate(mUpdater, 0, UPDATE_INTERVAL_SECS * 1000);
mIsConnected = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
mIsConnected = false;
mProcessList = null;
mAdapter.notifyDataSetChanged();
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindService(new Intent(this, ScriptingLayerService.class), mConnection, 0);
CustomizeWindow.requestCustomTitle(this, "Script Monitor", R.layout.script_monitor);
mAdapter = new ScriptMonitorAdapter();
setListAdapter(mAdapter);
registerForContextMenu(getListView());
Analytics.trackActivity(this);
}
@Override
public void onPause() {
super.onPause();
if (mUpdater != null) {
mUpdater.cancel();
}
mTimer.purge();
}
@Override
public void onResume() {
super.onResume();
if (mIsConnected) {
try {
mUpdater = new ScriptListAdapter();
mTimer.scheduleAtFixedRate(mUpdater, 0, UPDATE_INTERVAL_SECS * 1000);
} catch (IllegalStateException e) {
Log.e(e.getMessage(), e);
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
mTimer.cancel();
unbindService(mConnection);
}
@Override
protected void onListItemClick(ListView list, View view, int position, long id) {
final InterpreterProcess script = (InterpreterProcess) list.getItemAtPosition(position);
Intent intent = new Intent(this, ConsoleActivity.class);
intent.putExtra(Constants.EXTRA_PROXY_PORT, script.getPort());
startActivity(intent);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
menu.add(Menu.NONE, 0, Menu.NONE, "Stop");
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info;
try {
info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
} catch (ClassCastException e) {
Log.e("Bad menuInfo", e);
return false;
}
InterpreterProcess script = mAdapter.getItem(info.position);
if (script == null) {
Log.v("No script selected.");
return false;
}
Intent intent = new Intent(ScriptProcessMonitor.this, ScriptingLayerService.class);
intent.setAction(Constants.ACTION_KILL_PROCESS);
intent.putExtra(Constants.EXTRA_PROXY_PORT, script.getPort());
startService(intent);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.clear();
// TODO(damonkohler): How could mProcessList ever be null?
if (mProcessList != null && !mProcessList.isEmpty()) {
menu.add(Menu.NONE, 0, Menu.NONE, R.string.stop_all).setIcon(
android.R.drawable.ic_menu_close_clear_cancel);
}
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent = new Intent(this, ScriptingLayerService.class);
intent.setAction(Constants.ACTION_KILL_ALL);
startService(intent);
return true;
}
private class ScriptListAdapter extends TimerTask {
private int mmExpectedModCount = 0;
private volatile List<InterpreterProcess> mmList;
@Override
public void run() {
if (mService == null) {
mmList.clear();
mTimer.cancel();
} else {
int freshModCount = mService.getModCount();
if (freshModCount != mmExpectedModCount) {
mmExpectedModCount = freshModCount;
mmList = mService.getScriptProcessesList();
}
}
runOnUiThread(new Runnable() {
public void run() {
mProcessList = mUpdater.getFreshProcessList();
mAdapter.notifyDataSetChanged();
}
});
}
private List<InterpreterProcess> getFreshProcessList() {
return mmList;
}
}
private class ScriptMonitorAdapter extends BaseAdapter {
@Override
public int getCount() {
if (mProcessList == null) {
return 0;
}
return mProcessList.size();
}
@Override
public InterpreterProcess getItem(int position) {
return mProcessList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View itemView;
if (convertView == null) {
LayoutInflater inflater =
(LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
itemView = inflater.inflate(R.layout.script_monitor_list_item, parent, false);
} else {
itemView = convertView;
}
InterpreterProcess process = mProcessList.get(position);
((TextView) itemView.findViewById(R.id.process_title)).setText(process.getName());
((TextView) itemView.findViewById(R.id.process_age)).setText(process.getUptime());
((TextView) itemView.findViewById(R.id.process_details)).setText(process.getHost() + ":"
+ process.getPort());
((TextView) itemView.findViewById(R.id.process_status)).setText("PID " + process.getPid());
return itemView;
}
}
}