com.hhunj.hhudata.SearchBookContentsActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.hhunj.hhudata.SearchBookContentsActivity.java

Source

/*
 * Copyright (C) 2008 ZXing authors
 *
 * 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.hhunj.hhudata;

import android.content.ContentUris;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.content.res.Configuration;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpUriRequest;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.hhunj.hhudata.alarm.AndroidHttpClient;
import com.hhunj.hhudata.alarm.Intents;
import com.hhunj.hhudata.alarm.Intents.SearchBookContents;
import com.hhunj.hhudata.db.NotePad;
import com.hhunj.hhudata.db.SearchBookContentsResult;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.Date;

import android.telephony.SmsManager;
import android.app.PendingIntent;
import android.content.IntentFilter;

import android.widget.Toast;

import android.content.BroadcastReceiver;
import android.content.Context;

/**
 * Uses Google Book Search to find a word or phrase in the requested book.
 *
 * @author dswitkin@google.com (Daniel Switkin)
 */
public final class SearchBookContentsActivity extends Activity {

    private static final String TAG = SearchBookContentsActivity.class.getSimpleName();

    private static final String USER_AGENT = "ZXing (Android)";
    private static final Pattern TAG_PATTERN = Pattern.compile("\\<.*?\\>");
    private static final Pattern LT_ENTITY_PATTERN = Pattern.compile("&lt;");
    private static final Pattern GT_ENTITY_PATTERN = Pattern.compile("&gt;");
    private static final Pattern QUOTE_ENTITY_PATTERN = Pattern.compile("&#39;");
    private static final Pattern QUOT_ENTITY_PATTERN = Pattern.compile("&quot;");

    private NetworkThread networkThread;
    private String isbn;
    private EditText queryTextView;
    private Button queryButton;
    private ListView resultListView;
    private TextView headerView;

