| /* |
| * 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; |
| } |
| } |
| } |