## Request search content UI view generator

We have added the support of returning search content UI view in the SDK.
`Search Content` is a general term representing multiple types of content
features, check following sections for how to request each type of content
feature respectively.

### Search repeat

To get the UI view for search repeat, you should get its search content
generator first by the following steps:

1. Override `GetSearchContentViewGeneratorCallback` class's `onSuccess` and `onError` methods.
2. Create an instance for the `GetSearchContentViewGeneratorCallback` class.
3. Construct the `GetSearchContentViewOptions` class instance and set the search repeat context by calling the method `setSearchRepeatContext`. (Optional) This object also takes a `SearchContentViewOptions` object which provides some options to customize the appearance of the UI.
4. Call `SearchInAppsService`'s `getSearchContentView(GetSearchContentViewOptions,
   GetSearchContentViewGeneratorCallback)` function.
5. After you get the UI generator, you can consider storing it in a ViewModel so that you don't need to ask for the generator again when the activity needs to recreate (like when the configuration has changed while the app is running).

Sample code

### Java

    package ...;

    ...
    import androidx.appcompat.app.AppCompatActivity;
    import com.google.android.libraries.searchinapps.GetSearchContentViewGeneratorCallback;
    import com.google.android.libraries.searchinapps.GetSearchContentViewOptions;
    import com.google.android.libraries.searchinapps.SearchInAppsService;
    import com.google.android.libraries.searchinapps.SearchContentViewGenerator;
    ...

    public class MainActivity extends AppCompatActivity {
      private SearchInAppsService service;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
        ...
        service = SearchInAppsService.create(this);
        GetSearchContentViewGeneratorCallback searchContentCallback =
          new GetSearchContentViewGeneratorCallback() {
            @Override
            public void onSuccess(SearchContentViewGenerator generator) {
              ...
            }

            @Override
            public void onError(String errorMessage) {
              ...
            }
          };

        // Uses the default SearchContentViewOptions.
        service.getSearchContentView(
          new GetSearchContentViewOptions().setSearchRepeatContext(
              "sample search repeat"), searchContentCallback);
        ...
      }

      @Override
      public void onDestroy() {
        service.shutDown();
        super.onDestroy();
      }
    }

### Jetpack Compose

    package ...

    ...
    import android.os.Bundle
    import androidx.activity.compose.setContent
    import androidx.appcompat.app.AppCompatActivity
    import androidx.compose.runtime.Composable
    import androidx.compose.runtime.DisposableEffect
    import androidx.compose.runtime.mutableStateOf
    import androidx.compose.ui.platform.LocalContext
    import com.google.android.libraries.searchinapps.GetSearchContentViewGeneratorCallback
    import com.google.android.libraries.searchinapps.GetSearchContentViewOptions
    import com.google.android.libraries.searchinapps.SearchInAppsService
    import com.google.android.libraries.searchinapps.SearchContentViewGenerator
    ...

    class MainActivity : AppCompatActivity() {
      override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
          SearchRepeatUI()
        }
      }

      @Composable
      fun SearchRepeatUI() {
        ...
        var service by remember {
          mutableStateOf<SearchInAppsService?>(
            SearchInAppsService.create(LocalContext.current))
        }
        DisposableEffect(Unit) { onDispose { service?.shutDown() } }
        val callback =
                object : GetSearchContentViewGeneratorCallback() {
                  override fun onSuccess(generator: SearchContentViewGenerator) {
                    ...
                  }

                  override fun onError(errorMessage: String) {
                    ...
                  }
                }
        // Uses the default SearchContentViewOptions.
        var options: GetSearchContentViewOptions =
                GetSearchContentViewOptions()
                  .setSearchRepeatContext("sample search repeat")
        service?.let { service ->
          service.getSearchContentView(options, callback)
        }
        ...
      }
    }

## Add search content UI View

For `getSearchContentView`, the final output is a `SearchContentViewGenerator`
object. You can use this object's `populateView(Context, int)` function to
generate the UI view and `updateView(View, Context)` to update the existing view
(especially for Jetpack Compose apps).

For Jetpack Compose apps, you should use [AndroidView](https://developer.android.com/jetpack/compose/migrate/interoperability-apis/views-in-compose) to consume the
generated classic view.

Sample code

### Java

    package ...;

    ...
    import androidx.appcompat.app.AppCompatActivity;
    import com.google.android.libraries.searchinapps.GetSearchContentViewGeneratorCallback;
    import com.google.android.libraries.searchinapps.GetSearchContentViewOptions;
    import com.google.android.libraries.searchinapps.SearchInAppsService;
    import com.google.android.libraries.searchinapps.SearchContentViewGenerator;
    import java.util.Arrays;
    import java.util.List;
    ...

    public class MainActivity extends AppCompatActivity {
      private SearchInAppsService service;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
        ...
        service = SearchInAppsService.create(this);
        GetSearchContentViewGeneratorCallback searchContentCallback =
          new GetSearchContentViewGeneratorCallback() {
            @Override
            public void onSuccess(SearchContentViewGenerator generator) {
              ViewGroup container = findViewById(R.id.[container_id]);
              container.removeAllViews();
              searchContentBlock = 0;
              // If you don't specify "numberOfBlocksToRequest" in
              // GetSearchContentViewOptions, by default
              // SearchContentViewGenerator.getSearchContentBlockCount() always
              // returns 1.
              while (searchContentBlock <
                generator.getSearchContentBlockCount()) {
                  container.addView(
                      generator.populateView(MainActivity.this,
                        searchContentBlock));
                  searchContentBlock++;
              }
            }

            @Override
            public void onError(String errorMessage) {
              ...
            }
          };

        // Uses the default SearchContentViewOptions.
        service.getSearchContentView(
          new GetSearchContentViewOptions().setSearchRepeatContext(
            "sample search repeat"), searchContentCallback);
        ...
      }

      @Override
      public void onDestroy() {
        service.shutDown();
        super.onDestroy();
      }
    }

### Jetpack Compose

    package ...

    ...
    import android.os.Bundle
    import androidx.activity.compose.setContent
    import androidx.appcompat.app.AppCompatActivity
    import androidx.compose.foundation.layout.Column
    import androidx.compose.foundation.layout.Row
    import androidx.compose.foundation.rememberScrollState
    import androidx.compose.foundation.verticalScroll
    import androidx.compose.runtime.Composable
    import androidx.compose.runtime.DisposableEffect
    import androidx.compose.runtime.mutableStateOf
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.platform.LocalContext
    import androidx.compose.ui.viewinterop.AndroidView
    import com.google.android.libraries.searchinapps.GetSearchContentViewGeneratorCallback
    import com.google.android.libraries.searchinapps.GetSearchContentViewOptions
    import com.google.android.libraries.searchinapps.SearchInAppsService
    import com.google.android.libraries.searchinapps.SearchContentViewGenerator
    ...

    class MainActivity : AppCompatActivity() {
      override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent { SearchRepeatUI() }
      }

      @Composable
      fun SearchRepeatUI() {
        ...
        var service by remember {
          mutableStateOf<SearchInAppsService?>(
            SearchInAppsService.create(LocalContext.current))
        }
        var viewGenerator by remember {
            mutableStateOf<SearchContentViewGenerator?>(null) }
        var searchContentBlockNumber by remember { mutableStateOf(0) }
        DisposableEffect(Unit) { onDispose { service?.shutDown() } }
        val callback =
                object : GetSearchContentViewGeneratorCallback() {
                  override fun onSuccess(
                      generator: SearchContentViewGenerator) {
                    viewGenerator = generator
                    // If you don't specify "numberOfBlocksToRequest" in
                    // GetSearchContentViewOptions, by default
                    // SearchContentViewGenerator.getSearchContentBlockCount()
                    // always returns 1.
                    searchContentBlockNumber =
                      generator.getSearchContentBlockCount()
                  }

                  override fun onError(errorMessage: String) {
                    ...
                  }
                }
        // Uses the default SearchContentViewOptions.
        var options: GetSearchContentViewOptions =
                GetSearchContentViewOptions()
                  .setSearchRepeatContext("sample search repeat")
        service?.getSearchContentView(options, callback)
        SearchRepeatUIComposable(viewGenerator, searchContentBlockNumber)
        ...
    }

      @Composable
      fun SearchRepeatUIComposable(viewGenerator: SearchContentViewGenerator?,
      searchContentBlockNumber: Int,) {
        viewContentGenerator?.let { viewContentGenerator ->
          var context = LocalContext.current
          Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
          for (index in 0..searchContentBlockNumber - 1) {
            Row {
              AndroidView(
                factory = { context ->
                  viewContentGenerator.populateView(context, index) },
                update = { view ->
                  viewContentGenerator.updateView(view, context) },
              )
            }
          }
        }
      }
    }

[Next: Display search results](https://developers.google.com/search-in-apps/android/display_search_results)