Using a web URL for SUGGEST_COLUMN_ICON_1 for Search Suggestions
Asked Answered
C

2

8

I have a SearchManager setup where a suggestions dropdown will display as the user types. The results are from my server (http). I would like to display an icon with each option (if the file in fact does exist).

Looking at the docs, I see the options for the constant column SUGGEST_COLUMN_ICON_1 allows for these options:

Column name for suggestions cursor. Optional. If your cursor includes this column, then all suggestions will be provided in a format that includes space for two small icons, one at the left and one at the right of each suggestion. The data in the column must be a resource ID of a drawable, or a URI in one of the following formats:

content (SCHEME_CONTENT)
android.resource (SCHEME_ANDROID_RESOURCE)
file (SCHEME_FILE) 

All I have is a URL. Which option would work best for me?

Here is the class where I am doing this:

public class MyCustomSuggestionProvider extends SearchRecentSuggestionsProvider {

    public static final String AUTHORITY = "---.MyCustomSuggestionProvider";
    public static final int MODE = DATABASE_MODE_QUERIES;
    private final static String[] COLUMN_NAMES = {BaseColumns._ID,
            SearchManager.SUGGEST_COLUMN_TEXT_1,
            SearchManager.SUGGEST_COLUMN_TEXT_2,
            SearchManager.SUGGEST_COLUMN_QUERY,
            SearchManager.SUGGEST_COLUMN_INTENT_DATA,
            SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA,
            SearchManager.SUGGEST_COLUMN_ICON_1,
            SearchManager.SUGGEST_COLUMN_INTENT_ACTION};

    public MyCustomSuggestionProvider() {
        setupSuggestions(AUTHORITY, MODE);
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {

        Cursor recentCursor = super.query(uri, projection, selection,
                selectionArgs, sortOrder);

        String query = selectionArgs[0];
        if (query == null || query.length() < 3) {
            return recentCursor;
        }

        final MatrixCursor customCursor = new MatrixCursor(COLUMN_NAMES);

        // Get web results from Retrofit Library
        List<TheProfile> suggestions = RestClient.get().getCustomSearch(query, MyApp.getUserId());

        for (TheProfile suggestion : suggestions) {


            Uri searchIconUri = Uri.parse("http:/---/profile_images/" + String.valueOf(suggestion.id) + ".png");
            try {
                customCursor.addRow(new Object[]{
                        suggestion.id, suggestion.profile, suggestion.subcategory, suggestion.profile, suggestion.profile, suggestion.subcategory, searchIconUri, "android.intent.action.SEARCH"});
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return customCursor;
    }
}
Chuch answered 24/8, 2015 at 3:0 Comment(0)
V
4

For those, who's still looking the answer for this question, like I did. It's pretty similar to my code, so I decided to share it. I spent hours putting this all together. Maybe, I'll save some time for someone. First of all, you'll need the Glide library.

Add it to your app's build.gradle file:

repositories {
    mavenCentral() // jcenter() works as well because it pulls from Maven Central
}

dependencies {
    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'com.android.support:support-v4:19.1.0'
}

Now let's make some changes to the code from the question (in MyCustomSuggestionProvider class): Put it inside your for (TheProfile suggestion : suggestions) {

FutureTarget<File> futureTarget  = Glide
        .with(getContext().getApplicationContext())
        .load(searchIcon)
        .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);

File cacheFile = futureTarget.get();
Uri searchIconUri = Uri.fromFile(cacheFile);

Pay attention to this line of code: .with(getContext().getApplicationContext()) That's very important to get Application Context, not just Context, since we're not going to show bmp in ImageView. Official Glide documentation for this type of Glide usage.

And after all you can call:

// do things with bitmap and then release when finished:
Glide.clear(futureTarget);
Valleau answered 30/5, 2016 at 19:39 Comment(1)
True story: I searched this same question once again, found this page and implemented this solution. Works great. Well, mostly. Part of the issue is I that I have left is I need .placeholder() and haven't figured it out yet to work with above. But I am getting the images. I was wondering why this wasn't marked correct. Then I noticed it was I who asked this question! Well, two years later, I am marking it correct. Excuse the delay ;)Chuch
P
2
  1. Collect up all the files you are going to use as icons. They are probably on your server; you need to embed them in your app.

  2. If they are not in .PNG format, convert them to .PNG format. Scale them to the size you need for displaying in your app.

  3. Add them to your Android project in the /res/drawable-mdpi folder. Putting them in the mdpi-specific folder will scale them at the same size across different device resolutions.

  4. The first part of the code for the icons is having URIs to return for SearchManager. Use the "android.resource" scheme in the format:

    android.resource://<package-name>/<resource-type>/<resource-name>
    

    For instance, you could create a final URI for each icon. Here is an example of a URI that I used in my project for /res/drawable-mdpi/ic_autocomplete_1.png:

    private final Uri searchIconUri = Uri.parse("android.resource://com.mycompany.android/drawable/ic_autocomplete_1");
    
  5. As you are looping through your suggestions, determine which icon is necessary, for example with a switch statement, and put that URI in your row object, as you have in your code.

Perdomo answered 24/8, 2015 at 3:54 Comment(9)
Yes, I assumed as much. Any idea on how to do this part? That was part of my question, but I didn't explain that very good. "Grab the all the icons you will be displaying from the server and create drawable resources with them". Also, I am looping through my suggestion results. Can I do this one at a time? (adding code to the question).Chuch
no, you dont need to store them in res/drawable at all, since you can use either: resource ID (pretty same as URI with SCHEME_ANDROID_RESOURCE) or a URI n one of the following formats: SCHEME_CONTENT, SCHEME_ANDROID_RESOURCE (what you suggest) or SCHEME_FILE, so you can use SCHEME_CONTENT or SCHEME_FILE to point to the icon fileTaber
@KickingLettuce, I updated my answer to be a little more explicit and specific. Let me know if you have more questions.Perdomo
I am not sure this will work for me. I have hundreds of icons (with more added on a regular basis), it is not practical to convert each into a resource and put into the folder?Chuch
The SearchManager is set up mainly for database access, so that's how all the logic is oriented. You might be able to do this with a custom ContentProvider that fetches the icon image data stream from the server and returns it, then use the content:// scheme to access the icon data. I've never tried that, so I'd have to test it first before I could recommend it...Perdomo
@KickingLettuce use Uri with scheme: content:// or file://, the former needs ContentProvider support (which you already have i assume), the latter points to the physical file system where you store imagesTaber
Thanks for your help. I'd be lying if I said I understood this. This was far more complicated then I wanted before I set out. I simply wanted to retrieve an image from the web (url), and populate what seems like an ImageView. It seems you can't do that directly here. As far as a ContentProvider: kind of. I am doing this inside a SearchRecentSuggestionsProvider class, in the query method. It gets results first from recent suggestions, then the web once user types more than 2 char's.We can rule out file:// since this isn't local. That is all I am really sure of.Chuch
@KickingLettuce The app I'm responsible for has server-generated suggestions as well (although each one falls into one of three categories so I only have three icons, which come from the app), so I've already been down this path. I started out about where you are, then I ended up ditching SearchManager altogether. I put aSearchView on the action bar, then use an AsyncTask to do the remote access and return a MatrixCursor to drive the adapter for the SearchView and got ContentProvider completely out of the way.Perdomo
@krislarson Well that sounds similar, except I am using Retrofit and not a task to do that. Just for your reference, I added the entire class above. It really consists of the one method mostly. Not too big.Chuch

© 2022 - 2024 — McMap. All rights reserved.