andlabs.lounge.lobby.util.parser.PlayParser.java Source code

Java tutorial

Introduction

Here is the source code for andlabs.lounge.lobby.util.parser.PlayParser.java

Source

/*
 * Copyright (C) 2012, 2013 ANDLABS GmbH. All rights reserved.
 *
 * www.lounge.andlabs.com
 * lounge@andlabs.com
 * 
 * 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 andlabs.lounge.lobby.util.parser;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set;

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.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.Log;

public class PlayParser {

    private static final String TAG = "PlayParser";

    private static final int CONNECT_TIMEOUT = 15000 /* milliseconds */;

    private static final String PLAY_BASE_URL = "https://play.google.com/store/apps/details?id=";

    private static final String PLAY_PATTERN_START = "<div class=\"doc-banner-image-container\"><img src=";

    private static final String PLAY_PATTERN_END = "\" alt=\"";

    private static final int MAX_WIDTH = 1024;

    private static final int DEFAULT_HEIGHT_DP = 80;

    private Queue<QueryData> mQueries = new PriorityQueue<PlayParser.QueryData>();

    private Set<String> mPackagesInQueue = new HashSet<String>();

    private List<PlayListener> mListener = new ArrayList<PlayParser.PlayListener>();

    private Map<String, Drawable> mResults = new HashMap<String, Drawable>();

    private boolean mIsQuerying = false;

    private Context mContext;

    private static PlayParser sInstance;

    private PlayParser(Context context) {
        mContext = context;
    }

    public static PlayParser getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new PlayParser(context);
        }
        return sInstance;
    }

    public void addListener(PlayListener listener) {
        mListener.add(listener);
    }

    public void removeListener(PlayListener listener) {
        mListener.remove(listener);
    }

    public Drawable getResult(String packageName) {
        return mResults.get(packageName);
    }

    private void notifyListener() {
        for (PlayListener listener : mListener) {
            listener.onPlayResult(mResults);
        }

        if (mQueries.size() > 0) {
            queryNext();
        } else {
            mIsQuerying = false;
        }
    }

    public void queryPlay(final String packageName) {
        queryPlay(packageName, Math.min(MAX_WIDTH, mContext.getResources().getDisplayMetrics().widthPixels),
                (int) (DEFAULT_HEIGHT_DP * mContext.getResources().getDisplayMetrics().density));
    }

    public void queryPlay(final String packageName, final int imageWidth, final int imageHeight) {

        if (packageName != null && !mResults.containsKey(packageName) && !mPackagesInQueue.contains(packageName)) {

            Drawable cached = readFileFromInternalStorage(packageName, imageHeight);

            if (cached != null) {
                // Log.d(TAG, "Added cached result for " + packageName);
                mResults.put(packageName, cached);
                notifyListener();
            } else {

                mPackagesInQueue.add(packageName);
                mQueries.add(new QueryData(packageName, imageWidth, imageHeight));

                // Log.d(TAG, "Added play query for " + packageName);
                if (!mIsQuerying) {
                    queryNext();
                }
            }
        }
    }

    private void queryNext() {
        if (mQueries.size() > 0) {
            mIsQuerying = true;

            final QueryData data = mQueries.poll();
            final String packageName = data.getPackageName();
            final int imageWidth = data.getWidth();
            final int imageHeight = data.getHeight();

            // Log.d(TAG,
            // "**************************************************************");

            // Log.d(TAG, "Started play query for " + packageName);

            UrlDownloadTask urlTask = new UrlDownloadTask(packageName, imageWidth, imageHeight);
            urlTask.execute(PLAY_BASE_URL + packageName);
        } else {
            mIsQuerying = false;
        }
    }

    private String parseImageUrl(String html) {
        if (html != null && html.contains(PLAY_PATTERN_START)) {
            int start = html.indexOf(PLAY_PATTERN_START);
            start += PLAY_PATTERN_START.length() + 1;
            final String secondHalf = html.subSequence(start, start + 300).toString();

            int end = secondHalf.indexOf(PLAY_PATTERN_END);

            final String imageString = secondHalf.substring(0, end);

            String returnString = "";
            String[] strings = imageString.split("w");
            for (int i = 0; i < strings.length - 1; i++) {
                returnString += strings[i] + "w";
            }
            return returnString;
        }

        return null;
    }

    private String downloadUrl(String url) throws IOException {

        InputStream is = null;
        try {
            is = downloadStream(url);

            // Convert the InputStream into a string
            if (is != null) {
                String contentAsString = convertStreamToString(is);
                return contentAsString;
            } else {
                return null;
            }

            // Makes sure that the InputStream is closed after the app is
            // finished using it.
        } finally {
            if (is != null) {
                is.close();
            }
        }
    }

    private void writeFileToInternalStorage(InputStream is, String packageName) {
        FileOutputStream out = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
            byteArrayOutputStream = new ByteArrayOutputStream();

            int input = is.read();
            while (input != -1) {
                byteArrayOutputStream.write(input);
                input = is.read();
            }
            byte[] returnByteArray = byteArrayOutputStream.toByteArray();

            out = mContext.openFileOutput(packageName, Context.MODE_PRIVATE);
            out.write(returnByteArray);

            Log.d(TAG, "Saved promo graphic for " + packageName);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (byteArrayOutputStream != null) {
                try {
                    byteArrayOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private Drawable readFileFromInternalStorage(String packageName, int height) {
        InputStream is = null;
        try {
            is = mContext.openFileInput(packageName);
            final Bitmap bitmap = new BitmapDrawable(is).getBitmap();
            int y = (bitmap.getHeight() - height) / 2;

            return new BitmapDrawable(Bitmap.createBitmap(bitmap, 0, y, bitmap.getWidth(), height));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return null;
    }

    private String convertStreamToString(final InputStream inputStream) {
        final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        StringBuilder stringBuilder = new StringBuilder();
        String line = null;
        try {
            while ((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return stringBuilder.toString();
    }

    private InputStream downloadStream(String url) {
        InputStream inputStream = null;
        HttpClient client = new DefaultHttpClient();
        HttpGet getRequest = new HttpGet(url);
        HttpResponse response = null;

        if (url == null) {
            return null;
        }

        HttpParams clientParams = client.getParams();
        HttpConnectionParams.setConnectionTimeout(clientParams, CONNECT_TIMEOUT);
        HttpConnectionParams.setSoTimeout(clientParams, CONNECT_TIMEOUT);

        try {
            response = client.execute(getRequest);

            HttpEntity entity = response.getEntity();
            int responseCode = response.getStatusLine().getStatusCode();

            if (responseCode == 200 && entity != null) {

                inputStream = response.getEntity().getContent();
                return inputStream;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;

    }

    public interface PlayListener {

        public void onPlayResult(Map<String, Drawable> pResults);
    }

    private class QueryData implements Comparable<QueryData> {

        String mPackageName;
        int mWidth;
        int mHeight;

        public QueryData(String pPackageName, int pImageWidth, int pImageHeight) {
            super();
            mPackageName = pPackageName;
            mWidth = pImageWidth;
            mHeight = pImageHeight;
        }

        public int getHeight() {
            return mHeight;
        }

        public void setHeight(int pHeight) {
            mHeight = pHeight;
        }

        public String getPackageName() {
            return mPackageName;
        }

        public void setPackageName(String pPackageName) {
            mPackageName = pPackageName;
        }

        public int getWidth() {
            return mWidth;
        }

        public void setWidth(int pWidth) {
            mWidth = pWidth;
        }

        @Override
        public int compareTo(QueryData pAnother) {
            return 0;
        }
    }

    private class UrlDownloadTask extends AsyncTask<String, Void, Drawable> {

        private int mImageWidth;
        private int mImageHeight;
        private String mPackageName;

        public UrlDownloadTask(String packageName, int imageWidth, int imageHeight) {
            mPackageName = packageName;
            mImageWidth = imageWidth;
            mImageHeight = imageHeight;
        }

        @Override
        protected Drawable doInBackground(String... pParams) {
            String html = null;
            try {
                Log.d(TAG, "Downloading HTML for " + pParams[0]);
                html = downloadUrl(pParams[0]);
                Log.d(TAG, "Received HTML for " + pParams[0] + "\n" + html);
            } catch (IOException e) {
                e.printStackTrace();
            }

            String url = parseImageUrl(html);
            if (url != null) {
                url += mImageWidth;
            }

            Log.d(TAG, "Image URL for " + pParams[0] + " is " + url);

            if (url != null) {
                Log.d(TAG, "**************************************************************");
                Log.d(TAG, "Downloading banner for " + pParams[0]);

                InputStream is = null;
                try {
                    is = downloadStream(url);
                    if (is != null) {
                        writeFileToInternalStorage(is, mPackageName);
                        Log.d(TAG, "Saved stream for " + pParams[0]);

                        return readFileFromInternalStorage(mPackageName, mImageHeight);
                    } else {
                        queryNext();
                    }
                    return null;
                } finally {
                    if (is != null) {
                        try {
                            is.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            } else {
                queryNext();
            }
            return null;
        }

        protected void onPostExecute(Drawable result) {
            if (result != null) {
                notifyListener();
            }
        };
    }
}