Advanced Place Details component

The Advanced version of the Place Details component offers the same features as Places Details Essentials. It also lets you configure the action buttons of the component and apply search and filtering options to the reviews and media that are displayed.

Advanced Place Details configuration

Use the AdvancedPlaceDetailsFragment or the AdvancedPlaceDetailsCompactFragment to access advanced features.

Configure action buttons

Use the PlaceActionProvider interface of the AdvancedPlaceDetailsFragment or the AdvancedPlaceDetailsCompactFragment to define and customize action buttons.

Visual attribution requirements

Place details compact view with customized buttons
Advanced Place Details compact view with customized button

Important: You must make it clear to end-users when a custom action button will share user information with a third party other than Google. See visual attribution requirements.

The example at the right shows a custom image that makes it clear that user information will be sent to "Altostrat".

Apply search and filtering options

Use the SearchMediaOptions and SearchReviewsOptions interfaces of AdvancedPlaceDetailsFragment or AdvancedPlaceDetailsCompactFragment to enable search and filtering for media or reviews.

Advanced Place Details examples

Customize action buttons

Use the PlaceActionProvider interface to control which actions are available for each place.

Kotlin

class PlaceDetailsWidgetTestActivity : BaseActivity() {

// simplified example of starting the fragment
fun setupPPDFragment() {
   fullWidgetSelectedContent = AdvancedPlaceDetailsFragment.ALL_CONTENT.toMutableList()
   AdvancedPlaceDetailsFragment.newInstance(fullWidgetSelectedContent, Orientation.VERTICAL)
   supportFragmentManager
      .beginTransaction()
      .replace(R.id.fragment_container, fragment!!)
      .commitNow()
}

// you can set the callback elsewhere, but this is the ideal callback spot
override fun onAttachFragment(fragment: Fragment) {
    super.onAttachFragment(fragment)
    when (fragment) {
      is PlaceActionController -> setPlaceActionProvider(fragment)
    }
}

// have this callback return an empty list to hide all buttons
// if this callback isn't set, default buttons appear
 private fun setPlaceActionProvider(fragment: PlaceActionController) {
    fragment.setPlaceActionProvider(
        object : PlaceActionProvider {
        override fun getMainPlaceActions(place: Place): List<PlaceAction> = buildList {
            // predefined actions can be mixed in with custom ones
            add(PlaceAction.OPEN_IN_MAPS)

            // example of button with both text label and icon
            add(
              PlaceAction.builder()
                .setLabelTextResId(R.string.custom_action)
                .setIconResId(R.drawable.gs_custom_action_icon)
                .setContentDescriptionResId(R.string.custom_action_description)
                .setOnClickListener { /* todo perform action */ }
                .build()
            )

            // icon only button
            add(
              PlaceAction.builder()
                .setIconResId(R.drawable.custom_action_icon_2)
                .setContentDescriptionResId(R.string.custom_action_description_2)
                .setOnClickListener { /* todo perform action */}
                .build()
            )

            // text label only button
            add(
              PlaceAction.builder()
                .setLabelTextResId(R.string.custom_action_3)
                .setContentDescriptionResId(R.string.custom_action_description_2)
                .setOnClickListener {/* todo perform action */ }
                .build()
            )
          }

         /**
         You can also specify whether corner buttons should appear.  
         For either callback, returning an empty list results in no buttons appearing
         */
         override fun getCornerPlaceActions(place: Place): List<PlaceAction> {
           return emptyList()
         }

        override fun addPlaceActionsChangedListener(
          listener: PlaceActionProvider.OnChangedListener
        ) {
          // in this example, just one listener and widget
          this@HostAppActivity.listener = listener
        }

        override fun removePlaceActionsChangedListener(
          listener: PlaceActionProvider.OnChangedListener
        ) {
          // if there are multiple listeners, remove only the provided listener
          this@HostAppActivity.listener = null
        }
      })
  }
}

Add custom and predefined actions

