Support app bar customization

Introduce ui_guides.xml which contains spacers that can be referenced
by other views to give them the right offsets.

GuidelinesUpdater is tasked with updating those views based on
the insets computed by the car-ui-lib.

Include the new toolbar layout and guides and constrain Media UI elements
to them.

Fixes: 155102696
Test: manual and with VerticalToolbarRRO
Change-Id: I4ad6a570640777c21d097bc6c032cbe3df3b656b
diff --git a/res/layout/fragment_browse.xml b/res/layout/fragment_browse.xml
index 60216a9..6a10890 100644
--- a/res/layout/fragment_browse.xml
+++ b/res/layout/fragment_browse.xml
@@ -20,14 +20,16 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
+    <include layout="@layout/ui_guides"/>
+
     <ImageView
         android:id="@+id/error_icon"
         android:layout_width="@dimen/missing_permission_icon_size"
         android:layout_height="@dimen/missing_permission_icon_size"
-        app:layout_constraintTop_toBottomOf="@+id/app_bar"
+        app:layout_constraintTop_toBottomOf="@+id/ui_content_top_guideline"
         app:layout_constraintBottom_toTopOf="@+id/error_message"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="@+id/ui_content_start_guideline"
+        app:layout_constraintEnd_toEndOf="@+id/ui_content_end_guideline"
         app:layout_constraintVertical_chainStyle="packed"
         android:src="@drawable/error_illustration"
         android:visibility="gone"
@@ -40,17 +42,21 @@
         android:layout_height="wrap_content"
         android:layout_marginTop="@dimen/browse_state_error_margin_top"
         app:layout_constraintTop_toBottomOf="@+id/error_icon"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintBottom_toBottomOf="@+id/ui_content_bottom_guideline"
+        app:layout_constraintStart_toStartOf="@+id/ui_content_start_guideline"
+        app:layout_constraintEnd_toEndOf="@+id/ui_content_end_guideline"
         android:maxLines="3"
         android:text="@string/nothing_to_play"
         android:visibility="gone" />
 
     <com.android.car.ui.recyclerview.CarUiRecyclerView
         android:id="@+id/browse_list"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        app:layout_constraintStart_toStartOf="@+id/ui_content_start_guideline"
+        app:layout_constraintEnd_toEndOf="@+id/ui_content_end_guideline"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toTopOf="@+id/ui_content_bottom_guideline"
         android:clickable="true"
         android:focusable="true"
         android:clipToPadding="false"
@@ -59,12 +65,6 @@
         app:numOfColumns="@integer/num_browse_columns"
     />
 
-    <com.android.car.media.widgets.AppBarView
-        android:id="@+id/app_bar"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        app:layout_constraintTop_toTopOf="parent"
-        app:showMenuItemsWhileSearching="false"
-    />
+    <include layout="@layout/car_ui_base_layout_toolbar"/>
 
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/res/layout/fragment_error.xml b/res/layout/fragment_error.xml
index 872adc2..7a70cc7 100644
--- a/res/layout/fragment_error.xml
+++ b/res/layout/fragment_error.xml
@@ -21,14 +21,16 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
+    <include layout="@layout/ui_guides"/>
+
     <com.android.car.apps.common.UxrTextView
         android:id="@+id/error_message"
         style="@style/FullScreenErrorMessageStyle"
         android:layout_marginHorizontal="@dimen/fragment_error_message_margin_x"
         app:layout_constraintVertical_chainStyle="packed"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/app_bar"
+        app:layout_constraintStart_toStartOf="@+id/ui_content_start_guideline"
+        app:layout_constraintEnd_toEndOf="@+id/ui_content_end_guideline"
+        app:layout_constraintTop_toBottomOf="@+id/ui_content_top_guideline"
         app:layout_constraintBottom_toTopOf="@+id/error_button"
     />
 
@@ -37,18 +39,12 @@
         style="@style/FullScreenErrorButtonStyle"
         android:layout_marginTop="@dimen/fragment_error_button_margin_top"
         android:layout_marginBottom="@dimen/fragment_error_button_margin_bottom"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="@+id/ui_content_start_guideline"
