Java tutorial
/** * Copyright (C) 2009 Anders Aagaard <aagaande@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.neuron.trafikanten; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Locale; import java.util.TimeZone; import java.util.zip.GZIPInputStream; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.DefaultHttpClient; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Typeface; import android.os.Build; import android.util.Log; /* * Small helper functions used by multiple classes. */ public class HelperFunctions { private final static String TAG = "Trafikanten-HelperFunctions"; public final static SimpleDateFormat hourFormater = new SimpleDateFormat("HH:mm"); public static final String KEY_DOWNLOADBYTE = "downloadkb"; public static final int SECOND = 1000; public static final int MINUTE = 60 * SECOND; public static final int HOUR = 60 * MINUTE; /* * Render time in the way trafikanten.no wants * From 1-9 minutes we use "X m", above that we use HH:MM */ private static CharSequence nowText; public static void renderTime(final StringBuffer txt, Long currentTime, Context context, long time) { int diffMinutes = Math.round(((float) (time - currentTime)) / MINUTE); if (diffMinutes < -1) { // Negative time! diffMinutes = diffMinutes * -1; txt.append("-"); txt.append(diffMinutes); txt.append(" min"); return; } else if (diffMinutes < 1) { if (nowText == null) { nowText = context.getText(R.string.now); } txt.append(nowText); return; } else if (diffMinutes <= 9) { txt.append(diffMinutes); txt.append(" min"); return; } //TODO Performance : hourFormater slow? can we construct HH:mm faster ourselfes and write directly to stringbuffer? aprox 110ms here txt.append(hourFormater.format(time)); } private static String _applicationVersion = null; public static String GetApplicationVersion(Context context) { if (_applicationVersion == null) { try { _applicationVersion = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName; } catch (NameNotFoundException e) { e.printStackTrace(); _applicationVersion = "0"; } } return _applicationVersion; } private static String userAgentString = null; private static String getUserAgent(Context context) { if (userAgentString == null) { CharSequence appVersion = GetApplicationVersion(context); userAgentString = "TrafikantenAndroid/" + appVersion + " (aagaande) Device/" + Build.VERSION.RELEASE + " (" + Locale.getDefault() + "; " + Build.MODEL + ")"; // + Locale.getDefault() + ")"; } return userAgentString; } /* * Do proper encoding that doesn't add + to the string (with JSON doesn't want) */ public static String properEncode(String query) throws UnsupportedEncodingException { return URLEncoder.encode(query.trim(), "UTF-8").replace("+", "%20"); } /* * Convert trafikanten's json date to an actual date */ public static Long jsonToDate(String jsonString) { Calendar calendar = Calendar.getInstance(); int indexOfPlus = jsonString.indexOf("+"); int startOfDate = 5; if (jsonString.startsWith("/")) { // LEGACY : parse /Date( strings : Some date strings are /Date(253402297140000+0100)/, new ones are Date(253402297140000+0100) startOfDate = 6; calendar.setTimeInMillis(Long.parseLong( jsonString.substring(startOfDate, indexOfPlus > 0 ? indexOfPlus : jsonString.length() - 2))); } else { calendar.setTimeInMillis(Long.parseLong( jsonString.substring(startOfDate, indexOfPlus > 0 ? indexOfPlus : jsonString.length() - 1))); } if (indexOfPlus > -1) { calendar.setTimeZone( TimeZone.getTimeZone("GMT-" + jsonString.substring(indexOfPlus, indexOfPlus + 3) + ":00")); } return calendar.getTimeInMillis(); } /* * Converts inputstream to string */ public static String InputStreamToString(InputStream stream) throws IOException { //long perfSTART = System.currentTimeMillis(); final InputStreamReader input = new InputStreamReader(stream, "UTF-8"); final char[] buffer = new char[8192]; final StringBuilder output = new StringBuilder(8192); try { for (int read = input.read(buffer, 0, buffer.length); read != -1; read = input.read(buffer, 0, buffer.length)) { output.append(buffer, 0, read); } } catch (IOException e) { } //Log.i(TAG,"PERF : Downloading web request took " + ((System.currentTimeMillis() - perfSTART)) + "ms"); return output.toString(); } /* * Updates statistics for byte downloaded. */ private static void updateStatistics(Context context, long size) { if (size == 0) return; final SharedPreferences preferences = context.getSharedPreferences("trafikantenandroid", Context.MODE_PRIVATE); Long downloadByte = preferences.getLong(KEY_DOWNLOADBYTE, 0) + size; final SharedPreferences.Editor editor = preferences.edit(); editor.putLong(KEY_DOWNLOADBYTE, downloadByte); editor.commit(); } /* * Decides on whether or not we should use gzip compression or not. */ public static class StreamWithTime { public InputStream stream; public long timeDifference; public StreamWithTime(InputStream stream, long timeDifference) { this.stream = stream; this.timeDifference = timeDifference; } } public static StreamWithTime executeHttpRequest(Context context, HttpUriRequest request, boolean parseTime) throws IOException { //long perfSTART = System.currentTimeMillis(); /* * Add gzip header */ request.setHeader("Accept-Encoding", "gzip"); request.setHeader("User-Agent", getUserAgent(context)); /* * Get the response, if we use gzip use the GZIPInputStream */ long responseTime = System.currentTimeMillis(); HttpResponse response = new DefaultHttpClient().execute(request); responseTime = (System.currentTimeMillis() - responseTime) / 2; InputStream content = response.getEntity().getContent(); /* * Get trafikanten time to calculate time difference */ long timeDifference = 0; if (parseTime) { try { final String header = response.getHeaders("Date")[0].getValue(); final long trafikantenTime = new Date(header).getTime(); //timeDifference = System.currentTimeMillis() - (System.currentTimeMillis() - timeDifference) - trafikantenTime; timeDifference = System.currentTimeMillis() - responseTime - trafikantenTime; Log.i(TAG, "Timedifference between local clock and trafikanten server : " + timeDifference + "ms (" + (timeDifference / 1000) + "s)"); } catch (Exception e) { e.printStackTrace(); // ignore this error, it's not critical. } } Header contentEncoding = response.getFirstHeader("Content-Encoding"); Header contentLength = response.getFirstHeader("Content-Length"); if (contentLength != null) { updateStatistics(context, Long.parseLong(contentLength.getValue())); } else { Log.e(TAG, "Contentlength is invalid!"); } if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) { content = new GZIPInputStream(content); //Log.i(TAG,"Recieved compressed data - OK"); } else { Log.i(TAG, "Recieved UNCOMPRESSED data - Problem server side"); } //Log.i(TAG,"PERF : Sending web request took " + ((System.currentTimeMillis() - perfSTART)) + "ms"); //return content; return new StreamWithTime(content, timeDifference); } /* * Create custom font for devi. */ private static Typeface mTypeface = null; public static Typeface getTypeface(Activity activity) { if (mTypeface == null) { mTypeface = Typeface.createFromAsset(activity.getAssets(), "fonts/DejaVuSans.ttf"); } return mTypeface; } }