/* * 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; // 消息继续向下传递 } }