+        app:layout_constraintEnd_toEndOf="@+id/ui_content_end_guideline"
         app:layout_constraintTop_toBottomOf="@+id/error_message"
-        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintBottom_toBottomOf="@+id/ui_content_bottom_guideline"
     />
 
-    <com.android.car.media.widgets.AppBarView
-        android:id="@+id/app_bar"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        app:layout_constraintTop_toTopOf="parent"
-        app:showMenuItemsWhileSearching="false"
-    />
+    <include layout="@layout/car_ui_base_layout_toolbar"/>
 
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/res/layout/fragment_playback.xml b/res/layout/fragment_playback.xml
index 50eeb3e..6d090a9 100644
--- a/res/layout/fragment_playback.xml
+++ b/res/layout/fragment_playback.xml
@@ -21,12 +21,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <androidx.constraintlayout.widget.Guideline
-        android:id="@+id/app_bar_guideline"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        app:layout_constraintGuide_begin="@dimen/car_ui_toolbar_first_row_height"/>
+    <include layout="@layout/ui_guides"/>
 
     <Space
         android:id="@+id/control_bar_first_row_guideline"
@@ -50,13 +45,7 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"/>
 
-    <com.android.car.ui.toolbar.Toolbar
-        android:id="@+id/toolbar"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        app:title="@string/fragment_playback_title"
-        app:layout_constraintTop_toTopOf="parent"
-        app:car_ui_state="subpage"/>
+    <include layout="@layout/car_ui_base_layout_toolbar"/>
 
     <include
         style="@style/MetadataContainerStyle"
@@ -64,7 +53,7 @@
         layout="@layout/metadata_normal"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/app_bar_guideline"
+        app:layout_constraintTop_toBottomOf="@id/ui_content_top_guideline"
         app:layout_constraintBottom_toTopOf="@+id/control_bar_first_row_guideline"/>
 
     <!-- @id/seek_bar should be hidden when @id/control_bar_scrim is expanded, and shown when the
@@ -102,7 +91,7 @@
         android:id="@+id/queue_list_top_constraint"
         android:layout_width="match_parent"
         android:layout_height="@dimen/fragment_playback_queue_overlap_top"
-        app:layout_constraintBottom_toBottomOf="@+id/app_bar_guideline"/>
+        app:layout_constraintBottom_toBottomOf="@+id/ui_content_top_guideline"/>
 
     <Space
         android:id="@+id/queue_list_bottom_constraint"
diff --git a/res/layout/ui_guides.xml b/res/layout/ui_guides.xml
new file mode 100644
index 0000000..a2312f7
--- /dev/null
+++ b/res/layout/ui_guides.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<merge
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <Space
+        android:id="@+id/ui_content_start_guideline"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_marginLeft="0dp"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+    />
+
+    <Space
+        android:id="@+id/ui_content_top_guideline"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_marginTop="@dimen/car_ui_toolbar_first_row_height"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+    />
+
+    <Space
+        android:id="@+id/ui_content_end_guideline"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_marginRight="0dp"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+    />
+
+    <Space
+        android:id="@+id/ui_content_bottom_guideline"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_marginBottom="0dp"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+    />
+
+</merge>
diff --git a/src/com/android/car/media/BrowseViewController.java b/src/com/android/car/media/BrowseViewController.java
index dd6de4b..2aff6b4 100644
--- a/src/com/android/car/media/BrowseViewController.java
+++ b/src/com/android/car/media/BrowseViewController.java
@@ -44,7 +44,7 @@
 import com.android.car.media.common.MediaItemMetadata;
 import com.android.car.media.common.browse.MediaBrowserViewModel;
 import com.android.car.media.common.source.MediaSource;
-import com.android.car.media.widgets.AppBarView;
+import com.android.car.media.widgets.AppBarController;
 import com.android.car.ui.toolbar.Toolbar;
 
 import java.util.ArrayList;
