Home | History | Annotate | Download | only in activity
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.googlecode.android_scripting.activity;
     18 
     19 import android.app.ListActivity;
     20 import android.content.ComponentName;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.ServiceConnection;
     24 import android.os.Bundle;
     25 import android.os.IBinder;
     26 import android.view.ContextMenu;
     27 import android.view.ContextMenu.ContextMenuInfo;
     28 import android.view.LayoutInflater;
     29 import android.view.Menu;
     30 import android.view.MenuItem;
     31 import android.view.View;
     32 import android.view.ViewGroup;
     33 import android.widget.AdapterView;
     34 import android.widget.BaseAdapter;
     35 import android.widget.ListView;
     36 import android.widget.TextView;
     37 
     38 import com.googlecode.android_scripting.Constants;
     39 import com.googlecode.android_scripting.Log;
     40 import com.googlecode.android_scripting.R;
     41 import com.googlecode.android_scripting.interpreter.InterpreterProcess;
     42 import com.googlecode.android_scripting.service.ScriptingLayerService;
     43 
     44 import java.util.List;
     45 import java.util.Timer;
     46 import java.util.TimerTask;
     47 
     48 import org.connectbot.ConsoleActivity;
     49 
     50 /**
     51  * An activity that allows to monitor running scripts.
     52  *
     53  */
     54 public class ScriptProcessMonitor extends ListActivity {
     55 
     56   private final static int UPDATE_INTERVAL_SECS = 1;
     57 
     58   private final Timer mTimer = new Timer();
     59 
     60   private volatile ScriptingLayerService mService;
     61 
     62   private ScriptListAdapter mUpdater;
     63   private List<InterpreterProcess> mProcessList;
     64   private ScriptMonitorAdapter mAdapter;
     65   private boolean mIsConnected = false;
     66 
     67   private ServiceConnection mConnection = new ServiceConnection() {
     68     @Override
     69     public void onServiceConnected(ComponentName name, IBinder service) {
     70       mService = ((ScriptingLayerService.LocalBinder) service).getService();
     71       mUpdater = new ScriptListAdapter();
     72       mTimer.scheduleAtFixedRate(mUpdater, 0, UPDATE_INTERVAL_SECS * 1000);
     73       mIsConnected = true;
     74     }
     75 
     76     @Override
     77     public void onServiceDisconnected(ComponentName name) {
     78       mService = null;
     79       mIsConnected = false;
     80       mProcessList = null;
     81       mAdapter.notifyDataSetChanged();
     82     }
     83   };
     84 
     85   @Override
     86   public void onCreate(Bundle savedInstanceState) {
     87     super.onCreate(savedInstanceState);
     88     bindService(new Intent(this, ScriptingLayerService.class), mConnection, 0);
     89     CustomizeWindow.requestCustomTitle(this, "Script Monitor", R.layout.script_monitor);
     90     mAdapter = new ScriptMonitorAdapter();
     91     setListAdapter(mAdapter);
     92     registerForContextMenu(getListView());
     93   }
     94 
     95   @Override
     96   public void onPause() {
     97     super.onPause();
     98     if (mUpdater != null) {
     99       mUpdater.cancel();
    100     }
    101     mTimer.purge();
    102   }
    103 
    104   @Override
    105   public void onResume() {
    106     super.onResume();
    107     if (mIsConnected) {
    108       try {
    109         mUpdater = new ScriptListAdapter();
    110         mTimer.scheduleAtFixedRate(mUpdater, 0, UPDATE_INTERVAL_SECS * 1000);
    111       } catch (IllegalStateException e) {
    112         Log.e(e.getMessage(), e);
    113       }
    114     }
    115   }
    116 
    117   @Override
    118   public void onDestroy() {
    119     super.onDestroy();
    120     mTimer.cancel();
    121     unbindService(mConnection);
    122   }
    123 
    124   @Override
    125   protected void onListItemClick(ListView list, View view, int position, long id) {
    126     final InterpreterProcess script = (InterpreterProcess) list.getItemAtPosition(position);
    127     Intent intent = new Intent(this, ConsoleActivity.class);
    128     intent.putExtra(Constants.EXTRA_PROXY_PORT, script.getPort());
    129     startActivity(intent);
    130   }
    131 
    132   @Override
    133   public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
    134     menu.add(Menu.NONE, 0, Menu.NONE, "Stop");
    135   }
    136 
    137   @Override
    138   public boolean onContextItemSelected(MenuItem item) {
    139     AdapterView.AdapterContextMenuInfo info;
    140     try {
    141       info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
    142     } catch (ClassCastException e) {
    143       Log.e("Bad menuInfo", e);
    144       return false;
    145     }
    146 
    147     InterpreterProcess script = mAdapter.getItem(info.position);
    148     if (script == null) {
    149       Log.v("No script selected.");
    150       return false;
    151     }
    152 
    153     Intent intent = new Intent(ScriptProcessMonitor.this, ScriptingLayerService.class);
    154     intent.setAction(Constants.ACTION_KILL_PROCESS);
    155     intent.putExtra(Constants.EXTRA_PROXY_PORT, script.getPort());
    156     startService(intent);
    157 
    158     return true;
    159   }
    160 
    161   @Override
    162   public boolean onPrepareOptionsMenu(Menu menu) {
    163     menu.clear();
    164     // TODO(damonkohler): How could mProcessList ever be null?
    165     if (mProcessList != null && !mProcessList.isEmpty()) {
    166       menu.add(Menu.NONE, 0, Menu.NONE, R.string.stop_all).setIcon(
    167           android.R.drawable.ic_menu_close_clear_cancel);
    168     }
    169     return super.onPrepareOptionsMenu(menu);
    170   }
    171 
    172   @Override
    173   public boolean onOptionsItemSelected(MenuItem item) {
    174     Intent intent = new Intent(this, ScriptingLayerService.class);
    175     intent.setAction(Constants.ACTION_KILL_ALL);
    176     startService(intent);
    177     return true;
    178   }
    179 
    180   private class ScriptListAdapter extends TimerTask {
    181     private int mmExpectedModCount = 0;
    182     private volatile List<InterpreterProcess> mmList;
    183 
    184     @Override
    185     public void run() {
    186       if (mService == null) {
    187         mmList.clear();
    188         mTimer.cancel();
    189       } else {
    190         int freshModCount = mService.getModCount();
    191         if (freshModCount != mmExpectedModCount) {
    192           mmExpectedModCount = freshModCount;
    193           mmList = mService.getScriptProcessesList();
    194         }
    195       }
    196       runOnUiThread(new Runnable() {
    197         public void run() {
    198           mProcessList = mUpdater.getFreshProcessList();
    199           mAdapter.notifyDataSetChanged();
    200         }
    201       });
    202     }
    203 
    204     private List<InterpreterProcess> getFreshProcessList() {
    205       return mmList;
    206     }
    207   }
    208 
    209   private class ScriptMonitorAdapter extends BaseAdapter {
    210 
    211     @Override
    212     public int getCount() {
    213       if (mProcessList == null) {
    214         return 0;
    215       }
    216       return mProcessList.size();
    217     }
    218 
    219     @Override
    220     public InterpreterProcess getItem(int position) {
    221       return mProcessList.get(position);
    222     }
    223 
    224     @Override
    225     public long getItemId(int position) {
    226       return position;
    227     }
    228 
    229     @Override
    230     public View getView(int position, View convertView, ViewGroup parent) {
    231       View itemView;
    232       if (convertView == null) {
    233         LayoutInflater inflater =
    234             (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    235         itemView = inflater.inflate(R.layout.script_monitor_list_item, parent, false);
    236       } else {
    237         itemView = convertView;
    238       }
    239       InterpreterProcess process = mProcessList.get(position);
    240       ((TextView) itemView.findViewById(R.id.process_title)).setText(process.getName());
    241       ((TextView) itemView.findViewById(R.id.process_age)).setText(process.getUptime());
    242       ((TextView) itemView.findViewById(R.id.process_details)).setText(process.getHost() + ":"
    243           + process.getPort());
    244       ((TextView) itemView.findViewById(R.id.process_status)).setText("PID " + process.getPid());
    245       return itemView;
    246     }
    247   }
    248 }
    249