Java tutorial
/* * AnyPlace: A free and open Indoor Navigation Service with superb accuracy! * * Anyplace is a first-of-a-kind indoor information service offering GPS-less * localization, navigation and search inside buildings using ordinary smartphones. * * Author(s): Timotheos Constambeys * * Supervisor: Demetrios Zeinalipour-Yazti * * URL: http://anyplace.cs.ucy.ac.cy * Contact: anyplace@cs.ucy.ac.cy * * Copyright (c) 2015, Data Management Systems Lab (DMSL), University of Cyprus. * All rights reserved. * * 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. * */ package com.dmsl.anyplace.tasks; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.SocketTimeoutException; import org.apache.http.conn.ConnectTimeoutException; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.os.AsyncTask; import android.os.Handler; import com.dmsl.anyplace.AnyplaceAPI; import com.dmsl.anyplace.utils.AndroidUtils; import com.dmsl.anyplace.utils.NetworkUtils; public class FetchFloorPlanTask extends AsyncTask<Void, Void, String> { private final static Object sync = new Object(); public interface FetchFloorPlanTaskListener { void onPrepareLongExecute(); void onErrorOrCancel(String result); void onSuccess(String result, File floor_plan_file); } private FetchFloorPlanTaskListener mListener; private Context ctx; private String buid; private String floor_number; private File floor_plan_file; private boolean success = false; // Sync/Run PreExecute Listener on UI Thread final Object syncListener = new Object(); boolean run = false; public FetchFloorPlanTask(Context ctx, String buid, String floor_number) { this.ctx = ctx; this.buid = buid; this.floor_number = floor_number; } public void setCallbackInterface(FetchFloorPlanTaskListener fetchFloorPlanTaskListener) { this.mListener = fetchFloorPlanTaskListener; } public void copy(File src, File dst) throws IOException { InputStream in = null; OutputStream out = null; try { in = new FileInputStream(src); out = new FileOutputStream(dst); // Transfer bytes from in to out byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } } finally { if (in != null) in.close(); if (out != null) out.close(); } } @Override protected String doInBackground(Void... params) { OutputStream output = null; InputStream is = null; File tempFile = null; try { // check sdcard state if (!AndroidUtils.checkExternalStorageState()) { // we cannot download the floor plan on the sdcard return "Error: It seems that we cannot write on your sdcard!"; } File sdcard_root = ctx.getExternalFilesDir(null); if (sdcard_root == null) { return "Error: It seems we cannot save the floorplan on sdcard!"; } File root = new File(sdcard_root, "floor_plans" + File.separatorChar + buid + File.separatorChar + floor_number); root.mkdirs(); File dest_path = new File(root, "tiles_archive.zip"); File okfile = new File(root, "ok.txt"); // check if the file already exists and if yes return // immediately if (dest_path.exists() && dest_path.canRead() && dest_path.isFile() && okfile.exists()) { floor_plan_file = dest_path; success = true; return "Successfully read floor plan from cache!"; } runPreExecuteOnUI(); okfile.delete(); // prepare the json object request JSONObject j = new JSONObject(); j.put("username", "username"); j.put("password", "pass"); is = NetworkUtils.downloadHttpClientJsonPostStream( AnyplaceAPI.getServeFloorTilesZipUrl(buid, floor_number), j.toString()); tempFile = new File(ctx.getCacheDir(), "FloorPlan" + Integer.toString((int) (Math.random() * 100))); if (tempFile.exists()) throw new Exception("Temp File already in use"); output = new FileOutputStream(tempFile); byte[] buffer = new byte[4096]; int bytesRead = 0; while ((bytesRead = is.read(buffer, 0, buffer.length)) >= 0) { output.write(buffer, 0, bytesRead); } output.close(); // Critical Block - Added for safety synchronized (sync) { copy(tempFile, dest_path); // unzip the tiles_archive AndroidUtils.unzip(dest_path.getAbsolutePath()); FileWriter out = new FileWriter(okfile); out.write("ok;version:0;"); out.close(); } floor_plan_file = dest_path; waitPreExecute(); success = true; return "Successfully fetched floor plan"; } catch (ConnectTimeoutException e) { return "Cannot connect to Anyplace service!"; } catch (SocketTimeoutException e) { return "Communication with the server is taking too long!"; } catch (JSONException e) { return "JSONException: " + e.getMessage(); } catch (Exception e) { return "Error fetching floor plan. [ " + e.getMessage() + " ]"; } finally { if (is != null) try { is.close(); } catch (IOException e) { } if (output != null) try { output.close(); } catch (IOException e) { } if (tempFile != null) { tempFile.delete(); } } } @Override protected void onPostExecute(String result) { if (success) { mListener.onSuccess(result, floor_plan_file); } else { // there was an error during the process mListener.onErrorOrCancel(result); } } private void runPreExecuteOnUI() { // Get a handler that can be used to post to the main thread Handler mainHandler = new Handler(ctx.getMainLooper()); Runnable myRunnable = new Runnable() { @Override public void run() { try { mListener.onPrepareLongExecute(); } finally { synchronized (syncListener) { run = true; syncListener.notifyAll(); } } } }; mainHandler.post(myRunnable); } private void waitPreExecute() throws InterruptedException { synchronized (syncListener) { while (run == false) { syncListener.wait(); } } } @Override protected void onCancelled(String result) { mListener.onErrorOrCancel("Floor plan loading cancelled..."); } @Override protected void onCancelled() { // just for < API 11 mListener.onErrorOrCancel("Floor plan loading cancelled..."); } }// end of floor plan downloader