package com.eolwral.osmonitor;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.os.IBinder;
import android.support.v7.app.NotificationCompat;
import android.widget.RemoteViews;
import com.eolwral.osmonitor.core.cpuInfo;
import com.eolwral.osmonitor.core.cpuInfoList;
import com.eolwral.osmonitor.core.networkInfo;
import com.eolwral.osmonitor.core.networkInfoList;
import com.eolwral.osmonitor.core.osInfo;
import com.eolwral.osmonitor.core.processInfo;
import com.eolwral.osmonitor.core.processInfoList;
import com.eolwral.osmonitor.ipc.IpcService;
import com.eolwral.osmonitor.ipc.IpcService.ipcClientListener;
import com.eolwral.osmonitor.ipc.ipcCategory;
import com.eolwral.osmonitor.ipc.ipcData;
import com.eolwral.osmonitor.ipc.ipcMessage;
import com.eolwral.osmonitor.settings.Settings;
import com.eolwral.osmonitor.settings.Settings.NotificationType;
import com.eolwral.osmonitor.settings.Settings.StatusBarColor;
import com.eolwral.osmonitor.util.CoreUtil;
import com.eolwral.osmonitor.util.ProcessUtil;
import com.eolwral.osmonitor.util.UserInterfaceUtil;
import java.nio.ByteBuffer;
import java.util.Locale;
public class OSMonitorService extends Service implements ipcClientListener {
private static final int NOTIFYID = 20100811;
private IpcService ipcService = null;
private int UpdateInterval = 2;
private boolean isRegistered = false;
private NotificationManager nManager = null;
private NotificationCompat.Builder nBuilder = null;
// process
private int iconColor = 0;
private int fontColor = 0;
private int backgroundColor = 0;
private boolean isSetTop = false;
private float cpuUsage = 0;
private float ioWaitUsage = 0;
private float[] topUsage = new float[3];
private String[] topProcess = new String[3];
// memory
private long memoryTotal = 0;
private long memoryFree = 0;
// battery
private boolean useCelsius = false;
private int battLevel = 0; // percentage value or -1 for unknown
private int temperature = 0;
// network
private long trafficOut = 0;
private long trafficIn = 0;
// private
private ProcessUtil infoHelper = null;
private Settings settings = null;
private int notificationType = NotificationType.MEMORY_BATTERY;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
settings = Settings.getInstance(this);
IpcService.Initialize(this);
ipcService = IpcService.getInstance();
refreshSettings();
initializeNotification();
if (settings.isEnableCPUMeter()) {
infoHelper = ProcessUtil.getInstance(this, false);
initService();
}
}
private void refreshSettings() {
// use notification for meta color
if (CoreUtil.isGreaterThanMarshmallow()) {
iconColor = R.drawable.ic_cpu_graph_meta;
}
else {
switch (settings.getCPUMeterColor()) {
case StatusBarColor.GREEN:
iconColor = R.drawable.ic_cpu_graph_green;
break;
case StatusBarColor.BLUE:
iconColor = R.drawable.ic_cpu_graph_blue;
break;
case StatusBarColor.WHITE:
iconColor = R.drawable.ic_cpu_graph_meta;
}
}
notificationType = settings.getNotificationType();
fontColor = settings.getNotificationFontColor();
backgroundColor = settings.getNotificationBackgroundColor();
isSetTop = settings.isNotificationOnTop();
useCelsius = settings.isUseCelsius();
// recreate connection type when refreshing settings
ipcService.createConnection();
}
@Override
public void onDestroy() {
endNotification();
endService();
if (!settings.getSessionValue().equals("Non-Exit"))
android.os.Process.killProcess(android.os.Process.myPid());
super.onDestroy();
}
private void endNotification() {
nManager.cancel(NOTIFYID);
stopForeground(true);
}
private void initializeNotification() {
Intent notificationIntent = new Intent(this, OSMonitor.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(
this.getBaseContext(), 0, notificationIntent, 0);
nManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nBuilder = new NotificationCompat.Builder(this);
nBuilder.setContentTitle(getResources().getText(R.string.ui_appname));
nBuilder.setContentText(getResources().getText(R.string.ui_shortcut_detail));
nBuilder.setOnlyAlertOnce(true);
nBuilder.setOngoing(true);
nBuilder.setContentIntent(contentIntent);
nBuilder.setCategory(Notification.CATEGORY_STATUS);
// Set infos as public
nBuilder.setVisibility(Notification.VISIBILITY_PUBLIC);
// Use new style icon for Lollipop
if (CoreUtil.isGreaterThanMarshmallow())
nBuilder.setSmallIcon(R.drawable.ic_stat_notify);
else
nBuilder.setSmallIcon(R.drawable.ic_launcher);
if (isSetTop)
nBuilder.setPriority(NotificationCompat.PRIORITY_MAX);
Notification osNotification = nBuilder.build();
nManager.notify(NOTIFYID, osNotification);
// set foreground to avoid recycling
startForeground(NOTIFYID, osNotification);
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
goSleep();
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON))
wakeUp();
}
};
private void registerScreenEvent() {
IntentFilter filterScreenON = new IntentFilter(Intent.ACTION_SCREEN_ON);
registerReceiver(mReceiver, filterScreenON);
IntentFilter filterScreenOFF = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(mReceiver, filterScreenOFF);
}
private void initService() {
if (!isRegistered) {
registerScreenEvent();
isRegistered = true;
}
wakeUp();
}
private void endService() {
if (isRegistered) {
unregisterReceiver(mReceiver);
isRegistered = false;
}
goSleep();
}
private byte[] getReceiveDataType() {
byte newCommand[] = { ipcCategory.PROCESS, ipcCategory.CPU, ipcCategory.OS };
switch (notificationType) {
case NotificationType.MEMORY_BATTERY:
newCommand = new byte[] { ipcCategory.PROCESS, ipcCategory.OS };
break;
case NotificationType.MEMORY_DISKIO:
newCommand = new byte[] { ipcCategory.PROCESS, ipcCategory.CPU, ipcCategory.OS };
break;
case NotificationType.BATTERY_DISKIO:
newCommand = new byte[] { ipcCategory.PROCESS, ipcCategory.CPU };
break;
case NotificationType.NETWORKIO:
newCommand = new byte[] { ipcCategory.PROCESS, ipcCategory.NETWORK };
break;
}
return newCommand;
}
private void wakeUp() {
UpdateInterval = settings.getInterval();
byte newCommand[] = getReceiveDataType();
ipcService.removeRequest(this);
ipcService.addRequest(newCommand, 0, this);
startBatteryMonitor();
}
private void goSleep() {
ipcService.removeRequest(this);
stopBatteryMonitor();
}
private void startBatteryMonitor() {
if (notificationType != NotificationType.MEMORY_BATTERY
&& notificationType != NotificationType.BATTERY_DISKIO)
return;
if (!isRegisterBattery) {
IntentFilter battFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(battReceiver, battFilter);
isRegisterBattery = true;
}
}
private void stopBatteryMonitor() {
if (isRegisterBattery) {
unregisterReceiver(battReceiver);
isRegisterBattery = false;
}
}
private boolean isRegisterBattery = false;
private BroadcastReceiver battReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
int rawlevel = intent.getIntExtra("level", -1);
int scale = intent.getIntExtra("scale", -1);
temperature = intent.getIntExtra("temperature", -1);
if (rawlevel >= 0 && scale > 0) {
battLevel = (rawlevel * 100) / scale;
}
}
};
@Override
public void onRecvData(byte [] result) {
if (result == null) {
byte newCommand[] = getReceiveDataType();
ipcService.addRequest(newCommand, UpdateInterval, this);
return;
}
// gather data
cpuUsage = 0;
// empty
for (int index = 0; index < 3; index++) {
topUsage[index] = 0;
topProcess[index] = "";
}
try {
ipcMessage ipcMessageResult = ipcMessage.getRootAsipcMessage(ByteBuffer.wrap(result));
for (int index = 0; index < ipcMessageResult.dataLength(); index++) {
ipcData rawData = ipcMessageResult.data(index);
if (rawData.category() == ipcCategory.OS)
extractOSInfo(rawData);
else if (rawData.category() == ipcCategory.CPU)
extractCPUInfo(rawData);
else if (rawData.category() == ipcCategory.NETWORK)
extractNetworkInfo(rawData);
else if (rawData.category() == ipcCategory.PROCESS)
extractProcessInfo(rawData);
}
} catch (Exception e) {}
refreshNotification();
// send command again
byte newCommand[] = getReceiveDataType();
ipcService.addRequest(newCommand, UpdateInterval, this);
}
private void extractProcessInfo(ipcData rawData)
{
processInfoList infoList = processInfoList.getRootAsprocessInfoList(rawData.payloadAsByteBuffer().asReadOnlyBuffer());
for (int count = 0; count < infoList.listLength(); count++) {
processInfo item = infoList.list(count);
cpuUsage += item.cpuUsage();
for (int check = 0; check < 3; check++) {
if (topUsage[check] >= item.cpuUsage())
continue;
// keep top 3 usage
for (int push = 2; push > check; push--) {
topUsage[push] = topUsage[push - 1];
topProcess[push] = topProcess[push - 1];
}
topUsage[check] = item.cpuUsage();
topProcess[check] = infoHelper.getPackageName(item.name());
// if name is not ready, use process name
if (topProcess[check] == null)
topProcess[check] = item.name();
// check cached status
if (infoHelper.checkPackageInformation(item.name()))
break;
// prepare to do cache
if (item.name().toLowerCase(Locale.getDefault()).contains("osmcore"))
infoHelper.doCacheInfo(android.os.Process.myUid(), item.owner(), item.name());
else
infoHelper.doCacheInfo(item.uid(), item.owner(), item.name());
break;
}
}
}
private void extractNetworkInfo(ipcData rawData)
{
// process processInfo
trafficOut = 0;
trafficIn = 0;
networkInfoList nwInfoList = networkInfoList.getRootAsnetworkInfoList(rawData.payloadAsByteBuffer().asReadOnlyBuffer());
for (int count = 0; count < nwInfoList.listLength(); count++) {
networkInfo nwInfo = nwInfoList.list(count);
trafficOut += nwInfo.transUsage();
trafficIn += nwInfo.recvUsage();
}
}
private void extractCPUInfo(ipcData rawData)
{
cpuInfoList infoList = cpuInfoList.getRootAscpuInfoList(rawData.payloadAsByteBuffer().asReadOnlyBuffer());
for(int count = 0; count < infoList.listLength(); count++) {
cpuInfo info = infoList.list(count);
ioWaitUsage = info.ioUtilization();
break;
}
}
private void extractOSInfo(ipcData rawData)
{
osInfo info = osInfo.getRootAsosInfo(rawData.payloadAsByteBuffer().asReadOnlyBuffer());
memoryFree = info.freeMemory() + info.bufferedMemory() + info.cachedMemory();
memoryTotal = info.totalMemory();
}
private String getBatteryInfo() {
String info = "";
if (useCelsius)
info = battLevel + "% (" + temperature / 10 + "\u2103)";
else
info = battLevel + "% (" + ((int) temperature / 10 * 9 / 5 + 32) + "\u2109)";
return info;
}
private void refreshNotification() {
Notification osNotification;
// set current iconLevel
// Fix: Android 6.0 issue
if (CoreUtil.isGreaterThanMarshmallow()) {
int iconLevel = 0;
if (cpuUsage < 20)
iconLevel = 1;
else if (cpuUsage < 40)
iconLevel = 2;
else if (cpuUsage < 60)
iconLevel = 3;
else if (cpuUsage < 80)
iconLevel = 4;
else if (cpuUsage < 100)
iconLevel = 5;
else
iconLevel = 6;
osNotification = nBuilder.setSmallIcon(iconColor, iconLevel).build();
}
else {
osNotification = nBuilder.build();
}
osNotification.contentView = new RemoteViews(getPackageName(), R.layout.ui_notification);
// set contentIntent to fix
// "android.app.RemoteServiceException: Bad notification posted from package"
Intent notificationIntent = new Intent(this, OSMonitor.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
osNotification.contentIntent = PendingIntent.getActivity( this.getBaseContext(), 0, notificationIntent, 0);
osNotification.contentView.setTextViewText(R.id.notification_cpu, "CPU: " + UserInterfaceUtil.convertToUsage(cpuUsage) + "%");
osNotification.contentView.setProgressBar(R.id.notification_cpu_bar, 100, (int) cpuUsage, false);
switch (notificationType) {
case NotificationType.MEMORY_BATTERY:
osNotification.contentView.setTextViewText(R.id.notification_1nd, "MEM: "
+ UserInterfaceUtil.convertToSize(memoryFree, true));
osNotification.contentView.setTextViewText(R.id.notification_2nd, "BAT: " + getBatteryInfo());
osNotification.contentView.setProgressBar(R.id.notification_1nd_bar, (int) memoryTotal,
(int) (memoryTotal - memoryFree), false);
osNotification.contentView.setProgressBar(R.id.notification_2nd_bar, 100, (int) battLevel, false);
break;
case NotificationType.MEMORY_DISKIO:
osNotification.contentView.setTextViewText(R.id.notification_1nd, "MEM: "
+ UserInterfaceUtil.convertToSize(memoryFree, true));
osNotification.contentView.setTextViewText(R.id.notification_2nd, "IO: "
+ UserInterfaceUtil.convertToUsage(ioWaitUsage) + "%");
osNotification.contentView.setProgressBar(R.id.notification_1nd_bar, (int) memoryTotal,
(int) (memoryTotal - memoryFree), false);
osNotification.contentView.setProgressBar(R.id.notification_2nd_bar, 100, (int) ioWaitUsage, false);
break;
case NotificationType.BATTERY_DISKIO:
osNotification.contentView.setTextViewText(R.id.notification_1nd, "BAT: " + getBatteryInfo());
osNotification.contentView.setTextViewText(R.id.notification_2nd, "IO: "
+ UserInterfaceUtil.convertToUsage(ioWaitUsage) + "%");
osNotification.contentView.setProgressBar(R.id.notification_1nd_bar, 100, (int) battLevel, false);
osNotification.contentView.setProgressBar(R.id.notification_2nd_bar, 100, (int) ioWaitUsage, false);
break;
case NotificationType.NETWORKIO:
osNotification.contentView.setTextViewText(R.id.notification_1nd, "OUT: "
+ UserInterfaceUtil.convertToSize(trafficOut, true));
osNotification.contentView.setTextViewText(R.id.notification_2nd, "IN: "
+ UserInterfaceUtil.convertToSize(trafficIn, true));
osNotification.contentView.setProgressBar(R.id.notification_1nd_bar,
(int) (trafficOut + trafficIn), (int) trafficOut, false);
osNotification.contentView.setProgressBar(R.id.notification_2nd_bar,
(int) (trafficOut + trafficIn), (int) trafficIn, false);
break;
}
osNotification.contentView.setTextViewText(R.id.notification_top1st,
UserInterfaceUtil.convertToUsage(topUsage[0]) + "% " + topProcess[0]);
osNotification.contentView.setTextViewText(R.id.notification_top2nd,
UserInterfaceUtil.convertToUsage(topUsage[1]) + "% " + topProcess[1]);
osNotification.contentView.setTextViewText(R.id.notification_top3nd,
UserInterfaceUtil.convertToUsage(topUsage[2]) + "% " + topProcess[2]);
// use customize font color
if (fontColor == -1 && !CoreUtil.isGreaterThanIceCreamSandwich()) {
osNotification.contentView.setTextColor(R.id.notification_2nd, Color.BLACK);
osNotification.contentView.setTextColor(R.id.notification_1nd, Color.BLACK);
osNotification.contentView.setTextColor(R.id.notification_cpu, Color.BLACK);
osNotification.contentView.setTextColor(R.id.notification_top1st, Color.BLACK);
osNotification.contentView.setTextColor(R.id.notification_top2nd, Color.BLACK);
osNotification.contentView.setTextColor(R.id.notification_top3nd, Color.BLACK);
}
else if (fontColor != -1) {
osNotification.contentView.setTextColor(R.id.notification_2nd, fontColor);
osNotification.contentView.setTextColor(R.id.notification_1nd, fontColor);
osNotification.contentView.setTextColor(R.id.notification_cpu, fontColor);
osNotification.contentView.setTextColor(R.id.notification_top1st, fontColor);
osNotification.contentView.setTextColor(R.id.notification_top2nd, fontColor);
osNotification.contentView.setTextColor(R.id.notification_top3nd, fontColor);
}
// use customize background color
if (backgroundColor != -1) {
osNotification.contentView.setInt(R.id.custom_notification, "setBackgroundColor", backgroundColor);
}
/* Fix compatible issue for Notification Icon */
if (!CoreUtil.isGreaterThanMarshmallow()) {
osNotification.icon = iconColor;
if (cpuUsage < 20)
osNotification.iconLevel = 1;
else if (cpuUsage < 40)
osNotification.iconLevel = 2;
else if (cpuUsage < 60)
osNotification.iconLevel = 3;
else if (cpuUsage < 80)
osNotification.iconLevel = 4;
else if (cpuUsage < 100)
osNotification.iconLevel = 5;
else
osNotification.iconLevel = 6;
}
nManager.notify(NOTIFYID, osNotification);
}
}