com.scm.reader.livescanner.search.ImageRecognizer.java Source code

Java tutorial

Introduction

Here is the source code for com.scm.reader.livescanner.search.ImageRecognizer.java

Source

/*
 * Copyright 2015 Shortcut Media AG.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
 * and associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package com.scm.reader.livescanner.search;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.provider.Settings.Secure;
import android.util.Log;

import com.scm.reader.livescanner.sdk.KConfig;
import com.scm.reader.livescanner.util.LogUtils;
import com.scm.shortcutreadersdk.R;

import org.apache.http.client.methods.HttpPost;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;

public class ImageRecognizer {

    public static final String TAG = ImageRecognizer.class.getSimpleName();

    private static final String API_KEY_NAME = "com.shortcutmedia.shortcut.sdk.API_KEY";
    private static final String API_SECRET_NAME = "com.shortcutmedia.shortcut.sdk.API_SECRET";

    private static final String SHORTCUT_SERVER = "http://shortcut-service.shortcutmedia.com";
    private HttpPost searchRequest;
    private Object searchRequestLock = new Object();

    private boolean cancelled;

    public Search query(final Context context, Search dataToPopulate) throws IOException {

        String searchUrl = KConfig.getConfig().getServer();

        LogUtils.logDebug("qurl " + searchUrl);

        String apiKey = null;
        String apiSecret = null;

        try {
            ApplicationInfo ai = context.getPackageManager().getApplicationInfo(context.getPackageName(),
                    PackageManager.GET_META_DATA);
            Bundle bundle = ai.metaData;
            apiKey = bundle.getString(API_KEY_NAME);
            apiSecret = bundle.getString(API_SECRET_NAME);

        } catch (NameNotFoundException e) {
            Log.e(TAG, "Failed to load API_KEY or SECRET from meta-data, NameNotFound: " + e.getMessage());
            throw new RuntimeException("API_KEY or SECRET not found.");
        } catch (NullPointerException e) {
            Log.e(TAG, "Failed to load API_KEY or SECRET from meta-data, NullPointer: " + e.getMessage());
            throw new RuntimeException("API_KEY or SECRET not found.");
        }

        SearchRequestBuilder requestBuilderV4 = new SearchRequestBuilder(
                new SearchRequestData(dataToPopulate.getImage(), dataToPopulate.getLatitude(),
                        dataToPopulate.getLongitude(), searchUrl, getDeviceId(context)),
                getPackageInfo(context), apiKey, apiSecret);

        String response = "";

        try {

            Map<String, String> params = new HashMap<String, String>();
            params.put("location:", dataToPopulate.getLatitude() + ", " + dataToPopulate.getLongitude());
            response = requestBuilderV4.query();

        } catch (InvalidKeyException e1) {
            e1.printStackTrace();
        } catch (NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            LogUtils.logWarn("IO exception while sending HTTP request and parsing response", e);
            throw e;
        }

        // Print the response to console
        System.out.println("HTTP Status: " + requestBuilderV4.getResponseStatus());
        System.out.println("HTTP Response: " + requestBuilderV4.getResponseBody());

        Search result = null;
        try {
            result = parseJSON(context, response, dataToPopulate);

        } catch (JSONException e) {
            e.printStackTrace();
        }
        return result;

    }

    private String getDeviceId(Context context) {
        String deviceId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
        return deviceId;
    }

    private PackageInfo getPackageInfo(Context context) {
        PackageInfo pInfo = null;
        try {
            pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return pInfo;
    }

    //parsing resultUrl string
    public String createResultUrl(String uuid, String recId) {
        String url = "";
        url += SHORTCUT_SERVER + "/app#/results/";
        url += uuid;
        url += "_";
        url += modifySH1String(recId);

        return url;
    }

    //modifying SH1 string for url
    public String modifySH1String(String shaString) {
        shaString = shaString.replace("image.sha1:", "");
        return shaString;
    }

    private String extractFromLanguageString(JSONObject langObj) throws JSONException {
        String userLang = Locale.getDefault().getLanguage();
        String fallbackLang = "en";
        return langObj.has(userLang) ? langObj.getString(userLang) : langObj.getString(fallbackLang);
    }

    /**
     * @param context
     * @param data
     * @param dataToPopulate
     * @return
     * @throws IOException
     * @throws JSONException
     * @return Search object
     * 
     * TODO refactor and make this method more readable if time
     */
    public Search parseJSON(Context context, String data, Search dataToPopulate) throws IOException, JSONException {
        dataToPopulate.setSearchTime(new Date());
        dataToPopulate.setPending(false);
        JSONObject jObject;

        jObject = new JSONObject(data);

        dataToPopulate.setUuid(jObject.getString("query_id"));

        JSONArray resultArray = (JSONArray) jObject.get("results");

        //no results
        if (resultArray.length() == 0) {
            dataToPopulate.setRecognized(false);
            dataToPopulate.setTitle(context.getResources().getString(R.string.image_not_recognized_title));
            dataToPopulate.setUrl("http://");
        }

        //only one item result
        else if (resultArray.length() < 2) {
            System.out.println("only one item result");
            JSONObject result = resultArray.getJSONObject(0);
            JSONArray recognitions = result.getJSONArray("recognitions");

            dataToPopulate.setRecognized(true);
            //dataToPopulate.setTitle(result.getString("title"));

            JSONArray metaDataArray = result.getJSONArray("metadata");
            JSONObject metaDataObj = metaDataArray.getJSONObject(0);
            JSONObject recognition = recognitions.getJSONObject(0);

            //setting right language
            String title = extractFromLanguageString(metaDataObj.getJSONObject("title"));
            dataToPopulate.setTitle(title);

            String subtitle = extractFromLanguageString(metaDataObj.getJSONObject("subtitle"));
            dataToPopulate.setDetail(subtitle);
            dataToPopulate.setItemUuid(metaDataObj.getString("uuid"));

            String url = "";
            if (metaDataObj.has("response")) {
                System.out.println("direct response");
                JSONObject responseObject = metaDataObj.getJSONObject("response");
                url = responseObject.getString("content");
                LogUtils.logDebug("response qurl " + url);
                System.out.println(url);
            } else {
                System.out.println("normal response");
                url = createResultUrl(metaDataObj.getString("uuid"), recognition.getString("id"));
                LogUtils.logDebug("normal response response qurl " + url);

            }
            dataToPopulate.setUrl(url);
        }
        //multiple results
        else {
            //reading objects inside "results" node

            //inserting ads first
            for (int i = 0; i < resultArray.length(); i++) {
                JSONObject result = resultArray.getJSONObject(i);
                JSONArray metaDataArray = result.getJSONArray("metadata");
                JSONObject metaDataObj = metaDataArray.getJSONObject(0);

                boolean hasKind = false;
                for (int ind = 0; ind < metaDataArray.length(); ind++) {
                    if (metaDataArray.getJSONObject(ind).has("kind")) {
                        hasKind = true;
                        break;
                    }
                }

                if (hasKind) {
                    if (!dataToPopulate.hasSections() && metaDataObj.getString("kind").equals("Ad")) {
                        dataToPopulate.addSection(parseSectionJSON(resultArray, result));
                    }
                }
            }

            //inserting everything else than ads

            for (int i = 0; i < resultArray.length(); i++) {
                JSONObject result = resultArray.getJSONObject(i);

                JSONArray metaDataArray = result.getJSONArray("metadata");
                JSONObject metaDataObj = metaDataArray.getJSONObject(0);

                dataToPopulate.setTitle(context.getResources().getString(R.string.multiple_matches));
                if (dataToPopulate.hasSections()) {
                    //checking that there is no two of same headers

                    /**
                     * If any of the sections contains same header the insert boolean
                     * will be set false and loop is determined
                     */
                    boolean insert = false;
                    for (int index = 0; index < dataToPopulate.getSections().size(); index++) {
                        if (!metaDataObj.has("kind")) {
                            break;
                        }
                        SearchResultSection section = dataToPopulate.getSections().get(index);
                        if (!metaDataObj.getString("kind").equals(section.getHeader())) {
                            insert = true;
                        } else {
                            insert = false;
                            break;
                        }
                    }
                    if (insert) {
                        dataToPopulate.addSection(parseSectionJSON(resultArray, result));
                    }

                } else {
                    dataToPopulate.addSection(parseSectionJSON(resultArray, result));
                }

            }

            dataToPopulate.setRecognized(true);
        }
        //TODO check here
        if (!dataToPopulate.hasSections()) {
            if (dataToPopulate.getUrl() == null || dataToPopulate.getUrl().length() == 0) {
                throw new JSONException("url not found");
            }
            if (dataToPopulate.getTitle() == null || dataToPopulate.getTitle().length() == 0) {
                System.out.println(dataToPopulate.getTitle());
                throw new JSONException("title not found");
            }
        } else {
            // If we have a section with a single object, set title to the item's title
            // This is to avoid bug KOOABA-20
            LinkedList<SearchResultSection> sections = dataToPopulate.getSections();
            if (sections.size() == 1) {
                LinkedList<SearchResultItem> items = sections.getFirst().getItems();
                if (items.size() == 1) {
                    dataToPopulate.setTitle(items.getFirst().getTitle());
                }
            }
        }
        return dataToPopulate;
    }

    public SearchResultSection parseSectionJSON(JSONArray resultArray, JSONObject sResult)
            throws IOException, JSONException {
        SearchResultSection section = new SearchResultSection();
        JSONArray metaDataArray = sResult.getJSONArray("metadata");
        JSONObject metaDataObj = metaDataArray.getJSONObject(0);

        //header is kind in metaData object
        if (metaDataObj.has("kind")) {
            String header = metaDataObj.getString("kind");
            section.setHeader(header);

            for (int i = 0; i < resultArray.length(); i++) {
                JSONObject result = resultArray.getJSONObject(i);
                JSONArray metaArray = result.getJSONArray("metadata");
                JSONObject meta = metaArray.getJSONObject(0);

                if (header.equals(meta.getString("kind"))) {
                    section.addItem(parseSectionItemJSON(result));
                }
            }
        } else {
            //have to set some header even if we wouldn't show it
            section.setHeader("");
            for (int i = 0; i < resultArray.length(); i++) {
                JSONObject result = resultArray.getJSONObject(i);

                section.addItem(parseSectionItemJSON(result));
            }
        }
        return section;
    }

    public SearchResultItem parseSectionItemJSON(JSONObject result) throws IOException, JSONException {
        SearchResultItem item = new SearchResultItem();

        if (result != null) {
            item.setTitle(result.getString("title"));
            JSONArray recognitions = result.getJSONArray("recognitions");
            JSONArray metaDataArray = result.getJSONArray("metadata");
            JSONObject metaDataObj = metaDataArray.getJSONObject(0);
            JSONObject recognition = recognitions.getJSONObject(0);

            item.setImageId(recognition.getString("id"));
            String url = createResultUrl(metaDataObj.getString("uuid"), recognition.getString("id"));

            //set up language settings
            String title = extractFromLanguageString(metaDataObj.getJSONObject("title"));
            item.setTitle(title);

            String subtitle = extractFromLanguageString(metaDataObj.getJSONObject("subtitle"));
            item.setDetail(subtitle);

            item.setItemUuid(metaDataObj.getString("uuid"));
            item.setImageUrl(metaDataObj.getString("thumbnail_url"));

            if (metaDataObj.has("response")) {
                System.out.println("direct response");
                JSONObject responseObject = metaDataObj.getJSONObject("response");
                url = responseObject.getString("content");
                LogUtils.logDebug("response qurl " + url);
                System.out.println(url);
            } else {
                System.out.println("normal response");
            }

            item.setResultUrl(url);

        }
        return item;
    }

    public void cancelRequest() {
        synchronized (searchRequestLock) {
            cancelled = true;
            if (searchRequest != null) {
                searchRequest.abort();
            }
        }
    }

    public boolean isCancelled() {
        return cancelled;
    }
}