2

I have implemented a search interface with recent searches suggestions as explained in the documentation, and for some reason the history icon comes from the wrong theme (dark instead of light.

enter image description here

My current task is to change this icon. I believe my theming is correct so I am trying to override the SearchRecentSuggestionsProvider but without any success. I took inspiration from 2 posts (there and there) I have tried the following things:

Override query() and specify another projection

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    Uri iconUri = Uri.parse("android.resource://" + getContext().getPackageName() + "/drawable/icon_search_history");
    projection = new String[] {
            "_id",
            "display1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1,
            "query AS " + SearchManager.SUGGEST_COLUMN_QUERY,
            "'" + iconUri + "'" + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1
    };

   return super.query(uri, projection, selection, selectionArgs, sortOrder);
}

I also tried overriding setupSuggestions()

@Override
protected void setupSuggestions(String authority, int mode) {
    super.setupSuggestions(authority, mode);
    Uri iconUri = Uri.parse("android.resource://" + RFDApplication.getApplicationPackageName() + "/drawable/icon_search_history");
    Field f = null;
    try {
        f = getClass().getDeclaredField("mSuggestionProjection");
        f.setAccessible(true);
        String[] projection = new String [] {
                "0 AS " + SearchManager.SUGGEST_COLUMN_FORMAT,
                "'" + iconUri + "'" + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1,
                "display1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1,
                "query AS " + SearchManager.SUGGEST_COLUMN_QUERY,
                "_id"};
        f.set(this,projection);


    } catch (Exception e) {
        e.printStackTrace();
    }
}

I never imagined I would have such a hard time changing an icon :) Any help or suggestion would be much appreciated...

EDIT I found a half satisfactory solution: replacing the whole cursor in query(). I would still prefer to avoid going iterating the results twice (although I know the overhead might be negligible in this case). So the question remains open

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    // File to use
    Cursor parent = super.query(uri, projection, selection, selectionArgs, sortOrder);
    Uri iconUri = Uri.parse("android.resource://" + getContext().getPackageName() + "/drawable/icon_search_history");
    MatrixCursor cursor = new MatrixCursor(parent.getColumnNames());
    parent.moveToFirst();
    while (parent.moveToNext()){
        cursor.addRow(new Object[]{
                parent.getInt(parent.getColumnIndex("suggest_format")),
                iconUri,
                parent.getString(parent.getColumnIndex("suggest_text_1")),
                parent.getString(parent.getColumnIndex("suggest_intent_query")),
                parent.getInt(parent.getColumnIndex("_id"))
        });
    }

   return cursor;
}
Community
  • 1
  • 1
znat
  • 13,144
  • 17
  • 71
  • 106

2 Answers2

4
  • Wrap the Cursor with the results; then override getString() to return your custom icon's uri.

In setupSuggestions(), SearchRecentSuggestionsProvider uses the private field mSuggestionProjection to define the alias SearchManager.SUGGEST_COLUMN_ICON_1 for the recents icon uri. This returned in the Cursor for all the recents you get when you query the provider.

Now, you don't want to do fishy things like using reflection to change private fields value, as they are implementation dependent and this is likely to break in the future. What you want to do instead, is to route every call from Cursor.getMyOldIconUri() to Cursor.getMyNewIconUri() so that from outside it looks like you effectively changed the icon. And you don't need to iterate through the results beforehand.

The implementation is straightforward with CursorWrapper:

String mIconUri; // a drawable ID as a String will also do!

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

    class Wrapper extends CursorWrapper {
         Wrapper(Cursor c) {
             super(c);
         }

         public String getString(int columnIndex) {
             if (columnIndex != -1
                 && columnIndex == getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1))
                 return mIconUri;

             return super.getString(columnIndex);
         }
    }  

    return new Wrapper(super.query(Uri uri, String[] projection, String selection,
       String[] selectionArgs, String sortOrder);
}
Gil Vegliach
  • 3,542
  • 2
  • 25
  • 37
0

Check this this documentation it's described in details. You have to change this : cursor.addRow(new Object[]{ parent.getInt(parent.getColumnIndex("suggest_format")), iconUri, parent.getString(parent.getColumnIndex("suggest_text_1")), parent.getString(parent.getColumnIndex("suggest_intent_query")), parent.getInt(parent.getColumnIndex("_id")) });

to : cursor.addRow(new Object[]{ parent.getString(parent.getColumnIndex("suggest_text_1")), iconUri, parent.getString(parent.getColumnIndex("suggest_intent_query")) });

and change this : projection = new String[] { "_id", "display1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, "query AS " + SearchManager.SUGGEST_COLUMN_QUERY, "'" + iconUri + "'" + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 };

to this : projection = { SearchManager.SUGGEST_COLUMN_TEXT_1, SearchManager.SUGGEST_COLUMN_ICON_1, SearchManager.SUGGEST_COLUMN_QUERY};

awsleiman
  • 1,879
  • 20
  • 14