/* * Copyright (C) 2007 The Android Open Source Project * * 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.eolwral.osmonitor.processes; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.List; import android.app.ActivityManager; import android.app.AlertDialog; import android.app.Dialog; import android.app.ListActivity; import android.app.TabActivity; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.widget.ListView; import android.view.ContextMenu; import android.view.Gravity; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ContextMenu.ContextMenuInfo; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.widget.AbsListView; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; import android.widget.Toast; import android.widget.AbsListView.OnScrollListener; import android.widget.AdapterView.AdapterContextMenuInfo; import android.view.GestureDetector; import android.view.GestureDetector.OnGestureListener; import com.eolwral.osmonitor.*; import com.eolwral.osmonitor.messages.DebugBox; import com.eolwral.osmonitor.preferences.Preferences; import com.eslab.osmonitor.providerDB.SaveInformationActivity; public class ProcessList extends ListActivity implements OnGestureListener, OnTouchListener, ListView.OnScrollListener { private boolean mBusy = false; private static ProcessListAdapter UpdateInterface = null; private static ProcessList Self = null; private static JNIInterface JNILibrary = JNIInterface.getInstance(); private static int OrderBy = JNILibrary.doSortPID; //기본적인 정렬방법은 PID로 정렬 하는 것이다. private ProcessInfoQuery ProcessInfo = null; // TextView private static TextView CPUUsage = null; private static TextView RunProcess = null; private static TextView MemTotal = null; private static TextView MemFree = null; private static DecimalFormat MemoryFormat = new DecimalFormat(",000"); // Short & Click private static int longClick = 2; private static int shortClick = 3; private static boolean shortTOlong = false; private static boolean longTOshort = false; // Selected item private static int selectedPosition = 0; private static String selectedPackageName = null; private static int selectedPackagePID = 0; // MultiSelect private static CheckBox MultiSelect = null; private static Button MultiKill = null; // Freeze private static CheckBox Freeze = null; private static boolean FreezeIt = false; private static boolean FreezeTask = false; // Root private static boolean Rooted = false; // Slow Adapter private static boolean SlowAdapter = false; // Gesture private GestureDetector gestureScanner = new GestureDetector(this);; private static boolean GestureLong = false; private static boolean GestureSingleTap = false; @Override public boolean onTouchEvent(MotionEvent me) { return gestureScanner.onTouchEvent(me); } @Override public boolean onDown(MotionEvent e) { return false; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { try { if (Math.abs(e1.getY() - e2.getY()) > CompareFunc.SWIPE_MAX_OFF_PATH) return false; else if (e1.getX() - e2.getX() > CompareFunc.SWIPE_MIN_DISTANCE && Math.abs(velocityX) > CompareFunc.SWIPE_THRESHOLD_VELOCITY){ //옆으로 밀어서 넘기는 제스처를 제거 한다. //((TabActivity) this.getParent()).getTabHost().setCurrentTab(1); } else if (e2.getX() - e1.getX() > CompareFunc.SWIPE_MIN_DISTANCE && Math.abs(velocityX) > CompareFunc.SWIPE_THRESHOLD_VELOCITY){ //옆으로 밀어서 넘기는 제스처를 제거 한다. //((TabActivity) this.getParent()).getTabHost().setCurrentTab(4); } else return false; } catch (Exception e) { // nothing } GestureLong = false; return true; } @Override public void onLongPress(MotionEvent e) { //performLongClick(); GestureLong = true; return; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } @Override public void onShowPress(MotionEvent e) { return; } @Override public boolean onSingleTapUp(MotionEvent e) { GestureSingleTap = true; return true; } @Override public boolean onTouch(View v, MotionEvent event) { GestureSingleTap = false; if(gestureScanner.onTouchEvent(event)) { GestureLong = false; if(GestureSingleTap == true) v.onTouchEvent(event); return true; } else { if(v.onTouchEvent(event)) return true; return false; } } //핸들러에 의해서 동작하는 Thread이다. private Runnable uiRunnable = new Runnable() { public void run() { //전체적인 cpu 사용률과 실핼중인 프로세스의 수와 총 사용 메모리, Free 메모리를 표시한다. if(JNILibrary.doDataLoad() == 1) { CPUUsage.setText(JNILibrary.GetCPUUsage()); RunProcess.setText(JNILibrary.GetProcessCounts()+""); MemTotal.setText(MemoryFormat.format(JNILibrary.GetMemTotal())+ "K"); MemFree.setText(MemoryFormat.format(JNILibrary.GetMemBuffer() +JNILibrary.GetMemCached()+JNILibrary.GetMemFree())+ "K"); Self.onRefresh(); } else { //정지를 체크 했다면 Thread 동작을 멈춰 준다. 멈춘 상태에서도 지속적으로 이 핸들러는 동작하기 때문에 //다시 멈춤을 풀어 줄 수가 있는 것이다. if(FreezeIt) { if(!FreezeTask) { JNILibrary.doTaskStop(); FreezeTask = true; } else CPUUsage.setText(JNILibrary.GetCPUUsage()); } else { if(FreezeTask) { JNILibrary.doTaskStart(JNILibrary.doTaskProcess); FreezeTask = false; } } } //0.05초 마다 핸들러를 발생 시키기 때문에 응답성을 매우 높일 수가 있다. uiHandler.postDelayed(this, 50); } }; private Handler uiHandler = new Handler(); private ActivityManager ActivityMan = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); gestureScanner = new GestureDetector(this); // Use a custom layout file setContentView(R.layout.processlayout); //4가지 정보를 출력하기 위함 이다. CPUUsage = (TextView) findViewById(R.id.CPUUsage); RunProcess = (TextView) findViewById(R.id.RunProcessText); MemTotal = (TextView) findViewById(R.id.MemTotalText); MemFree = (TextView) findViewById(R.id.MemFreeText); // Tell the list view which view to display when the list is empty // empty일때 empty라는 글자를 표시해 주기 위함 이다. getListView().setEmptyView(findViewById(R.id.empty)); // Use our own list adapter // ListActivity를 상속 받았기 떄문에 이런식으로 처리 한다. // Self는 자기 자신에 대한 객체 이다. Self = this; Self.getListView().setOnTouchListener(this); //리스너를 등록해 준다. setListAdapter(new ProcessListAdapter(this)); //커스터마이즈한 어뎁터를 달아준다. UpdateInterface = (ProcessListAdapter) getListAdapter(); //할당한 어뎁터를 다시 읽어 들인다. ProcessInfo = ProcessInfoQuery.getInstance(this); //Thread를 생성해서 시작 시킨다. ActivityMan = (ActivityManager) getSystemService(ACTIVITY_SERVICE); // 엑티비티 관리자를 얻어온다. getListView().setOnScrollListener(this); // 스크롤 리스너를 설정한다. //MultiKill 멀티 선택을 했을때 멀티 킬을 할 수 있도록 도와주는 것이다. MultiKill = (Button) findViewById(R.id.MultiKill); MultiKill.setOnClickListener( new OnClickListener(){ public void onClick(View v) { String KillCmd = ""; //현재 화며에 표시되는 프로세스 리스트중에서 선택 된 것을 추출 한다. ArrayList<String> KillList = ProcessInfo.getSelected(); for(String pid:KillList) { int tPID = Integer.parseInt(pid); //root 권할일 때와 root 권한이 아닐 때를 구분하여 킬 한다. if(Rooted) { if(KillCmd.length() == 0) KillCmd += "kill -9 "+tPID; else KillCmd += ";kill -9 "+tPID; } else { for(int i =0; i < JNILibrary.GetProcessCounts(); i++) { if(JNILibrary.GetProcessPID(i) == tPID) { //PID 값을 가지고 프로세스를 종료 시킨다. android.os.Process.killProcess(tPID); //2.1에서는 사용가능하지만 2.2 이상 부터는 동작하지 않는다. //ActivityMan.restartPackage(JNILibrary.GetProcessName(i)); //2.2에서 허용하는 코드이다. 하지만 깔끔하게 종료 되지는 않는다. ActivityMan.killBackgroundProcesses(JNILibrary.GetProcessName(i)); break; } } } } //루투 권한을 선택 하였을 때 그냥 커멘드창에다가 명령어를 입력해서 종료하는 방식이다. if(Rooted) JNILibrary.execCommand(KillCmd+"\n"); //선택된 정보들을 삭제한다. ProcessInfo.clearSelected(); //데이터를 리플래쉬 한다. JNILibrary.doDataRefresh(); //어뎁터에게 데이터가 변화됬음을 알려서 다시 ListView를 채우도록 한다. UpdateInterface.notifyDataSetChanged(); Toast.makeText(Self, "Kill "+KillList.size()+" Process..", Toast.LENGTH_SHORT).show(); } } ); // Freeze 체크 박스 리스너이다. Freeze = (CheckBox) findViewById(R.id.Freeze); Freeze.setOnClickListener( new OnClickListener(){ public void onClick(View v) { if(FreezeIt) { FreezeIt = false; } else { FreezeIt = true; } } } ); // Multi-Select MultiSelect = (CheckBox) findViewById(R.id.MultiSelect); MultiSelect.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged( CompoundButton buttonView, boolean isChecked) { if(isChecked) { MultiKill.setEnabled(true); } else { MultiKill.setEnabled(false); ProcessInfo.clearSelected(); UpdateInterface.notifyDataSetChanged(); } } } ); // restore 컨텍스트 메뉴를 ListView에 설정 한다. registerForContextMenu(getListView()); } //어뎁터를 갱신해주는 기능을 한다. public void onRefresh() { JNILibrary.doDataSwap(); // 단순히 data_refresh값을 리턴해주는 기능을 가진다. 큰의미는 없는것 같다. UpdateInterface.notifyDataSetChanged(); } //사용자의 설정값을 읽어와서 그에 맞는 동작을 하도록 처리한다. private void restorePrefs() { //system 관련 Application을 제외할지에 대한 것을 판단한다. boolean ExcludeSystem = false; boolean SortIn = false; int Algorithm = 1; // load settings 디펄트 셋팅 객체를 로드 한다. SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); try { /* * 사용자 엑션에 대한 설정 값들이다. 1: show Detial 2: Actio Menu 3: Right Detail/Left Action */ longClick = Integer.parseInt(settings.getString(Preferences.PREF_LONGBEHAVIOR, "2")); shortClick = Integer.parseInt(settings.getString(Preferences.PREF_SHORTBEHAVIOR, "3")); //프로세스 업데이트 시간을 설정 한다. (default는 2초 이다.) JNILibrary.doDataTime(Integer.parseInt(settings.getString(Preferences.PREF_UPDATE, "2"))); //소팅 종류와 소팅 알고리즘을 선택 한다. OrderBy = Integer.parseInt(settings.getString(Preferences.PREF_ORDER, "1")); Algorithm = Integer.parseInt(settings.getString(Preferences.PREF_ALGORITHM, "1")); } catch(Exception e) {} SortIn = settings.getBoolean(Preferences.PREF_SORT, false); ExcludeSystem = settings.getBoolean(Preferences.PREF_EXCLUDE, false); // change options JNILibrary.SetProcessSort(OrderBy); JNILibrary.SetProcessAlgorithm(Algorithm); if(ExcludeSystem) JNILibrary.SetProcessFilter(1); else JNILibrary.SetProcessFilter(0); if(SortIn) JNILibrary.SetProcessOrder(0); else JNILibrary.SetProcessOrder(1); // change display TextView OrderType = (TextView) findViewById(R.id.OrderType); switch(OrderBy) { case 1: case 2: case 5: OrderType.setText(getResources().getString(R.string.load_text)); break; case 3: OrderType.setText(getResources().getString(R.string.mem_text)); break; case 4: OrderType.setText(getResources().getString(R.string.thread_text)); break; } UpdateInterface.OrderBy = OrderBy; // 선택된 mode로 정렬하기 위해서 사용한다. TableLayout Msv = (TableLayout) findViewById(R.id.MultiSelectView); if(settings.getBoolean(Preferences.PREF_HIDEMULTISELECT, false)) Msv.setVisibility(View.GONE); else Msv.setVisibility(View.VISIBLE); // Status Bar if(settings.getBoolean(Preferences.PREF_STATUSBAR, false)) { if(OSMonitorService.getInstance() == null) startService(new Intent(this, OSMonitorService.class)); else OSMonitorService.getInstance().Notify(); } else if(OSMonitorService.getInstance() != null) OSMonitorService.getInstance().stopSelf(); // Root Rooted = settings.getBoolean(Preferences.PREF_ROOTED, false); // Slow Adapter SlowAdapter = settings.getBoolean(Preferences.PREF_SLOWADAPTER, false); } public boolean onCreateOptionsMenu(Menu optionMenu) { super.onCreateOptionsMenu(optionMenu); optionMenu.add(0, 1, 0, getResources().getString(R.string.options_text)); optionMenu.add(0, 4, 0, getResources().getString(R.string.aboutoption_text)); optionMenu.add(0, 5, 0, getResources().getString(R.string.forceexit_text)); optionMenu.add(0, 6, 0, getResources().getString(R.string.open_db_information)); return true; } @Override protected Dialog onCreateDialog(int id) { switch (id) { case 0: return new AlertDialog.Builder(this) .setIcon(R.drawable.monitor) .setTitle(R.string.app_name) .setMessage(R.string.about_text) .setPositiveButton(R.string.aboutbtn_text, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { } }) .create(); case 1: return null; } return null; } protected void onActivityResult(int requestCode, int resultCode, Intent data) { restorePrefs(); } //opTion 메뉴를 눌렀을 때의 동작에 대해서 기술 되어 있다. @Override public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item); switch(item.getItemId()) { case 1: Intent launchPreferencesIntent = new Intent().setClass( this, Preferences.class); startActivityForResult(launchPreferencesIntent, 0); break; case 4: this.showDialog(0); break; case 5: if(OSMonitorService.getInstance() != null) OSMonitorService.getInstance().stopSelf(); JNILibrary.killSelf(this); break; //청크 DB를 open하는 코드이다. case 6: Intent intentDB = new Intent().setClass( this, SaveInformationActivity.class); startActivityForResult(intentDB, 0); break; } return true; } @Override public void onPause() { uiHandler.removeCallbacks(uiRunnable); JNILibrary.doTaskStop(); if(Freeze.isChecked()) { Freeze.setChecked(false); FreezeIt = false; } if(MultiSelect.isChecked()) { MultiSelect.setChecked(false); MultiKill.setEnabled(false); ProcessInfo.clearSelected(); } super.onPause(); } //create에서 ProcessInfoQuery 클래스의 Thread를 수행 한다면 이건에서는 JIN로 작성된 Native Thread를 수행한다. @Override protected void onResume() { //프리퍼런스 설정값대로 설정을 읽어 드려서 그대로 시스템이 동작하도록 만든다. restorePrefs(); //native Thread를 수행 시켜 준다. Thread의 기능이 틀린데 그 기능을 Type으로 구분하여 하나의 Thread로 여러 동작을 하도록 설정 했다. JNILibrary.doTaskStart(JNILibrary.doTaskProcess); //정치를 체크 했을 때 반응하는 것과 4개의 메이저 정보를 출력하는 것을 담당하는 핸들러이다. 0.05초 마다 한번씩 동작하게 되어 진다. uiHandler.post(uiRunnable); super.onResume(); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { boolean useMenu = false; ProcessDetailView selectedItemView = (ProcessDetailView) ((AdapterContextMenuInfo)menuInfo).targetView; if(!GestureLong) { selectedItemView.setSelected(true); return; } selectedPosition = (int) ((AdapterContextMenuInfo)menuInfo).position; selectedPackageName = ProcessInfo.getPacakge(selectedPosition); selectedPackagePID = JNILibrary.GetProcessPID(selectedPosition); if(shortTOlong) { useMenu = true; shortTOlong = false; } else { if(longClick == 1) ((ProcessListAdapter)getListAdapter()).toggle(selectedItemView, selectedPosition, false, false); else if(longClick == 2) useMenu = true; else if(longClick == 3) if(!((ProcessListAdapter)getListAdapter()).toggle(selectedItemView, selectedPosition, true, false)) useMenu = true; } if(useMenu) { menu.setHeaderTitle(ProcessInfo.getPackageName(selectedPosition)); menu.add(0, 1, 0, getResources().getString(R.string.killdialog_text)); menu.add(0, 2, 0, getResources().getString(R.string.switchdialog_text)); menu.add(0, 3, 0, getResources().getString(R.string.watchlog_text)); menu.add(0, 4, 0, getResources().getString(R.string.btncancel_title)); } else { menu.clear(); longTOshort = true; } } @Override public boolean onContextItemSelected(MenuItem item) { switch(item.getItemId()) { case 1: if(Rooted) { JNILibrary.execCommand("kill -9 "+JNILibrary.GetProcessPID(selectedPosition)+"\n"); } else { android.os.Process.killProcess(JNILibrary.GetProcessPID(selectedPosition)); ActivityMan.restartPackage(selectedPackageName); } if(FreezeIt && FreezeTask) { JNILibrary.doTaskStart(JNILibrary.doTaskProcess); JNILibrary.doDataRefresh(); JNILibrary.doTaskStop(); } else { JNILibrary.doDataRefresh(); } UpdateInterface.notifyDataSetChanged(); return true; case 2: String ClassName = null; // find ClassName PackageManager QueryPackage = this.getPackageManager(); Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); List<ResolveInfo> appList = QueryPackage.queryIntentActivities(mainIntent, 0); for(int i=0; i<appList.size(); i++) { if(appList.get(i).activityInfo.applicationInfo.packageName.equals(selectedPackageName)) ClassName = appList.get(i).activityInfo.name; } if(ClassName != null) { Intent switchIntent = new Intent(); switchIntent.setAction(Intent.ACTION_MAIN); switchIntent.addCategory(Intent.CATEGORY_LAUNCHER); switchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); switchIntent.setComponent(new ComponentName(selectedPackageName, ClassName)); startActivity(switchIntent); finish(); } return true; case 3: Intent WatchLog = new Intent(this, DebugBox.class); WatchLog.putExtra("targetPID", selectedPackagePID); startActivity(WatchLog); return true; } return super.onContextItemSelected(item); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { if(!GestureSingleTap && !GestureLong) { ((ProcessDetailView) v).setSelected(false); return; } if(GestureLong) { v.performLongClick(); return; } if(longTOshort) { longTOshort = false; return; } if(MultiSelect.isChecked()) { ((ProcessListAdapter)getListAdapter()).toggle((ProcessDetailView) v, position, false, MultiSelect.isChecked()); return; } if(shortClick == 1) ((ProcessListAdapter)getListAdapter()).toggle((ProcessDetailView) v, position, false, false); else if(shortClick == 2) { shortTOlong = true; GestureLong = true; v.performLongClick(); } else if(shortClick == 3) if(!((ProcessListAdapter)getListAdapter()).toggle((ProcessDetailView) v, position, true, false)) { shortTOlong = true; GestureLong = true; v.performLongClick(); } } //커스터 마이즈한 리스트 어뎁터 이다. 결국 모든것은 이 어뎁터에 의해서 수행되어 질 것이다. private class ProcessListAdapter extends BaseAdapter { // onCreate에서 한번 해줫기 때문에 여기서 또 해줄 필요가 없어서 주석 처리 했다. // private ProcessInfoQuery ProcessInfo = null; public int OrderBy = JNILibrary.doSortPID; public ProcessListAdapter(Context context) { // ProcessInfo = ProcessInfoQuery.getInstance(context); mContext = context; } public int getCount() { return JNILibrary.GetProcessCounts(); //전체 길이에 대한 정보이다. } public Object getItem(int position) { return position; // 현재 위치에대한 정보 } public long getItemId(int position) { return position; // 현재 아이디에 대한 정보 } //실제적으로 ListView를 채우는 코드이다. public View getView(int position, View convertView, ViewGroup parent) { ProcessDetailView sv = null; ProcessInfo.doCacheInfo(position); String OrderValue = ""; switch(OrderBy) { case 1: case 2: case 5: OrderValue = ProcessInfo.getProcessLoad(position); break; case 3: OrderValue = ProcessInfo.getProcessMem(position); break; case 4: OrderValue = ProcessInfo.getProcessThreads(position); break; } //맨 오르쪽에 있는 세모 화살표를 제어 한다. Drawable DetailIcon = null; if(!ProcessInfo.getExpaned(position)) DetailIcon = mContext.getResources().getDrawable(R.drawable.dshow); else DetailIcon = mContext.getResources().getDrawable(R.drawable.dclose); if (convertView == null && mBusy == true) { sv = new ProcessDetailView(mContext, ProcessInfo.getProcessPID(position), ProcessInfo.getExpaned(position), position); } else if (convertView == null && mBusy == false) { sv = new ProcessDetailView(mContext, ProcessInfo.getAppIcon(position), ProcessInfo.getProcessPID(position), ProcessInfo.getPackageName(position), OrderValue, ProcessInfo.getAppInfo(position), ProcessInfo.getExpaned(position), position, DetailIcon); } else if (mBusy == true) { sv = (ProcessDetailView)convertView; sv.setView(ProcessInfo.getProcessPID(position), position); sv.setContext(""); sv.setExpanded(ProcessInfo.getExpaned(position)); sv.setMultiSelected(ProcessInfo.getSelected(position)); } else { sv = (ProcessDetailView)convertView; sv.setView( ProcessInfo.getAppIcon(position), ProcessInfo.getProcessPID(position), ProcessInfo.getPackageName(position), OrderValue, position, DetailIcon); sv.setContext(ProcessInfo.getAppInfo(position)); sv.setExpanded(ProcessInfo.getExpaned(position)); sv.setMultiSelected(ProcessInfo.getSelected(position)); } return sv; } public boolean toggle(ProcessDetailView v, int position, boolean split, boolean multi) { if(multi) { if(ProcessInfo.getSelected(position)) ProcessInfo.setSelected(position, false); else ProcessInfo.setSelected(position, true); notifyDataSetChanged(); return false; } if(v.checkClick() != 1 && split == true) { return false; } else { if(ProcessInfo.getExpaned(position)) ProcessInfo.setExpaned(position, false); else ProcessInfo.setExpaned(position, true); } notifyDataSetChanged(); return true; } private Context mContext; } /* * ListView의 한셀 한셀을 나타낸다. Expanded의 값에 따라서 자세한 정보가 보여질지 안보여질지를 결정 한다. * TableLayout을 상속 받아서 프로세스 정보를 표시해 주는 용도로 완성 시킨다. */ private class ProcessDetailView extends TableLayout { private TableRow TitleRow; private TextView PIDField; private ImageView IconField; private TextView NameField; private ImageView DetailField; private TextView ValueField; private TextView AppInfoField; private boolean Expanded = false; public ProcessDetailView(Context context, Drawable Icon, int PID, String Name, String Value, String AppInfo, boolean expanded, int position, Drawable DetailIcon) { super(context); this.setColumnStretchable(2, true); //this.setOrientation(VERTICAL); PIDField = new TextView(context); // 프로세스 ID를 표시한다. IconField = new ImageView(context); // 어플리케이션 아이콘을 표시 한다. NameField = new TextView(context); // 어플리케이션의 이름을 표시 한다. ValueField = new TextView(context); AppInfoField = new TextView(context); DetailField = new ImageView(context); DetailField.setImageDrawable(DetailIcon); // 화살표 아이콘을 의미 한다. DetailField.setPadding(3, 3, 3, 3); PIDField.setText(""+PID); // PID 정보를 삽입한다. IconField.setImageDrawable(Icon); IconField.setPadding(8, 3, 3, 3); NameField.setText(Name); ValueField.setText(Value); //Odervalue가 된다. PIDField.setGravity(Gravity.LEFT); PIDField.setPadding(3, 3, 3, 3); //스크린 사이즈에 따른 처리를 해주는 것이다. if(CompareFunc.getScreenSize() == 2) PIDField.setWidth(90); else if(CompareFunc.getScreenSize() == 0) PIDField.setWidth(35); else PIDField.setWidth(55); NameField.setPadding(3, 3, 3, 3); NameField.setGravity(Gravity.LEFT); NameField.setWidth(getWidth()- IconField.getWidth() - DetailField.getWidth() - 115); ValueField.setPadding(3, 3, 8, 3); if(CompareFunc.getScreenSize() == 2) ValueField.setWidth(80); else if (CompareFunc.getScreenSize() == 0) ValueField.setWidth(35); else ValueField.setWidth(50); /* * 최종적으로 TableRow를 셍상히야 값을 달아준다. * PID Icon(application) Name Value(load값) DetailField(Icon) */ TitleRow = new TableRow(context); TitleRow.addView(PIDField); TitleRow.addView(IconField); TitleRow.addView(NameField); TitleRow.addView(ValueField); TitleRow.addView(DetailField); addView(TitleRow); //DetailField 버튼을 눌렀을때 나오는정보를 할당한다. (ProcessInfoQuery에 의해서 값이 만들어 진다.) AppInfoField.setText(AppInfo); addView(AppInfoField); //혹장 상태 여부에 따라서 VISIBLE 인지 GONE인지를 결정한다. GONE은 자리까지 제거해서 사라지게 하는 것이다. AppInfoField.setVisibility(expanded ? VISIBLE : GONE); //포지션마다 백그라운드 색을 다르게 한다. if(position % 2 == 0) setBackgroundColor(0x80444444); else setBackgroundColor(0x80000000); } public ProcessDetailView(Context context, int PID, boolean expanded,int position) { super(context); this.setColumnStretchable(2, true); PIDField = new TextView(context); IconField = new ImageView(context); NameField = new TextView(context); ValueField = new TextView(context); AppInfoField = new TextView(context); DetailField = new ImageView(context); DetailField.setImageDrawable(null); DetailField.setPadding(3, 3, 3, 3); IconField.setImageDrawable(null); IconField.setPadding(8, 3, 3, 3); PIDField.setText(""+PID); PIDField.setGravity(Gravity.LEFT); PIDField.setPadding(3, 3, 3, 3); if(CompareFunc.getScreenSize() == 2) PIDField.setWidth(90); else if(CompareFunc.getScreenSize() == 0) PIDField.setWidth(35); else PIDField.setWidth(55); NameField.setPadding(3, 3, 3, 3); NameField.setGravity(Gravity.LEFT); NameField.setWidth(getWidth()- IconField.getWidth() - DetailField.getWidth() - 115); ValueField.setPadding(3, 3, 8, 3); if(CompareFunc.getScreenSize() == 2) ValueField.setWidth(80); else if (CompareFunc.getScreenSize() == 0) ValueField.setWidth(35); else ValueField.setWidth(50); NameField.setText("Loading"); TitleRow = new TableRow(context); TitleRow.addView(PIDField); TitleRow.addView(IconField); TitleRow.addView(NameField); TitleRow.addView(ValueField); TitleRow.addView(DetailField); addView(TitleRow); addView(AppInfoField); AppInfoField.setVisibility(expanded ? VISIBLE : GONE); if(position % 2 == 0) setBackgroundColor(0x80444444); else setBackgroundColor(0x80000000); } public void setContext(String AppInfo) { AppInfoField.setText(AppInfo); } public void setView( Drawable Icon, int PID, String Name, String Value, int position, Drawable DetailIcon) { IconField.setImageDrawable(Icon); DetailField.setImageDrawable(DetailIcon); PIDField.setText(""+PID); NameField.setText(Name); ValueField.setText(Value); if(position % 2 == 0) setBackgroundColor(0x80444444); else setBackgroundColor(0x80000000); } public void setView(int PID, int position) { IconField.setImageDrawable(null); DetailField.setImageDrawable(null); // IconField.setVisibility(View.GONE); // DetailField.setVisibility(View.INVISIBLE); PIDField.setText(""+PID); NameField.setText("Loading"); ValueField.setText(""); if(position % 2 == 0) setBackgroundColor(0x80444444); else setBackgroundColor(0x80000000); } /** * Convenience method to expand or hide the dialogue */ public void setExpanded(boolean expanded) { AppInfoField.setVisibility(expanded ? VISIBLE : GONE); } public void setMultiSelected(boolean selected) { if(selected) setBackgroundColor(0x803CC8FF); } public boolean onTouchEvent(MotionEvent event) { if(event.getX() > getWidth()/3*2 ) Expanded = true; else if (event.getX() <= getWidth()/3*2 ) Expanded = false; return super.onTouchEvent(event); } public int checkClick() { if(Expanded == true) { Expanded = false; return 1; } return 0; } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // TODO Auto-generated method stub } // 스크롤 리스너이다. 화면이 맨 아래로 이동 했을때 다음 내용이 자동적으로 나오도록 처리 하기 위해서 // 리스너를 등록해 주었다. @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // TODO Auto-generated method stub switch (scrollState) { case OnScrollListener.SCROLL_STATE_IDLE: mBusy = false; if(SlowAdapter) { int count = view.getChildCount(); for (int i=0; i<count; i++) { view.getChildAt(i).refreshDrawableState(); } } break; case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: case OnScrollListener.SCROLL_STATE_FLING: if(SlowAdapter) mBusy = true; else mBusy = false; break; } } }