com.github.sgelb.booket.SearchResultActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.github.sgelb.booket.SearchResultActivity.java

Source

/*******************************************************************************
 * Copyright (C) 2014  sgelb
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
package com.github.sgelb.booket;

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.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;

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

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Html;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.github.sgelb.booket.R;

public class SearchResultActivity extends Activity {

    public static ArrayList<Book> bookList;
    private ProgressBar downloadProgressBar;
    private ListView resultList;
    private BookResultAdapter adapter;
    private BooksDataSource datasource;
    private TextView noResults;
    private Bitmap defaultThumbnail;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search_results);
        getActionBar().setDisplayHomeAsUpEnabled(true);
        noResults = (TextView) findViewById(R.id.noResultsTextView);
        defaultThumbnail = BitmapFactory.decodeResource(getResources(), R.drawable.ic_default_cover);

        bookList = new ArrayList<>();
        resultList = (ListView) findViewById(R.id.searchResultsList);
        downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);
        datasource = new BooksDataSource(this);

        BookInfos bookInfos = new BookInfos();
        bookInfos.execute(createUrl());
        adapter = new BookResultAdapter(bookList, this);
        resultList.setAdapter(adapter);

        // Save book in database
        resultList.setOnItemLongClickListener(new OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {

                AlertDialog alert = new AlertDialog.Builder(SearchResultActivity.this).create();
                alert.setTitle(
                        Html.fromHtml(getString(R.string.dialog_save_book, bookList.get(position).getTitle())));
                alert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.ok), new OnClickListener() {
                    public void onClick(final DialogInterface dialog, final int which) {
                        saveBook(position);
                    }
                });
                alert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel), new OnClickListener() {
                    public void onClick(final DialogInterface dialog, final int which) {
                    }
                });
                alert.show();

                return true;
            }
        });

        // Expand list row
        resultList.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                adapter.toggleExpand(view, position);
            }
        });

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private String createUrl() {
        Intent intent = getIntent();
        String author = intent.getStringExtra(BookSearchActivity.AUTHOR);
        String title = intent.getStringExtra(BookSearchActivity.TITLE);
        String isbn = intent.getStringExtra(BookSearchActivity.ISBN);
        String keyword = intent.getStringExtra(BookSearchActivity.KEYWORD);
        String language = intent.getStringExtra(BookSearchActivity.LANGUAGE);

        String query = "";
        try {
            if (!isbn.isEmpty()) {
                query += "+isbn:" + URLEncoder.encode(isbn, "utf-8");
            } else {
                if (!author.isEmpty())
                    query += "+inauthor:" + URLEncoder.encode(author, "utf-8");
                if (!title.isEmpty())
                    query += "+intitle:" + URLEncoder.encode(title, "utf-8");
                if (!keyword.isEmpty())
                    query += URLEncoder.encode(keyword, "utf-8");
                if (!language.isEmpty())
                    query += "&langRestrict=" + URLEncoder.encode(language, "utf-8");
            }
        } catch (UnsupportedEncodingException e) {
        }
        query += "&fields=items(volumeInfo,id)&maxResults=40";
        Log.d("R2R", "URL: " + query);
        return "https://www.googleapis.com/books/v1/volumes?q=" + query;
    }

    private class BookInfos extends AsyncTask<String, Integer, String> {

        @Override
        protected void onPreExecute() {
            downloadProgressBar.setVisibility(View.VISIBLE);
        }

        @Override
        protected String doInBackground(String... urls) {
            Log.d("R2R", "BookInfo started");
            StringBuilder builder = new StringBuilder();
            URL url = null;
            HttpURLConnection con = null;

            try {
                url = new URL(urls[0]);
                con = (HttpURLConnection) url.openConnection();
                if (con.getResponseCode() == HttpURLConnection.HTTP_OK) {
                    InputStream content = new BufferedInputStream(con.getInputStream());
                    BufferedReader reader = new BufferedReader(new InputStreamReader(content));
                    String line;
                    while ((line = reader.readLine()) != null) {
                        builder.append(line);
                    }
                }
            } catch (MalformedURLException e) {
                Log.d("R2R", "MalformedURLException: " + e.getMessage());
            } catch (IOException e) {
                Log.d("R2R", "IOException: " + e.getMessage());
            } finally {
                con.disconnect();
            }

            return builder.toString();
        }

        @Override
        protected void onPostExecute(String result) {
            Log.d("R2R", "BookInfo finished");
            downloadProgressBar.setVisibility(View.GONE);
            processResult(result);
        }
    }

    private class DownloadThumbNail extends AsyncTask<String, Void, Bitmap> {
        private Book book;

        public DownloadThumbNail(Book book) {
            this.book = book;
        }

        @Override
        protected Bitmap doInBackground(String... urls) {
            Bitmap thumbnail = null;
            URL url = null;
            HttpURLConnection con = null;

            try {
                url = new URL(urls[0]);
                con = (HttpURLConnection) url.openConnection();
                con.setDoInput(true);
                con.connect();
                if (con.getResponseCode() == HttpURLConnection.HTTP_OK) {
                    InputStream input = con.getInputStream();
                    thumbnail = BitmapFactory.decodeStream(input);
                    return thumbnail;
                }
            } catch (MalformedURLException e) {
                Log.d("R2R", "MalformedURLException: " + e.getMessage());
            } catch (IOException e) {
                Log.d("R2R", "IOException: " + e.getMessage());
            } finally {
                con.disconnect();
            }
            return thumbnail;
        }

        @Override
        protected void onPostExecute(Bitmap thumbnail) {
            // amazon returns 1x1 pixel if no cover found.
            if (thumbnail.getWidth() < 2) {
                book.setThumbnailBitmap(defaultThumbnail);
            } else {
                book.setThumbnailBitmap(thumbnail);
                adapter.notifyDataSetChanged();
            }
        }
    }

    private void processResult(String result) {
        JSONArray items = null;
        try {
            JSONObject jsonObject = new JSONObject(result);
            items = jsonObject.getJSONArray("items");
        } catch (JSONException e) {
            noResults.setVisibility(View.VISIBLE);
            return;
        }

        try {

            // iterate over items aka books
            Log.d("R2R", "Items: " + items.length());
            for (int i = 0; i < items.length(); i++) {
                Log.d("R2R", "\nBook " + (i + 1));
                JSONObject item = (JSONObject) items.get(i);
                JSONObject info = item.getJSONObject("volumeInfo");
                Book book = new Book();

                // add authors
                String authors = "";
                if (info.has("authors")) {
                    JSONArray jAuthors = info.getJSONArray("authors");
                    for (int j = 0; j < jAuthors.length() - 1; j++) {
                        authors += jAuthors.getString(j) + ", ";
                    }
                    authors += jAuthors.getString(jAuthors.length() - 1);
                } else {
                    authors = "n/a";
                }
                book.setAuthors(authors);
                Log.d("R2R", "authors " + book.getAuthors());

                // add title
                if (info.has("title")) {
                    book.setTitle(info.getString("title"));
                    Log.d("R2R", "title " + book.getTitle());
                }

                // add pageCount
                if (info.has("pageCount")) {
                    book.setPageCount(info.getInt("pageCount"));
                    Log.d("R2R", "pageCount " + book.getPageCount());
                }

                // add publisher
                if (info.has("publisher")) {
                    book.setPublisher(info.getString("publisher"));
                    Log.d("R2R", "publisher " + book.getPublisher());
                }

                // add description
                if (info.has("description")) {
                    book.setDescription(info.getString("description"));
                    Log.d("R2R", "description " + book.getDescription());
                }

                // add isbn
                if (info.has("industryIdentifiers")) {
                    JSONArray ids = info.getJSONArray("industryIdentifiers");
                    for (int k = 0; k < ids.length(); k++) {
                        JSONObject id = ids.getJSONObject(k);
                        if (id.getString("type").equalsIgnoreCase("ISBN_13")) {
                            book.setIsbn(id.getString("identifier"));
                            break;
                        }
                        if (id.getString("type").equalsIgnoreCase("ISBN_10")) {
                            book.setIsbn(id.getString("identifier"));
                        }
                    }
                    Log.d("R2R", "isbn " + book.getIsbn());
                }

                // add published date
                if (info.has("publishedDate")) {
                    book.setYear(info.getString("publishedDate").substring(0, 4));
                    Log.d("R2R", "publishedDate " + book.getYear());
                }

                // add cover thumbnail
                book.setThumbnailBitmap(defaultThumbnail);

                if (info.has("imageLinks")) {
                    // get cover url from google
                    JSONObject imageLinks = info.getJSONObject("imageLinks");
                    if (imageLinks.has("thumbnail")) {
                        book.setThumbnailUrl(imageLinks.getString("thumbnail"));
                    }
                } else if (book.getIsbn() != null) {
                    // get cover url from amazon
                    String amazonCoverUrl = "http://ecx.images-amazon.com/images/P/" + isbn13to10(book.getIsbn())
                            + ".01._SCMZZZZZZZ_.jpg";
                    book.setThumbnailUrl(amazonCoverUrl);
                }

                // download cover thumbnail
                if (book.getThumbnailUrl() != null && !book.getThumbnailUrl().isEmpty()) {
                    new DownloadThumbNail(book).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
                            book.getThumbnailUrl());
                    Log.d("R2R", "thumbnail " + book.getThumbnailUrl());
                }

                // add google book id
                if (item.has("id")) {
                    book.setGoogleId(item.getString("id"));
                }

                bookList.add(book);

            }
        } catch (Exception e) {
            Log.d("R2R", "Exception: " + e.toString());
            // FIXME: catch exception
        }
    }

    private String isbn13to10(String isbn) {
        if (isbn.length() == 10) {
            return isbn;
        }
        // cut leading 3 characters and wrong checksum from isbn13 
        String isbn9 = isbn.substring(3, 12);
        int sum = 0;
        for (int i = 0; i < isbn9.length(); i++) {
            sum += Integer.parseInt("" + isbn9.charAt(i)) * (10 - i);
        }
        // return isbn10 with checksum
        String checksum = "X";
        if ((11 - sum % 11) < 10) {
            checksum = String.valueOf(11 - sum % 11);
        }
        return isbn9 + checksum;
    }

    private void saveBook(int position) {
        datasource.open();
        boolean addedNewBook = datasource.createBook(bookList.get(position));
        datasource.close();
        String msg = getString(R.string.saved, bookList.get(position).getTitle());
        if (!addedNewBook) {
            msg = getString(R.string.alreadySaved, bookList.get(position).getTitle());
        }
        Toast.makeText(getBaseContext(), Html.fromHtml(msg), Toast.LENGTH_SHORT).show();
    }

}