/* Copyright 2012 Google Inc.
*
* 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 com.mobilyzer.util;
import android.content.Context;
import android.net.TrafficStats;
import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidParameterException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.mobilyzer.Config;
/**
* Utility class for Speedometer that does not require runtime information
*/
public class Util {
/**
* Filter out values equal or beyond the bounds and then compute the average
* of valid data
* @param vals the list of values to be filtered
* @param lowerBound the lower bound of valid data
* @param upperBound the upper bound of valid data
* @return a list of filtered data within the specified bounds
*/
public static ArrayList<Double> applyInnerBandFilter(ArrayList<Double> vals,
double lowerBound, double upperBound) throws InvalidParameterException {
double rrtTotal = 0;
int initResultLen = vals.size();
if (initResultLen == 0) {
// Return the original array if it is of zero length.
throw new InvalidParameterException("The array size passed in is zero");
}
double rrtAvg = rrtTotal / initResultLen;
// we should filter out the outliers in the rrt result based on the average
ArrayList<Double> finalRrtResults = new ArrayList<Double>();
int finalResultCnt = 0;
rrtTotal = 0;
for (double rrtVal : vals) {
if (rrtVal <= upperBound && rrtVal >= lowerBound) {
finalRrtResults.add(rrtVal);
}
}
return finalRrtResults;
}
/**
* Compute the sum of the values in list
* @param vals the list of values to sum up
* @return the sum of the values in the list
*/
public static double getSum(ArrayList<Double> vals) {
double sum = 0;
for (double val : vals) {
sum += val;
}
return sum;
}
public static String constructCommand(Object... strings)
throws InvalidParameterException {
String finalCommand = "";
int len = strings.length;
if (len < 0) {
throw new InvalidParameterException("0 arguments passed in for " +
"constructing command");
}
for (int i = 0; i < len - 1; i++) {
finalCommand += (strings[i] + " ");
}
finalCommand += strings[len - 1];
return finalCommand;
}
/**
* Prepare the internal User-Agent string for use. This requires a
* {@link Context} to pull the package name and version number for this
* application.
*/
public static String prepareUserAgent() {
return Config.USER_AGENT;
}
public static double getStandardDeviation(ArrayList<Double> values, double avg) {
double total = 0;
for (double val : values) {
double dev = val - avg;
total += (dev * dev);
}
if (total > 0) {
return Math.sqrt(total / values.size());
} else {
return 0;
}
}
public static String getTimeStringFromMicrosecond(long microsecond) {
Date timestamp = new Date(microsecond / 1000);
return timestamp.toString();
}
/**
* Returns a String array that contains the ICMP sequence number and the round
* trip time extracted from a ping output. The first array element is the
* sequence number and the second element is the round trip time.
*
* Returns a null object if either element cannot be found.
*/
public static String[] extractInfoFromPingOutput(String outputLine) {
try {
Pattern pattern = Pattern.compile("icmp_seq=([0-9]+)\\s.* time=([0-9]+(\\.[0-9]+)?)");
Matcher matcher = pattern.matcher(outputLine);
matcher.find();
return new String[] {matcher.group(1), matcher.group(2)};
} catch (IllegalStateException e) {
return null;
}
}
/**
* Returns an integer array that contains the number of ICMP requests sent and the number
* of responses received. The first element is the requests sent and the second element
* is the responses received.
*
* Returns a null object if either element cannot be found.
*/
public static int[] extractPacketLossInfoFromPingOutput(String outputLine) {
try {
Pattern pattern = Pattern.compile("([0-9]+)\\spackets.*\\s([0-9]+)\\sreceived");
Matcher matcher = pattern.matcher(outputLine);
matcher.find();
return new int[] {Integer.parseInt(matcher.group(1)),
Integer.parseInt(matcher.group(2))};
} catch (IllegalStateException e) {
return null;
} catch (NumberFormatException e) {
return null;
} catch (NullPointerException e) {
return null;
}
}
/**
* Return a list of system environment path
*/
public static String[] fetchEnvPaths() {
String path = "";
Map<String, String> env = System.getenv();
if (env.containsKey("PATH")) {
path = env.get("PATH");
}
return (path.contains(":")) ? path.split(":") : (new String[]{path});
}
/**
* Determine the ping executable based on ip address byte length
*/
public static String pingExecutableBasedOnIPType (int ipByteLen) {
Process testPingProc = null;
String[] progList = fetchEnvPaths();
String pingExecutable = null;
if (progList != null && progList.length != 0) {
for (String pingLocation : progList) {
try {
if (ipByteLen == 4) {
pingExecutable = pingLocation + "/" + Config.PING_EXECUTABLE;
// context.getString(R.string.ping_executable);
} else if (ipByteLen == 16) {
pingExecutable = pingLocation + "/" + Config.PING6_EXECUTABLE;
// context.getString(R.string.ping6_executable);
}
testPingProc = Runtime.getRuntime().exec(pingExecutable);
} catch (IOException e) {
// reset the executable
pingExecutable = null;
// The ping command doesn't exist in that path, try another one
continue;
} finally {
if (testPingProc != null)
testPingProc.destroy();
}
break;
}
}
return pingExecutable;
}
/**
* Generates a random string (10 chars) that can be used as client key
* @return 10 least significant bytes of a random UUID
*/
public static String generateRandomClientKey(){
UUID uuid=UUID.randomUUID();
String uuidStr=uuid.toString();
return uuidStr.substring(uuidStr.length()-10);
}
public static long getCurrentRxTxBytes(){
int uid = android.os.Process.myUid();
return TrafficStats.getUidRxBytes(uid)+TrafficStats.getUidTxBytes(uid);
}
}