/* * Copyright 2013 RobustNet Lab, University of Michigan. All Rights Reserved. * * 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; import java.util.ArrayList; import java.util.HashMap; import java.util.Timer; import java.util.TimerTask; import android.annotation.SuppressLint; import android.net.TrafficStats; import com.mobilyzer.util.PhoneUtils; /** * * @author Jack Jia, Ashkan Nikravesh (ashnik@umich.edu) Collects context information periodically * (using a Timer). User can specify the interval. */ public class ContextCollector { private volatile ArrayList<HashMap<String, String>> contextResultArray; private PhoneUtils phoneUtils; private int interval; private Timer timer; private volatile boolean isRunning; private int count; public volatile String ipConnectivity = ""; public volatile String dnsConnectivity = ""; private long prevSend; private long prevRecv; private long prevPktSend; private long prevPktRecv; public ContextCollector() { phoneUtils = PhoneUtils.getPhoneUtils(); this.isRunning = false; this.timer = new Timer(); contextResultArray = new ArrayList<HashMap<String, String>>(); count = 0; prevSend = -1; prevRecv = -1; prevPktSend = -1; prevPktRecv = -1; } /** * this function sets the interval of context collection (in seconds) * * @param intervalSecond time between each context info snapshot */ public void setInterval(int intervalSecond) { this.interval = intervalSecond; if (intervalSecond <= 0) { this.interval = Config.DEFAULT_CONTEXT_INTERVAL_SEC; } } /** * called by the timer and return the current context info of device * * @return a hash map that contains all the context data */ @SuppressLint("NewApi") private HashMap<String, String> getCurrentContextInfo() { HashMap<String, String> currentContext = new HashMap<String, String>();; long intervalPktSend = 0; long intervalPktRecv = 0; long intervalSend = 0; long intervalRecv = 0; long sendBytes = TrafficStats.getTotalTxBytes(); long recvBytes = TrafficStats.getTotalRxBytes(); long sendPkt = TrafficStats.getTotalTxPackets(); long recvPkt = TrafficStats.getTotalRxPackets(); if (prevSend != -1 && prevRecv != -1) { intervalSend = sendBytes - prevSend; intervalRecv = recvBytes - prevRecv; } if (prevPktSend != -1 && prevPktRecv != -1) { intervalPktSend = sendPkt - prevPktSend; intervalPktRecv = recvPkt - prevPktRecv; } // we only return the context info if (1) it's the first time it gets called (2) we have // change in the amount of packet/byte sent/received. if (prevSend == -1 || prevRecv == -1 || prevPktSend == -1 || prevPktRecv == -1 || intervalSend != 0 || intervalRecv != 0 || intervalPktSend != 0 || intervalPktRecv != 0) { currentContext.put("timestamp", (System.currentTimeMillis() * 1000) + ""); // currentContext.put("rssi", phoneUtils.getCurrentRssi() + ""); currentContext.put("inc_total_bytes_send", intervalSend + ""); currentContext.put("inc_total_bytes_recv", intervalRecv + ""); currentContext.put("inc_total_pkt_send", intervalPktSend + ""); currentContext.put("inc_total_pkt_recv", intervalPktRecv + ""); currentContext.put("battery_level", phoneUtils.getCurrentBatteryLevel() + ""); } prevSend = sendBytes; prevRecv = recvBytes; prevPktSend = sendPkt; prevPktRecv = recvPkt; return currentContext; } /** * Starts the context collection timer task. It should be called when a measurement task gets * started. * * @return false if the collector is already running. */ public boolean startCollector() { if (isRunning) { return false; } isRunning = true; timer.scheduleAtFixedRate(timerTask, 0, interval * 1000); return true; } /** * Stops the context collection task. It attaches the current context data to the results * * @return array of all context info collected at specific time intervals */ public ArrayList<HashMap<String, String>> stopCollector() { if (!isRunning) { return null; } timerTask.cancel(); timer.cancel(); isRunning = false; HashMap<String, String> currentContext = getCurrentContextInfo(); if (currentContext.size() != 0) { contextResultArray.add(currentContext); } // if(ipConnectivity.equals("")){ // ipConnectivity = phoneUtils.getIpConnectivity(); // } // if(dnsConnectivity.equals("")){ // dnsConnectivity = phoneUtils.getDnResolvability(); // } if(ipConnectivity.equals("")){ ipConnectivity = "NOT SUPPORTED"; } if(dnsConnectivity.equals("")){ dnsConnectivity = "NOT SUPPORTED"; } return contextResultArray; } /** * Return the current Ip connectivity * * @return A string that represents the current ip connectivity. */ public String getCurrentIPConnectivity() { return ipConnectivity; } /** * Return the current DNS resolvability * * @return A string that represents the current DNS resolvability. */ public String getCurrentDNSConnectivity() { return dnsConnectivity; } private TimerTask timerTask = new TimerTask() { @Override public void run() { if (ContextCollector.this.count < Config.MAX_CONTEXT_INFO_COLLECTIONS_PER_TASK) { HashMap<String, String> currentContext = getCurrentContextInfo(); if (currentContext.size() != 0) { contextResultArray.add(currentContext); ContextCollector.this.count++; if(ipConnectivity.equals("")){ ipConnectivity = phoneUtils.getIpConnectivity(); } if(dnsConnectivity.equals("")){ dnsConnectivity = phoneUtils.getDnResolvability(); } } } } }; }