@@ -220,7 +220,7 @@
 
         if (mIsSearchController) {
             updateSearchQuery(mViewModel.getSearchQuery());
-            mAppBarView.setSearchQuery(mSearchQuery);
+            mAppBarController.setSearchQuery(mSearchQuery);
             mBrowseStack = mViewModel.getSearchStack();
             mShowSearchResults.setValue(isAtTopStack());
         } else {
@@ -249,7 +249,7 @@
         mLoadingIndicatorDelay = mContent.getContext().getResources()
                 .getInteger(R.integer.progress_indicator_delay);
 
-        mAppBarView.setListener(mAppBarListener);
+        mAppBarController.setListener(mAppBarListener);
         mBrowseList = mContent.findViewById(R.id.browse_list);
         mErrorIcon = mContent.findViewById(R.id.error_icon);
         mMessage = mContent.findViewById(R.id.error_message);
@@ -268,7 +268,7 @@
                 .observe(activity, futureData -> onItemsUpdate(/* forRoot */ true, futureData));
 
         mRootMediaBrowserViewModel.supportsSearch().observe(activity,
-                mAppBarView::setSearchSupported);
+                mAppBarController::setSearchSupported);
 
 
         // Browse logic for current node
@@ -297,7 +297,7 @@
         updateAppBar();
     }
 
