|
@@ -0,0 +1,236 @@
|
|
|
|
+package com.edufound.bytedance.util;
|
|
|
|
+
|
|
|
|
+import android.app.Activity;
|
|
|
|
+import android.app.ActivityManager;
|
|
|
|
+import android.content.Context;
|
|
|
|
+import android.graphics.Color;
|
|
|
|
+import android.os.Build;
|
|
|
|
+import android.os.Debug;
|
|
|
|
+import android.os.Handler;
|
|
|
|
+import android.os.Message;
|
|
|
|
+import android.os.Process;
|
|
|
|
+import android.view.Display;
|
|
|
|
+import android.view.Gravity;
|
|
|
|
+import android.view.KeyEvent;
|
|
|
|
+import android.view.LayoutInflater;
|
|
|
|
+import android.view.View;
|
|
|
|
+import android.view.WindowManager;
|
|
|
|
+import android.widget.TextView;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+import androidx.annotation.RequiresApi;
|
|
|
|
+
|
|
|
|
+import com.edufound.bytedance.R;
|
|
|
|
+
|
|
|
|
+import java.io.RandomAccessFile;
|
|
|
|
+import java.util.Map;
|
|
|
|
+
|
|
|
|
+public class ShowSamplerInfo implements Handler.Callback {
|
|
|
|
+
|
|
|
|
+ private static final int MSG_SHOW_EFKEY = Integer.MIN_VALUE;
|
|
|
|
+ private static final int GET_INFO = Integer.MIN_VALUE + 0x31;
|
|
|
|
+ private Handler mHandlerUi = new Handler(this);
|
|
|
|
+ private Handler mHandlerBackground = new Handler(this);
|
|
|
|
+ private static final int[] EFKEY = {KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_UP,
|
|
|
|
+ KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_DOWN,
|
|
|
|
+ KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_UP};
|
|
|
|
+ private static final int EFKEY_LENGTH = EFKEY.length;
|
|
|
|
+ private static final long INPUT_INTERVAL = 10 * 1000L;
|
|
|
|
+ private long mLastInputTime;
|
|
|
|
+ private int mIndex;
|
|
|
|
+ private static Activity mContext;
|
|
|
|
+ private static final ShowSamplerInfo INSTANCE = new ShowSamplerInfo();
|
|
|
|
+ private boolean isShowing = false;
|
|
|
|
+ private Long lastCpuTime;
|
|
|
|
+ private Long lastAppCpuTime;
|
|
|
|
+ private RandomAccessFile procStatFile;
|
|
|
|
+ private RandomAccessFile appStatFile;
|
|
|
|
+ private int CPUInfo = 0;
|
|
|
|
+ private int MemInfo = 0;
|
|
|
|
+ private ActivityManager activityManager;
|
|
|
|
+
|
|
|
|
+ private void input(int keyCode) {
|
|
|
|
+ if (System.currentTimeMillis() - mLastInputTime > INPUT_INTERVAL) {
|
|
|
|
+ mIndex = 0;
|
|
|
|
+ }
|
|
|
|
+ if (mIndex >= EFKEY_LENGTH || mIndex < 0) {
|
|
|
|
+ mIndex = 0;
|
|
|
|
+ }
|
|
|
|
+ if (EFKEY[mIndex] == keyCode) {
|
|
|
|
+ mLastInputTime = System.currentTimeMillis();
|
|
|
|
+ mIndex++;
|
|
|
|
+ if (mIndex == EFKEY_LENGTH) {
|
|
|
|
+ mHandlerUi.sendEmptyMessage(MSG_SHOW_EFKEY);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ mLastInputTime = System.currentTimeMillis();
|
|
|
|
+ mIndex = 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ View infoView;
|
|
|
|
+ TextView text;
|
|
|
|
+ WindowManager windowManager;
|
|
|
|
+
|
|
|
|
+ private void show() {
|
|
|
|
+ if (isShowing) {
|
|
|
|
+ mHandlerBackground.removeMessages(GET_INFO);
|
|
|
|
+ isShowing = false;
|
|
|
|
+ windowManager.removeView(infoView);
|
|
|
|
+ windowManager = null;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
|
|
|
|
+ infoView = LayoutInflater.from(mContext).inflate(R.layout.window_deviceinfo, null);
|
|
|
|
+ text = (TextView) infoView.findViewById(R.id.deviceinfo);
|
|
|
|
+ text.setTextSize(30);
|
|
|
|
+ text.setTextColor(Color.RED);
|
|
|
|
+ text.setGravity(Gravity.CENTER);
|
|
|
|
+ WindowManager m = mContext.getWindowManager();
|
|
|
|
+ Display d = m.getDefaultDisplay(); // 获取屏幕宽、高用
|
|
|
|
+ //类型是TYPE_TOAST,像一个普通的Android Toast一样。这样就不需要申请悬浮窗权限了。
|
|
|
|
+ WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_TOAST);
|
|
|
|
+ //初始化后不首先获得窗口焦点。不妨碍设备上其他部件的点击、触摸事件。
|
|
|
|
+ params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
|
|
|
+ params.width = (int) (d.getWidth() * 0.8);
|
|
|
|
+ params.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
|
|
|
+ params.gravity = Gravity.TOP;
|
|
|
|
+ windowManager = (WindowManager) ContextUtil.getmApplicationContext().getSystemService(ContextUtil.getmApplicationContext().WINDOW_SERVICE);
|
|
|
|
+ windowManager.addView(infoView, params);
|
|
|
|
+ isShowing = true;
|
|
|
|
+ mHandlerBackground.sendEmptyMessage(GET_INFO);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ public static void dispatchKeyEvent(KeyEvent e, Activity context) {
|
|
|
|
+ try {
|
|
|
|
+ mContext = context;
|
|
|
|
+ getInstance().dispathInput(e);
|
|
|
|
+ } catch (final Exception ex) {
|
|
|
|
+ ex.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static ShowSamplerInfo getInstance() {
|
|
|
|
+ return INSTANCE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void dispathInput(final KeyEvent e) {
|
|
|
|
+ mHandlerBackground.sendEmptyMessage(e.getKeyCode());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean handleMessage(Message msg) {
|
|
|
|
+ try {
|
|
|
|
+ switch (msg.what) {
|
|
|
|
+ case MSG_SHOW_EFKEY:
|
|
|
|
+ show();
|
|
|
|
+ break;
|
|
|
|
+ case GET_INFO:
|
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
|
|
+ text.setText("CPU: " + (int) sampleCPU() + "%" + " RunningMemory: " + (int) getRunningMemory() + "MB");
|
|
|
|
+ } else {
|
|
|
|
+ text.setText("CPU: " + (int) sampleCPU() + "%" + " TotalPPS: " + (int) sampleMemory() + "MB");
|
|
|
|
+ }
|
|
|
|
+ mHandlerBackground.sendEmptyMessageDelayed(GET_INFO, 1000);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ input(msg.what);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ } catch (final Exception ex) {
|
|
|
|
+ ex.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private double sampleCPU() {
|
|
|
|
+ long cpuTime;
|
|
|
|
+ long appTime;
|
|
|
|
+ double sampleValue = 0.0D;
|
|
|
|
+ try {
|
|
|
|
+ if (procStatFile == null || appStatFile == null) {
|
|
|
|
+ procStatFile = new RandomAccessFile("/proc/stat", "r");
|
|
|
|
+ appStatFile = new RandomAccessFile("/proc/" + Process.myPid() + "/stat", "r");
|
|
|
|
+ } else {
|
|
|
|
+ procStatFile.seek(0L);
|
|
|
|
+ appStatFile.seek(0L);
|
|
|
|
+ }
|
|
|
|
+ String procStatString = procStatFile.readLine();
|
|
|
|
+ String appStatString = appStatFile.readLine();
|
|
|
|
+ String procStats[] = procStatString.split(" ");
|
|
|
|
+ String appStats[] = appStatString.split(" ");
|
|
|
|
+ cpuTime = Long.parseLong(procStats[2]) + Long.parseLong(procStats[3])
|
|
|
|
+ + Long.parseLong(procStats[4]) + Long.parseLong(procStats[5])
|
|
|
|
+ + Long.parseLong(procStats[6]) + Long.parseLong(procStats[7])
|
|
|
|
+ + Long.parseLong(procStats[8]);
|
|
|
|
+ appTime = Long.parseLong(appStats[13]) + Long.parseLong(appStats[14]);
|
|
|
|
+ if (lastCpuTime == null && lastAppCpuTime == null) {
|
|
|
|
+ lastCpuTime = cpuTime;
|
|
|
|
+ lastAppCpuTime = appTime;
|
|
|
|
+ return sampleValue;
|
|
|
|
+ }
|
|
|
|
+ sampleValue = ((double) (appTime - lastAppCpuTime) / (double) (cpuTime - lastCpuTime)) * 100D;
|
|
|
|
+ lastCpuTime = cpuTime;
|
|
|
|
+ lastAppCpuTime = appTime;
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ return sampleValue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ @RequiresApi(api = Build.VERSION_CODES.M)
|
|
|
|
+ private double getRunningMemory() {
|
|
|
|
+ double mem = 0.0D;
|
|
|
|
+ try {
|
|
|
|
+ // 统计进程的内存信息 totalPss
|
|
|
|
+ final Debug.MemoryInfo[] memInfo = activityManager.getProcessMemoryInfo(new int[]{Process.myPid()});
|
|
|
|
+ if (memInfo.length > 0) {
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 读取内存信息,跟Android Profiler 分析一致
|
|
|
|
+ */
|
|
|
|
+ Map<String, String> params = memInfo[0].getMemoryStats();
|
|
|
|
+ String java_mem = params.get("summary.java-heap");
|
|
|
|
+ String native_mem = params.get("summary.native-heap");
|
|
|
|
+ String graphics_mem = params.get("summary.graphics");
|
|
|
|
+ String stack_mem = params.get("summary.stack");
|
|
|
|
+ String code_mem = params.get("summary.code");
|
|
|
|
+ String others_mem = params.get("summary.system");
|
|
|
|
+ final int dalvikPss = Integer.valueOf(java_mem)
|
|
|
|
+ + Integer.valueOf(native_mem)
|
|
|
|
+ + Integer.valueOf(graphics_mem)
|
|
|
|
+ + Integer.valueOf(stack_mem)
|
|
|
|
+ + Integer.valueOf(code_mem)
|
|
|
|
+ + Integer.valueOf(others_mem);
|
|
|
|
+ if (dalvikPss >= 0) {
|
|
|
|
+ // Mem in MB
|
|
|
|
+ mem = dalvikPss / 1024.0D;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ return mem;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private double sampleMemory() {
|
|
|
|
+ double mem = 0.0D;
|
|
|
|
+ try {
|
|
|
|
+ // 统计进程的内存信息 totalPss
|
|
|
|
+ final Debug.MemoryInfo[] memInfo = activityManager.getProcessMemoryInfo(new int[]{Process.myPid()});
|
|
|
|
+ if (memInfo.length > 0) {
|
|
|
|
+ // TotalPss = dalvikPss + nativePss + otherPss, in KB
|
|
|
|
+ final int totalPss = memInfo[0].getTotalPss();
|
|
|
|
+ if (totalPss >= 0) {
|
|
|
|
+ // Mem in MB
|
|
|
|
+ mem = totalPss / 1024.0D;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ return mem;
|
|
|
|
+ }
|
|
|
|
+}
|