package com.baru.barukill.ui;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.baru.barukill.R;
import com.baru.barukill.common.BaseActivity;
import com.baru.barukill.common.anno.InjectView;
import com.baru.barukill.util.CLogger;
/**
*
* <h3><b>MainActivity</b></h3></br>
*
* 메인화면
*
* @author aincc@barusoft.com
* @version 1.0.0
* @since 1.0.0
*/
public class MainActivity extends BaseActivity implements OnClickListener, OnItemClickListener
{
/**
* 최대 서비스 수집 개수
*
* @since 1.0.0
*/
private static final int MAX_SERVICE = 100;
/**
* 사용자 어플리케이션 정보 테이블
*
* @since 1.0.0
*/
private Map<String, PackageInfo> userPackageList = new Hashtable<String, PackageInfo>();
/**
* 어플리케이션 종료 버튼
*
* @since 1.0.0
*/
@InjectView(id = R.id.killAppsBtn)
private Button killAppsBtn;
/**
* 갱신 버튼
*
* @since 1.0.0
*/
@InjectView(id = R.id.refreshBtn)
private ImageButton refreshBtn;
/**
* 전체 선택 버튼
*
* @since 1.0.0
*/
@InjectView(id = R.id.allSelectBtn)
private ImageButton allSelectBtn;
/**
* 리스트뷰
*
* @since 1.0.0
*/
@InjectView(id = R.id.listView)
private ListView listView;
/**
* 어댑터
*
* @since 1.0.0
*/
private CAdapter adapter;
private String myApp = "com.baru.barukill";
private ExecutorService executor = Executors.newSingleThreadExecutor();
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
CLogger.i("MainActivity::onCreate()");
setContentView(R.layout.activity_main);
myApp = getApplicationInfo().packageName;
CLogger.i("MainActivity::onCreate() myAppInfo = " + myApp);
adapter = new CAdapter(this, userPackageList.values());
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
killAppsBtn.setOnClickListener(this);
refreshBtn.setOnClickListener(this);
allSelectBtn.setOnClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// getMenuInflater().inflate(R.menu.activity_main, menu);
return false;
}
@Override
protected void onResume()
{
reloadRunningApps();
super.onResume();
}
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.killAppsBtn:
// for (PackageInfo pi : adapter.getCheckedList())
// {
// CLogger.d(">> checked : " + pi.packageName);
// }
killSelectedProcesses();
break;
case R.id.refreshBtn:
reloadRunningApps();
break;
case R.id.allSelectBtn:
allSelectList();
break;
}
}
@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
{
CLogger.d("clicked : " + position);
adapter.setCheckItem(position);
adapter.notifyDataSetChanged();
}
/**
* 리스트뷰 갱신
*
* @since 1.0.0
*/
private void refreshList()
{
runOnUiThread(new Runnable()
{
@Override
public void run()
{
adapter.setList(userPackageList.values());
adapter.notifyDataSetChanged();
}
});
}
/**
* 전체선택
*
* @since 1.0.0
*/
private void allSelectList()
{
runOnUiThread(new Runnable()
{
@Override
public void run()
{
adapter.allSelectList();
adapter.notifyDataSetChanged();
}
});
}
/**
* 동작중인 어플리케이션 정보 로딩
*
* @since 1.0.0
*/
private void reloadRunningApps()
{
executor.execute(new Runnable()
{
@Override
public void run()
{
startProgress("", false, null);
getUserPackages();
getRunningApps();
getRunningServices();
refreshList();
stopProgress();
}
});
}
/**
* 선택된 어플리케이션 종료
*
* @since 1.0.0
*/
private void killSelectedProcesses()
{
(new KillSelectedTask()).execute();
}
/**
* 사용자 어플리케이션 리스트 가져오기 (시스템 어플리케이션은 제외)
*
* @since 1.0.0
* @return
*/
private Map<String, PackageInfo> getUserPackages()
{
userPackageList.clear();
PackageManager pkgMng = getPackageManager();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> apps = pkgMng.queryIntentActivities(mainIntent, 0);
CLogger.d("USER PACKAGES ----------------------------------------------------------");
for (ResolveInfo app : apps)
{
try
{
ComponentName component = new ComponentName(app.activityInfo.packageName, app.activityInfo.name);
ApplicationInfo info = pkgMng.getApplicationInfo(component.getPackageName(), PackageManager.GET_META_DATA);
// aincc : get all package
// if (0 == (info.flags & ApplicationInfo.FLAG_SYSTEM))
// {
// userPackageList.put(info.packageName, new PackageInfo(info.packageName, info.className, info.loadLabel(pkgMng).toString(), info.loadIcon(pkgMng)));
// CLogger.d("userPackageList : " + info.packageName);
// }
userPackageList.put(info.packageName, new PackageInfo(info.packageName, info.className, info.loadLabel(pkgMng).toString(), info.loadIcon(pkgMng)));
CLogger.d("PackageList : " + info.packageName);
}
catch (NameNotFoundException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
}
return userPackageList;
}
/**
* 실행중인 어플리케이션 가져오기 <br>
* 반드시, getUserPackages() 가 선행되어야 한다.
*
* @since 1.0.0
*/
private void getRunningApps()
{
ActivityManager actMng = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningAppProcessInfo> applist = actMng.getRunningAppProcesses();
CLogger.d("RUNNING APPS ----------------------------------------------------------");
for (RunningAppProcessInfo rap : applist)
{
boolean isUserPackage = false;
for (String pkg : rap.pkgList)
{
isUserPackage = userPackageList.containsKey(pkg);
if (isUserPackage)
{
userPackageList.get(pkg).addRunningProcInfo(rap);
CLogger.d("runningAppList : " + pkg);
break;
}
}
}
}
/**
* 실행중인 서비스 가져오기 <br>
* 반드시, getUserPackages() 가 선행되어야 한다.
*
* @since 1.0.0
*/
private void getRunningServices()
{
ActivityManager actMng = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningServiceInfo> servicelist = actMng.getRunningServices(MAX_SERVICE);
CLogger.d("RUNNING SERVICES ----------------------------------------------------------");
for (RunningServiceInfo rsp : servicelist)
{
boolean isUserPackage = false;
isUserPackage = userPackageList.containsKey(rsp.service.getPackageName());
if (isUserPackage && rsp.started && 0 == rsp.restarting)
{
userPackageList.get(rsp.service.getPackageName()).addRunningServiceInfo(rsp);
CLogger.d("runningServiceList : " + rsp.service.getPackageName());
}
}
}
/**
*
* <h3><b>PackageInfo</b></h3></br>
*
* @author aincc@barusoft.com
* @version 1.0.0
* @since 1.0.0
*/
class PackageInfo
{
String packageName;
String activityName;
String labelName;
Drawable icon;
String pss;
List<RunningAppProcessInfo> runningProcInfo;
List<RunningServiceInfo> runningServiceInfo;
boolean isChecked;
/**
*
* @since 1.0.0
* @param packageName
* @param activityName
* @param labelName
* @param icon
*/
public PackageInfo(String packageName, String activityName, String labelName, Drawable icon)
{
this.packageName = packageName;
this.activityName = activityName;
this.labelName = labelName;
this.icon = icon;
runningProcInfo = new Vector<RunningAppProcessInfo>();
runningServiceInfo = new Vector<RunningServiceInfo>();
isChecked = false;
}
/**
* 실행중인 프로세스 정보 추가
*
* @since 1.0.0
* @param rap
*/
public void addRunningProcInfo(RunningAppProcessInfo rap)
{
runningProcInfo.add(rap);
// pid 정보를 사용하여 메모리 사용량을 가져온다.
int[] pids = new int[1];
pids[0] = rap.pid;
ActivityManager actMng = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
android.os.Debug.MemoryInfo[] mem = actMng.getProcessMemoryInfo(pids);
this.pss = String.format("%.1fM", (float) (mem[0].getTotalPss() / 1024.0));
CLogger.d("nativePss = " + mem[0].nativePss);
CLogger.d("dalvikPss = " + mem[0].dalvikPss);
CLogger.d("otherPss = " + mem[0].otherPss);
}
/**
* 실행중인 서비스 정보 추가
*
* @since 1.0.0
* @param rsp
*/
public void addRunningServiceInfo(RunningServiceInfo rsp)
{
runningServiceInfo.add(rsp);
}
}
/**
*
* <h3><b>CAdapter</b></h3></br>
*
* @author aincc@barusoft.com
* @version 1.0.0
* @since 1.0.0
*/
class CAdapter extends BaseAdapter
{
Context context;
List<PackageInfo> list = new Vector<PackageInfo>();
/**
*
* @since 1.0.0
* @param context
* @param list
*/
public CAdapter(Context context, Collection<PackageInfo> list)
{
this.context = context;
setList(list);
}
/**
* 어플리케이션 리스트를 추가한다.<br>
* 서비스/프로세스 개수가 1개 이상인 어플리케이션만 추가한다.
*
* @since 1.0.0
* @param list
*/
public void setList(Collection<PackageInfo> list)
{
this.list.clear();
for (PackageInfo pi : list)
{
if (0 < pi.runningProcInfo.size() || 0 < pi.runningServiceInfo.size())
{
this.list.add(pi);
}
}
}
/**
* 어플리케이션 전체 선택
*
* @since 1.0.0
*/
public void allSelectList()
{
for (PackageInfo pi : list)
{
pi.isChecked = true;
}
}
/**
* 지정한 위치의 어플리케이션 선택 상태 토글
*
* @since 1.0.0
* @param position
*/
public void setCheckItem(int position)
{
PackageInfo pi = (PackageInfo) getItem(position);
if (null != pi)
{
pi.isChecked = !pi.isChecked;
}
}
/**
* 선택된 어플리케이션 리스트 가져오기
*
* @since 1.0.0
* @return
*/
public List<PackageInfo> getCheckedList()
{
List<PackageInfo> checkedList = new Vector<PackageInfo>();
for (PackageInfo pi : list)
{
if (pi.isChecked)
{
checkedList.add(pi);
}
}
return checkedList;
}
@Override
public int getCount()
{
return list.size();
}
@Override
public Object getItem(int position)
{
if (position < list.size())
{
return list.get(position);
}
return null;
}
@Override
public long getItemId(int position)
{
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
View view = convertView;
ViewHolder viewHolder = null;
if (null == convertView)
{
LayoutInflater inflater = LayoutInflater.from(context);
view = inflater.inflate(R.layout.list_cell, parent, false);
viewHolder = new ViewHolder();
viewHolder.layout = (LinearLayout) view.findViewById(R.id.layout);
viewHolder.icon = (ImageView) view.findViewById(R.id.icon);
viewHolder.title = (TextView) view.findViewById(R.id.title);
viewHolder.mem = (TextView) view.findViewById(R.id.mem);
viewHolder.proc = (TextView) view.findViewById(R.id.proc);
viewHolder.serv = (TextView) view.findViewById(R.id.serv);
viewHolder.checkBox = (CheckBox) view.findViewById(R.id.checkBox);
viewHolder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
int position = (Integer) buttonView.getTag();
PackageInfo item = list.get(position);
item.isChecked = isChecked;
}
});
view.setTag(viewHolder);
}
else
{
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.checkBox.setTag(position);
PackageInfo item = list.get(position);
viewHolder.icon.setImageDrawable(item.icon);
viewHolder.title.setText(item.labelName);
viewHolder.mem.setText(item.pss);
viewHolder.proc.setText(getResources().getString(R.string.process_count) + item.runningProcInfo.size());
viewHolder.serv.setText(getResources().getString(R.string.service_count) + item.runningServiceInfo.size());
viewHolder.checkBox.setChecked(item.isChecked);
return view;
}
/**
*
* <h3><b>ViewHolder</b></h3></br>
*
* @author aincc@barusoft.com
* @version 1.0.0
* @since 1.0.0
*/
class ViewHolder
{
LinearLayout layout;
ImageView icon;
TextView title;
TextView mem;
TextView proc;
TextView serv;
CheckBox checkBox;
}
}
/**
*
* <h3><b>KillSelectedTask</b></h3></br>
*
* @author aincc@barusoft.com
* @version 1.0.0
* @since 1.0.0
*/
class KillSelectedTask extends AsyncTask<Void, Void, Void>
{
boolean needKillMe = false;
@Override
protected Void doInBackground(Void... params)
{
ActivityManager actMng = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (PackageInfo pi : adapter.getCheckedList())
{
for (RunningAppProcessInfo rap : pi.runningProcInfo)
{
// 다른 어플리케이션 종료
if (!rap.processName.equals(myApp))
{
CLogger.d("kill : " + pi.packageName + " = " + rap.pid);
actMng.killBackgroundProcesses(pi.packageName);
}
else
{
// 내 어플리케이션 종료 플래그 설정
needKillMe = true;
}
}
}
return null;
}
@Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
if (needKillMe)
{
moveTaskToBack(true);
finish();
}
else
{
// 화면 갱신 요청
reloadRunningApps();
}
}
}
/**
*
* <h3><b>TopTask</b></h3></br>
*
* @author aincc@barusoft.com
* @version 1.0.0
* @since 1.0.0
*/
class TopTask extends AsyncTask<Void, Void, Void>
{
@Override
protected Void doInBackground(Void... params)
{
Runtime runtime = Runtime.getRuntime();
Process process;
try
{
String cmd = "top -n 1";
process = runtime.exec(cmd);
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null)
{
CLogger.d(">> " + line);
String segs[] = line.trim().split("[ ]+");
for (String seg : segs)
{
CLogger.d("seg : " + seg);
}
}
br.close();
isr.close();
is.close();
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
}
}
//
// private void killroot()
// {
// try
// {
// Process rootProcess = Runtime.getRuntime().exec(new String[]
// { "su" });
//
// String command = "kill - 9 <pid>";
//
// BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(rootProcess.getOutputStream()), 2048);
// try
// {
// bw.write(command);
// bw.newLine();
// bw.flush();
// }
// catch (IOException e)
// {
// // Handle error
// }
// }
// catch (Exception e)
// {
// e.printStackTrace();
// // Device not rooted!
// }
// }
}