Java tutorial
package net.hockeyapp.android.internal; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import net.hockeyapp.android.Constants; import net.hockeyapp.android.Strings; import net.hockeyapp.android.Tracking; import net.hockeyapp.android.UpdateActivity; import net.hockeyapp.android.UpdateFragment; import net.hockeyapp.android.UpdateManager; import net.hockeyapp.android.UpdateManagerListener; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.app.AlertDialog; import android.app.DialogFragment; import android.app.Fragment; import android.app.FragmentTransaction; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.AsyncTask; import android.provider.Settings; import android.util.Log; import android.widget.Toast; /** * <h4>Description</h4> * * Internal helper class. Checks if a new update is available by * fetching version data from Hockeyapp. * * <h4>License</h4> * * <pre> * Copyright (c) 2012 Codenauts UG * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * </pre> * * @author Thomas Dohmke **/ public class CheckUpdateTask extends AsyncTask<String, String, JSONArray> { protected String urlString = null; protected String appIdentifier = null; private Activity activity = null; private Boolean mandatory = false; private UpdateManagerListener listener; private long usageTime = 0; public CheckUpdateTask(Activity activity, String urlString) { this.appIdentifier = null; this.activity = activity; this.urlString = urlString; this.usageTime = Tracking.getUsageTime(activity); Constants.loadFromContext(activity); } public CheckUpdateTask(Activity activity, String urlString, String appIdentifier) { this.appIdentifier = appIdentifier; this.activity = activity; this.urlString = urlString; this.usageTime = Tracking.getUsageTime(activity); Constants.loadFromContext(activity); } public CheckUpdateTask(Activity activity, String urlString, String appIdentifier, UpdateManagerListener listener) { this.appIdentifier = appIdentifier; this.activity = activity; this.urlString = urlString; this.listener = listener; this.usageTime = Tracking.getUsageTime(activity); Constants.loadFromContext(activity); } public void attach(Activity activity) { this.activity = activity; Constants.loadFromContext(activity); } public void detach() { activity = null; } protected int getVersionCode() { try { return activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_META_DATA).versionCode; } catch (NameNotFoundException e) { return 0; } } @Override protected JSONArray doInBackground(String... args) { try { int versionCode = getVersionCode(); JSONArray json = new JSONArray(VersionCache.getVersionInfo(activity)); if ((getCachingEnabled()) && (findNewVersion(json, versionCode))) { return json; } URL url = new URL(getURLString("json")); URLConnection connection = createConnection(url); connection.connect(); InputStream inputStream = new BufferedInputStream(connection.getInputStream()); String jsonString = convertStreamToString(inputStream); inputStream.close(); json = new JSONArray(jsonString); if (findNewVersion(json, versionCode)) { return json; } } catch (Exception e) { e.printStackTrace(); } return null; } protected URLConnection createConnection(URL url) throws IOException { URLConnection connection = url.openConnection(); connection.addRequestProperty("User-Agent", "Hockey/Android"); connection.setRequestProperty("connection", "close"); return connection; } private boolean findNewVersion(JSONArray json, int versionCode) { try { for (int index = 0; index < json.length(); index++) { JSONObject entry = json.getJSONObject(index); if (entry.getInt("version") > versionCode) { if (entry.has("mandatory")) { mandatory = entry.getBoolean("mandatory"); } return true; } } return false; } catch (JSONException e) { return false; } } @Override protected void onPostExecute(JSONArray updateInfo) { // if (updateInfo != null) { // if (listener != null) { // listener.onUpdateAvailable(); // } // // showDialog(updateInfo); // } // else { // if (listener != null) { // listener.onNoUpdateAvailable(); // } // } } private void cleanUp() { activity = null; urlString = null; appIdentifier = null; } protected String getURLString(String format) { StringBuilder builder = new StringBuilder(); builder.append(urlString); builder.append("api/2/apps/"); builder.append((this.appIdentifier != null ? this.appIdentifier : activity.getPackageName())); builder.append("?format=" + format); String deviceIdentifier = Settings.Secure.getString(activity.getContentResolver(), Settings.Secure.ANDROID_ID); if (deviceIdentifier != null) { builder.append("&udid=" + encodeParam( Settings.Secure.getString(activity.getContentResolver(), Settings.Secure.ANDROID_ID))); } builder.append("&os=Android"); builder.append("&os_version=" + encodeParam(Constants.ANDROID_VERSION)); builder.append("&device=" + encodeParam(Constants.PHONE_MODEL)); builder.append("&oem=" + encodeParam(Constants.PHONE_MANUFACTURER)); builder.append("&app_version=" + encodeParam(Constants.APP_VERSION)); builder.append("&sdk=" + encodeParam(Constants.SDK_NAME)); builder.append("&sdk_version=" + encodeParam(Constants.SDK_VERSION)); builder.append("&usage_time=" + usageTime); return builder.toString(); } private String encodeParam(String param) { try { return URLEncoder.encode(param, "UTF-8"); } catch (UnsupportedEncodingException e) { // UTF-8 should be available, so just in case return ""; } } private void showDialog(final JSONArray updateInfo) { if (getCachingEnabled()) { VersionCache.setVersionInfo(activity, updateInfo.toString()); } if ((activity == null) || (activity.isFinishing())) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setTitle(Strings.get(listener, Strings.UPDATE_DIALOG_TITLE_ID)); if (!mandatory) { builder.setMessage(Strings.get(listener, Strings.UPDATE_DIALOG_MESSAGE_ID)); builder.setNegativeButton(Strings.get(listener, Strings.UPDATE_DIALOG_NEGATIVE_BUTTON_ID), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { cleanUp(); } }); builder.setPositiveButton(Strings.get(listener, Strings.UPDATE_DIALOG_POSITIVE_BUTTON_ID), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (getCachingEnabled()) { VersionCache.setVersionInfo(activity, "[]"); } if ((UpdateManager.fragmentsSupported()) && (UpdateManager.runsOnTablet(activity))) { showUpdateFragment(updateInfo); } else { startUpdateIntent(updateInfo, false); } } }); builder.create().show(); } else { Toast.makeText(activity, Strings.get(listener, Strings.UPDATE_MANDATORY_TOAST_ID), Toast.LENGTH_LONG) .show(); startUpdateIntent(updateInfo, true); } } private void startUpdateIntent(final JSONArray updateInfo, Boolean finish) { Class<?> activityClass = UpdateActivity.class; if (listener != null) { activityClass = listener.getUpdateActivityClass(); } Intent intent = new Intent(); intent.setClass(activity, activityClass); intent.putExtra("json", updateInfo.toString()); intent.putExtra("url", getURLString("apk")); activity.startActivity(intent); if (finish) { activity.finish(); } cleanUp(); } private void showUpdateFragment(final JSONArray updateInfo) { FragmentTransaction fragmentTransaction = activity.getFragmentManager().beginTransaction(); fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); Fragment existingFragment = activity.getFragmentManager().findFragmentByTag("hockey_update_dialog"); if (existingFragment != null) { fragmentTransaction.remove(existingFragment); } fragmentTransaction.addToBackStack(null); // Create and show the dialog Class<? extends UpdateFragment> fragmentClass = UpdateFragment.class; if (listener != null) { fragmentClass = listener.getUpdateFragmentClass(); } try { Method method = fragmentClass.getMethod("newInstance", JSONArray.class, String.class); DialogFragment updateFragment = (DialogFragment) method.invoke(null, updateInfo, getURLString("apk")); updateFragment.show(fragmentTransaction, "hockey_update_dialog"); } catch (Exception e) { Log.d(Constants.TAG, "An exception happened while showing the update fragment:"); e.printStackTrace(); Log.d(Constants.TAG, "Showing update activity instead."); startUpdateIntent(updateInfo, false); } } private static String convertStreamToString(InputStream inputStream) { BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream), 1024); StringBuilder stringBuilder = new StringBuilder(); String line = null; try { while ((line = reader.readLine()) != null) { stringBuilder.append(line + "\n"); } } catch (IOException e) { e.printStackTrace(); } finally { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } return stringBuilder.toString(); } protected boolean getCachingEnabled() { return true; } }