This sample adds a toggle button for a user to favorite or unfavorite a place.

Kotlin

private var listener: PlaceActionProvider.OnChangedListener? = null

private fun setPlaceActionProvider(fragment: PlaceActionController) {
    fragment.setPlaceActionProvider(
      object : PlaceActionProvider {
        private var placeFavorited = false

        override fun getMainPlaceActions(place: Place): List<PlaceAction> {
          val buttonList = mutableListOf<PlaceAction>()

          if (placeFavorited) {
            buttonList.add(
              PlaceAction.builder()
                .setLabelTextResId(R.string.place_details_button_config_favorite)
                .setIconResId(R.drawable.gs_web_vd_theme_24)
                .setOnClickListener {
                  placeFavorited = !placeFavorited
                  refreshButtonConfigs()
                }
                .build()
            )
          } else {
            buttonList.add(
              PlaceAction.builder()
                .setLabelTextResId(R.string.place_details_button_config_unfavorite)
                .setIconResId(R.drawable.gs_web_vd_theme_24)
                .setOnClickListener {
                  placeFavorited = !placeFavorited
                  refreshButtonConfigs()
                }
                .build()
            )
          }

          return buttonList
        }

        override fun addPlaceActionsChangedListener(
          listener: PlaceActionProvider.OnChangedListener
        ) {
          this@PlaceDetailsWidgetTestActivity.listener = listener
        }

        override fun removePlaceActionsChangedListener(
          listener: PlaceActionProvider.OnChangedListener
        ) {
          // if there are multiple listeners, remove only the provided listener
          this@PlaceDetailsWidgetTestActivity.listener = null
        }
      }
    )
  }

private fun refreshButtonConfigs() {
    listener?.onPlaceActionsChanged()
}

Use predefined standard buttons

Create action buttons that perform standard Google-defined actions.

Kotlin

  override fun getMainPlaceActions(place: Place): List<PlaceAction> {
    val buttonList = mutableListOf<PlaceAction>()
// these buttons will have different background and text color than user-created buttons.  
    // Text and icon button
    buttonList.add(PlaceAction.OPEN_IN_MAPS)
    // Icon-only buttons not enabled for main action buttons
    // Use of kotlin extension to do the same.  see
    PlaceAction.OPEN_IN_MAPS {
       setIconResId(0)
     }

    return buttonList
  }

Omit the Place name

Kotlin

// Omit this to hide the name.
// Non-pro fragments might also have the enum
AdvancedPlaceDetailsFragment.newInstance(
      listOf(
        //Content.NAME,
        Content.MEDIA,
        Content.ADDRESS,
        Content.RATING,
      ), orientation)

Filter reviews and media

This code sample shows only media and reviews that mention "spaghetti" and "tasty".

Kotlin

    import com.google.android.libraries.places.widget.AdvancedPlaceDetailsFragment
    import com.google.android.libraries.places.widget.model.SearchMediaOptions
    import com.google.android.libraries.places.widget.model.SearchReviewsOptions
    import com.google.android.libraries.places.widget.model.Orientation
    import com.google.android.libraries.places.R
  
     // 1. Create options using the Java builders (called from Kotlin)
    val mediaOptions = SearchMediaOptions.builder()
        .setQuery("spaghetti")
        .setRankPreference(SearchMediaOptions.RankPreference.MOST_RELEVANT)
        .build()

    val reviewOptions = SearchReviewsOptions.builder()
        .setQuery("tasty")
        .setRankPreference(SearchReviewsOptions.RankPreference.NEWEST)
        .build()

    // 2. Create the fragment
    val fragment = AdvancedPlaceDetailsFragment.newInstance(
        AdvancedPlaceDetailsFragment.STANDARD_CONTENT,
        Orientation.VERTICAL,
        R.style.PlacesMaterialTheme
    )

    // 3. Apply options to the fragment
    fragment.applySearchMediaOptions(mediaOptions)
    fragment.applySearchReviewsOptions(reviewOptions)