com.spoiledmilk.ibikecph.search.SearchAutocompleteActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.spoiledmilk.ibikecph.search.SearchAutocompleteActivity.java

Source

// Copyright (C) 2013 City of Copenhagen.
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at 
// http://mozilla.org/MPL/2.0/.
package com.spoiledmilk.ibikecph.search;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.ProgressBar;

import com.fasterxml.jackson.databind.JsonNode;
import com.google.analytics.tracking.android.EasyTracker;
import com.spoiledmilk.ibikecph.IbikeApplication;
import com.spoiledmilk.ibikecph.R;
import com.spoiledmilk.ibikecph.map.MapFragmentBase;
import com.spoiledmilk.ibikecph.navigation.routing_engine.SMLocationManager;
import com.spoiledmilk.ibikecph.search.SearchListItem.nodeType;
import com.spoiledmilk.ibikecph.util.DB;
import com.spoiledmilk.ibikecph.util.LOG;
import com.spoiledmilk.ibikecph.util.Util;

public class SearchAutocompleteActivity extends Activity {

    public static final int RESULT_AUTOTOCMPLETE_SET = 103;
    public static final int RESULT_AUTOTOCMPLETE_NOT_SET = 104;

    private Button btnClose;
    private ImageButton btnClear;
    private EditText textSrch;
    private ListView listSearch;
    private AutocompleteAdapter adapter;
    private SearchListItem currentSelection;
    private int lastTextSize = 0;
    private boolean addressPicked = false, isA = false, isOirestFetched = false, isFoursquareFetched = false,
            isClose = false, isAddressSearched = false;
    private Address addr;
    private ProgressBar progressBar;

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search_autocomplete_activiy);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);
        progressBar.setVisibility(View.INVISIBLE);
        Bundle data = getIntent().getExtras();
        if (data != null) {
            isA = data.getBoolean("isA", false);
        }
        btnClose = (Button) findViewById(R.id.btnClose);
        btnClose.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                isClose = true;
                finishEditing();
            }
        });
        btnClear = (ImageButton) findViewById(R.id.btnClear);
        textSrch = (EditText) findViewById(R.id.textLocation);
        textSrch.addTextChangedListener(new MyTextWatcher());
        textSrch.setImeActionLabel("Go", KeyEvent.KEYCODE_ENTER);
        textSrch.setOnKeyListener(new OnKeyListener() {
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_ENTER) {
                    if (currentSelection == null && listSearch.getAdapter() != null
                            && listSearch.getAdapter().getCount() > 0) {
                        onItemClicked(0, false);
                    } else if (currentSelection != null) {
                        finishEditing();
                    }
                    return true;
                }
                return false;
            }
        });
        listSearch = (ListView) findViewById(R.id.listSearch);
        adapter = new AutocompleteAdapter(this, new ArrayList<SearchListItem>(), isA);
        listSearch.setAdapter(adapter);
        if (isA) {
            adapter.add(new CurrentLocation());
        }
        listSearch.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long arg3) {
                onItemClicked(position, true);
            }

        });
        if (data != null && data.containsKey("lastName")) {
            ArrayList<SearchListItem> listData = new ArrayList<SearchListItem>();
            DB db = new DB(this);
            String reuseName = data.getString("lastName");
            SearchListItem sli = db.getFavoriteByName(reuseName);
            if (sli != null) {
                listData.add(sli);
            } else {
                sli = db.getSearchHistoryByName(reuseName);
                if (sli != null) {
                    listData.add(sli);
                } else {
                    SharedPreferences prefs = getPreferences(MODE_PRIVATE);
                    String nodeStr = prefs.getString("lastSearchItem", null);
                    if (nodeStr != null) {
                        JsonNode node = Util.stringToJsonNode(nodeStr);
                        if (node != null) {
                            sli = SearchListItem.instantiate(node);
                            if (sli != null) {
                                listData.add(sli);
                            }
                        }
                    }
                }
            }
            db.close();
            addr = AddressParser.parseAddressRegex(reuseName);
            adapter.updateListData(listData, AddressParser.addresWithoutNumber(reuseName), addr);
            textSrch.setText(reuseName);
            textSrch.setSelection(reuseName.length());
        }
    }

    private void onItemClicked(int position, boolean isFromAdapter) {
        currentSelection = (SearchListItem) listSearch.getAdapter().getItem(position);
        boolean isFinishing = false;
        if (currentSelection.type != SearchListItem.nodeType.ORIEST
                && currentSelection.type != SearchListItem.nodeType.CURRENT_POSITION) {
            isFinishing = true;
            finishAndPutData();
        } else if (currentSelection.type == SearchListItem.nodeType.CURRENT_POSITION) {
            isFinishing = true;
            (new Thread() {

                @Override
                public void run() {
                    JsonNode node = HTTPAutocompleteHandler.getOiorestAddress(currentSelection.getLatitude(),
                            currentSelection.getLongitude());
                    if (node != null) {
                        currentSelection.jsonNode = node;
                    }

                    runOnUiThread(new Runnable() {
                        public void run() {
                            finishAndPutData();
                        }
                    });
                }
            }).start();
        } else if (currentSelection instanceof KortforData) {
            if (((KortforData) currentSelection).isPlace()) {
                isFinishing = true;
                finishAndPutData();
            } else {
                KortforData kd = (KortforData) currentSelection;
                if (kd.getNumber() != null && !kd.getNumber().equals("") && kd.hasCoordinates()) {
                    isAddressSearched = true;
                    addr.number = kd.getNumber();
                    isFinishing = true;
                    finishAndPutData();
                }
            }
        }

        if (!isFinishing) {
            addressPicked = true;
            String number = AddressParser.numberFromAddress(textSrch.getText().toString());
            if (isFromAdapter) {
                textSrch.setText(currentSelection.getOneLineName());
            }
            int firstCommaIndex = textSrch.getText().toString().indexOf(',');
            if (number != null) {
                if (firstCommaIndex > 0) {
                    String street = textSrch.getText().toString().replaceAll("\n", ",").substring(0,
                            firstCommaIndex);
                    String city = textSrch.getText().toString().replaceAll("\n", ",").substring(firstCommaIndex,
                            textSrch.getText().toString().length() - 1);
                    if (isFromAdapter) {
                        textSrch.setText(street + " " + number + city);
                        textSrch.setSelection(street.length() + 2);
                    }
                } else
                    textSrch.setText(textSrch.getText().toString() + " " + number);
            } else if (firstCommaIndex > 0) {
                // add a whitespace for a house number input
                if (isFromAdapter) {
                    textSrch.setText(
                            textSrch.getText().toString().substring(0, firstCommaIndex) + " " + textSrch.getText()
                                    .toString().substring(firstCommaIndex, textSrch.getText().toString().length()));
                    textSrch.setSelection(firstCommaIndex + 1);
                }
            }
            if (!isFromAdapter) {
                if (addr.number == null || addr.number.equals("") && currentSelection != null
                        && currentSelection.getNumber() != null) {
                    addr.number = currentSelection.getName();
                }
                finishEditing();
            }

            else if (currentSelection != null && currentSelection.getNumber() != null
                    && !currentSelection.number.equals("")) {
                addr.number = currentSelection.getNumber();
                finishEditing();
            }
        }

    }

    private void finishEditing() {
        progressBar.setVisibility(View.VISIBLE);
        if (addr != null && (addr.number == null || addr.number.equals("")) && currentSelection != null
                && currentSelection instanceof KortforData && !((KortforData) currentSelection).isPlace()) {
            addr.number = "1";
        }
        performGeocode();
    }

    private void performGeocode() {
        (new Thread() {
            @Override
            public void run() {
                isAddressSearched = true;
                if (addr != null && addr.number != null && !addr.number.trim().equals("") && !isClose) {
                    JsonNode node;
                    try {
                        if (currentSelection == null) {
                            currentSelection = new KortforData(
                                    AddressParser.addresWithoutNumber(textSrch.getText().toString()), addr.number);
                        }
                        LOG.d("Street searchfor the number " + addr.number);
                        String urlString = "http://geo.oiorest.dk/adresser.json?q="
                                + URLEncoder.encode(currentSelection.getStreet() + " " + addr.number, "UTF-8");
                        boolean coordinatesFound = false;
                        if (adapter != null && adapter.getCount() > 0
                                && adapter.getItem(0) instanceof KortforData) {
                            KortforData kd = (KortforData) adapter.getItem(0);
                            LOG.d("search first item number = " + kd.getNumber() + " parsed addres number = "
                                    + addr.number + " first item lattitude = " + kd.getLatitude());
                            if (kd.getNumber() != null && kd.getNumber().equals(addr.number)
                                    && kd.hasCoordinates()) {
                                currentSelection.setLatitude(kd.getLatitude());
                                currentSelection.setLongitude(kd.getLongitude());
                                coordinatesFound = true;
                            }
                        }
                        if (!coordinatesFound) {
                            node = HTTPAutocompleteHandler.getOiorestGeocode(urlString, "" + addr.number);
                            if (node != null) {
                                if (node.has("wgs84koordinat") && node.get("wgs84koordinat").has("bredde")) {
                                    currentSelection.setLatitude(
                                            Double.parseDouble(node.get("wgs84koordinat").get("bredde").asText()));
                                }
                                if (node.has("wgs84koordinat") && node.get("wgs84koordinat").has("lngde")) {
                                    currentSelection.setLongitude(
                                            Double.parseDouble(node.get("wgs84koordinat").get("lngde").asText()));
                                }
                            }
                        }
                        if (currentSelection != null && currentSelection.getLatitude() > -1
                                && currentSelection.getLongitude() > -1)
                            runOnUiThread(new Runnable() {
                                public void run() {
                                    finishAndPutData();
                                }
                            });
                    } catch (Exception e) {
                        LOG.e(e.getLocalizedMessage());
                    }

                } else if (isClose)
                    finishAndPutData();
            }

        }).start();
    }

    public void onClearTextClick(View v) {
        textSrch.setText("");
        btnClear.setVisibility(View.GONE);
    }

    @Override
    public void onResume() {
        super.onResume();
        initStrings();
        InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
        imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
        progressBar.setVisibility(View.INVISIBLE);
    }

    @Override
    public void onPause() {
        super.onPause();
        hideKeyboard();
    }

    private void initStrings() {
        btnClose.setText(IbikeApplication.getString("close"));
        btnClose.setTypeface(IbikeApplication.getBoldFont());
    }

    public void updateListData(List<SearchListItem> list, String tag, Address addr) {
        if (textSrch.getText().toString().equals(tag)) {
            adapter.updateListData(list, AddressParser.addresWithoutNumber(textSrch.getText().toString()), addr);
        }
        if (isOirestFetched && isFoursquareFetched) {
            progressBar.setVisibility(View.INVISIBLE);
        }
    }

    public void hideKeyboard() {
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
    }

    private class MyTextWatcher implements TextWatcher {

        @Override
        public void afterTextChanged(Editable statusText) {
            if (kmsThread != null && kmsThread.isAlive()) {
                kmsThread.interrupt();
            }
            if (foursquareThread != null && foursquareThread.isAlive()) {
                foursquareThread.interrupt();
            }
            Address temp;
            temp = AddressParser.parseAddressRegex(textSrch.getText().toString().replaceAll("\n", ","));
            LOG.d("after text changed");
            if (addr == null || !addr.equals(temp)) {
                LOG.d("clearing the adapter and spawning the search threads");
                adapter.clear();
                if (textSrch.getText().toString().length() >= 2) {
                    final Location loc1;
                    if (SMLocationManager.getInstance().hasValidLocation()) {
                        loc1 = SMLocationManager.getInstance().getLastValidLocation();
                    } else if (SMLocationManager.getInstance().getLastKnownLocation() != null) {
                        loc1 = SMLocationManager.getInstance().getLastKnownLocation();
                    } else {
                        loc1 = MapFragmentBase.locCopenhagen;
                    }
                    final String searchText = AddressParser.addresWithoutNumber(textSrch.getText().toString());
                    isOirestFetched = false;
                    isFoursquareFetched = !(textSrch.getText().toString().length() > 2);
                    isAddressSearched = false;
                    final Handler handler = new Handler();
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            spawnSearchThreads(loc1, searchText, addr, textSrch.getText().toString());
                        }
                    }, 500);

                    adapter.updateListData(textSrch.getText().toString(), addr);

                    if (textSrch.getText().toString().length() != lastTextSize
                            && textSrch.getText().toString().length() > 1 && !addressPicked) {
                        progressBar.setVisibility(View.VISIBLE);
                    }
                    addressPicked = false;
                    lastTextSize = textSrch.getText().toString().length();
                }
            }
            addr = temp;
            if (textSrch.getText().toString().length() != 0) {
                btnClear.setVisibility(View.VISIBLE);
            } else {
                btnClear.setVisibility(View.GONE);
            }
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int count, int after) {

        }
    }

    private Thread kmsThread, foursquareThread;
    private Address lastAddress = null;

    private void spawnSearchThreads(final Location loc, final String searchText, final Address addr,
            final String tag) {

        if (lastAddress != null && lastAddress.equals(addr) && adapter != null && adapter.getCount() != 0) {
            return;
        } else {
            lastAddress = addr;
        }
        if (!Util.isNetworkConnected(this)) {
            Util.launchNoConnectionDialog(this);
            progressBar.setVisibility(View.INVISIBLE);
        } else {
            // fetch the Kortforsyningen autocomplete
            kmsThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    // final List<JsonNode> kortforsyningenList = new ArrayList<JsonNode>();
                    final ArrayList<SearchListItem> data = new ArrayList<SearchListItem>();
                    if (!(addr.street == null || addr.street.trim().equals(""))) {

                        List<JsonNode> list = HTTPAutocompleteHandler.getKortforsyningenAutocomplete(loc, addr);

                        int count = 0;
                        if (list != null) {
                            for (JsonNode node : list) {
                                if (count == 10) {
                                    break;
                                }
                                KortforData kd = new KortforData(node);
                                if (kd.getCity() != null && addr.city != null
                                        && kd.getCity().toLowerCase(Locale.US).contains(addr.city)) {
                                    LOG.d("kd = " + kd);
                                }
                                if (addr.zip != null && !addr.zip.equals("") && kd.getZip() != null) {
                                    if (!addr.zip.trim().toLowerCase(Locale.UK)
                                            .equals(kd.getZip().toLowerCase(Locale.UK))) {
                                        continue;
                                    }
                                }
                                LOG.d("kd = " + kd);
                                if (kd.getCity() != null && addr.city != null
                                        && kd.getCity().toLowerCase(Locale.US).contains(addr.city)
                                        && kd.getCity().contains("Aarhus")) {
                                    LOG.d("kd.city = " + kd.getCity() + " addr city = " + addr.city);
                                }
                                if (addr.city != null && !addr.city.equals("") && !addr.city.equals(addr.street)
                                        && kd.getCity() != null) {
                                    if (!(addr.city.trim().toLowerCase(Locale.UK)
                                            .contains(kd.getCity().toLowerCase(Locale.UK))
                                            || kd.getCity().trim().toLowerCase(Locale.UK)
                                                    .contains(addr.city.toLowerCase(Locale.UK)))) {
                                        continue;
                                    }
                                }
                                LOG.d("adding a kd to the list " + kd);
                                data.add(kd);
                                count++;
                            }

                        }
                    }
                    if (!addr.isAddress()) {
                        List<JsonNode> places = HTTPAutocompleteHandler.getKortforsyningenPlaces(loc, addr);
                        if (places != null) {
                            int count = 0;
                            if (places != null) {
                                LOG.d("places count = " + places.size() + " data = " + places.toString());
                                for (JsonNode node : places) {
                                    if (count == 10) {
                                        break;
                                    }
                                    KortforData kd = new KortforData(node);
                                    if (addr.zip != null && !addr.zip.equals("") && kd.getZip() != null) {
                                        if (!addr.zip.trim().toLowerCase(Locale.UK)
                                                .equals(kd.getZip().toLowerCase(Locale.UK))) {
                                            continue;
                                        }
                                    }
                                    if (addr.city != null && !addr.city.equals("") && !addr.city.equals(addr.street)
                                            && kd.getCity() != null) {
                                        if (!(addr.city.trim().toLowerCase(Locale.UK)
                                                .contains(kd.getCity().toLowerCase(Locale.UK))
                                                || kd.getCity().trim().toLowerCase(Locale.UK)
                                                        .contains(addr.city.toLowerCase(Locale.UK)))) {
                                            continue;
                                        }
                                    }
                                    data.add(kd);
                                    count++;
                                }

                            }
                        }
                    }
                    isOirestFetched = true;
                    runOnUiThread(new Runnable() {
                        public void run() {
                            updateListData(data, tag, addr);

                        }
                    });
                }

            });
            kmsThread.start();
            if (textSrch.getText().toString().length() >= 3 && addr.isFoursquare()) {
                // fetch the Foursquare autocomplete
                foursquareThread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        List<JsonNode> list = HTTPAutocompleteHandler.getFoursquareAutocomplete(addr,
                                SearchAutocompleteActivity.this, loc);
                        final ArrayList<SearchListItem> data = new ArrayList<SearchListItem>();
                        if (list != null) {
                            int count = 0;
                            for (JsonNode node : list) {
                                if (count == 3) {
                                    break;
                                }
                                JsonNode location = node.path("location");
                                if (location.has("lat") && location.has("lng")
                                        && location.get("lat").asDouble() != 0
                                        && location.get("lng").asDouble() != 0) {
                                    String country = location.has("country") ? location.get("country").asText()
                                            : "";
                                    if (country.contains("Denmark") || country.contains("Dansk")
                                            || country.contains("Danmark")) {
                                        FoursquareData fd = new FoursquareData(node);
                                        fd.setDistance(loc.distanceTo(
                                                Util.locationFromCoordinates(fd.getLatitude(), fd.getLongitude())));
                                        data.add(fd);
                                        count++;
                                    }
                                }
                            }
                        }
                        isFoursquareFetched = true;
                        runOnUiThread(new Runnable() {
                            public void run() {
                                updateListData(data, tag, addr);
                            }
                        });
                    }
                });
                foursquareThread.start();
            } else {
                isFoursquareFetched = true;
            }
        }
    }

    boolean isFinishing = false;

    public void finishAndPutData() {
        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                progressBar.setVisibility(View.INVISIBLE);
                if (isFinishing) {
                    return;
                }
                isFinishing = true;
                Intent intent = new Intent();
                if (currentSelection != null) {
                    if (isAddressSearched && addr != null) {
                        intent.putExtra("number", addr.number);
                    }
                    if (currentSelection instanceof KortforData && !((KortforData) currentSelection).isPlace()) {
                        String name = currentSelection.getName();
                        if (addr != null && addr.number != null && !addr.number.equals("")
                                && !addr.number.equals("1") && AddressParser.containsNumber(addr.number)) {
                            name += " " + addr.number;
                        }
                        if (currentSelection.getZip() != null && !currentSelection.getZip().equals("")) {
                            name += ", " + currentSelection.getZip();
                        }
                        if (currentSelection.getCity() != null && !currentSelection.getCity().equals("")) {
                            name += " " + currentSelection.getCity();
                        }
                        intent.putExtra("name", name);
                    } else {
                        intent.putExtra("name", currentSelection.getName());
                    }
                    if (currentSelection.type == nodeType.FOURSQUARE || (currentSelection instanceof KortforData
                            && ((KortforData) currentSelection).isPlace()))
                        intent.putExtra("poi", currentSelection.getName());
                    if (currentSelection.getAdress() != null) {
                        String address = currentSelection.getAdress();
                        intent.putExtra("address", address);
                    }
                    intent.putExtra("source", currentSelection.getSource());
                    intent.putExtra("subsource", currentSelection.getSubSource());
                    intent.putExtra("lat", currentSelection.getLatitude());
                    intent.putExtra("lon", currentSelection.getLongitude());
                    if (currentSelection instanceof FoursquareData || (currentSelection instanceof KortforData
                            && ((KortforData) currentSelection).isPlace())) {
                        intent.putExtra("isPoi", true);
                    }
                    if (currentSelection.getZip() != null && !currentSelection.getZip().trim().equals("")) {
                        intent.putExtra("zip", currentSelection.getZip());
                    }
                    if (currentSelection.getCity() != null && !currentSelection.getCity().trim().equals("")) {
                        intent.putExtra("city", currentSelection.getCity());
                    }
                    if (currentSelection.getStreet() != null && !currentSelection.getStreet().trim().equals("")) {
                        intent.putExtra("street", currentSelection.getStreet());
                    }
                    SearchAutocompleteActivity.this.setResult(RESULT_AUTOTOCMPLETE_SET, intent);
                } else {
                    SearchAutocompleteActivity.this.setResult(RESULT_AUTOTOCMPLETE_NOT_SET, intent);
                }
                SharedPreferences prefs = getPreferences(MODE_PRIVATE);
                if (currentSelection != null) {
                    JsonNode node = currentSelection.getJsonNode();
                    if (node != null) {
                        prefs.edit().putString("lastSearchItem", node.toString()).commit();
                    }
                }
                finish();
            }
        });
    }

    @Override
    public void onStart() {
        super.onStart();
        EasyTracker.getInstance().activityStart(this);
    }

    @Override
    public void onStop() {
        super.onStop();
        EasyTracker.getInstance().activityStop(this);
    }

}