com.appsimobile.appsii.module.weather.ImageDownloadHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.appsimobile.appsii.module.weather.ImageDownloadHelper.java

Source

/*
 * Copyright 2015. Appsi Mobile
 *
 * 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.appsimobile.appsii.module.weather;

import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import android.util.LruCache;
import android.widget.ImageView;

import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.RetryPolicy;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.RequestFuture;
import com.android.volley.toolbox.Volley;
import com.appsimobile.appsii.R;
import com.appsimobile.appsii.ResponseParserException;
import com.appsimobile.appsii.SimpleJson;

import org.json.JSONArray;
import org.json.JSONObject;

import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Created by nick on 12/04/15.
 */
public class ImageDownloadHelper {

    public static final int MAX_CACHE_SIZE = 10 * 1024 * 1024;

    public static final String FLICKR_API_KEY = "11ed8a19c24662dc6b18979902dc6494";

    static final String extras = "tags, url_o, url_h";

    private static ImageDownloadHelper sImageDownloadHelper;

    final RequestQueue sRequestQueue;

    final ImageLoader sImageLoader;

    private ImageDownloadHelper(Context context) {
        sRequestQueue = Volley.newRequestQueue(context, null, MAX_CACHE_SIZE);
        sImageLoader = new ImageLoader(sRequestQueue, createImageCache()) {
            final RetryPolicy mRetryPolicy = new DefaultRetryPolicy(30000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                    DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);

            @Override
            protected Request<Bitmap> makeImageRequest(String requestUrl, int maxWidth, int maxHeight,
                    ImageView.ScaleType scaleType, String cacheKey) {
                Request<Bitmap> result = super.makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType,
                        cacheKey);

                result.setRetryPolicy(mRetryPolicy);
                return result;
            }
        };

    }

    /**
     * Creates a new ImageCache object, used to simplify the constructor
     */
    private static ImageLoader.ImageCache createImageCache() {
        // Get max available VM memory, exceeding this amount will throw an
        // OutOfMemory exception. Stored in kilobytes as LruCache takes an
        // int in its constructor.
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

        // Use 1/8th of the available memory for this memory cache.
        final int cacheSize = maxMemory / 8;

        return new FlickrImageCache(cacheSize);
    }

    public synchronized static ImageDownloadHelper getInstance(Context context) {
        if (sImageDownloadHelper == null) {
            sImageDownloadHelper = new ImageDownloadHelper(context.getApplicationContext());
        }
        return sImageDownloadHelper;
    }

    public static int getRotationFromJson(JSONObject result) {

        SimpleJson simpleJson = new SimpleJson(result);
        try {
            return simpleJson.getInt("rotation", 0);
        } catch (ResponseParserException e) {
            Log.e("ImageDownloadHelper", "No rotation attr", e);
            return 0;
        }
    }

    public static int getFallbackDrawableForConditionCode(boolean isDay, int conditionCode) {
        // http://developer.yahoo.com/weather/
        switch (conditionCode) {
        case 19: // dust or sand
        case 21: // haze
        case 20: // foggy
        case 22: // smoky
        case 24: // windy
        case 25: // cold
        case 26: // cloudy
        case 27: // mostly cloudy (night)
        case 28: // mostly cloudy (day)
        case 29: // partly cloudy (night)
        case 30: // partly cloudy (day)
        case 44: // partly cloudy
            return isDay ? R.drawable.weather_cloudy_day : R.drawable.weather_cloudy_night;
        case 31: // clear (night)
        case 33: // fair (night)
            return R.drawable.weather_clear_night;
        default:
        case 34: // fair (day)
        case 32: // sunny
        case 36: // hot
            return isDay ? R.drawable.weather_clear_day : R.drawable.weather_clear_night;
        case 0: // tornado
        case 2: // hurricane
        case 1: // tropical storm
        case 4: // thunderstorms
        case 23: // blustery
            // TODO: add wind
        case 3: // severe thunderstorms
            // TODO: add thunder
        case 5: // mixed rain and snow
        case 6: // mixed rain and sleet
        case 7: // mixed snow and sleet
        case 8: // freezing drizzle
        case 10: // freezing rain
        case 13: // snow flurries
        case 14: // light snow showers
        case 42: // scattered snow showers
        case 15: // blowing snow
        case 16: // snow
        case 41: // heavy snow
        case 43: // heavy snow
        case 46: // snow showers
            return isDay ? R.drawable.weather_snowy_day : R.drawable.weather_snowy_night;

        case 18: // sleet
        case 9: // drizzle
        case 11: // showers
        case 12: // showers
        case 17: // hail
        case 35: // mixed rain and hail
        case 37: // isolated thunderstorms
        case 38: // scattered thunderstorms
        case 39: // scattered thunderstorms
        case 40: // scattered showers
        case 45: // thundershowers
        case 47: // isolated thundershowers
            return isDay ? R.drawable.weather_cloudy_day : R.drawable.weather_cloudy_night;
        }
    }

    public static void getEligiblePhotosFromResponse(@Nullable JSONObject jsonObject, List<PhotoInfo> result,
            int minDimension) {
        result.clear();

        if (jsonObject == null)
            return;

        JSONObject photos = jsonObject.optJSONObject("photos");
        if (photos == null)
            return;

        JSONArray photoArr = photos.optJSONArray("photo");
        if (photoArr == null)
            return;

        int N = photoArr.length();
        for (int i = 0; i < N; i++) {
            JSONObject object = photoArr.optJSONObject(i);
            if (object == null)
                continue;
            String id = object.optString("id");
            if (TextUtils.isEmpty(id))
                continue;
            String urlH = urlFromImageObject(object, "url_h", "width_h", "height_h", minDimension - 100);
            String urlO = urlFromImageObject(object, "url_o", "width_o", "height_o", minDimension - 100);

            if (urlH != null) {
                result.add(new PhotoInfo(id, urlH));
            } else if (urlO != null) {
                result.add(new PhotoInfo(id, urlO));
            }
        }

    }

    static String urlFromImageObject(JSONObject object, String u, String w, String h, int minDimension) {
        String url = object.optString(u);
        if (TextUtils.isEmpty(url))
            return null;
        int heightO = object.optInt(h);
        int widthO = object.optInt(w);
        if (heightO < minDimension || widthO < minDimension)
            return null;
        return url;
    }

    private static String getTagForConditionCode(int conditionCode) {
        // http://developer.yahoo.com/weather/
        switch (conditionCode) {
        case 19: // dust or sand
            return "dust";
        case 21: // haze
            return "haze";
        case 20: // foggy
            return "fog";
        case 22: // smoky
            return "smoky";
        case 24: // windy
            return "windy";
        case 25: // cold
            return "cold";
        case 26: // cloudy
        case 27: // mostly cloudy (night)
        case 28: // mostly cloudy (day)
        case 29: // partly cloudy (night)
        case 30: // partly cloudy (day)
        case 44: // partly cloudy
            return "cloudy";
        case 31: // clear (night)
        case 33: // fair (night)
        case 34: // fair (day)
            return "clear";
        case 32: // sunny
            return "sunny";
        case 36: // hot
            return "hot";
        case 0: // tornado
            return "tornado";
        case 2: // hurricane
            return "hurricane";
        case 1: // tropical storm
        case 3: // severe thunderstorms
        case 4: // thunderstorms
        case 23: // blustery
            return "thunder";
        case 5: // mixed rain and snow
        case 6: // mixed rain and sleet
        case 7: // mixed snow and sleet
        case 8: // freezing drizzle
        case 10: // freezing rain
        case 18: // sleet
            return "snow";
        case 9: // drizzle
            return "drizzle";
        case 11: // showers
        case 12: // showers
            return "showers";
        case 17: // hail
        case 35: // mixed rain and hail
            return "hail";
        case 37: // isolated thunderstorms
        case 38: // scattered thunderstorms
        case 39: // scattered thunderstorms
            return "thunder";
        case 40: // scattered showers
            return "rainy";
        case 45: // thundershowers
        case 47: // isolated thundershowers
            return "thunder";
        case 13: // snow flurries
        case 14: // light snow showers
        case 42: // scattered snow showers
        case 15: // blowing snow
        case 16: // snow
        case 41: // heavy snow
        case 43: // heavy snow
        case 46: // snow showers
            return "snow";
        }

        return "clear";
    }

    public ImageLoader getImageLoader() {
        return sImageLoader;
    }

    @Nullable
    public JSONObject searchCityWeatherPhotos(String woeid, int conditionCode, boolean day) throws VolleyError {

        String tags = getTagForConditionCode(conditionCode) + "," + (day ? "day" : "night");

        Uri uri = Uri.parse("https://api.flickr.com/services/rest/").buildUpon()
                .appendQueryParameter("method", "flickr.photos.search")
                .appendQueryParameter("api_key", FLICKR_API_KEY).appendQueryParameter("sort", "relevance")
                .appendQueryParameter("tags", tags).appendQueryParameter("tag_mode", "all")
                .appendQueryParameter("privacy_filter", "1").appendQueryParameter("content_type", "1")
                .appendQueryParameter("group_id", "1463451@N25").
                //                appendQueryParameter("group_id", "1553326@N24").
                appendQueryParameter("woe_id", woeid).appendQueryParameter("media", "photos")
                .appendQueryParameter("extras", extras).appendQueryParameter("format", "json")
                .appendQueryParameter("nojsoncallback", "1").build();

        String url = uri.toString();

        RequestFuture<JSONObject> requestFuture = RequestFuture.newFuture();

        JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, requestFuture, requestFuture);
        sRequestQueue.add(request);

        return getResult(requestFuture);
    }

    private <T> T getResult(RequestFuture<T> requestFuture) throws VolleyError {
        try {
            return requestFuture.get(10, TimeUnit.SECONDS);
        } catch (InterruptedException | TimeoutException e) {
            return null;
        } catch (ExecutionException e) {
            Throwable cause = e.getCause();
            if (cause instanceof VolleyError)
                throw (VolleyError) cause;
            return null;
        }

    }
    //
    //    public static void getImageUrlsFromResult(JSONObject jsonObject, List<String> result,
    //            int minDimension) {
    //        result.clear();
    //
    //        JSONObject photos = jsonObject.optJSONObject("photos");
    //        if (photos == null) return;
    //
    //        JSONArray photoArr = photos.optJSONArray("photo");
    //        if (photoArr == null) return;
    //
    //        int N = photoArr.length();
    //        for (int i = 0; i < N; i++) {
    //            JSONObject object = photoArr.optJSONObject(i);
    //            if (object == null) continue;
    //
    //            String urlH = urlFromImageObject(
    //                    object, "url_h", "width_h", "height_h", minDimension - 100);
    //
    //            if (urlH != null) {
    //                result.add(urlH);
    //            } else {
    //                String urlO = urlFromImageObject(
    //                        object, "url_o", "width_o", "height_o", minDimension - 100);
    //                if (urlO != null) {
    //                    result.add(urlO);
    //                }
    //            }
    //        }
    //    }

    public JSONObject searchCityImage(String woeid) throws VolleyError {

        Uri uri = Uri.parse("https://api.flickr.com/services/rest/").buildUpon()
                .appendQueryParameter("method", "flickr.photos.search")
                .appendQueryParameter("api_key", FLICKR_API_KEY).appendQueryParameter("sort", "relevance")
                .appendQueryParameter("tag_mode", "all").appendQueryParameter("privacy_filter", "1")
                .appendQueryParameter("content_type", "1").appendQueryParameter("group_id", "1463451@N25")
                .appendQueryParameter("woe_id", woeid).appendQueryParameter("media", "photos")
                .appendQueryParameter("extras", extras).appendQueryParameter("format", "json")
                .appendQueryParameter("nojsoncallback", "1").build();

        String url = uri.toString();

        RequestFuture<JSONObject> requestFuture = RequestFuture.newFuture();

        JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, requestFuture, requestFuture);
        sRequestQueue.add(request);
        return getResult(requestFuture);
    }

    public JSONObject loadPhotoInfo(Context context, String photoId) throws VolleyError {

        Uri uri = Uri.parse("https://api.flickr.com/services/rest/").buildUpon()
                .appendQueryParameter("method", "flickr.photos.getInfo")
                .appendQueryParameter("api_key", FLICKR_API_KEY).appendQueryParameter("photo_id", photoId)
                .appendQueryParameter("format", "json").appendQueryParameter("nojsoncallback", "1").build();

        String url = uri.toString();

        RequestFuture<JSONObject> requestFuture = RequestFuture.newFuture();

        JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, requestFuture, requestFuture);
        sRequestQueue.add(request);
        return getResult(requestFuture);
    }

    public static class PhotoInfo {

        public final String id;

        public final String url;

        public PhotoInfo(String id, String url) {
            this.id = id;
            this.url = url;
        }
    }

    /**
     * Implements the ImageCache. This is needed for the ImageLoader.
     * This class uses a simply implementation of LruCache to provide
     * memory sensitive caching.
     */
    private static class FlickrImageCache implements ImageLoader.ImageCache {

        private final LruCache<String, Bitmap> mCache;

        private final int mCacheSize;

        FlickrImageCache(int cacheSize) {
            mCacheSize = cacheSize;
            mCache = new ImageLruCache(mCacheSize);
        }

        @Override
        public Bitmap getBitmap(String url) {
            return mCache.get(url);
        }

        @Override
        public void putBitmap(String url, Bitmap bitmap) {
            mCache.put(url, bitmap);
        }
    }

    /**
     * The memory cache for the images. This is used by the ImageLoader
     */
    private static class ImageLruCache extends LruCache<String, Bitmap> {

        ImageLruCache(int cacheSize) {
            super(cacheSize);
        }

        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            // The cache size will be measured in kilobytes rather than
            // number of items.
            return bitmap.getByteCount() / 1024;
        }
    }

}