package com.ittianyu.mobileguard.engine;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Debug;
import android.provider.Settings;
import android.support.annotation.RequiresApi;
import android.text.TextUtils;
import com.ittianyu.mobileguard.domain.ProcessInfoBean;
import com.jaredrummler.android.processes.AndroidProcesses;
import com.jaredrummler.android.processes.models.AndroidAppProcess;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import okio.BufferedSource;
import okio.Okio;
/**
* Created by yu.
* manage alive app
*/
public class ProcessManagerEngine {
/**
* @return the device total memory in byte
*/
public static long getTotalMemory() {
File file = new File("/proc/meminfo");
BufferedSource source = null;
try {
// read meminfo file
source = Okio.buffer(Okio.source(file));
String totalMemoryStr = source.readUtf8Line();
// get total memory
String[] split = totalMemoryStr.split("\\s+");
return Integer.valueOf(split[1]).intValue() * 1024;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (source != null) {
source.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return 0;
}
/**
* @param context
* @return the system free memory in byte
*/
public static long getFreeMemory(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
am.getMemoryInfo(memoryInfo);
return memoryInfo.availMem;
}
/**
* get running processes info
* @param context
* @return
*/
public static List<ProcessInfoBean> getRunningProcessesInfo(Context context) {
List<ProcessInfoBean> list = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
list = getRunningProcessesInfoByProc(context);
} else {
list = getRunningProcessesInfoCompat(context);
}
return list;
}
/**
* get running processes info
* you just can use it before Android 5.0
* @param context
* @return
*/
public static List<ProcessInfoBean> getRunningProcessesInfoCompat(Context context) {
// get manager
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
PackageManager pm = context.getPackageManager();
// get processes info
List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
// create list. Specific it init size
List<ProcessInfoBean> infos = new ArrayList<>(processes.size());
// get info
for (ActivityManager.RunningAppProcessInfo processInfo : processes) {
// create bean
ProcessInfoBean bean = new ProcessInfoBean();
// set value
bean.setPackageName(processInfo.processName);
// get package info
ApplicationInfo applicationInfo = null;
try {
applicationInfo = pm.getApplicationInfo(bean.getPackageName(), PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
// if package is empty, continue
continue;
}
// set icon
bean.setIcon(applicationInfo.loadIcon(pm));
// app name
bean.setAppName(applicationInfo.loadLabel(pm).toString());
// system app
if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
bean.setSystemApp(true);
}// if not, need set false. Actually it was.
// memory
Debug.MemoryInfo[] processMemoryInfo = am.getProcessMemoryInfo(new int[]{processInfo.pid});
if (processMemoryInfo.length >= 1) {
bean.setMemory(processMemoryInfo[0].getTotalPss() * 1024);
}
// add to list
infos.add(bean);
}
return infos;
}
/**
* get running processes info by proc
* @param context
* @return
*/
public static List<ProcessInfoBean> getRunningProcessesInfoByProc(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
PackageManager pm = context.getPackageManager();
// get running app processes info
List<AndroidAppProcess> processes = AndroidProcesses.getRunningAppProcesses();
// create list. Specific it init size
List<ProcessInfoBean> infos = new ArrayList<>(processes.size());
for (AndroidAppProcess process: processes) {
// create bean
ProcessInfoBean bean = new ProcessInfoBean();
// get package name
bean.setPackageName(process.getPackageName());
// check empty
if(TextUtils.isEmpty(bean.getPackageName())) {
continue;
}
// get package info
ApplicationInfo applicationInfo = null;
try {
applicationInfo = pm.getApplicationInfo(bean.getPackageName(), PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
// if package is empty, continue
continue;
}
// set icon
bean.setIcon(applicationInfo.loadIcon(pm));
// app name
bean.setAppName(applicationInfo.loadLabel(pm).toString());
// system app
if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
bean.setSystemApp(true);
}// if not, need set false. Actually it was.
// memory
Debug.MemoryInfo[] processMemoryInfo = am.getProcessMemoryInfo(new int[]{process.pid});
if (processMemoryInfo.length >= 1) {
bean.setMemory(processMemoryInfo[0].getTotalPss() * 1024);
}
// add to list
infos.add(bean);
}
return infos;
}
/**
* get current task top app package name
* @param context
* @param am
* @return the top app package name
*/
public static String getTaskTopAppPackageName(Context context, ActivityManager am) {
String packageName = "";
// if the sdk >= 21. It can only use getRunningAppProcesses to get task top package name
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
UsageStatsManager usage = (UsageStatsManager)context.getSystemService(Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List<UsageStats> stats = usage.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 10, time);
if (stats != null) {
SortedMap<Long, UsageStats> runningTask = new TreeMap<Long,UsageStats>();
for (UsageStats usageStats : stats) {
runningTask.put(usageStats.getLastTimeUsed(), usageStats);
}
if (runningTask.isEmpty()) {
return null;
}
packageName = runningTask.get(runningTask.lastKey()).getPackageName();
}
} else {// if sdk <= 20, can use getRunningTasks
List<ActivityManager.RunningTaskInfo> infos = am.getRunningTasks(1);
packageName = infos.get(0).topActivity.getPackageName();
}
return packageName;
}
/**
* check whether has permission to get usage stats
* @param context
* @return true if have, false otherwise
*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static boolean hasGetUsageStatsPermission(Context context) {
AppOpsManager appOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
int mode = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), context.getPackageName());
}
return mode == AppOpsManager.MODE_ALLOWED;
}
/**
* request the get usage states permission.
* @param context
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public static void requestUsageStatesPermission(Context context) {
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}