at.the.gogo.panoramio.panoviewer.ImageManager.java Source code

Java tutorial

Introduction

Here is the source code for at.the.gogo.panoramio.panoviewer.ImageManager.java

Source

/*
 * Copyright (C) 2008 Google Inc.
 *
 * 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 at.the.gogo.panoramio.panoviewer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.util.ArrayList;
import java.util.Locale;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.os.Handler;
import android.util.Log;
import at.the.gogo.panoramio.panoviewer.activities.PanoViewerActivity;

/**
 * This class is responsible for downloading and parsing the search results for
 * a particular area. All of the work is done on a separate thread, and progress
 * is reported back through the DataSetObserver set in
 * {@link #addObserver(DataSetObserver). State is held in memory by in memory
 * maintained by a single instance of the ImageManager class.
 */
public class ImageManager {
    private static final String TAG = "Panoramio";

    /**
     * Base URL for Panoramio's web API
     */
    //   private static final String THUMBNAIL_URL = "//www.panoramio.com/map/get_panoramas.php?order=popularity&set=public&from=0&to=20&miny=%.6f&minx=%.6f&maxy=%.6f&maxx=%.6f&size=thumbnail&mapfilter=true";
    private static final String THUMBNAIL_URL = "//www.panoramio.com/map/get_panoramas.php?order=popularity&set=public&from=0&to=25&miny=%.6f&minx=%.6f&maxy=%.6f&maxx=%.6f&size=medium&mapfilter=true";

    /**
     * Used to post results back to the UI thread
     */
    private final Handler mHandler = new Handler();

    /**
     * Holds the single instance of a ImageManager that is shared by the
     * process.
     */
    private static ImageManager sInstance;

    /**
     * Holds the images and related data that have been downloaded
     */
    private final ArrayList<PanoramioItem> mImages = new ArrayList<PanoramioItem>();

    /**
     * Observers interested in changes to the current search results
     */
    private final ArrayList<WeakReference<DataSetObserver>> mObservers = new ArrayList<WeakReference<DataSetObserver>>();

    /**
     * True if we are in the process of loading
     */
    private boolean mLoading;

    private final Context mContext;

    /**
     * Key for an Intent extra. The value is the zoom level selected by the
     * user.
     */
    public static final String ZOOM_EXTRA = "zoom";

    /**
     * Key for an Intent extra. The value is the latitude of the center of the
     * search area chosen by the user.
     */
    public static final String LATITUDE_E6_EXTRA = "latitudeE6";

    /**
     * Key for an Intent extra. The value is the latitude of the center of the
     * search area chosen by the user.
     */
    public static final String LONGITUDE_E6_EXTRA = "longitudeE6";

    // keys for bounding area
    public static final String LATITUDE_E6_MIN = "latMin";
    public static final String LATITUDE_E6_MAX = "latMax";
    public static final String LONGITUDE_E6_MIN = "lonMin";
    public static final String LONGITUDE_E6_MAX = "lonMax";

    /**
     * Key for an Intent extra. The value is an item to display
     */
    public static final String PANORAMIO_ITEM_EXTRA = "item";

    public static ImageManager getInstance(final Context c) {
        if (sInstance == null) {
            sInstance = new ImageManager(c.getApplicationContext());
        }
        return sInstance;
    }

    private ImageManager(final Context c) {
        mContext = c;
    }

    /**
     * @return True if we are still loading content
     */
    public boolean isLoading() {
        return mLoading;
    }

    /**
     * Clear all downloaded content
     */
    public void clear() {
        mImages.clear();
        notifyObservers();
    }

    /**
     * Add an item to and notify observers of the change.
     * 
     * @param item
     *            The item to add
     */
    private void add(final PanoramioItem item) {
        mImages.add(item);
        notifyObservers();
    }

    /**
     * @return The number of items displayed so far
     */
    public int size() {
        return mImages.size();
    }

    /**
     * Gets the item at the specified position
     */
    public PanoramioItem get(final int position) {
        return mImages.get(position);
    }

