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;
    }
}
TheLettuceMaster
  • 15,594
  • 48
  • 153
  • 259

2 Answers2

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);
Sergey
  • 106
  • 7
  • 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 ;) – TheLettuceMaster Aug 25 '17 at 22:06
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.

kris larson
  • 30,387
  • 5
  • 62
  • 74
  • 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). – TheLettuceMaster Aug 24 '15 at 04:12
  • 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 file – pskink Aug 24 '15 at 05:16
  • @KickingLettuce, I updated my answer to be a little more explicit and specific. Let me know if you have more questions. – kris larson Aug 24 '15 at 13:26
  • 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? – TheLettuceMaster Aug 24 '15 at 14:43
  • 1
    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... – kris larson Aug 24 '15 at 15:18
  • 1
    @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 images – pskink Aug 24 '15 at 16:58
  • 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. – TheLettuceMaster Aug 25 '15 at 15:06
  • @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 a`SearchView` 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. – kris larson Aug 25 '15 at 15:25
  • @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. – TheLettuceMaster Aug 25 '15 at 15:42