/* 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); } }