/*
* Copyright (C) 2013 CyanKang Project
* Copyright (C) 2014 Peter Gregus for GravityBox Project (C3C076@xda)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 hello.dcsms.omzen.Traffic;
import android.content.Context;
import android.content.Intent;
import android.net.TrafficStats;
import android.os.Handler;
import android.os.SystemClock;
import android.util.TypedValue;
import android.view.View;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.File;
import de.robv.android.xposed.XSharedPreferences;
public class TrafficMeter extends TrafficMeterAbstract {
public static final int INACTIVITY_MODE_DEFAULT = 0;
public static final int INACTIVITY_MODE_HIDDEN = 1;
public static final int INACTIVITY_MODE_SUMMARY = 2;
boolean mTrafficMeterHide;
boolean mCanReadFromFile;
int mTrafficMeterSummaryTime;
long mTotalRxBytes;
long mLastUpdateTime;
long mTrafficBurstStartTime;
long mTrafficBurstStartBytes;
long mKeepOnUntil = Long.MIN_VALUE;
String mB = "B";
String mKB = "K";
String mMB = "M";
String mS = "s";
NumberFormat mDecimalFormat = new DecimalFormat("##0.0");
NumberFormat mIntegerFormat = NumberFormat.getIntegerInstance();
public TrafficMeter(Context context) {
super(context);
}
@Override
protected void onInitialize(XSharedPreferences prefs) {
mCanReadFromFile = canReadFromFile();
try {
int inactivityMode = Integer.valueOf("0");
setInactivityMode(inactivityMode);
} catch (NumberFormatException nfe) {
log("Invalid preference value for PREF_KEY_DATA_TRAFFIC_INACTIVITY_MODE");
}
}
@Override
protected void onPreferenceChanged(Intent intent) {
}
@Override
protected void startTrafficUpdates() {
mTotalRxBytes = getTotalReceivedBytes();
mLastUpdateTime = SystemClock.elapsedRealtime();
mTrafficBurstStartTime = Long.MIN_VALUE;
getHandler().removeCallbacks(mRunnable);
getHandler().post(mRunnable);
}
@Override
protected void stopTrafficUpdates() {
final Handler h = getHandler();
if (h != null && mRunnable != null) {
h.removeCallbacks(mRunnable);
}
}
private String formatTraffic(long bytes, boolean speed) {
if (bytes > 10485760) { // 1024 * 1024 * 10
return (speed ? "" : "(")
+ mIntegerFormat.format(bytes / 1048576)
+ (speed ? mMB + "/" + mS : mMB + ")");
} else if (bytes > 1048576) { // 1024 * 1024
return (speed ? "" : "(")
+ mDecimalFormat.format(((float) bytes) / 1048576f)
+ (speed ? mMB + "/" + mS : mMB + ")");
} else if (bytes > 10240) { // 1024 * 10
return (speed ? "" : "(")
+ mIntegerFormat.format(bytes / 1024)
+ (speed ? mKB + "/" + mS : mKB + ")");
} else { // 1024
return (speed ? "" : "(")
+ mDecimalFormat.format(((float) bytes) / 1024f)
+ (speed ? mKB + "/" + mS : mKB + ")");
}
}
Runnable mRunnable = new Runnable() {
@Override
public void run() {
long td = SystemClock.elapsedRealtime() - mLastUpdateTime;
if (!mAttached) {
return;
}
long currentRxBytes = mCanReadFromFile ? getTotalReceivedBytes() : TrafficStats.getTotalRxBytes();
long newBytes = currentRxBytes - mTotalRxBytes;
boolean disconnected = false;
if (mCanReadFromFile && newBytes < 0) {
// It's impossible to get a speed under 0
currentRxBytes = 0;
newBytes = 0;
disconnected = true;
}
if (mTrafficMeterHide && newBytes == 0) {
long trafficBurstBytes = (mCanReadFromFile && disconnected) ? mTotalRxBytes - mTrafficBurstStartBytes : currentRxBytes - mTrafficBurstStartBytes;
if (trafficBurstBytes != 0 && mTrafficMeterSummaryTime != 0) {
setText(formatTraffic(trafficBurstBytes, false));
if (DEBUG) log("Traffic burst ended: " + trafficBurstBytes + "B in "
+ (SystemClock.elapsedRealtime() - mTrafficBurstStartTime)
/ 1000 + "s");
mKeepOnUntil = SystemClock.elapsedRealtime() + mTrafficMeterSummaryTime;
mTrafficBurstStartTime = Long.MIN_VALUE;
mTrafficBurstStartBytes = currentRxBytes;
}
} else {
if (mTrafficMeterHide && mTrafficBurstStartTime == Long.MIN_VALUE) {
mTrafficBurstStartTime = mLastUpdateTime;
mTrafficBurstStartBytes = mTotalRxBytes;
}
if (td > 0) {
setText(formatTraffic(newBytes * 1000 / td, true));
}
}
// Hide if there is no traffic
if (mTrafficMeterHide && newBytes == 0) {
if (getVisibility() != GONE
&& mKeepOnUntil < SystemClock.elapsedRealtime()) {
setText("");
setVisibility(View.GONE);
}
} else {
if (getVisibility() != VISIBLE) {
setVisibility(View.VISIBLE);
}
}
mTotalRxBytes = (mCanReadFromFile && disconnected) ? mTotalRxBytes : currentRxBytes;
mLastUpdateTime = SystemClock.elapsedRealtime();
getHandler().postDelayed(mRunnable, mInterval);
}
};
private boolean canReadFromFile() {
return new File("/proc/net/dev").exists();
}
private long getTotalReceivedBytes() {
String line;
String[] segs;
long received = 0;
int i;
long tmp = 0;
boolean isNum;
try {
FileReader fr = new FileReader("/proc/net/dev");
BufferedReader in = new BufferedReader(fr);
while ((line = in.readLine()) != null) {
line = line.trim();
if (line.contains(":") && !line.startsWith("lo")) {
segs = line.split(":")[1].split(" ");
for (i = 0; i < segs.length; i++) {
isNum = true;
try {
tmp = Long.parseLong(segs[i]);
} catch (Exception e) {
isNum = false;
}
if (isNum == true) {
received = received + tmp;
break;
}
}
}
}
in.close();
} catch (IOException e) {
return -1;
}
return received;
}
private void setInactivityMode(int mode) {
switch (mode) {
case INACTIVITY_MODE_HIDDEN:
mTrafficMeterHide = true;
mTrafficMeterSummaryTime = 0;
break;
case INACTIVITY_MODE_SUMMARY:
mTrafficMeterHide = true;
mTrafficMeterSummaryTime = 3000;
break;
case INACTIVITY_MODE_DEFAULT:
default:
mTrafficMeterHide = false;
mTrafficMeterSummaryTime = 0;
break;
}
}
}