Tutorial 2: Search an image from Phone

In the first tutorial, we have shown you how to use the SDK builtin scanner, but sometimes you might need more control on what is sent to the server. In this tutorial, we will create an app that let users pick an image from their Phones' photo gallery as the data source to the search query. Firstly, you need to create a new App, add dependency and AppID. Please follow step 1-3 in Tutorial 1.

1. Initialize the SDK

Since in every app you need to initialize the SDK, we will bring it up first before introduce the MainActivity class. As usual, initialize in the Application class, the code is almost the same, just the Application Class name is different:

Application class


public class ImageFileApplication extends Application {
    private static final String TAG = ImageFileApplication.class.getSimpleName();

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

        Log.d(TAG, "ImageFileApplication Started");

        String serverUrl = BuildConfig.AIQ_APP_SERVER;

        if (TextUtils.isEmpty(serverUrl)) {
            serverUrl = AIQKit.getServiceEndPoint(AIQKit.ServiceType.STAG);
            Log.d(TAG, "Using AIQ staging server");
        }

        //initialize aiqkit
        AIQKit.init(this, BuildConfig.AIQ_APP_ID, BuildConfig.AIQ_APP_SECRET, serverUrl);
        Log.d(TAG, "Initialized AIQKit SDK");
    }
}
                    

2. The Activity class

Again, this app has one MainActivity class inflating from the same layout file. However, click on the button will trigger the system to open the default Photo App, let the user pick one photo to start searching it. Here is the code for the MainActivity class:

MainActivity


public class MainActivity extends Activity {
    private static final String TAG = MainActivity.class.getName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void OnClick(View view) {
        Intent intent = new Intent();
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(Intent.createChooser(intent, getString(R.string.pick_image)), 0);
    }

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == RESULT_OK && data != null) {
            Uri uri = data.getData();
            if (uri == null) {
                Log.e(TAG, "No uri returned, cannot search");
                return;
            }

            Observable<AIQKit.MatchResult> result = AIQKit.matchImage(uri);
            // use blocking mode to wait for the result
            try {
                AIQKit.MatchResult matchResult = result.toBlocking().first();
                if (matchResult != null) {
                    Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(matchResult.getPayload()));
                    startActivity(myIntent);
                }
            } catch (Throwable t) {
                if (AIQKit.isImageNotFoundError(t.getCause())) {
                    showToast("No match found");
                } else {
                    showToast("Error: " + t.getCause().getMessage());
                }
            }
        }
    }

    private void showToast(String text) {
        Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
    }
}
                    

The AIQKit.matchImage() function returns a RxJava1.* Observable, which you can play with your imagination. Here, we're converting to a BlockingObserver and takes the first MatchResult item. This method will block the search thread until one is returned. The most important information in MatchResult is probably the Payload, which is a url links to the queried image. This app simply sends a ACTION_VIEW intent to the system, normally the system browser will open the url. One final note on the code aspect, a blocking query is usually not a good choice, especially on the UI thread as it may leads to your app crash. This app is just for demo purpose, in the next tutorial we will show you how to split the observable pipeline to different threads.

3. Test the app

As the user of the app, you should make sure you send in an image from the pre-ingsted set. You can take a photo of any of the images, make sure the photo you taken is clear and sharp. Otherwise you might get a "No match found" toast.