    /**
     * Adds an observer to be notified when the set of items held by this
     * ImageManager changes.
     */
    public void addObserver(final DataSetObserver observer) {
        final WeakReference<DataSetObserver> obs = new WeakReference<DataSetObserver>(observer);
        mObservers.add(obs);
    }

    /**
     * Load a new set of search results for the specified area.
     * 
     * @param minLong
     *            The minimum longitude for the search area
     * @param maxLong
     *            The maximum longitude for the search area
     * @param minLat
     *            The minimum latitude for the search area
     * @param maxLat
     *            The minimum latitude for the search area
     */
    public void load(final float minLong, final float maxLong, final float minLat, final float maxLat) {
        mLoading = true;
        new Thread(new ImageGatherer(minLong, maxLong, minLat, maxLat)).start();
    }

    /**
     * Called when something changes in our data set. Cleans up any weak
     * references that are no longer valid along the way.
     */
    private void notifyObservers() {
        final ArrayList<WeakReference<DataSetObserver>> observers = mObservers;
        final int count = observers.size();
        for (int i = count - 1; i >= 0; i--) {
            final WeakReference<DataSetObserver> weak = observers.get(i);
            final DataSetObserver obs = weak.get();
            if (obs != null) {
                obs.onChanged();
            } else {
                observers.remove(i);
            }
        }

    }

    /**
     * This thread does the actual work of downloading and parsing data.
     * 
     */
    private class ImageGatherer implements Runnable {

        private final float mMinLong;
        private final float mMaxLong;
        private final float mMinLat;
        private final float mMaxLat;

        public ImageGatherer(final float minLong, final float maxLong, final float minLat, final float maxLat) {
            mMinLong = minLong;
            mMaxLong = maxLong;
            mMinLat = minLat;
            mMaxLat = maxLat;
        }

        @Override
        public void run() {

            String url = THUMBNAIL_URL;
            url = String.format(Locale.US, url, mMinLat, mMinLong, mMaxLat, mMaxLong);
            Log.i(TAG, "Pano request URL: " + url);
            try {
                final URI uri = new URI("http", url, null);
                final HttpGet get = new HttpGet(uri);

                final HttpClient client = new DefaultHttpClient();
                final HttpResponse response = client.execute(get);
                final HttpEntity entity = response.getEntity();
                final String str = convertStreamToString(entity.getContent());
                final JSONObject json = new JSONObject(str);
                parse(json);
            } catch (final Exception e) {
                Log.e(TAG, e.toString());
            }
        }

        private void parse(final JSONObject json) {
            try {
                final JSONArray array = json.getJSONArray("photos");
                final int count = array.length();
                for (int i = 0; i < count; i++) {
                    final JSONObject obj = array.getJSONObject(i);

                    final long id = obj.getLong("photo_id");
                    String title = obj.getString("photo_title");
                    final String owner = obj.getString("owner_name");
                    final String thumb = obj.getString("photo_file_url");
                    final String ownerUrl = obj.getString("owner_url");
                    final String photoUrl = obj.getString("photo_url");

                    final double latitude = obj.getDouble("latitude");
                    final double longitude = obj.getDouble("longitude");
                    final Bitmap b = BitmapUtils.loadBitmap(thumb);
                    if (title == null) {
                        title = mContext.getString(R.string.untitled);
                    }

                    final PanoramioItem item = new PanoramioItem(id, thumb, b,
                            (int) (latitude * PanoViewerActivity.MILLION),
                            (int) (longitude * PanoViewerActivity.MILLION), title, owner, ownerUrl, photoUrl);
                    final boolean done = i == (count - 1);
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {

                            sInstance.mLoading = !done;
                            sInstance.add(item);
                        }
                    });
                }
            } catch (final JSONException e) {
                Log.e(TAG, e.toString());
            }
        }

        private String convertStreamToString(final InputStream is) {
            final BufferedReader reader = new BufferedReader(new InputStreamReader(is), 8 * 1024);
            final StringBuilder sb = new StringBuilder();

            String line = null;
            try {
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "\n");
                }
            } catch (final IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    is.close();
                } catch (final IOException e) {
                    e.printStackTrace();
                }
            }

            return sb.toString();
        }

    }

}