-    private AppBarView.AppBarListener mAppBarListener = new BasicAppBarListener() {
+    private AppBarController.AppBarListener mAppBarListener = new BasicAppBarListener() {
         @Override
         public void onTabSelected(MediaItemMetadata item) {
             if (mAcceptTabSelection) {
@@ -450,8 +450,8 @@
         mTopItems = items;
 
         if (mTopItems == null || mTopItems.isEmpty()) {
-            mAppBarView.setItems(null);
-            mAppBarView.setActiveItem(null);
+            mAppBarController.setItems(null);
+            mAppBarController.setActiveItem(null);
             if (items != null) {
                 // Only do this when not loading the tabs or we loose the saved one.
                 showTopItem(null);
@@ -463,11 +463,11 @@
         MediaItemMetadata oldTab = mViewModel.getSelectedTab();
         try {
             mAcceptTabSelection = false;
-            mAppBarView.setItems(mTopItems.size() == 1 ? null : mTopItems);
+            mAppBarController.setItems(mTopItems.size() == 1 ? null : mTopItems);
             updateAppBar();
 
             if (items.contains(oldTab)) {
-                mAppBarView.setActiveItem(oldTab);
+                mAppBarController.setActiveItem(oldTab);
             } else {
                 showTopItem(items.get(0));
             }
@@ -495,7 +495,7 @@
             title = getAppBarDefaultTitle(mediaSource);
         }
 
-        mAppBarView.setTitle(title);
+        mAppBarController.setTitle(title);
     }
 
     /**
@@ -509,8 +509,8 @@
         Toolbar.State unstackedState =
                 mIsSearchController ? Toolbar.State.SEARCH : Toolbar.State.HOME;
         updateAppBarTitle();
-        mAppBarView.setState(isStacked ? Toolbar.State.SUBPAGE : unstackedState);
-        mAppBarView.showSearchIfSupported(!mIsSearchController || isStacked);
+        mAppBarController.setState(isStacked ? Toolbar.State.SUBPAGE : unstackedState);
+        mAppBarController.showSearchIfSupported(!mIsSearchController || isStacked);
     }
 
     private String getErrorMessage(boolean forRoot) {
diff --git a/src/com/android/car/media/ErrorViewController.java b/src/com/android/car/media/ErrorViewController.java
index e455092..f67e22c 100644
--- a/src/com/android/car/media/ErrorViewController.java
+++ b/src/com/android/car/media/ErrorViewController.java
@@ -40,8 +40,8 @@
     void onMediaSourceChanged(@Nullable MediaSource mediaSource) {
         super.onMediaSourceChanged(mediaSource);
 
-        mAppBarView.setListener(new BasicAppBarListener());
-        mAppBarView.setTitle(getAppBarDefaultTitle(mediaSource));
+        mAppBarController.setListener(new BasicAppBarListener());
+        mAppBarController.setTitle(getAppBarDefaultTitle(mediaSource));
 
         ViewUtils.hideViewAnimated(mErrorMessageView, 0);
         ViewUtils.hideViewAnimated(mErrorButton, 0);
diff --git a/src/com/android/car/media/GuidelinesUpdater.java b/src/com/android/car/media/GuidelinesUpdater.java
new file mode 100644
index 0000000..c546298
--- /dev/null
+++ b/src/com/android/car/media/GuidelinesUpdater.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.media;
+
+import android.app.Activity;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.car.ui.baselayout.Insets;
+import com.android.car.ui.baselayout.InsetsChangedListener;
+import com.android.car.ui.core.BaseLayoutController;
+import com.android.car.ui.utils.CarUiUtils;
+
+/**
+ * Applies the insets computed by the car-ui-lib to the spacer views in ui_guides.xml. This allows
+ * the Media app to have different instances of the application bar.
+ */
+class GuidelinesUpdater implements InsetsChangedListener {
+
+    private final View mGuidedView;
+
+    public GuidelinesUpdater(Activity activity, View guidedView) {
+        mGuidedView = guidedView;
+
+        View baseLayout = mGuidedView.findViewWithTag("CarUiBaseLayoutToolbar");
+        View content = CarUiUtils.requireViewByRefId(baseLayout, R.id.content);
+        InsetsUpdater insetsUpdater = new InsetsUpdater(activity, baseLayout, content, this);
+    }
+
+    // Read the results of the base layout measurements and adjust the guidelines to match
+    public void onCarUiInsetsChanged(@NonNull Insets insets) {
+        View startPad = mGuidedView.findViewById(R.id.ui_content_start_guideline);
+        ConstraintLayout.LayoutParams start =
+                (ConstraintLayout.LayoutParams)startPad.getLayoutParams();
+        start.setMargins(insets.getLeft(), 0,0, 0);
+        startPad.setLayoutParams(start);
+
+        View endPad = mGuidedView.findViewById(R.id.ui_content_end_guideline);
+        ConstraintLayout.LayoutParams end = (ConstraintLayout.LayoutParams)endPad.getLayoutParams();
+        end.setMargins(0, 0, insets.getRight(), 0);
+        endPad.setLayoutParams(end);
+
+        View topPad = mGuidedView.findViewById(R.id.ui_content_top_guideline);
+        ConstraintLayout.LayoutParams top = (ConstraintLayout.LayoutParams)topPad.getLayoutParams();
+        top.setMargins(0, insets.getTop(), 0, 0);
+        topPad.setLayoutParams(top);
+
+        View bottomPad = mGuidedView.findViewById(R.id.ui_content_bottom_guideline);
+        ConstraintLayout.LayoutParams bottom =
+                (ConstraintLayout.LayoutParams)bottomPad.getLayoutParams();
+        bottom.setMargins(0, 0, 0, insets.getBottom());
+        bottomPad.setLayoutParams(bottom);
+    }
+
+
+
+    private static class InsetsUpdater extends BaseLayoutController.InsetsUpdater {
+
+        private final View mContentView;
+
+        InsetsUpdater(Activity activity, View baseLayout, View contentView,
+                InsetsChangedListener listener) {
+            super(activity, baseLayout, contentView);
+            replaceInsetsChangedListenerWith(listener);
+            mContentView = contentView;
+
+            installListeners();
+        }
+
+        @Override
+        protected View getContentView() {
+            return mContentView;
+        }
+    }
+}
diff --git a/src/com/android/car/media/PlaybackFragment.java b/src/com/android/car/media/PlaybackFragment.java
index dcaf7dc..0277ea4 100644
--- a/src/com/android/car/media/PlaybackFragment.java
+++ b/src/com/android/car/media/PlaybackFragment.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
-import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.os.Bundle;
@@ -51,6 +50,7 @@
 import com.android.car.media.common.PlaybackControlsActionBar;
 import com.android.car.media.common.playback.PlaybackViewModel;
 import com.android.car.media.common.source.MediaSourceViewModel;
+import com.android.car.media.widgets.AppBarController;
 import com.android.car.ui.toolbar.MenuItem;
 import com.android.car.ui.toolbar.Toolbar;
 
@@ -69,6 +69,7 @@
     private static final String TAG = "PlaybackFragment";
 
     private ImageBinder<MediaItemMetadata.ArtworkRef> mAlbumArtBinder;
+    private AppBarController mAppBarController;
     private BackgroundImageView mAlbumBackground;
     private View mBackgroundScrim;
     private View mControlBarScrim;
@@ -77,7 +78,6 @@
     private RecyclerView mQueue;
     private ViewGroup mSeekBarContainer;
     private SeekBar mSeekBar;
-    private Toolbar mToolbar;
     private List<View> mViewsToHideForCustomActions;
     private List<View> mViewsToHideWhenQueueIsVisible;
     private List<View> mViewsToShowWhenQueueIsVisible;
@@ -357,26 +357,27 @@
         mQueue = view.findViewById(R.id.queue_list);
         mSeekBarContainer = view.findViewById(R.id.seek_bar_container);
         mSeekBar = view.findViewById(R.id.seek_bar);
-        mToolbar = view.findViewById(R.id.toolbar);
-        if (mToolbar != null) {
-            mToolbar.setBackgroundShown(false);
-            mToolbar.setNavButtonMode(Toolbar.NavButtonMode.DOWN);
+        mAppBarController = new AppBarController(view);
 
-            // Notify listeners when toolbar's down button is pressed.
-            mToolbar.registerOnBackListener(() -> {
-                if (mListener != null) {
-                    mListener.onCollapse();
-                }
-                return true;
-            });
+        mAppBarController.setTitle(R.string.fragment_playback_title);
+        mAppBarController.setBackgroundShown(false);
+        mAppBarController.setNavButtonMode(Toolbar.NavButtonMode.DOWN);
 
-            // Update toolbar's logo
-            MediaSourceViewModel mediaSourceViewModel = getMediaSourceViewModel();
-            mediaSourceViewModel.getPrimaryMediaSource().observe(this, mediaSource ->
-                mToolbar.setLogo(mediaSource != null
-                        ? new BitmapDrawable(getResources(), mediaSource.getCroppedPackageIcon())
-                        : null));
-        }
+        // Notify listeners when toolbar's down button is pressed.
+        mAppBarController.registerOnBackListener(() -> {
+            if (mListener != null) {
+                mListener.onCollapse();
+            }
+            return true;
+        });
+
+        // Update toolbar's logo
+        MediaSourceViewModel mediaSourceViewModel = getMediaSourceViewModel();
+        mediaSourceViewModel.getPrimaryMediaSource().observe(this, mediaSource ->
+                mAppBarController.setLogo(mediaSource != null
+                    ? new BitmapDrawable(getResources(), mediaSource.getCroppedPackageIcon())
+                    : null));
+
         mBackgroundScrim = view.findViewById(R.id.background_scrim);
         ViewUtils.setVisible(mBackgroundScrim, false);
         mControlBarScrim = view.findViewById(R.id.control_bar_scrim);
@@ -453,6 +454,7 @@
                 item -> mAlbumArtBinder.setImage(PlaybackFragment.this.getContext(),
                         item != null ? item.getArtworkKey() : null));
 
+        new GuidelinesUpdater(requireActivity(), view);
         return view;
     }
 
@@ -583,17 +585,15 @@
     private void setQueueVisible(boolean visible) {
         mQueueIsVisible = visible;
 
-        if (mToolbar != null) {
-            if (mHasQueue) {
-                MenuItem queueMenuItem = MenuItem.builder(getContext())
-                        .setIcon(R.drawable.ic_queue_button)
-                        .setActivated(mQueueIsVisible)
-                        .setOnClickListener(button -> toggleQueueVisibility())
-                        .build();
-                mToolbar.setMenuItems(Collections.singletonList(queueMenuItem));
-            } else {
-                mToolbar.setMenuItems(Collections.emptyList());
-            }
+        if (mHasQueue) {
+            MenuItem queueMenuItem = MenuItem.builder(getContext())
+                    .setIcon(R.drawable.ic_queue_button)
+                    .setActivated(mQueueIsVisible)
+                    .setOnClickListener(button -> toggleQueueVisibility())
+                    .build();
+            mAppBarController.setMenuItems(Collections.singletonList(queueMenuItem));
+        } else {
+            mAppBarController.setMenuItems(Collections.emptyList());
         }
 
         if (mQueueIsVisible) {
diff --git a/src/com/android/car/media/ViewControllerBase.java b/src/com/android/car/media/ViewControllerBase.java
index a4c413d..156c6b2 100644
--- a/src/com/android/car/media/ViewControllerBase.java
+++ b/src/com/android/car/media/ViewControllerBase.java
@@ -40,7 +40,7 @@
 import com.android.car.apps.common.util.CarPackageManagerUtils;
 import com.android.car.media.common.source.MediaSource;
 import com.android.car.media.common.source.MediaSourceViewModel;
-import com.android.car.media.widgets.AppBarView;
+import com.android.car.media.widgets.AppBarController;
 
 /**
  * Functionality common to content view controllers. It mainly handles the AppBar view,
@@ -55,7 +55,7 @@
     final FragmentActivity mActivity;
     final int mFadeDuration;
     final View mContent;
-    final AppBarView mAppBarView;
+    final AppBarController mAppBarController;
     final MediaSourceViewModel mMediaSourceVM;
 
     private Intent mCurrentSourcePreferences;
@@ -70,9 +70,9 @@
         LayoutInflater inflater = LayoutInflater.from(container.getContext());
         mContent = inflater.inflate(resource, container, false);
 
-        mAppBarView = mContent.findViewById(R.id.app_bar);
-        mAppBarView.setSearchSupported(false);
-        mAppBarView.setHasEqualizer(false);
+        mAppBarController = new AppBarController(mContent);
+        mAppBarController.setSearchSupported(false);
+        mAppBarController.setHasEqualizer(false);
 
         container.addView(mContent);
 
@@ -80,6 +80,8 @@
 
         mMediaSourceVM = MediaSourceViewModel.get(activity.getApplication(),
                 MEDIA_SOURCE_MODE_BROWSE);
+
+        new GuidelinesUpdater(activity, mContent);
     }
 
     CharSequence getAppBarDefaultTitle(@Nullable MediaSource mediaSource) {
@@ -87,7 +89,7 @@
                 : mActivity.getResources().getString(R.string.media_app_title);
     }
 
-    class BasicAppBarListener extends AppBarView.AppBarListener {
+    class BasicAppBarListener extends AppBarController.AppBarListener {
         @Override
         protected void onSettingsSelection() {
             if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -127,8 +129,8 @@
             packageName = mediaSource.getPackageName();
         }
 
-        mAppBarView.setLogo(icon);
-        mAppBarView.setSearchIcon(searchIcon);
+        mAppBarController.setLogo(icon);
+        mAppBarController.setSearchIcon(searchIcon);
         updateSourcePreferences(packageName);
     }
 
@@ -142,13 +144,13 @@
             if (info != null && info.activityInfo != null && info.activityInfo.exported) {
                 mCurrentSourcePreferences = new Intent(prefsIntent.getAction())
                         .setClassName(info.activityInfo.packageName, info.activityInfo.name);
-                mAppBarView.setSettingsDistractionOptimized(
+                mAppBarController.setSettingsDistractionOptimized(
                         CarPackageManagerUtils.isDistractionOptimized(
                                 mCarPackageManager, info.activityInfo));
             }
         }
-        mAppBarView.setHasSettings(mCurrentSourcePreferences != null);
-        mAppBarView.setHasEqualizer(mShouldShowSoundSettings);
+        mAppBarController.setHasSettings(mCurrentSourcePreferences != null);
+        mAppBarController.setHasEqualizer(mShouldShowSoundSettings);
     }
 
 
diff --git a/src/com/android/car/media/widgets/AppBarView.java b/src/com/android/car/media/widgets/AppBarController.java
similarity index 87%
rename from src/com/android/car/media/widgets/AppBarView.java
rename to src/com/android/car/media/widgets/AppBarController.java
index b17a773..e319d96 100644
--- a/src/com/android/car/media/widgets/AppBarView.java
+++ b/src/com/android/car/media/widgets/AppBarController.java
@@ -3,7 +3,7 @@
 import android.car.drivingstate.CarUxRestrictions;
 import android.content.Context;
 import android.content.Intent;
-import android.util.AttributeSet;
+import android.view.View;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -13,6 +13,7 @@
 import com.android.car.media.common.source.MediaSource;
 import com.android.car.ui.toolbar.MenuItem;
 import com.android.car.ui.toolbar.Toolbar;
+import com.android.car.ui.toolbar.ToolbarControllerImpl;
 
 import java.util.Arrays;
 import java.util.List;
@@ -24,13 +25,14 @@
  * views via {@link #setState}. A detailed explanation of all possible states of this application
  * bar can be seen at {@link Toolbar.State}.
  */
-public class AppBarView extends Toolbar {
+public class AppBarController extends ToolbarControllerImpl {
 
     private static final int MEDIA_UX_RESTRICTION_DEFAULT =
             CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP;
     private static final int MEDIA_UX_RESTRICTION_NONE = CarUxRestrictions.UX_RESTRICTIONS_BASELINE;
 
     private int mMaxTabs;
+    private final Context mContext;
 
     @NonNull
     private AppBarListener mListener = new AppBarListener();
@@ -84,23 +86,12 @@
         protected void onHeightChanged(int height) {}
     }
 
-    public AppBarView(Context context) {
-        this(context, null);
-    }
+    public AppBarController(View view) {
+        super(view);
+        mContext = view.getContext();
+        mMaxTabs = mContext.getResources().getInteger(R.integer.max_tabs);
 
-    public AppBarView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public AppBarView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        init(context);
-    }
-
-    private void init(Context context) {
-        mMaxTabs = context.getResources().getInteger(R.integer.max_tabs);
-
-        mAppSelectorIntent = MediaSource.getSourceSelectorIntent(context, false);
+        mAppSelectorIntent = MediaSource.getSourceSelectorIntent(mContext, false);
 
         registerOnTabSelectedListener(tab ->
                 mListener.onTabSelected(((MediaItemTab) tab).getItem()));
@@ -110,21 +101,21 @@
         });
         registerOnSearchListener(query -> mListener.onSearch(query));
         registerToolbarHeightChangeListener(height -> mListener.onHeightChanged(height));
-        mSearch = MenuItem.Builder.createSearch(context, v -> mListener.onSearchSelection());
-        mSettings = new MenuItem.Builder(context)
+        mSearch = MenuItem.Builder.createSearch(mContext, v -> mListener.onSearchSelection());
+        mSettings = new MenuItem.Builder(mContext)
                 .setToSettings()
                 .setUxRestrictions(MEDIA_UX_RESTRICTION_DEFAULT)
                 .setOnClickListener(v -> mListener.onSettingsSelection())
                 .build();
-        mEqualizer = new MenuItem.Builder(context)
+        mEqualizer = new MenuItem.Builder(mContext)
                 .setTitle(R.string.menu_item_sound_settings_title)
                 .setIcon(R.drawable.ic_equalizer)
                 .setOnClickListener(v -> mListener.onEqualizerSelection())
                 .build();
-        mAppSelector = new MenuItem.Builder(context)
+        mAppSelector = new MenuItem.Builder(mContext)
                 .setTitle(R.string.menu_item_app_selector_title)
                 .setIcon(R.drawable.ic_app_switch)
-                .setOnClickListener(m -> getContext().startActivity(mAppSelectorIntent))
+                .setOnClickListener(m -> mContext.startActivity(mAppSelectorIntent))
                 .build();
         setMenuItems(Arrays.asList(mSearch, mEqualizer, mSettings, mAppSelector));