    private final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            switch (message.what) {
            case R.id.search_book_contents_succeeded:
                handleSearchResults((JSONObject) message.obj);
                resetForNewQuery();
                break;
            case R.id.search_book_contents_failed:
                resetForNewQuery();
                headerView.setText(R.string.msg_sbc_failed);
                break;
            }
        }
    };

    private final Button.OnClickListener buttonListener = new Button.OnClickListener() {
        public void onClick(View view) {
            launchSearch();
        }
    };

    private final View.OnKeyListener keyListener = new View.OnKeyListener() {
        public boolean onKey(View view, int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_ENTER) {
                launchSearch();
                return true;
            }
            return false;
        }
    };

    String getISBN() {
        return isbn;
    }

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        // Make sure that expired cookies are removed on launch.
        CookieSyncManager.createInstance(this);
        CookieManager.getInstance().removeExpiredCookie();

        Intent intent = getIntent();
        if (intent == null || (!intent.getAction().equals(Intents.SearchBookContents.ACTION))) {
            finish();
            return;
        }

        //pageid,pagenumber
        //ISBN  ---stationid,
        isbn = intent.getStringExtra(Intents.SearchBookContents.ISBN);//stationid
        if (isbn.startsWith("http://google.com/books?id=")) {
            setTitle(getString(R.string.sbc_name));
        } else {
            setTitle(getString(R.string.sbc_name) + ": ISBN " + isbn);
        }

        setContentView(R.layout.search_book_contents);
        queryTextView = (EditText) findViewById(R.id.query_text_view);

        String initialQuery = intent.getStringExtra(Intents.SearchBookContents.QUERY);
        if (initialQuery != null && initialQuery.length() > 0) {
            // Populate the search box but don't trigger the search
            queryTextView.setText(initialQuery);
        }
        queryTextView.setOnKeyListener(keyListener);

        queryButton = (Button) findViewById(R.id.query_button);
        queryButton.setOnClickListener(buttonListener);

        resultListView = (ListView) findViewById(R.id.result_list_view);
        LayoutInflater factory = LayoutInflater.from(this);
        headerView = (TextView) factory.inflate(R.layout.search_book_contents_header, resultListView, false);
        resultListView.addHeaderView(headerView);
    }

    @Override
    protected void onResume() {
        super.onResume();
        queryTextView.selectAll();
    }

    @Override
    public void onConfigurationChanged(Configuration config) {
        // Do nothing, this is to prevent the activity from being restarted when the keyboard opens.
        super.onConfigurationChanged(config);
    }

    private void resetForNewQuery() {
        networkThread = null;
        queryTextView.setEnabled(true);
        queryTextView.selectAll();
        queryButton.setEnabled(true);
    }

    private void launchSearch() {
        if (networkThread == null) {
            String query = queryTextView.getText().toString();
            if (query != null && query.length() > 0) {
                networkThread = new NetworkThread(isbn, query, handler);
                networkThread.start();
                headerView.setText(R.string.msg_sbc_searching_book);
                resultListView.setAdapter(null);
                queryTextView.setEnabled(false);
                queryButton.setEnabled(false);
            }
        }
    }

    ////////////////////////////////////////  
    public void updatedb(List<SearchBookContentsResult> items) {
        int max_alarm_time_span = 60;
        ContentResolver resolver = getApplicationContext().getContentResolver();

        ContentValues values = new ContentValues();

        for (int i = 0; i < items.size(); i++) {

            SearchBookContentsResult res = items.get(i);
            long stationid = Long.parseLong(res.getPageNumber());

            values.put(NotePad.Notes.TITLE, res.getName());
            values.put(NotePad.Notes.NOTE, "");

            values.put(NotePad.Notes.LONGITUTE, 108.0);
            values.put(NotePad.Notes.LATITUDE, 32.0);
            values.put(NotePad.Notes.SPEED, 55);
            values.put(NotePad.Notes.ALTITUDE, 55);

            values.put(NotePad.Notes.CREATEDDATE, res.getRectime().getTime());

            values.put(NotePad.Notes._ID, stationid);//id

            Uri urlNote = NotePad.Notes.CONTENT_URI;

            Uri myUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, stationid);

            Cursor cur = resolver.query(myUri, NotePad.Notes.PROJECTION, null, null, null);

            if (cur != null && cur.moveToFirst()) {
                try {
                    long id = cur.getLong(NotePad.Notes._ID_COLUMN);
                    Date oldtime = new Date(cur.getLong(cur.getColumnIndex(NotePad.Notes.CREATEDDATE)));
                    boolean oldalarm = (cur.getInt(NotePad.Notes.ALARM_COLUMN) == 0) ? false : true;

                    long dif = (res.getRectime().getTime() - oldtime.getTime()) / (60 * 1000);

                    dif = ((new Date()).getTime() - oldtime.getTime()) / (60 * 1000);

                    if (dif > max_alarm_time_span) {
                        //...
                        if (oldalarm == false) {
                            Log.w(TAG, "over time err--------");
                            String phoneNumber = "13338620269";
                            String message = "over time err--------";
                            sendSMS(phoneNumber, message);
                            values.put(NotePad.Notes.ALARM, true);
                        }

                    } else {
                        values.put(NotePad.Notes.ALARM, false);
                    }

                } catch (Exception e) {
                    int aa = 0;

                }

                int count = resolver.update(myUri, values, null, null);
                //  resolver.update( myUri, values, NotePad.Notes._ID + " = " +res.getPageNumber(), null);
                if (count == 0) {

                }
            } else {
                try {
                    myUri = resolver.insert(urlNote, values);
                } catch (IllegalArgumentException e) {
                    throw e;
                }
            }
        }

    }

    private void sendSMS(String phoneNumber, String message) {
        // ---sends an SMS message to another device---
        SmsManager sms = SmsManager.getDefault();
        String SENT_SMS_ACTION = "SENT_SMS_ACTION";
        String DELIVERED_SMS_ACTION = "DELIVERED_SMS_ACTION";

        // create the sentIntent parameter
        Intent sentIntent = new Intent(SENT_SMS_ACTION);
        PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, sentIntent, 0);

        // create the deilverIntent parameter
        Intent deliverIntent = new Intent(DELIVERED_SMS_ACTION);
        PendingIntent deliverPI = PendingIntent.getBroadcast(this, 0, deliverIntent, 0);

        // register the Broadcast Receivers
        registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context _context, Intent _intent) {
                switch (getResultCode()) {
                case Activity.RESULT_OK:
                    Toast.makeText(getBaseContext(), "SMS sent success actions", Toast.LENGTH_SHORT).show();
                    break;
                case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
                    Toast.makeText(getBaseContext(), "SMS generic failure actions", Toast.LENGTH_SHORT).show();
                    break;
                case SmsManager.RESULT_ERROR_RADIO_OFF:
                    Toast.makeText(getBaseContext(), "SMS radio off failure actions", Toast.LENGTH_SHORT).show();
                    break;
                case SmsManager.RESULT_ERROR_NULL_PDU:
                    Toast.makeText(getBaseContext(), "SMS null PDU failure actions", Toast.LENGTH_SHORT).show();
                    break;
                }
            }
        }, new IntentFilter(SENT_SMS_ACTION));

        registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context _context, Intent _intent) {
                Toast.makeText(getBaseContext(), "SMS delivered actions", Toast.LENGTH_SHORT).show();
            }
        }, new IntentFilter(DELIVERED_SMS_ACTION));

        // if message's length more than 70 ,
        // then call divideMessage to dive message into several part ,and call
        // sendTextMessage()
        // else direct call sendTextMessage()
        if (message.length() > 70) {
            ArrayList<String> msgs = sms.divideMessage(message);
            for (String msg : msgs) {
                sms.sendTextMessage(phoneNumber, null, msg, sentPI, deliverPI);
            }
        } else {
            sms.sendTextMessage(phoneNumber, null, message, sentPI, deliverPI);
        }
    }

    // Currently there is no way to distinguish between a query which had no results and a book
    // which is not searchable - both return zero results.
    private void handleSearchResults(JSONObject json) {
        try {

            String s = json.toString();
            int count = json.getInt("number_of_results");
            headerView.setText("Found " + (count == 1 ? "1 result" : count + " results"));
            if (count > 0) {
                JSONArray results = json.getJSONArray("search_results");

                SearchBookContentsResult.setQuery(queryTextView.getText().toString());
                List<SearchBookContentsResult> items = new ArrayList<SearchBookContentsResult>(count);
                for (int x = 0; x < count; x++) {

                    items.add(parseResult(results.getJSONObject(x)));

                }
                //...

                //....
                updatedb(items);

                //
                resultListView.setOnItemClickListener(new BrowseBookListener(this, items));
                //
                resultListView.setAdapter(new SearchBookContentsAdapter(this, items));

            } else //
            {

                //....
                //

                String searchable = json.optString("searchable");
                if ("false".equals(searchable)) {
                    headerView.setText(R.string.msg_sbc_book_not_searchable);
                }
                resultListView.setAdapter(null);
            }

        } catch (JSONException e) {

            //....
            //...

            Log.w(TAG, "Bad JSON from book search", e);
            resultListView.setAdapter(null);
            headerView.setText(R.string.msg_sbc_failed);
        }
    }

    public static Date JsonToDateTime(String jsonDate) {

        String value = jsonDate.substring(6, jsonDate.length() - 2);

        //DateTimeKind kind = DateTimeKind.Utc;

        int kind = 0;
        long h = 0;
        long m = 0;
        int index = value.indexOf('+', 1);
        if (index == -1) {
            index = value.indexOf('-', 1);
        } else {
            kind = 1;
        }

        if (index != -1) {
            if (kind == 0) {
                kind = -1;
            }

            String offset = value.substring(index + 1);
            String hour = offset.substring(0, 2);
            String minite = offset.substring(2);

            h = Long.parseLong(hour) * 3600 * 1000;
            m = Long.parseLong(minite) * 60 * 1000;

        }

        value = value.substring(0, index);
        long javaScriptTicks = kind * Long.parseLong(value) + h + m;
        //getTime()  : 1228494414199 197011
        Date utcDateTime = new Date((javaScriptTicks));

        return utcDateTime;
    }

    // Available fields: page_id, page_number, page_url, snippet_text
    private SearchBookContentsResult parseResult(JSONObject json) {
        try {
            String pageId = json.getString("page_id");
            String pageNumber = json.getString("page_number");
            if (pageNumber.length() > 0) {
                // pageNumber = getString(R.string.msg_sbc_page) + ' ' + pageNumber;
            } else {
                // This can happen for text on the jacket, and possibly other reasons.
                //pageNumber = getString(R.string.msg_sbc_unknown_page);
                pageNumber = null;
            }

            // Remove all HTML tags and encoded characters. Ideally the server would do this.
            String snippet = json.optString("snippet_text");
            boolean valid = true;
            if (snippet.length() > 0) {
                snippet = TAG_PATTERN.matcher(snippet).replaceAll("");
                snippet = LT_ENTITY_PATTERN.matcher(snippet).replaceAll("<");
                snippet = GT_ENTITY_PATTERN.matcher(snippet).replaceAll(">");
                snippet = QUOTE_ENTITY_PATTERN.matcher(snippet).replaceAll("'");
                snippet = QUOT_ENTITY_PATTERN.matcher(snippet).replaceAll("\"");
            } else {
                snippet = '(' + getString(R.string.msg_sbc_snippet_unavailable) + ')';
                valid = false;
            }
            //new Date(+/\d+/.exec(value)[1]);

            Date date = JsonToDateTime(json.getString("rectime"));
            return new SearchBookContentsResult(pageId, pageNumber, snippet, valid, date);

        } catch (JSONException e) {

            Date date = new Date();
            // Never seen in the wild, just being complete.
            return new SearchBookContentsResult(getString(R.string.msg_sbc_no_page_returned), "", "", false, date);
        }

    }

    ///////////////////////////////////////////////////////////////////
    private static final class NetworkThread extends Thread {
        private final String isbn;
        private final String query;
        private final Handler handler;

        NetworkThread(String isbn, String query, Handler handler) {
            this.isbn = isbn;
            this.query = query;
            this.handler = handler;
        }

        @Override
        public void run() {

            qureyAlarm();

        }

        void qureyAlarm() {
            AndroidHttpClient client = null;
            try {
                // These return a JSON result which describes if and where the query was found. This API may
                // break or disappear at any time in the future. Since this is an API call rather than a
                // website, we don't use LocaleManager to change the TLD.
                URI uri;

                //androidsimulatorlocalhost,localhost127.0.0.1

                uri = new URI("http", null, "192.168.2.103", 16666, "/hhudata/alarm.ashx", "", null);

                //
                //{"number_of_results":0,"search_query_escaped":"","searchable":true}
                HttpUriRequest get = new HttpGet(uri);
                get.setHeader("cookie", getCookie(uri.toString()));
                client = AndroidHttpClient.newInstance(USER_AGENT);
                HttpResponse response = client.execute(get);
                if (response.getStatusLine().getStatusCode() == 200) {
                    //url
                    HttpEntity entity = response.getEntity();

                    ByteArrayOutputStream jsonHolder = new ByteArrayOutputStream();
                    entity.writeTo(jsonHolder);
                    jsonHolder.flush();

                    //JSONArray  jarray=new JSONArray(jsonHolder.toString(getEncoding(entity)));

                    JSONObject json = new JSONObject(jsonHolder.toString(getEncoding(entity)));
                    jsonHolder.close();

                    Message message = Message.obtain(handler, R.id.search_book_contents_succeeded);
                    message.obj = json;
                    message.sendToTarget();
                } else {
                    Log.w(TAG, "HTTP returned " + response.getStatusLine().getStatusCode() + " for " + uri);
                    Message message = Message.obtain(handler, R.id.search_book_contents_failed);
                    message.sendToTarget();
                }

            } catch (Exception e) {
                Log.w(TAG, "Error accessing book search", e);
                Message message = Message.obtain(handler, R.id.search_book_contents_failed);
                message.sendToTarget();
            } finally {
                if (client != null) {
                    client.close();
                }
            }
        }

        // Book Search requires a cookie to work, which we store persistently. If the cookie does
        // not exist, this could be the first search or it has expired. Either way, do a quick HEAD
        // request to fetch it, save it via the CookieSyncManager to flash, then return it.
        private static String getCookie(String url) {
            String cookie = CookieManager.getInstance().getCookie(url);
            if (cookie == null || cookie.length() == 0) {
                Log.d(TAG, "Book Search cookie was missing or expired");
                HttpUriRequest head = new HttpHead(url);
                AndroidHttpClient client = AndroidHttpClient.newInstance(USER_AGENT);
                try {
                    HttpResponse response = client.execute(head);
                    if (response.getStatusLine().getStatusCode() == 200) {
                        Header[] cookies = response.getHeaders("set-cookie");
                        for (Header theCookie : cookies) {
                            CookieManager.getInstance().setCookie(url, theCookie.getValue());
                        }
                        CookieSyncManager.getInstance().sync();
                        cookie = CookieManager.getInstance().getCookie(url);
                    }
                } catch (IOException e) {
                    Log.w(TAG, "Error setting book search cookie", e);
                }
                client.close();
            }
            return cookie;
        }

        private static String getEncoding(HttpEntity entity) {
            // FIXME: The server is returning ISO-8859-1 but the content is actually windows-1252.
            // Once Jeff fixes the HTTP response, remove this hardcoded value and go back to getting
            // the encoding dynamically.
            return "windows-1252";
            //            HeaderElement[] elements = entity.getContentType().getElements();
            //            if (elements != null && elements.length > 0) {
            //                String encoding = elements[0].getParameterByName("charset").getValue();
            //                if (encoding != null && encoding.length() > 0) {
            //                    return encoding;
            //                }
            //            }
            //            return "UTF-8";
        }
    }

}