package com.eslab.osmonitor.traffic;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import android.app.ActivityManager;
import android.app.ListActivity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.TrafficStats;
import android.os.Bundle;
import android.os.Handler;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.GestureDetector.OnGestureListener;
import android.view.View.OnTouchListener;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import com.eolwral.osmonitor.CompareFunc;
import com.eolwral.osmonitor.JNIInterface;
import com.eolwral.osmonitor.R;
import com.eolwral.osmonitor.processes.ProcessInfoQuery;
/*
* 어플리케이션별 Traffic 정보를 출력해주는 Class이다.
*/
public class ApplicationTrafficList extends ListActivity implements
OnGestureListener, OnTouchListener, ListView.OnScrollListener {
private static ApplicationTrafficList Self = null;
private static JNIInterface JNILibrary = JNIInterface.getInstance();
// 것이다.
private ProcessInfoQuery ProcessInfo = null;
// TextView
private TextView mWIFIStateText = null;
private TextView RunProcess = null;
private TextView MemTotal = null;
private TextView MemFree = null;
private TextView mWIFITxtext = null;
private TextView mWIFIRxtext = null;
private static DecimalFormat MemoryFormat = new DecimalFormat(",000");
// Gesture
private GestureDetector gestureScanner = new GestureDetector(this);;
List<ActivityManager.RunningAppProcessInfo> appList2;
private static boolean GestureSingleTap = false;
// 설치된 어플리케이션의 리스트 이다.
private ArrayList<Integer> items = new ArrayList();
private PackageManager mPackageManager;
ActivityManager activityManager;
@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
}
return true;
}
@Override
public void onLongPress(MotionEvent e) {
// performLongClick();
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)) {
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() {
// 3G통신의 데이터 RX(수신) KByte 값이다.
if (TrafficStats.getMobileRxBytes() == TrafficStats.UNSUPPORTED) {
MemTotal.setText("UNSUPPORTED!");
} else {
MemTotal.setText(MemoryFormat.format(TrafficStats
.getMobileRxBytes() / 1024)
+ "KB");
}
// 3G통신의 데이터 TX(송신) KByte 값이다.
if (TrafficStats.getMobileTxBytes() == TrafficStats.UNSUPPORTED) {
MemFree.setText("UNSUPPORTED!");
} else {
MemFree.setText(MemoryFormat.format(TrafficStats
.getMobileTxBytes() / 1024)
+ "KB");
}
// WIFI 통신의 데이터 RX(수신) KByte 값이다.
if (TrafficStats.getTotalRxBytes() == TrafficStats.UNSUPPORTED) {
mWIFIRxtext.setText("UNSUPPORTED!");
} else {
mWIFIRxtext.setText(MemoryFormat.format(TrafficStats
.getTotalRxBytes() / 1024)
+ "KB");
}
// WIFI 통신의 데이터 TX(송신) KByte 값이다.
if (TrafficStats.getTotalTxBytes() == TrafficStats.UNSUPPORTED) {
mWIFITxtext.setText("UNSUPPORTED!");
} else {
mWIFITxtext.setText(MemoryFormat.format(TrafficStats
.getTotalTxBytes() / 1024)
+ "KB");
}
appList2 = activityManager.getRunningAppProcesses();
RunProcess.setText(""+appList2.size());
// 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.traffic_list);
// UI Thread에서 관리하는 View들이다.
RunProcess = (TextView) findViewById(R.id.Traffic_RunProcessText);
MemTotal = (TextView) findViewById(R.id.Traffic_MemTotalText);
MemFree = (TextView) findViewById(R.id.Traffic_MemFreeText);
mWIFIRxtext = (TextView) findViewById(R.id.Traffic_MemTotalText2);
mWIFITxtext = (TextView) findViewById(R.id.Traffic_MemFreeText2);
// Tell the list view which view to display when the list is empty
// empty일때 empty라는 글자를 표시해 주기 위함 이다.
getListView().setEmptyView(findViewById(R.id.Traffic_empty));
// Use our own list adapter
// ListActivity를 상속 받았기 떄문에 이런식으로 처리 한다.
// Self는 자기 자신에 대한 객체 이다.
Self = this;
Self.getListView().setOnTouchListener(this); // 리스너를 등록해 준다.
ActivityMan = (ActivityManager) getSystemService(ACTIVITY_SERVICE); // 엑티비티
// 관리자를
// 얻어온다.
mPackageManager = getPackageManager();
// 실행중인 프로세스의 리스트를 얻어오기 위함 이다.
activityManager = (ActivityManager) this
.getSystemService(ACTIVITY_SERVICE);
appList2 = activityManager.getRunningAppProcesses();
Iterator it = appList2.iterator();
// 순회 하면서 실행중 프로세서들의 pid값을 얻어온다.
while (it.hasNext()) {
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) it
.next();
items.add(info.pid);
}
setListAdapter(new ProcessListAdapter(this,appList2)); //커스터마이즈한 어뎁터를 달아준다.
/*setListAdapter(new MyAdapter(this, R.layout.my_app_row,
R.id.traffic_pid, appList2));*/
}
// 어뎁터를 갱신해주는 기능을 한다.
public void onRefresh() {
}
@Override
public void onPause() {
uiHandler.removeCallbacks(uiRunnable);
super.onPause();
}
// create에서 ProcessInfoQuery 클래스의 Thread를 수행 한다면 이건에서는 JIN로 작성된 Native
// Thread를 수행한다.
@Override
protected void onResume() {
// 정치를 체크 했을 때 반응하는 것과 4개의 메이저 정보를 출력하는 것을 담당하는 핸들러이다. 0.05초 마다 한번씩 동작하게
// 되어 진다.
uiHandler.post(uiRunnable);
super.onResume();
}
// ArrayAdapter를 상속한 커스텀 어댑터 --> 데이터를 보기 좋게 커스터마이징
class MyAdapter extends ArrayAdapter {
public MyAdapter(Context context, int resource, int textViewResourceId,
List items) {
super(context, resource, textViewResourceId, items);
// TODO Auto-generated constructor stub
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
// 레이아웃을 확장 한다.
View row = getLayoutInflater().inflate(R.layout.my_app_row, null);
// 현재 위치의 아이템을 얻어온다.
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) getItem(position);
TextView PidTextView = (TextView) row
.findViewById(R.id.traffic_pid);
TextView ApplciationNameTextView = (TextView) row
.findViewById(R.id.traffic_application_name);
ImageView IconTextView = (ImageView) row
.findViewById(R.id.traffic_appicon);
PidTextView.setText(String.format("%d", info.pid));
ApplciationNameTextView.setText(info.processName);
try {
IconTextView.setImageDrawable(mPackageManager
.getApplicationIcon(mPackageManager
.getNameForUid(info.uid)));
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return row;
}
}
// 커스터 마이즈한 리스트 어뎁터 이다. 결국 모든것은 이 어뎁터에 의해서 수행되어 질 것이다.
private class ProcessListAdapter extends BaseAdapter {
public ProcessListAdapter(Context context, List<ActivityManager.RunningAppProcessInfo> arList) {
mContext = context;
mList = arList;
}
public int getCount() {
return appList2.size();
}
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;
PackageInfo appPackageInfo = null;
// 현재 위치의 아이템을 얻어온다.
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) mList.get(position);
/*mPackageManager
.getApplicationIcon(info.processName)*/
//이름에 ':'문자를 포함하고 있다면 :전까지의 내용을 PackageName으로 정의한다. 이렇게 해야 정상적으로 icon과 label을 추출 할 수 있다.
if(info.processName.contains(":")){
PackageName = info.processName.substring(0,info.processName.indexOf(":"));
}
else
PackageName = info.processName;
//해당 PackageName에 대한 정보를 PackageManager로 부터 받아 온다.
try {
appPackageInfo = mPackageManager.getPackageInfo(PackageName, 0);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//PackageName에 대한 정보가 없을경우 SearchObj에서 UID를 얻어온다.
if(appPackageInfo == null && info.uid >0)
{
//UID를 통해서 Package Name을 확보 한다.
String[] subPackageName = mPackageManager.getPackagesForUid(info.uid);
if(subPackageName != null)
{
for(int PackagePtr = 0; PackagePtr < subPackageName.length; PackagePtr++)
{
if (subPackageName[PackagePtr] == null)
continue;
try {
appPackageInfo = mPackageManager.getPackageInfo(subPackageName[PackagePtr], 0);
PackagePtr = subPackageName.length;
} catch (NameNotFoundException e) {}
}
}
}
//페키지 이름으로는 식별이 힘들기 때문에 페키지이름을 어플리케이션 라벨 이름으로 변환 시켜준다.
LabelName = appPackageInfo.applicationInfo.loadLabel(mPackageManager).toString();
Icon = resizeImage(appPackageInfo.applicationInfo.loadIcon(mPackageManager));
/* if (convertView == null) {
*/
sv = new ProcessDetailView(mContext,Icon, info.pid, info.uid, LabelName,position,
TrafficStats.getUidRxBytes(info.uid),
TrafficStats.getUidTxBytes(info.uid));
/* } else {
sv = (ProcessDetailView) convertView;
sv.setView(Icon,
info.pid,info.uid,
LabelName, position);
}*/
return sv;
}
private Context mContext;
private List<ActivityManager.RunningAppProcessInfo> mList;
private String PackageName = null;
private String LabelName = null;
public Drawable Icon;
}
/*
* ListView의 한셀 한셀을 나타낸다. Expanded의 값에 따라서 자세한 정보가 보여질지 안보여질지를 결정 한다.
* TableLayout을 상속 받아서 프로세스 정보를 표시해 주는 용도로 완성 시킨다.
*/
private class ProcessDetailView extends TableLayout {
private TableRow TitleRow;
private TextView PIDField;
private ImageView IconField;
private TextView NameField;
private TextView AppRxField;
private TextView AppTxField;
private boolean Expanded = false;
public ProcessDetailView(Context context,Drawable Icon, int PID ,int UID,
String Name,int position, long appRx, long appTx) {
super(context);
this.setColumnStretchable(2, true);
// this.setOrientation(VERTICAL);
PIDField = new TextView(context);// 프로세스 ID를 표시한다.
IconField = new ImageView(context);// 어플리케이션 아이콘을 표시 한다.
NameField = new TextView(context);// 어플리케이션의 이름을 표시 한다.
AppRxField = new TextView(context);// App별 Rx 정보 이다.
AppTxField = new TextView(context);// App별 Tx 정보 이다.
PIDField.setText("" + PID+"("+UID+")"); // PID 정보를 삽입한다.
IconField.setImageDrawable(Icon);
IconField.setPadding(8, 3, 3, 3);
NameField.setText(Name);
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());
/*
* 최종적으로 TableRow를 셍상히야 값을 달아준다. PID Icon(application) Name
* Value(load값) DetailField(Icon)
*/
TitleRow = new TableRow(context);
TitleRow.addView(PIDField);
TitleRow.addView(IconField);
TitleRow.addView(NameField);
addView(TitleRow);
// 어플리케이션별 Rx 정보이다.
AppRxField.setText("\tRx: "+MemoryFormat.format(appRx)+"Byte");
addView(AppRxField);
// 어플리케이션별 Tx 정보이다.
AppTxField.setText("\tTx: "+MemoryFormat.format(appTx)+"Byte");
addView(AppTxField);
// 포지션마다 백그라운드 색을 다르게 한다.
if (position % 2 == 0)
setBackgroundColor(0x80444444);
else
setBackgroundColor(0x80000000);
}
public void setContext(String AppInfo) {
AppRxField.setText(AppInfo);
}
public void setView(Drawable Icon,int PID, int UID, String Name, int position) {
IconField.setImageDrawable(Icon);
PIDField.setText("" + PID+"("+UID+")");
NameField.setText(Name);
if (position % 2 == 0)
setBackgroundColor(0x80444444);
else
setBackgroundColor(0x80000000);
}
public void setView(int PID, int position) {
IconField.setImageDrawable(null);
// IconField.setVisibility(View.GONE);
// DetailField.setVisibility(View.INVISIBLE);
PIDField.setText("" + PID);
NameField.setText("Loading");
if (position % 2 == 0)
setBackgroundColor(0x80444444);
else
setBackgroundColor(0x80000000);
}
/**
* Convenience method to expand or hide the dialogue
*/
public void setExpanded(boolean expanded) {
AppRxField.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);
}
}
@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
}
//applciation icon을 resize해줘야 같은 크기로 List에 출력 되어 지게된다.
private Drawable resizeImage(Drawable Icon) {
if(CompareFunc.getScreenSize() == 2)
{
Bitmap BitmapOrg = Bitmap.createBitmap(60, 60, Bitmap.Config.ARGB_8888);
Canvas BitmapCanvas = new Canvas(BitmapOrg);
Icon.setBounds(0, 0, 60, 60);
Icon.draw(BitmapCanvas);
return new BitmapDrawable(BitmapOrg);
}
else if (CompareFunc.getScreenSize() == 0)
{
Bitmap BitmapOrg = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
Canvas BitmapCanvas = new Canvas(BitmapOrg);
Icon.setBounds(0, 0, 10, 10);
Icon.draw(BitmapCanvas);
return new BitmapDrawable(BitmapOrg);
}
else
{
Bitmap BitmapOrg = Bitmap.createBitmap(22, 22, Bitmap.Config.ARGB_8888);
Canvas BitmapCanvas = new Canvas(BitmapOrg);
Icon.setBounds(0, 0, 22, 22);
Icon.draw(BitmapCanvas);
return new BitmapDrawable(BitmapOrg);
}
}
}