package org.gscript; import java.util.ArrayList; import org.gscript.process.IProcessService; import org.gscript.process.IServiceCallback; import org.gscript.process.ProcessDescriptor; import org.gscript.process.ProcessService; import org.gscript.process.ProcessState; import org.gscript.settings.ShellProfile; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.Checkable; import android.widget.ListView; import android.widget.TextView; import com.actionbarsherlock.view.ActionMode; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.view.SubMenu; public class FragmentProcess extends GenericListFragment { static final String LOG_TAG = FragmentProcess.class.getSimpleName(); IProcessService mProcessService; ProcessAdapter mProcessAdapter; boolean mIsBound; Handler mHandler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHandler = new Handler(); mProcessAdapter = new ProcessAdapter(getActivity()); initListFragment(R.layout.fragment_active, R.id.listViewActive, mProcessAdapter); setHasOptionsMenu(true); /* bind service */ bindProcessService(); } @Override public void onDestroy() { super.onDestroy(); /* unbind service */ unbindProcessService(); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.fragment_process, menu); /* add start sub-menu */ MenuItem startProcess = menu.findItem(R.id.menu_process_start); SubMenu submenu = startProcess.getSubMenu(); if (submenu != null) { ArrayList<String> profileKeys = ShellProfile.getKeys(this.getActivity()); for(String profileKey : profileKeys) { String profileName = ShellProfile.getName(getActivity(), profileKey); MenuItem item = submenu.add(profileName); Intent processIntent = new Intent(getActivity(), ProcessService.class); processIntent.setAction(ProcessService.ACTION_START); processIntent.putExtra(ProcessService.EXTRA_PROFILE, profileKey); item.setIntent(processIntent); } } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_process_kill_active: /* kill all running processes */ if (mProcessService != null) { try { mProcessService.requestKillProcesses(mServiceCallback); } catch (RemoteException e) { } } return true; default: if(item.getIntent() != null && ProcessService.ACTION_START.equals(item.getIntent().getAction())) { getActivity().startService(item.getIntent()); return true; } return super.onOptionsItemSelected(item); } } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ProcessDescriptor pd = (ProcessDescriptor) parent.getAdapter().getItem( position); startActivity(pd.getActivityIntent(getActivity())); } @Override public void onCreateActionMode(ActionMode mode, Menu menu) { MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.fragment_process_context, menu); } @Override public void onPrepareActionMode(ActionMode mode, Menu menu) { int checkedItems = getCheckedItemCount(); String title = getSherlockActivity().getResources().getString( R.string.menu_process_context_title); mode.setTitle(String.format(title, checkedItems)); } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.menu_process_context_kill: /* stop checked process items */ long[] ids = getCheckedItemIds(); for (long id : ids) { /* send kill request to selected process(es) */ Log.d(LOG_TAG, "stop process with id " + id); ProcessDescriptor pd = mProcessAdapter.getItemForId((int) id); if (pd != null) try { mProcessService.requestKillProcess(pd); } catch (RemoteException e) { } } mode.finish(); return true; default: mode.finish(); return true; } } class ProcessAdapter extends BaseAdapter { ProcessDescriptor[] pds; Context context; public ProcessAdapter(Context context) { this.context = context; } public void set(ProcessDescriptor[] pds) { this.pds = pds; this.notifyDataSetChanged(); } @Override public View getView(int position, View convertView, ViewGroup parent) { ProcessDescriptor pd = (ProcessDescriptor) getItem(position); View view = convertView; if (view == null) { LayoutInflater inflater; inflater = LayoutInflater.from(context); view = inflater.inflate(R.layout.list_active, null); } else { if (view instanceof Checkable) { Checkable checkable = (Checkable) view; checkable.setChecked(((ListView) parent) .isItemChecked(position)); } } if (pd != null) { TextView textViewTitle = (TextView) view .findViewById(R.id.list_item_title); textViewTitle.setText(pd.getIntent().getData() .getLastPathSegment()); } return view; } @Override public int getCount() { return (pds != null ? pds.length : 0); } @Override public Object getItem(int position) { return (pds != null ? pds[position] : null); } public ProcessDescriptor getItemForId(int id) { if (pds == null) return null; for (ProcessDescriptor pd : pds) if (pd.hashCode() == id) return pd; return null; } @Override public long getItemId(int position) { return ((pds != null && position < pds.length) ? pds[position] .hashCode() : -1); } @Override public boolean hasStableIds() { return true; } } void reloadProcesses() { this.mHandler.post(mReloadRunnable); } Runnable mReloadRunnable = new Runnable() { @Override public void run() { try { if (mProcessService != null) { ProcessDescriptor[] pds = mProcessService.getProcesses( mServiceCallback, ProcessState.STATE_RUNNING); mProcessAdapter.set(pds); restoreCheckedItems(); } } catch (RemoteException e) { e.printStackTrace(); } } }; IServiceCallback.Stub mServiceCallback = new IServiceCallback.Stub() { @Override public void OnProcessStateChanged(ProcessDescriptor pd, int state) throws RemoteException { reloadProcesses(); } }; private ServiceConnection mServiceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { mProcessService = IProcessService.Stub.asInterface(service); try { if (mProcessService != null) mProcessService.registerServiceCallback(mServiceCallback); reloadProcesses(); } catch (RemoteException e) { e.printStackTrace(); } } public void onServiceDisconnected(ComponentName className) { mProcessService = null; } }; void bindProcessService() { this.getActivity().bindService( new Intent(getActivity(), ProcessService.class), mServiceConnection, Context.BIND_AUTO_CREATE); mIsBound = true; } void unbindProcessService() { if (mIsBound) { try { if (mProcessService != null) mProcessService.unregisterServiceCallback(mServiceCallback); } catch (RemoteException e) { e.printStackTrace(); } this.getActivity().unbindService(mServiceConnection); mIsBound = false; } } }