package org.bitseal.util; import java.util.Random; import org.bitseal.core.App; import android.content.SharedPreferences; import android.preference.PreferenceManager; /** * This class provides convenience methods for getting and formatting * time values. * * @author Jonathan Coe */ public final class TimeUtils { /** * The range of time (in seconds) by which we 'fuzz' (obscure) certain time values. */ private static final int FUZZ_TIME_RANGE = 300; // Currently set to five minutes private static final int SECONDS_IN_A_DAY = 86400; private static final int SECONDS_IN_AN_HOUR = 3600; private static final int MINUTES_IN_AN_HOUR = 60; private static final int SECONDS_IN_A_MINUTE = 60; private static final int HOURS_IN_A_DAY = 24; /** A key used to store the time of the last successful 'check for new msgs' server request */ private static final String LAST_MSG_CHECK_TIME = "lastMsgCheckTime"; /** Stores the Unix timestamp of the last msg payload we processed. This can be used to tell us how far behind the network we are. */ private static final String LAST_PROCESSED_MSG_TIME = "lastProcessedMsgTime"; private TimeUtils() { // The constructor of this class is private in order to prevent the class being instantiated } /** * Returns a long containing the Unix timestamp for the current time, in seconds. */ public static long getUnixTime() { return System.currentTimeMillis() / 1000; } /** * Returns a 'time to live' value and uses it to produce a * fuzzed expiration time - which is the current time plus * the time to live, giving us a time value in the future. * * @param timeToLive - The 'time to live' value, in seconds * * @return The fuzzed expiration time */ public static long getFuzzedExpirationTime(long timeToLive) { return getFuzzedTime() + timeToLive; } /** * Returns the current Unix time, plus or minus a random value in a * pre-defined range. This fuzzing of time values is not strictly part * of the Bitmessage protocol, but is commonly done in order to reduce * the potential for security breaches caused by the various time values * embedded in Bitmessage data. */ private static long getFuzzedTime() { long currentTime = System.currentTimeMillis() / 1000; // Gets the current Unix time int timeModifier = (new Random().nextInt(FUZZ_TIME_RANGE * 2)) - FUZZ_TIME_RANGE; return currentTime + timeModifier; // Gives us the current Unix time plus or minus a random value within the 'fuzz time range' } /** * Returns a String containing a message describing how far * in time behind the network Bitseal is. <br><br> * * e.g. "Bitseal is 1 minute and 12 seconds behind the network." */ public static String getTimeBehindNetworkMessage() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(App.getContext()); long lastProcessedMsgTime = prefs.getLong(LAST_PROCESSED_MSG_TIME, 0); long lastMsgCheckTime = prefs.getLong(LAST_MSG_CHECK_TIME, 0); long currentTime = System.currentTimeMillis() / 1000; long secondsBehindNetwork; // We want the returned message to describe how far behind Bitseal is from having both downloaded // and processed all current msgs in the stream(s) in participates in. If we are significantly behind the // network, we use the 'lastMsgCheckTime' value. If we are relatively close to being caught up, we use the // 'lastProcessedMsgTime' value. if ((currentTime - lastMsgCheckTime) > (currentTime - lastProcessedMsgTime)) { secondsBehindNetwork = currentTime - lastMsgCheckTime; } else { secondsBehindNetwork = currentTime - lastProcessedMsgTime; } String timeMessage = getTimeMessage(secondsBehindNetwork); timeMessage = "Bitseal is " + timeMessage; timeMessage = timeMessage + " behind the network"; return timeMessage; } /** * Returns a String containing a message describing how long ago * the last successful server check for new msgs was. <br><br> * * e.g. "The last successful msg check was 1 minute and 12 seconds ago." */ public static String getLastMsgCheckTimeMessage() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(App.getContext()); long lastMsgCheckTime = prefs.getLong(LAST_MSG_CHECK_TIME, 0); long currentTime = System.currentTimeMillis() / 1000; long secondsBehindNetwork = currentTime - lastMsgCheckTime; String timeMessage = getTimeMessage(secondsBehindNetwork); timeMessage = "The last successful msg check was " + timeMessage; timeMessage = timeMessage + " ago"; return timeMessage; } /** * Takes a time value in seconds and returns a String which * gives the same time value in an easily human readable form.<br><br> * * NOTE: This method is designed to return a concise representation of the time, * therefore if the provided value is sufficiently large, the resulting message * may be 'rounded off'. If the time value provided is equal to many days, then the returned * message will contain the number of days and hours, but not the number of * remainder seconds. <br><br> * * e.g. 777329 returns "8 days and 23 hours" * * @param time A long containing a time value in seconds * * @return A String containing the time message */ public static String getTimeMessage(long time) { String timeMessage; long seconds = time; long minutes = seconds / SECONDS_IN_A_MINUTE; long hours = seconds / SECONDS_IN_AN_HOUR; long days = seconds / SECONDS_IN_A_DAY; if (seconds > SECONDS_IN_A_DAY) { long remainderHours = hours % HOURS_IN_A_DAY; if (days > 1) { if (remainderHours == 1) { timeMessage = days + " days and " + remainderHours + " hour"; } else { timeMessage = days + " days and " + remainderHours + " hours"; } } else { if (remainderHours == 1) { timeMessage = days + " day and " + remainderHours + " hour"; } else { timeMessage = days + " day and " + remainderHours + " hours"; } } } else if (seconds > SECONDS_IN_AN_HOUR) { long remainderMinutes = minutes % MINUTES_IN_AN_HOUR; if (hours > 1) { if (remainderMinutes == 1) { timeMessage = hours + " hours and " + remainderMinutes + " minute"; } else { timeMessage = hours + " hours and " + remainderMinutes + " minutes"; } } else { if (remainderMinutes == 1) { timeMessage = hours + " hour and " + remainderMinutes + " minute"; } else { timeMessage = hours + " hour and " + remainderMinutes + " minutes"; } } } else if (seconds > SECONDS_IN_A_MINUTE) { long remainderSeconds = seconds % SECONDS_IN_A_MINUTE; if (minutes > 1) { if (remainderSeconds == 1) { timeMessage = minutes + " minutes and " + remainderSeconds + " second"; } else { timeMessage = minutes + " minutes and " + remainderSeconds + " seconds"; } } else { if (remainderSeconds == 1) { timeMessage = minutes + " minute and " + remainderSeconds + " second"; } else { timeMessage = minutes + " minute and " + remainderSeconds + " seconds"; } } } else { if (seconds != 1) { timeMessage = seconds + " seconds"; } else { timeMessage = "1 second"; } } return timeMessage; } }