/*
* Tencent is pleased to support the open source community by making
* Tencent GT (Version 2.4 and subsequent versions) available.
*
* Notwithstanding anything to the contrary herein, any previous version
* of Tencent GT shall not be subject to the license hereunder.
* All right, title, and interest, including all intellectual property rights,
* in and to the previous version of Tencent GT (including any and all copies thereof)
* shall be owned and retained by Tencent and subject to the license under the
* Tencent GT End User License Agreement (http://gt.qq.com/wp-content/EULA_EN.html).
*
* Copyright (C) 2015 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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.tencent.wstt.gt.proInfo.floatView;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.TextView;
import com.tencent.wstt.gt.R;
import com.tencent.wstt.gt.api.utils.DeviceUtils;
import com.tencent.wstt.gt.api.utils.Env;
import com.tencent.wstt.gt.api.utils.ProcessUtils;
import com.tencent.wstt.gt.manager.AUTManager;
import com.tencent.wstt.gt.plugin.BaseService;
import com.tencent.wstt.gt.utils.GTUtils;
public class GTMemHelperFloatview extends BaseService implements OnTouchListener {
private WindowManager wm = null;
private WindowManager.LayoutParams wmParams = null;
private Context mContext = null;
public static View net_switch_view;
private float mTouchStartX;
private float mTouchStartY;
private float x;
private float y;
private float StartX;
private float StartY;
public boolean floatview_flag = true;
public boolean net_state_flag = true;
private final int SCREEN_HORIZONTALLY = 0;
private final int SCREEN_VERTICAL = 1;
private TextView showInfo;
public static int tagTimes = 0;
private Drawable draw;
private Drawable drawSelect;
private Handler handler;
private String pName = "";
private TextView tv_mem;
private TextView tv_dump;
private TextView tv_gc;
private boolean isGc;
private boolean isDump;
private boolean isMem;
private boolean isMoved; // 一次touch操作中是否有移动过
public static ArrayList<MemInfo> memInfoList = new ArrayList<MemInfo>();
private static GTMemHelperFloatview INSTANCE;
public static GTMemHelperFloatview getInstance() {
if (null == INSTANCE) {
INSTANCE = new GTMemHelperFloatview();
}
return INSTANCE;
}
@Override
public void onCreate(Context context) {
super.onCreate(context);
mContext = context;
net_switch_view = LayoutInflater.from(context).inflate(
R.layout.gt_float_getproinfo, null);
handler = new DrawHandler();
draw = context.getResources().getDrawable(R.drawable.memfloatview);
drawSelect = context.getResources().getDrawable(
R.drawable.selected_Blue);
createView();
netswitch();
}
private void netswitch() {
showInfo = (TextView) net_switch_view.findViewById(R.id.show_info);
tv_mem = (TextView) net_switch_view.findViewById(R.id.tv_mobile);
tv_dump = (TextView) net_switch_view.findViewById(R.id.tv_dump);
tv_gc = (TextView) net_switch_view.findViewById(R.id.tv_GC);
tv_mem.setOnTouchListener(this);
tv_dump.setOnTouchListener(this);
tv_gc.setOnTouchListener(this);
}
private void getProInfo(String pName) {
tagTimes++;
long time = System.currentTimeMillis();
if (!pName.equals("")) {
MemInfo mi = MemInfoByCMD.getMemInfo(pName);
mi.time = time;
if (mi.dalvikHeapSize != 0) {
showInfo.setText(mi.toString());
memInfoList.add(mi);
}
}
}
private void createView() {
wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
wmParams = new WindowManager.LayoutParams();
wmParams.type = 2002;
wmParams.flags |= 8;
wmParams.gravity = Gravity.LEFT | Gravity.TOP;
wmParams.x = 0;
wmParams.y = 0;
wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
wmParams.format = 1;
try
{
wm.addView(net_switch_view, wmParams);
}
catch (Exception e)
{
/*
* 有的Android6会报permission denied for this window type问题
* https://github.com/intercom/intercom-android/issues/116
* 在这种系统上直接屏蔽悬浮窗
*/
stopSelf();
return;
}
net_switch_view.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// 获取相对屏幕的坐标,即以屏幕左上角为原点
x = event.getRawX();
if (SCREEN_VERTICAL == checkScreenOrientation()) {
y = event.getRawY()
- DeviceUtils.getStatusBarHeight(mContext);
} else {
y = event.getRawY();
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
StartX = x;
StartY = y;
// 获取相对View的坐标,即以此View左上角为原点
mTouchStartX = event.getX();
mTouchStartY = event.getY();
isMoved = false;
break;
case MotionEvent.ACTION_MOVE:
updateViewPosition();
break;
case MotionEvent.ACTION_UP:
updateViewPosition();
mTouchStartX = mTouchStartY = 0;
if (!isMoved)
{
if (isMem)
{
tv_mem.setBackgroundDrawable(drawSelect);
handler.sendEmptyMessage(1);
isMem = false;
}
if (isDump)
{
tv_dump.setBackgroundDrawable(drawSelect);
handler.sendEmptyMessage(2);
isDump = false;
}
if (isGc)
{
tv_gc.setBackgroundDrawable(drawSelect);
handler.sendEmptyMessage(3);
isGc = false;
}
isMoved = false;
}
break;
}
return true;
}
});
}
private void updateViewPosition() {
// 更新浮动窗口位置参数
if (Math.abs(x - StartX) > 10 || Math.abs(y - StartY) > 10) {
wmParams.x = (int) (x - mTouchStartX);
wmParams.y = (int) (y - mTouchStartY);
isMoved = true;
wm.updateViewLayout(net_switch_view, wmParams);
}
}
private void gc() {
String pid = String.valueOf(ProcessUtils
.getProcessPID(AUTManager.pkn.toString()));
if (!pid.equals("-1")) {
boolean isSucess = true;
ProcessBuilder pb = null;
String cmd = "kill -10 " + pid;
pb = new ProcessBuilder("su", "-c", cmd);
Process exec = null;
pb.redirectErrorStream(true);
try {
exec = pb.start();
InputStream is = exec.getInputStream();
BufferedReader reader = new BufferedReader(
new InputStreamReader(is));
while ((reader.readLine()) != null) {
isSucess = false;
}
} catch (Exception e) {
e.printStackTrace();
isSucess = false;
}
// 至此命令算是执行成功
if (isSucess)
{
handler.sendEmptyMessage(5);
}
} else {
Log.d("gc error", "pid not found!");
}
}
private void dumpHeap() {
String pid = String.valueOf(ProcessUtils
.getProcessPID(AUTManager.pkn.toString()));
if (!pid.equals("-1")) {
boolean isSucess = true;
ProcessBuilder pb = null;
String sFolder = Env.S_ROOT_DUMP_FOLDER + AUTManager.pkn.toString() + "/";
File folder = new File(sFolder);
if (!folder.exists())
{
folder.mkdirs();
}
String cmd = "am dumpheap " + pid + " "// 命令
+ Env.S_ROOT_DUMP_FOLDER + AUTManager.pkn.toString() + "/"// 输出路径
+ "dump_" + pid + "_" + GTUtils.getSaveDate() + ".hprof"; // 输出文件名
pb = new ProcessBuilder("su", "-c", cmd);
Process exec = null;
pb.redirectErrorStream(true);
try {
exec = pb.start();
InputStream is = exec.getInputStream();
BufferedReader reader = new BufferedReader(
new InputStreamReader(is));
while ((reader.readLine()) != null) {
isSucess = false;
}
} catch (Exception e) {
e.printStackTrace();
isSucess = false;
}
// 至此命令算是执行成功
if (isSucess)
{
handler.sendEmptyMessage(6);
}
} else {
Log.d("dump error", "pid not found!");
}
}
private int checkScreenOrientation() {
int dev_width = DeviceUtils.getDevWidth();
int dev_height = DeviceUtils.getDevHeight();
int orientation = SCREEN_VERTICAL; // 0:竖屏 1:横屏
if (dev_width > dev_height) {
orientation = SCREEN_HORIZONTALLY;
}
return orientation;
}
@Override
public void onStart(Intent intent) {
pName = intent.getStringExtra("pName");
super.onStart(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
floatview_flag = false;
net_state_flag = false;
try{
wm.removeView(net_switch_view);
}
catch (Exception e)
{
}
INSTANCE = null;
}
@Override
public IBinder onBind() {
return null;
}
@SuppressLint("HandlerLeak")
class DrawHandler extends Handler {
@Override
public void handleMessage(Message msg) {
int type = msg.what;
if (type == 1)
{
getProInfo(pName);
tv_mem.setText("refresh(" + tagTimes + ")");
tv_mem.setBackgroundDrawable(draw);
}
else if (type == 2)
{
dumpHeap();
tv_dump.setBackgroundDrawable(draw);
}
else if (type == 3)
{
gc();
tv_gc.setBackgroundDrawable(draw);
}
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
if (v.getId() == tv_mem.getId())
{
isMem = true;
}
else if (v.getId() == tv_gc.getId())
{
isGc = true;
}
else if (v.getId() == tv_dump.getId())
{
isDump = true;
}
}
return false; // 消息继续向下传递
}
}