Combine settings suggestion and condition.

- Add a flag in dashboard feature provider to specify whether to use the
combined UI for suggestions and conditions.
- Move Conditions below Suggestions.
- Add dashboard entity for condition and suggestion container, and
  wrap the condition and suggestion list inside the container. The
  container itself will be a single dashboard item, and within it will
  be the list of suggestion or condition.
- Add suggestion/condition header that will show the combined info for
  the conditions and suggestion data, and have the expand button to
  control expanding both the suggestion and condition list.
- Change the individual condition card to be always expanded, and
remove the logic to collapse/expand individual condition card.
- Remove the divider between the action button and condition detail
  within each condition card.
- Add suggestion/condition footer for collapsing the whole suggestion and
  condition list.

Bug: 37645754
Test: make RunSettingsRoboTests
Change-Id: I86df75f7e4551778f79d730851c03121fd0dcbdf
diff --git a/res/layout/condition_header_icon.xml b/res/layout/condition_header_icon.xml
new file mode 100644
index 0000000..4f93f54
--- /dev/null
+++ b/res/layout/condition_header_icon.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 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.
+-->
+
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/icon"
+    android:layout_width="@dimen/dashboard_tile_image_size"
+    android:layout_height="@dimen/dashboard_tile_image_size"
+    android:layout_marginStart="0dp"
+    android:layout_marginEnd="24dp"
+    android:tint="?android:attr/colorAccent"
+    android:scaleType="centerInside"/>
diff --git a/res/layout/condition_tile_new_ui.xml b/res/layout/condition_tile_new_ui.xml
new file mode 100644
index 0000000..d8d2284
--- /dev/null
+++ b/res/layout/condition_tile_new_ui.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/colorSecondary"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="48dp"
+        android:background="?android:attr/selectableItemBackground"
+        android:orientation="horizontal"
+        android:gravity="center_vertical">
+
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="@dimen/dashboard_tile_image_size"
+            android:layout_height="@dimen/dashboard_tile_image_size"
+            android:layout_marginStart="14dp"
+            android:layout_marginEnd="24dp"
+            android:tint="?android:attr/colorAccent" />
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/colorAccent" />
+
+    </LinearLayout>
+
+    <TextView
+        android:id="@android:id/summary"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="62dp"
+        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+        android:paddingBottom="8dp"
+        android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+        android:alpha=".7"
+        android:textColor="?android:attr/textColorPrimary" />
+
+    <android.support.v7.widget.ButtonBarLayout
+        android:id="@+id/buttonBar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="62dp"
+        android:paddingBottom="8dp"
+        style="?android:attr/buttonBarStyle"
+        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+        <Button
+            android:id="@+id/first_action"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:paddingStart="0dp"
+            android:alpha=".8"
+            android:textAlignment="viewStart"
+            android:textColor="?android:attr/colorAccent"
+            style="?android:attr/buttonBarButtonStyle" />
+
+        <Button
+            android:id="@+id/second_action"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:alpha=".8"
+            android:textAlignment="viewStart"
+            android:textColor="?android:attr/colorAccent"
+            style="?android:attr/buttonBarButtonStyle" />
+
+    </android.support.v7.widget.ButtonBarLayout>
+
+    <include layout="@layout/horizontal_divider" />
+
+</LinearLayout>
diff --git a/res/layout/horizontal_divider.xml b/res/layout/horizontal_divider.xml
new file mode 100644
index 0000000..e4a277d
--- /dev/null
+++ b/res/layout/horizontal_divider.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 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.
+-->
+
+<View
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/divider"
+    android:layout_width="match_parent"
+    android:layout_height=".75dp"
+    android:background="?android:attr/dividerHorizontal" />
\ No newline at end of file
diff --git a/res/layout/suggestion_condition_container.xml b/res/layout/suggestion_condition_container.xml
new file mode 100644
index 0000000..089c2c8
--- /dev/null
+++ b/res/layout/suggestion_condition_container.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 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.
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    style="@style/SuggestionConditionStyle"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingStart="8dp"
+    android:paddingEnd="8dp"
+    android:paddingBottom="@dimen/dashboard_padding_bottom">
+
+    <android.support.v7.widget.CardView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:cardUseCompatPadding="true"
+        app:cardElevation="2dp">
+
+        <android.support.v7.widget.RecyclerView
+            android:id="@+id/data"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:scrollbars="none"/>
+
+    </android.support.v7.widget.CardView>
+
+</FrameLayout>
diff --git a/res/layout/suggestion_condition_footer.xml b/res/layout/suggestion_condition_footer.xml
new file mode 100644
index 0000000..4e1bbc8
--- /dev/null
+++ b/res/layout/suggestion_condition_footer.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/SuggestionConditionStyle"
+    android:layout_width="match_parent"
+    android:layout_height="56dp"
+    android:orientation="horizontal"
+    android:gravity="center|end">
+
+    <ImageView
+        android:id="@+id/collapse_button"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:padding="16dp"
+        android:src="@drawable/ic_expand_less"/>
+
+</LinearLayout>
diff --git a/res/layout/suggestion_condition_header.xml b/res/layout/suggestion_condition_header.xml
new file mode 100644
index 0000000..a0f73ae
--- /dev/null
+++ b/res/layout/suggestion_condition_header.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 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.
+-->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/SuggestionConditionStyle"
+    android:layout_width="match_parent"
+    android:layout_height="56dp"
+    android:layout_centerHorizontal="true">
+
+    <FrameLayout
+        android:id="@android:id/icon_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="24dp"
+        android:layout_centerVertical="true">
+
+        <include layout="@layout/condition_header_icon" />
+
+    </FrameLayout>
+
+    <ImageView
+        android:id="@+id/expand_indicator"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_alignParentEnd="true"
+        android:padding="16dp"
+        android:src="@drawable/ic_expand_more"/>
+
+    <TextView
+        android:id="@android:id/summary"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:layout_toStartOf="@id/expand_indicator"
+        android:layout_centerVertical="true"
+        android:gravity="end"
+        android:textAppearance="@style/TextAppearance.SuggestionTitle"
+        android:textColor="?android:attr/colorAccent" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toEndOf="@android:id/icon_frame"
+        android:layout_toStartOf="@android:id/summary"
+        android:layout_centerVertical="true"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:textAppearance="@style/TextAppearance.SuggestionTitle"
+        android:textColor="?android:attr/colorAccent" />
+
+    <LinearLayout
+        android:id="@+id/additional_icons"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_toStartOf="@android:id/summary"
+        android:layout_toEndOf="@android:id/icon_frame"
+        android:orientation="horizontal"
+        android:gravity="center_vertical"/>
+
+</RelativeLayout>
diff --git a/res/layout/suggestion_tile_new_ui.xml b/res/layout/suggestion_tile_new_ui.xml
new file mode 100644
index 0000000..e2dd13a
--- /dev/null
+++ b/res/layout/suggestion_tile_new_ui.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@android:color/white"
+        android:gravity="center_vertical"
+        android:orientation="horizontal"
+        android:minHeight="@dimen/dashboard_tile_minimum_height">
+
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="@dimen/dashboard_tile_image_size"
+            android:layout_height="@dimen/dashboard_tile_image_size"
+            android:layout_marginStart="14dp"
+            android:layout_marginEnd="24dp"/>
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <TextView android:id="@android:id/title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:textAppearance="@style/TextAppearance.TileTitle"
+                android:ellipsize="marquee"
+                android:fadingEdge="horizontal"/>
+
+            <TextView android:id="@android:id/summary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="@style/TextAppearance.Small"
+                android:textColor="?android:attr/textColorSecondary"/>
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <include layout="@layout/horizontal_divider" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 051bd68..e00ac81 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7999,12 +7999,30 @@
     <!-- Summary of condition that night display is on (renamed "Night Light" with title caps). [CHAR LIMIT=NONE] -->
     <string name="condition_night_display_summary">Screen is tinted amber. This may help you fall asleep.</string>
 
+    <!-- Summary for the condition section on the dashboard, representing number of conditions. [CHAR LIMIT=10] -->
+    <string name="condition_summary" translatable="false"><xliff:g name="count" example="3">%1$d</xliff:g></string>
+
     <!-- Title for the suggestions section on the dashboard [CHAR LIMIT=30] -->
     <string name="suggestions_title">Suggestions</string>
 
     <!-- Summary for the suggestions section on the dashboard, representing number of suggestions. [CHAR LIMIT=10] -->
     <string name="suggestions_summary">+<xliff:g name="count" example="3">%1$d</xliff:g></string>
 
+    <!-- Title for the suggestions section on the dashboard, representing number of suggestions to show when expanded. [CHAR LIMIT=10] -->
+    <string name="suggestions_more_title">+<xliff:g name="count" example="3">%1$d</xliff:g> more</string>
+
+    <!-- Title for the collapsed suggestions section on the dashboard, representing number of suggestions. [CHAR LIMIT=30] -->
+    <plurals name="suggestions_collapsed_title">
+        <item quantity="one">1 suggestion</item>
+        <item quantity="other"><xliff:g id="count" example="10">%1$d</xliff:g> suggestions</item>
+    </plurals>
+
+    <!-- Summary for the collapsed suggestions section on the dashboard, representing number of suggestions. [CHAR LIMIT=30] -->
+    <plurals name="suggestions_collapsed_summary">
+        <item quantity="one">+1 suggestion</item>
+        <item quantity="other">+<xliff:g id="count" example="10">%1$d</xliff:g> suggestions</item>
+    </plurals>
+
     <!-- Name of option to remove a suggestion from the list [CHAR LIMIT=30] -->
     <string name="suggestion_remove">Remove</string>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 31c965b..398bdbd 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -454,4 +454,8 @@
         <item name="android:visibility">gone</item>
     </style>
 
+    <style name="SuggestionConditionStyle">
+        <item name="android:background">@color/material_grey_300</item>
+    </style>
+
 </resources>
diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java
index eb74690..3a768cc 100644
--- a/src/com/android/settings/dashboard/DashboardAdapter.java
+++ b/src/com/android/settings/dashboard/DashboardAdapter.java
@@ -20,11 +20,13 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.support.annotation.VisibleForTesting;
 import android.support.v7.util.DiffUtil;
+import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -33,19 +35,28 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
+import com.android.settings.R.id;
 import com.android.settings.SettingsActivity;
 import com.android.settings.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.dashboard.DashboardData.SuggestionConditionHeaderData;
 import com.android.settings.dashboard.conditional.Condition;
+import com.android.settings.dashboard.conditional.ConditionAdapter;
 import com.android.settings.dashboard.conditional.ConditionAdapterUtils;
+import com.android.settings.dashboard.conditional.FocusRecyclerView;
+import com.android.settings.dashboard.suggestions.SuggestionAdapter;
+import com.android.settings.dashboard.suggestions.SuggestionDismissController;
 import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
 import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.Utils;
 import com.android.settingslib.drawer.DashboardCategory;
 import com.android.settingslib.drawer.Tile;
 
+import com.android.settingslib.suggestions.SuggestionParser;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -57,6 +68,7 @@
     private static final String STATE_SUGGESTION_MODE = "suggestion_mode";
     private static final String STATE_SUGGESTIONS_SHOWN_LOGGED = "suggestions_shown_logged";
     private static final int DONT_SET_BACKGROUND_ATTR = -1;
+    private static final String STATE_SUGGESTION_CONDITION_MODE = "suggestion_condition_mode";
 
     private final IconCache mCache;
     private final Context mContext;
@@ -65,6 +77,12 @@
     private final SuggestionFeatureProvider mSuggestionFeatureProvider;
     private final ArrayList<String> mSuggestionsShownLogged;
     private boolean mFirstFrameDrawn;
+    private boolean mCombineSuggestionAndCondition;
+    private RecyclerView mRecyclerView;
+    private SuggestionParser mSuggestionParser;
+    private SuggestionAdapter mSuggestionAdapter;
+    private SuggestionDismissController mSuggestionDismissHandler;
+    private SuggestionDismissController.Callback mCallback;
 
     @VisibleForTesting
     DashboardData mDashboardData;
@@ -81,43 +99,65 @@
 
         @Override
         public void onClick(View v) {
-            Condition expandedCondition = mDashboardData.getExpandedCondition();
-
-            //TODO: get rid of setTag/getTag
-            if (v.getTag() == expandedCondition) {
+            if (mCombineSuggestionAndCondition) {
+                Condition condition = (Condition) v.getTag();
+                //TODO: get rid of setTag/getTag
                 mMetricsFeatureProvider.action(mContext,
+                    MetricsEvent.ACTION_SETTINGS_CONDITION_CLICK,
+                    condition.getMetricsConstant());
+                condition.onPrimaryClick();
+            } else {
+                Condition expandedCondition = mDashboardData.getExpandedCondition();
+
+                //TODO: get rid of setTag/getTag
+                if (v.getTag() == expandedCondition) {
+                    mMetricsFeatureProvider.action(mContext,
                         MetricsEvent.ACTION_SETTINGS_CONDITION_CLICK,
                         expandedCondition.getMetricsConstant());
-                expandedCondition.onPrimaryClick();
-            } else {
-                expandedCondition = (Condition) v.getTag();
-                mMetricsFeatureProvider.action(mContext,
+                    expandedCondition.onPrimaryClick();
+                } else {
+                    expandedCondition = (Condition) v.getTag();
+                    mMetricsFeatureProvider.action(mContext,
                         MetricsEvent.ACTION_SETTINGS_CONDITION_EXPAND,
                         expandedCondition.getMetricsConstant());
 
-                updateExpandedCondition(expandedCondition);
+                    updateExpandedCondition(expandedCondition);
+                }
             }
         }
     };
 
+    @Deprecated
     public DashboardAdapter(Context context, Bundle savedInstanceState,
-            List<Condition> conditions) {
+        List<Condition> conditions) {
+        this(context, savedInstanceState, conditions, null, null);
+    }
+
+    public DashboardAdapter(Context context, Bundle savedInstanceState,
+            List<Condition> conditions, SuggestionParser suggestionParser,
+            SuggestionDismissController.Callback callback) {
         List<Tile> suggestions = null;
         List<DashboardCategory> categories = null;
         int suggestionMode = DashboardData.SUGGESTION_MODE_DEFAULT;
+        int suggestionConditionMode = DashboardData.HEADER_MODE_DEFAULT;
 
         mContext = context;
         final FeatureFactory factory = FeatureFactory.getFactory(context);
         mMetricsFeatureProvider = factory.getMetricsFeatureProvider();
         mDashboardFeatureProvider = factory.getDashboardFeatureProvider(context);
         mSuggestionFeatureProvider = factory.getSuggestionFeatureProvider(context);
+        mCombineSuggestionAndCondition = mDashboardFeatureProvider.combineSuggestionAndCondition();
         mCache = new IconCache(context);
+        mSuggestionParser = suggestionParser;
+        mCallback = callback;
 
         setHasStableIds(true);
 
         if (savedInstanceState != null) {
             suggestions = savedInstanceState.getParcelableArrayList(STATE_SUGGESTION_LIST);
             categories = savedInstanceState.getParcelableArrayList(STATE_CATEGORY_LIST);
+            suggestionConditionMode = savedInstanceState.getInt(
+                STATE_SUGGESTION_CONDITION_MODE, suggestionConditionMode);
             suggestionMode = savedInstanceState.getInt(
                     STATE_SUGGESTION_MODE, DashboardData.SUGGESTION_MODE_DEFAULT);
             mSuggestionsShownLogged = savedInstanceState.getStringArrayList(
@@ -131,6 +171,8 @@
                 .setSuggestions(suggestions)
                 .setCategories(categories)
                 .setSuggestionMode(suggestionMode)
+                .setCombineSuggestionAndCondition(mCombineSuggestionAndCondition)
+                .setSuggestionConditionMode(suggestionConditionMode)
                 .build();
     }
 
@@ -167,14 +209,24 @@
                 .build();
         notifyDashboardDataChanged(prevData);
         List<Tile> shownSuggestions = null;
-        switch (mDashboardData.getSuggestionMode()) {
-            case DashboardData.SUGGESTION_MODE_DEFAULT:
+        if (mCombineSuggestionAndCondition) {
+            final int mode = mDashboardData.getSuggestionConditionMode();
+            if (mode == DashboardData.HEADER_MODE_DEFAULT) {
                 shownSuggestions = suggestions.subList(0,
-                        Math.min(suggestions.size(), DashboardData.DEFAULT_SUGGESTION_COUNT));
-                break;
-            case DashboardData.SUGGESTION_MODE_EXPANDED:
+                    Math.min(suggestions.size(), DashboardData.DEFAULT_SUGGESTION_COUNT));
+            } else if (mode != DashboardData.HEADER_MODE_COLLAPSED) {
                 shownSuggestions = suggestions;
-                break;
+            }
+        } else {
+            switch (mDashboardData.getSuggestionMode()) {
+                case DashboardData.SUGGESTION_MODE_DEFAULT:
+                    shownSuggestions = suggestions.subList(0,
+                        Math.min(suggestions.size(), DashboardData.DEFAULT_SUGGESTION_COUNT));
+                    break;
+                case DashboardData.SUGGESTION_MODE_EXPANDED:
+                    shownSuggestions = suggestions;
+                    break;
+            }
         }
         if (shownSuggestions != null) {
             for (Tile suggestion : shownSuggestions) {
@@ -199,10 +251,16 @@
     public void setConditions(List<Condition> conditions) {
         final DashboardData prevData = mDashboardData;
         Log.d(TAG, "adapter setConditions called");
-        mDashboardData = new DashboardData.Builder(prevData)
+        if (mCombineSuggestionAndCondition) {
+            mDashboardData = new DashboardData.Builder(prevData)
+                .setConditions(conditions)
+                .build();
+        } else {
+            mDashboardData = new DashboardData.Builder(prevData)
                 .setConditions(conditions)
                 .setExpandedCondition(null)
                 .build();
+        }
         notifyDashboardDataChanged(prevData);
     }
 
@@ -218,8 +276,14 @@
 
     @Override
     public DashboardItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-        return new DashboardItemHolder(LayoutInflater.from(parent.getContext()).inflate(
-                viewType, parent, false));
+        final View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
+        if (viewType == R.layout.suggestion_condition_header) {
+            return new SuggestionAndConditionHeaderHolder(view);
+        }
+        if (viewType == R.layout.suggestion_condition_container) {
+            return new SuggestionAndConditionContainerHolder(view);
+        }
+        return new DashboardItemHolder(view);
     }
 
     @Override
@@ -277,6 +341,43 @@
                         (Condition) mDashboardData.getItemEntityByPosition(position),
                         holder, isExpanded, mConditionClickListener, v -> onExpandClick(v));
                 break;
+            case R.layout.suggestion_condition_container:
+                onBindConditionAndSuggestion(
+                    (SuggestionAndConditionContainerHolder) holder, position);
+                break;
+            case R.layout.suggestion_condition_header:
+                /* There are 2 different headers for the suggestions/conditions section. To minimize
+                   visual animation when expanding and collapsing the suggestions/conditions, we are
+                   using the same layout to represent the 2 headers:
+                   1. Suggestion header - when there is any suggestion shown, the suggestion header
+                      will be the first item on the section. It only has the text "Suggestion", and
+                      do nothing when clicked. This header will not be shown when the section is
+                      collapsed, in which case, the SuggestionCondition header will be
+                      shown instead to show the summary info.
+                   2. SuggestionCondition header - the header that shows the summary info for the
+                      suggestion/condition that is currently hidden. It has the expand button to
+                      expand the section. */
+                if (mDashboardData.getDisplayableSuggestionCount() > 0 && position == 1
+                        && mDashboardData.getSuggestionConditionMode()
+                            != DashboardData.HEADER_MODE_COLLAPSED) {
+                    onBindSuggestionHeader((SuggestionAndConditionHeaderHolder) holder);
+                } else {
+                    onBindSuggestionConditionHeader((SuggestionAndConditionHeaderHolder) holder,
+                        (SuggestionConditionHeaderData)
+                            mDashboardData.getItemEntityByPosition(position));
+                }
+                break;
+            case R.layout.suggestion_condition_footer:
+                holder.itemView.setOnClickListener(v -> {
+                    mMetricsFeatureProvider.action(mContext,
+                            MetricsEvent.ACTION_SETTINGS_CONDITION_EXPAND, false);
+                    DashboardData prevData = mDashboardData;
+                    mDashboardData = new DashboardData.Builder(prevData).setSuggestionConditionMode(
+                        DashboardData.HEADER_MODE_COLLAPSED).build();
+                    notifyDashboardDataChanged(prevData);
+                    mRecyclerView.scrollToPosition(1);
+                });
+                break;
         }
     }
 
@@ -295,6 +396,14 @@
         return mDashboardData.size();
     }
 
+    @Override
+    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+        super.onAttachedToRecyclerView(recyclerView);
+        // save the view so that we can scroll it when expanding/collapsing the suggestion and
+        // conditions.
+        mRecyclerView = recyclerView;
+    }
+
     public void onPause() {
         if (mDashboardData.getSuggestions() == null) {
             return;
@@ -310,6 +419,9 @@
         mSuggestionsShownLogged.clear();
     }
 
+    // condition card is always expanded in new suggestion/condition UI.
+    // TODO: Remove when completely move to new suggestion/condition UI
+    @Deprecated
     public void onExpandClick(View v) {
         Condition expandedCondition = mDashboardData.getExpandedCondition();
         if (v.getTag() == expandedCondition) {
@@ -330,6 +442,13 @@
         return mDashboardData.getItemEntityById(itemId);
     }
 
+    public Tile getSuggestion(int position) {
+        if (mCombineSuggestionAndCondition) {
+            return mSuggestionAdapter.getSuggestion(position);
+        }
+        return (Tile) getItem(getItemId(position));
+    }
+
     private void notifyDashboardDataChanged(DashboardData prevData) {
         if (mFirstFrameDrawn && prevData != null) {
             final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DashboardData
@@ -405,17 +524,7 @@
             final int suggestionMode;
             if (moreSuggestions) {
                 suggestionMode = DashboardData.SUGGESTION_MODE_EXPANDED;
-
-                for (Tile suggestion : mDashboardData.getSuggestions()) {
-                    final String suggestionId = mSuggestionFeatureProvider.getSuggestionIdentifier(
-                            mContext, suggestion);
-                    if (!mSuggestionsShownLogged.contains(suggestionId)) {
-                        mMetricsFeatureProvider.action(
-                                mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION,
-                                suggestionId);
-                        mSuggestionsShownLogged.add(suggestionId);
-                    }
-                }
+                logSuggestions();
             } else {
                 suggestionMode = DashboardData.SUGGESTION_MODE_COLLAPSED;
             }
@@ -428,6 +537,130 @@
         });
     }
 
+    private void logSuggestions() {
+        for (Tile suggestion : mDashboardData.getSuggestions()) {
+            final String suggestionId = mSuggestionFeatureProvider.getSuggestionIdentifier(
+                mContext, suggestion);
+            if (!mSuggestionsShownLogged.contains(suggestionId)) {
+                mMetricsFeatureProvider.action(
+                    mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION,
+                    suggestionId);
+                mSuggestionsShownLogged.add(suggestionId);
+            }
+        }
+    }
+
+    private void onBindSuggestionHeader(final SuggestionAndConditionHeaderHolder holder) {
+        holder.title.setText(R.string.suggestions_title);
+        holder.title.setTextColor(Color.BLACK);
+        holder.icon.setVisibility(View.INVISIBLE);
+        holder.icons.removeAllViews();
+        holder.icons.setVisibility(View.INVISIBLE);
+        holder.summary.setVisibility(View.INVISIBLE);
+        holder.expandIndicator.setVisibility(View.INVISIBLE);
+        holder.itemView.setOnClickListener(null);
+    }
+
+    private void onBindSuggestionConditionHeader(final SuggestionAndConditionHeaderHolder holder,
+            SuggestionConditionHeaderData data) {
+        final int curMode = mDashboardData.getSuggestionConditionMode();
+        final int nextMode = data.hiddenSuggestionCount > 0 && data.conditionCount > 0
+            && curMode != DashboardData.HEADER_MODE_SUGGESTION_EXPANDED
+            ? DashboardData.HEADER_MODE_SUGGESTION_EXPANDED
+            : DashboardData.HEADER_MODE_FULLY_EXPANDED;
+        final boolean moreSuggestions = data.hiddenSuggestionCount > 0;
+        final boolean hasConditions = data.conditionCount > 0;
+        if (data.conditionCount > 0) {
+            holder.icon.setImageIcon(data.conditionIcons.get(0));
+            holder.icon.setVisibility(View.VISIBLE);
+            if (data.conditionCount == 1) {
+                holder.title.setText(data.title);
+                holder.title.setTextColor(Utils.getColorAccent(mContext));
+                holder.icons.setVisibility(View.INVISIBLE);
+            } else {
+                holder.title.setText(null);
+                updateConditionIcons(data.conditionIcons, holder.icons);
+                holder.icons.setVisibility(View.VISIBLE);
+            }
+        } else {
+            holder.icon.setVisibility(View.INVISIBLE);
+            holder.icons.setVisibility(View.INVISIBLE);
+        }
+
+        if (data.hiddenSuggestionCount > 0) {
+            holder.summary.setTextColor(Color.BLACK);
+            if (curMode == DashboardData.HEADER_MODE_COLLAPSED) {
+                if (data.conditionCount > 0) {
+                    holder.summary.setText(mContext.getResources().getQuantityString(
+                        R.plurals.suggestions_collapsed_summary,
+                        data.hiddenSuggestionCount, data.hiddenSuggestionCount));
+                } else {
+                    holder.title.setText(mContext.getResources().getQuantityString(
+                        R.plurals.suggestions_collapsed_title,
+                        data.hiddenSuggestionCount, data.hiddenSuggestionCount));
+                    holder.title.setTextColor(Color.BLACK);
+                    holder.summary.setText(null);
+                }
+            } else if (curMode == DashboardData.HEADER_MODE_DEFAULT) {
+                if (data.conditionCount > 0) {
+                    holder.summary.setText(mContext.getString(
+                        R.string.suggestions_summary, data.hiddenSuggestionCount));
+                } else {
+                    holder.title.setText(mContext.getString(
+                        R.string.suggestions_more_title, data.hiddenSuggestionCount));
+                    holder.title.setTextColor(Color.BLACK);
+                    holder.summary.setText(null);
+                }
+            }
+        } else if (data.conditionCount > 1) {
+            holder.summary.setTextColor(Utils.getColorAccent(mContext));
+            holder.summary.setText(
+                mContext.getString(R.string.condition_summary, data.conditionCount));
+        } else {
+            holder.summary.setText(null);
+        }
+        holder.summary.setVisibility(View.VISIBLE);
+        holder.expandIndicator.setVisibility(View.VISIBLE);
+
+        holder.itemView.setOnClickListener(v -> {
+            if (moreSuggestions ) {
+                logSuggestions();
+            } else if (hasConditions) {
+                mMetricsFeatureProvider.action(mContext,
+                    MetricsEvent.ACTION_SETTINGS_CONDITION_EXPAND, true);
+            }
+            DashboardData prevData = mDashboardData;
+            final boolean wasCollapsed = curMode == DashboardData.HEADER_MODE_COLLAPSED;
+            mDashboardData = new DashboardData.Builder(prevData)
+                .setSuggestionConditionMode(nextMode).build();
+            notifyDashboardDataChanged(prevData);
+            if (wasCollapsed) {
+                mRecyclerView.scrollToPosition(1);
+            }
+        });
+    }
+
+    private void onBindConditionAndSuggestion(final SuggestionAndConditionContainerHolder holder,
+            int position) {
+        RecyclerView.Adapter<DashboardItemHolder> adapter;
+        // If there is suggestions to show, it will be at position 2 (position 0 = header spacer,
+        // position 1 is suggestion header.
+        if (position == 2 && mDashboardData.getSuggestions() != null) {
+            mSuggestionAdapter = new SuggestionAdapter(mContext, (List<Tile>)
+                mDashboardData.getItemEntityByPosition(position), mSuggestionsShownLogged);
+            adapter = mSuggestionAdapter;
+            mSuggestionDismissHandler = new SuggestionDismissController(mContext,
+                holder.data, mSuggestionParser, mCallback);
+        } else {
+            ConditionAdapterUtils.addDismiss(holder.data);
+            adapter = new ConditionAdapter(mContext,
+                (List<Condition>) mDashboardData.getItemEntityByPosition(position),
+                    mDashboardData.getSuggestionConditionMode());
+        }
+        holder.data.setLayoutManager(new LinearLayoutManager(mContext));
+        holder.data.setAdapter(adapter);
+    }
+
     private void onBindTile(DashboardItemHolder holder, Tile tile) {
         if (tile.remoteViews != null) {
             final ViewGroup itemView = (ViewGroup) holder.itemView;
@@ -460,9 +693,27 @@
         }
         outState.putInt(STATE_SUGGESTION_MODE, mDashboardData.getSuggestionMode());
         outState.putStringArrayList(STATE_SUGGESTIONS_SHOWN_LOGGED, mSuggestionsShownLogged);
+        outState.putInt(STATE_SUGGESTION_CONDITION_MODE,
+            mDashboardData.getSuggestionConditionMode());
     }
 
-    private static class IconCache {
+    private void updateConditionIcons(List<Icon> icons, ViewGroup parent) {
+        if (icons == null || icons.size() < 2) {
+            parent.setVisibility(View.INVISIBLE);
+            return;
+        }
+        final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+        parent.removeAllViews();
+        for (int i = 1, size = icons.size(); i < size; i++) {
+            ImageView icon = (ImageView) inflater.inflate(
+                R.layout.condition_header_icon, parent, false);
+            icon.setImageIcon(icons.get(i));
+            parent.addView(icon);
+        }
+        parent.setVisibility(View.VISIBLE);
+    }
+
+    public static class IconCache {
         private final Context mContext;
         private final ArrayMap<Icon, Drawable> mMap = new ArrayMap<>();
 
@@ -492,4 +743,25 @@
             summary = itemView.findViewById(android.R.id.summary);
         }
     }
+
+    public static class SuggestionAndConditionHeaderHolder extends DashboardItemHolder {
+        public final LinearLayout icons;
+        public final ImageView expandIndicator;
+
+        public SuggestionAndConditionHeaderHolder(View itemView) {
+            super(itemView);
+            icons = itemView.findViewById(id.additional_icons);
+            expandIndicator = itemView.findViewById(id.expand_indicator);
+        }
+    }
+
+    public static class SuggestionAndConditionContainerHolder extends DashboardItemHolder {
+        public final RecyclerView data;
+
+        public SuggestionAndConditionContainerHolder(View itemView) {
+            super(itemView);
+            data = itemView.findViewById(id.data);
+        }
+    }
+
 }
diff --git a/src/com/android/settings/dashboard/DashboardData.java b/src/com/android/settings/dashboard/DashboardData.java
index 60d7d8d..64e8af2 100644
--- a/src/com/android/settings/dashboard/DashboardData.java
+++ b/src/com/android/settings/dashboard/DashboardData.java
@@ -16,7 +16,9 @@
 package com.android.settings.dashboard;
 
 import android.annotation.IntDef;
+import android.graphics.drawable.Icon;
 import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
 import android.support.v7.util.DiffUtil;
 import android.text.TextUtils;
 
@@ -38,9 +40,22 @@
  * ItemsData has inner class Item, which represents the Item in data list.
  */
 public class DashboardData {
+    @Deprecated
     public static final int SUGGESTION_MODE_DEFAULT = 0;
+    @Deprecated
     public static final int SUGGESTION_MODE_COLLAPSED = 1;
+    @Deprecated
     public static final int SUGGESTION_MODE_EXPANDED = 2;
+
+    public static final int HEADER_MODE_DEFAULT = 0;
+    public static final int HEADER_MODE_SUGGESTION_EXPANDED = 1;
+    public static final int HEADER_MODE_FULLY_EXPANDED = 2;
+    public static final int HEADER_MODE_COLLAPSED = 3;
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({HEADER_MODE_DEFAULT, HEADER_MODE_SUGGESTION_EXPANDED, HEADER_MODE_FULLY_EXPANDED,
+        HEADER_MODE_COLLAPSED})
+    public @interface HeaderMode{}
+
     public static final int POSITION_NOT_FOUND = -1;
     public static final int DEFAULT_SUGGESTION_COUNT = 2;
 
@@ -49,14 +64,19 @@
     private static final int NS_SPACER = 1000;
     private static final int NS_ITEMS = 2000;
     private static final int NS_CONDITION = 3000;
+    private static final int NS_SUGGESTION_CONDITION = 4000;
 
     private final List<Item> mItems;
     private final List<DashboardCategory> mCategories;
     private final List<Condition> mConditions;
     private final List<Tile> mSuggestions;
+    @Deprecated
     private final int mSuggestionMode;
+    @Deprecated
     private final Condition mExpandedCondition;
+    private final @HeaderMode int mSuggestionConditionMode;
     private int mId;
+    private boolean mCombineSuggestionAndCondition;
 
     private DashboardData(Builder builder) {
         mCategories = builder.mCategories;
@@ -64,6 +84,8 @@
         mSuggestions = builder.mSuggestions;
         mSuggestionMode = builder.mSuggestionMode;
         mExpandedCondition = builder.mExpandedCondition;
+        mSuggestionConditionMode = builder.mSuggestionConditionMode;
+        mCombineSuggestionAndCondition = builder.mCombineSuggestionAndCondition;
 
         mItems = new ArrayList<>();
         mId = 0;
@@ -116,6 +138,11 @@
         return mSuggestionMode;
     }
 
+    public int getSuggestionConditionMode() {
+        return mSuggestionConditionMode;
+    }
+
+    @Deprecated
     public Condition getExpandedCondition() {
         return mExpandedCondition;
     }
@@ -177,14 +204,31 @@
      * @return the count of suggestions to display
      */
     public int getDisplayableSuggestionCount() {
-        final int suggestionSize = mSuggestions.size();
-        return mSuggestionMode == SUGGESTION_MODE_DEFAULT
-                ? Math.min(DEFAULT_SUGGESTION_COUNT, suggestionSize)
-                : mSuggestionMode == SUGGESTION_MODE_EXPANDED
-                        ? suggestionSize : 0;
+        final int suggestionSize = sizeOf(mSuggestions);
+        if (mCombineSuggestionAndCondition) {
+            if (mSuggestionConditionMode == HEADER_MODE_COLLAPSED) {
+                return 0;
+            }
+            if (mSuggestionConditionMode == HEADER_MODE_DEFAULT) {
+                return Math.min(DEFAULT_SUGGESTION_COUNT, suggestionSize);
+            }
+            return suggestionSize;
+        }
+        if (mSuggestionMode == SUGGESTION_MODE_DEFAULT) {
+            return Math.min(DEFAULT_SUGGESTION_COUNT, suggestionSize);
+        }
+        if (mSuggestionMode == SUGGESTION_MODE_EXPANDED) {
+            return suggestionSize;
+        }
+        return 0;
     }
 
     public boolean hasMoreSuggestions() {
+        if (mCombineSuggestionAndCondition) {
+            return mSuggestionConditionMode == HEADER_MODE_COLLAPSED && mSuggestions.size() > 0
+                || mSuggestionConditionMode == HEADER_MODE_DEFAULT
+                    && mSuggestions.size() > DEFAULT_SUGGESTION_COUNT;
+        }
         return mSuggestionMode == SUGGESTION_MODE_COLLAPSED
                 || (mSuggestionMode == SUGGESTION_MODE_DEFAULT
                 && mSuggestions.size() > DEFAULT_SUGGESTION_COUNT);
@@ -208,7 +252,11 @@
      */
     private void countItem(Object object, int type, boolean add, int nameSpace) {
         if (add) {
-            mItems.add(new Item(object, type, mId + nameSpace, object == mExpandedCondition));
+            if (mCombineSuggestionAndCondition) {
+                mItems.add(new Item(object, type, mId + nameSpace));
+            } else {
+                mItems.add(new Item(object, type, mId + nameSpace, object == mExpandedCondition));
+            }
         }
         mId++;
     }
@@ -238,26 +286,75 @@
         // add the view that goes under the search bar
         countItem(null, R.layout.dashboard_header_spacer, true, NS_HEADER_SPACER);
         resetCount();
-        boolean hasConditions = false;
-        for (int i = 0; mConditions != null && i < mConditions.size(); i++) {
-            boolean shouldShow = mConditions.get(i).shouldShow();
-            hasConditions |= shouldShow;
-            countItem(mConditions.get(i), R.layout.condition_card, shouldShow, NS_CONDITION);
-        }
+        final boolean hasSuggestions = sizeOf(mSuggestions) > 0;
+        if (!mCombineSuggestionAndCondition) {
+            boolean hasConditions = false;
+            for (int i = 0; mConditions != null && i < mConditions.size(); i++) {
+                boolean shouldShow = mConditions.get(i).shouldShow();
+                hasConditions |= shouldShow;
+                countItem(mConditions.get(i), R.layout.condition_card, shouldShow, NS_CONDITION);
+            }
 
-        resetCount();
-        final boolean hasSuggestions = mSuggestions != null && mSuggestions.size() != 0;
-        countItem(null, R.layout.dashboard_spacer, hasConditions && hasSuggestions, NS_SPACER);
-        countItem(buildSuggestionHeaderData(), R.layout.suggestion_header, hasSuggestions,
+            resetCount();
+            countItem(null, R.layout.dashboard_spacer, hasConditions && hasSuggestions, NS_SPACER);
+            countItem(buildSuggestionHeaderData(), R.layout.suggestion_header, hasSuggestions,
                 NS_SPACER);
 
-        resetCount();
-        if (mSuggestions != null) {
-            int maxSuggestions = getDisplayableSuggestionCount();
-            for (int i = 0; i < mSuggestions.size(); i++) {
-                countSuggestion(mSuggestions.get(i), i < maxSuggestions);
+            resetCount();
+            if (mSuggestions != null) {
+                int maxSuggestions = getDisplayableSuggestionCount();
+                for (int i = 0; i < mSuggestions.size(); i++) {
+                    countSuggestion(mSuggestions.get(i), i < maxSuggestions);
+                }
             }
+        } else {
+            final List<Condition> conditions = getConditionsToShow(mConditions);
+            final boolean hasConditions = sizeOf(conditions) > 0;
+
+            final List<Tile> suggestions = getSuggestionsToShow(mSuggestions);
+            final int hiddenSuggestion =
+                hasSuggestions ? sizeOf(mSuggestions) - sizeOf(suggestions) : 0;
+
+            resetCount();
+            /* Top suggestion/condition header. This will be present when there is any suggestion or
+             * condition to show, except in the case that there is only conditions to show and the
+             * mode is fully expanded. */
+            countItem(new SuggestionConditionHeaderData(conditions, hiddenSuggestion),
+                R.layout.suggestion_condition_header, hasSuggestions
+                    || hasConditions && mSuggestionConditionMode != HEADER_MODE_FULLY_EXPANDED,
+                NS_SUGGESTION_CONDITION);
+
+            /* Suggestion container. This is the card view that contains the list of suggestions.
+             * This will be added whenever the suggestion list is not empty */
+            countItem(suggestions, R.layout.suggestion_condition_container, sizeOf(suggestions) > 0,
+                NS_SUGGESTION_CONDITION);
+
+            /* Second suggestion/condition header. This will be added when there is at least one
+             * suggestion or condition that is not currently displayed, and the user can expand the
+              * section to view more items. */
+            countItem(new SuggestionConditionHeaderData(conditions, hiddenSuggestion),
+                R.layout.suggestion_condition_header,
+                mSuggestionConditionMode != HEADER_MODE_COLLAPSED
+                    && mSuggestionConditionMode != HEADER_MODE_FULLY_EXPANDED
+                    && (hiddenSuggestion > 0
+                        || hasConditions && hasSuggestions),
+                NS_SUGGESTION_CONDITION);
+
+            /* Condition container. This is the card view that contains the list of conditions.
+             * This will be added whenever the condition list is not empty */
+            countItem(conditions, R.layout.suggestion_condition_container,
+                hasConditions && mSuggestionConditionMode == HEADER_MODE_FULLY_EXPANDED,
+                NS_SUGGESTION_CONDITION);
+
+            /* Suggestion/condition footer. This will be present when the section is fully expanded
+             * or when there is no conditions and no hidden suggestions */
+            countItem(null, R.layout.suggestion_condition_footer,
+                (hasConditions || hasSuggestions) &&
+                    mSuggestionConditionMode == HEADER_MODE_FULLY_EXPANDED
+                || hasSuggestions && !hasConditions && hiddenSuggestion == 0,
+                NS_SUGGESTION_CONDITION);
         }
+
         resetCount();
         for (int i = 0; mCategories != null && i < mCategories.size(); i++) {
             DashboardCategory category = mCategories.get(i);
@@ -270,6 +367,10 @@
         }
     }
 
+    private static int sizeOf(List<?> list) {
+        return list == null ? 0 : list.size();
+    }
+
     private SuggestionHeaderData buildSuggestionHeaderData() {
         SuggestionHeaderData data;
         if (mSuggestions == null) {
@@ -285,19 +386,49 @@
         return data;
     }
 
+    private List<Condition> getConditionsToShow(List<Condition> conditions) {
+        if (conditions == null) {
+            return null;
+        }
+        List<Condition> result = new ArrayList<Condition>();
+        final int size = conditions == null ? 0 : conditions.size();
+        for (int i = 0; i < size; i++) {
+            final Condition condition = conditions.get(i);
+            if (condition.shouldShow()) {
+                result.add(condition);
+            }
+        }
+        return result;
+    }
+
+    private List<Tile> getSuggestionsToShow(List<Tile> suggestions) {
+        if (suggestions == null || mSuggestionConditionMode == HEADER_MODE_COLLAPSED) {
+            return null;
+        }
+        if (mSuggestionConditionMode != HEADER_MODE_DEFAULT
+                || suggestions.size() <= DEFAULT_SUGGESTION_COUNT) {
+            return suggestions;
+        }
+        return suggestions.subList(0, DEFAULT_SUGGESTION_COUNT);
+    }
+
     /**
      * Builder used to build the ItemsData
      * <p>
-     * {@link #mExpandedCondition} and {@link #mSuggestionMode} have default value
-     * while others are not.
+     * {@link #mExpandedCondition}, {@link #mSuggestionConditionMode} and {@link #mSuggestionMode}
+     * have default value while others are not.
      */
     public static class Builder {
+        @Deprecated
         private int mSuggestionMode = SUGGESTION_MODE_DEFAULT;
+        @Deprecated
         private Condition mExpandedCondition = null;
+        private @HeaderMode int mSuggestionConditionMode = HEADER_MODE_DEFAULT;
 
         private List<DashboardCategory> mCategories;
         private List<Condition> mConditions;
         private List<Tile> mSuggestions;
+        private boolean mCombineSuggestionAndCondition;
 
         public Builder() {
         }
@@ -308,6 +439,8 @@
             mSuggestions = dashboardData.mSuggestions;
             mSuggestionMode = dashboardData.mSuggestionMode;
             mExpandedCondition = dashboardData.mExpandedCondition;
+            mSuggestionConditionMode = dashboardData.mSuggestionConditionMode;
+            mCombineSuggestionAndCondition = dashboardData.mCombineSuggestionAndCondition;
         }
 
         public Builder setCategories(List<DashboardCategory> categories) {
@@ -330,11 +463,22 @@
             return this;
         }
 
+        @Deprecated
         public Builder setExpandedCondition(Condition expandedCondition) {
             this.mExpandedCondition = expandedCondition;
             return this;
         }
 
+        public Builder setSuggestionConditionMode(@HeaderMode int mode) {
+            this.mSuggestionConditionMode = mode;
+            return this;
+        }
+
+        public Builder setCombineSuggestionAndCondition(boolean combine) {
+            this.mCombineSuggestionAndCondition = combine;
+            return this;
+        }
+
         public DashboardData build() {
             return new DashboardData(this);
         }
@@ -373,6 +517,8 @@
             return mOldItems.get(oldItemPosition).equals(mNewItems.get(newItemPosition));
         }
 
+        // not needed in combined UI
+        @Deprecated
         @Nullable
         @Override
         public Object getChangePayload(int oldItemPosition, int newItemPosition) {
@@ -390,13 +536,24 @@
         // valid types in field type
         private static final int TYPE_DASHBOARD_CATEGORY = R.layout.dashboard_category;
         private static final int TYPE_DASHBOARD_TILE = R.layout.dashboard_tile;
+        @Deprecated
         private static final int TYPE_SUGGESTION_HEADER = R.layout.suggestion_header;
+        @Deprecated
         private static final int TYPE_SUGGESTION_TILE = R.layout.suggestion_tile;
+        private static final int TYPE_SUGGESTION_CONDITION_CONTAINER =
+            R.layout.suggestion_condition_container;
+        private static final int TYPE_SUGGESTION_CONDITION_HEADER =
+            R.layout.suggestion_condition_header;
+        @Deprecated
         private static final int TYPE_CONDITION_CARD = R.layout.condition_card;
+        private static final int TYPE_SUGGESTION_CONDITION_FOOTER =
+                R.layout.suggestion_condition_footer;
         private static final int TYPE_DASHBOARD_SPACER = R.layout.dashboard_spacer;
 
         @IntDef({TYPE_DASHBOARD_CATEGORY, TYPE_DASHBOARD_TILE, TYPE_SUGGESTION_HEADER,
-                TYPE_SUGGESTION_TILE, TYPE_CONDITION_CARD, TYPE_DASHBOARD_SPACER})
+                TYPE_SUGGESTION_TILE, TYPE_SUGGESTION_CONDITION_CONTAINER,
+                TYPE_SUGGESTION_CONDITION_HEADER, TYPE_CONDITION_CARD,
+                TYPE_SUGGESTION_CONDITION_FOOTER, TYPE_DASHBOARD_SPACER})
         @Retention(RetentionPolicy.SOURCE)
         public @interface ItemTypes{}
 
@@ -422,8 +579,10 @@
          * To store whether the condition is expanded, useless when {@link #type} is not
          * {@link #TYPE_CONDITION_CARD}
          */
+        @Deprecated
         public final boolean conditionExpanded;
 
+        @Deprecated
         public Item(Object entity, @ItemTypes int type, int id, boolean conditionExpanded) {
             this.entity = entity;
             this.type = type;
@@ -431,6 +590,10 @@
             this.conditionExpanded = conditionExpanded;
         }
 
+        public Item(Object entity, @ItemTypes int type, int id) {
+            this(entity, type, id, false);
+        }
+
         /**
          * Override it to make comparision in the {@link ItemsDataDiffCallback}
          * @param obj object to compared with
@@ -516,4 +679,27 @@
         }
     }
 
+    /**
+     * This class contains the data needed to build the suggestion/condition header. The data can
+     * also be used to check the diff in DiffUtil.Callback
+     */
+    public static class SuggestionConditionHeaderData {
+        public final List<Icon> conditionIcons;
+        public final CharSequence title;
+        public final int conditionCount;
+        public final int hiddenSuggestionCount;
+
+        public SuggestionConditionHeaderData(List<Condition> conditions,
+                int hiddenSuggestionCount) {
+            conditionCount = sizeOf(conditions);
+            this.hiddenSuggestionCount = hiddenSuggestionCount;
+            title = conditionCount > 0 ? conditions.get(0).getTitle() : null;
+            conditionIcons = new ArrayList<Icon>();
+            for (int i = 0; conditions != null && i < conditions.size(); i++) {
+                final Condition condition = conditions.get(i);
+                conditionIcons.add(condition.getIcon());
+            }
+        }
+    }
+
 }
\ No newline at end of file
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProvider.java b/src/com/android/settings/dashboard/DashboardFeatureProvider.java
index 15608a2..939a5d6 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProvider.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProvider.java
@@ -95,4 +95,9 @@
      */
     void openTileIntent(Activity activity, Tile tile);
 
+    /**
+     * Whether or not we should use new UI that combines the settings suggestions and conditions.
+     */
+    boolean combineSuggestionAndCondition();
+
 }
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
index 88cf666..dcae322 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
@@ -206,6 +206,11 @@
         launchIntentOrSelectProfile(activity, tile, intent, MetricsEvent.DASHBOARD_SUMMARY);
     }
 
+    @Override
+    public boolean combineSuggestionAndCondition() {
+        return false;
+    }
+
     private void launchIntentOrSelectProfile(Activity activity, Tile tile, Intent intent,
             int sourceMetricCategory) {
         if (!isIntentResolvable(intent)) {
diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java
index 9f6c61c..7bd11f5 100644
--- a/src/com/android/settings/dashboard/DashboardSummary.java
+++ b/src/com/android/settings/dashboard/DashboardSummary.java
@@ -196,13 +196,16 @@
         mDashboard.addItemDecoration(new DashboardDecorator(getContext()));
         mDashboard.setListener(this);
         Log.d(TAG, "adapter created");
-        mAdapter = new DashboardAdapter(getContext(), bundle, mConditionManager.getConditions());
+        mAdapter = new DashboardAdapter(getContext(), bundle, mConditionManager.getConditions(),
+            mSuggestionParser, this /* SuggestionDismissController.Callback */);
         mDashboard.setAdapter(mAdapter);
-        mSuggestionDismissHandler = new SuggestionDismissController(
+        if (!mDashboardFeatureProvider.combineSuggestionAndCondition()) {
+            mSuggestionDismissHandler = new SuggestionDismissController(
                 getContext(), mDashboard, mSuggestionParser, this);
+            ConditionAdapterUtils.addDismiss(mDashboard);
+        }
         mDashboard.setItemAnimator(new DashboardItemAnimator());
         mSummaryLoader.setSummaryConsumer(mAdapter);
-        ConditionAdapterUtils.addDismiss(mDashboard);
         if (DEBUG_TIMING) {
             Log.d(TAG, "onViewCreated took "
                     + (System.currentTimeMillis() - startTime) + " ms");
@@ -242,7 +245,7 @@
 
     @Override
     public Tile getSuggestionForPosition(int position) {
-        return (Tile) mAdapter.getItem(mAdapter.getItemId(position));
+        return mAdapter.getSuggestion(position);
     }
 
     @Override
diff --git a/src/com/android/settings/dashboard/conditional/ConditionAdapter.java b/src/com/android/settings/dashboard/conditional/ConditionAdapter.java
new file mode 100644
index 0000000..5827d14
--- /dev/null
+++ b/src/com/android/settings/dashboard/conditional/ConditionAdapter.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 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.settings.dashboard.conditional;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.dashboard.DashboardAdapter.DashboardItemHolder;
+import com.android.settings.dashboard.DashboardData;
+import com.android.settings.dashboard.DashboardData.HeaderMode;
+import com.android.settings.overlay.FeatureFactory;
+import java.util.List;
+import java.util.Objects;
+
+public class ConditionAdapter extends RecyclerView.Adapter<DashboardItemHolder> {
+    public static final String TAG = "ConditionAdapter";
+
+    private final Context mContext;
+    private final MetricsFeatureProvider mMetricsFeatureProvider;
+    private List<Condition> mConditions;
+    private @HeaderMode int mMode;
+
+    private View.OnClickListener mConditionClickListener = new View.OnClickListener() {
+
+        @Override
+        public void onClick(View v) {
+            //TODO: get rid of setTag/getTag
+            Condition condition = (Condition) v.getTag();
+            mMetricsFeatureProvider.action(mContext,
+                MetricsEvent.ACTION_SETTINGS_CONDITION_CLICK,
+                condition.getMetricsConstant());
+            condition.onPrimaryClick();
+        }
+    };
+
+    public ConditionAdapter(Context context, List<Condition> conditions, @HeaderMode int mode) {
+        mContext = context;
+        mConditions = conditions;
+        mMode = mode;
+        mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+
+        setHasStableIds(true);
+    }
+
+    public Object getItem(long itemId) {
+        for (Condition condition : mConditions) {
+            if (Objects.hash(condition.getTitle()) == itemId) {
+                return condition;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public DashboardItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        return new DashboardItemHolder(LayoutInflater.from(parent.getContext()).inflate(
+                viewType, parent, false));
+    }
+
+    @Override
+    public void onBindViewHolder(DashboardItemHolder holder, int position) {
+        // TODO: merge methods from ConditionAdapterUtils into this class
+        ConditionAdapterUtils.bindViews(mConditions.get(position), holder,
+            position == mConditions.size() - 1, mConditionClickListener);
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return Objects.hash(mConditions.get(position).getTitle());
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return R.layout.condition_tile_new_ui;
+    }
+
+    @Override
+    public int getItemCount() {
+        if (mMode == DashboardData.HEADER_MODE_FULLY_EXPANDED) {
+            return mConditions.size();
+        }
+        return 0;
+    }
+
+}
diff --git a/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java b/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java
index aebbf93..0e25723 100644
--- a/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java
+++ b/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java
@@ -44,22 +44,28 @@
             @Override
             public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                 return viewHolder.getItemViewType() == R.layout.condition_card
+                    || viewHolder.getItemViewType() == R.layout.condition_tile_new_ui
                         ? super.getSwipeDirs(recyclerView, viewHolder) : 0;
             }
 
             @Override
             public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
-                DashboardAdapter adapter = (DashboardAdapter) recyclerView.getAdapter();
-                Object item = adapter.getItem(viewHolder.getItemId());
-                if (item instanceof Condition) {
-                    ((Condition) item).silence();
+                Object item;
+                if (viewHolder.getItemViewType() == R.layout.condition_card) {
+                    DashboardAdapter adapter = (DashboardAdapter) recyclerView.getAdapter();
+                    item = adapter.getItem(viewHolder.getItemId());
+                } else {
+                    ConditionAdapter adapter = (ConditionAdapter) recyclerView.getAdapter();
+                    item = adapter.getItem(viewHolder.getItemId());
                 }
+                ((Condition) item).silence();
             }
         };
         ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
         itemTouchHelper.attachToRecyclerView(recyclerView);
     }
 
+    @Deprecated
     public static void bindViews(final Condition condition,
             DashboardAdapter.DashboardItemHolder view, boolean isExpanded,
             View.OnClickListener onClickListener, View.OnClickListener onExpandListener) {
@@ -121,6 +127,49 @@
         }
     }
 
+    public static void bindViews(final Condition condition,
+            DashboardAdapter.DashboardItemHolder view, boolean isLastItem,
+            View.OnClickListener onClickListener) {
+        if (condition instanceof AirplaneModeCondition) {
+            Log.d(TAG, "Airplane mode condition has been bound with "
+                + "isActive=" + condition.isActive() + ". Airplane mode is currently " +
+                WirelessUtils.isAirplaneModeOn(condition.mManager.getContext()));
+        }
+        View card = view.itemView.findViewById(R.id.content);
+        card.setTag(condition);
+        card.setOnClickListener(onClickListener);
+        view.icon.setImageIcon(condition.getIcon());
+        view.title.setText(condition.getTitle());
+
+        CharSequence[] actions = condition.getActions();
+        final boolean hasButtons = actions.length > 0;
+        setViewVisibility(view.itemView, R.id.buttonBar, hasButtons);
+
+        view.summary.setText(condition.getSummary());
+        for (int i = 0; i < 2; i++) {
+            Button button = (Button) view.itemView.findViewById(i == 0
+                ? R.id.first_action : R.id.second_action);
+            if (actions.length > i) {
+                button.setVisibility(View.VISIBLE);
+                button.setText(actions[i]);
+                final int index = i;
+                button.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        Context context = v.getContext();
+                        FeatureFactory.getFactory(context).getMetricsFeatureProvider()
+                            .action(context, MetricsEvent.ACTION_SETTINGS_CONDITION_BUTTON,
+                                condition.getMetricsConstant());
+                        condition.onActionClick(index);
+                    }
+                });
+            } else {
+                button.setVisibility(View.GONE);
+            }
+        }
+        setViewVisibility(view.itemView, R.id.divider, !isLastItem);
+    }
+
     private static void setViewVisibility(View containerView, int viewId, boolean visible) {
         View view = containerView.findViewById(viewId);
         if (view != null) {
diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java b/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java
new file mode 100644
index 0000000..3335950
--- /dev/null
+++ b/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2017 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.settings.dashboard.suggestions;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.R.layout;
+import com.android.settings.SettingsActivity;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.dashboard.DashboardAdapter.DashboardItemHolder;
+import com.android.settings.dashboard.DashboardAdapter.IconCache;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.drawer.Tile;
+import java.util.List;
+import java.util.Objects;
+
+public class SuggestionAdapter extends RecyclerView.Adapter<DashboardItemHolder> {
+    public static final String TAG = "SuggestionAdapter";
+
+    private final Context mContext;
+    private final MetricsFeatureProvider mMetricsFeatureProvider;
+    private final SuggestionFeatureProvider mSuggestionFeatureProvider;
+    private List<Tile> mSuggestions;
+    private final IconCache mCache;
+    private final List<String> mSuggestionsShownLogged;
+
+    public SuggestionAdapter(Context context, List<Tile> suggestions,
+            List<String> suggestionsShownLogged) {
+        mContext = context;
+        mSuggestions = suggestions;
+        mSuggestionsShownLogged = suggestionsShownLogged;
+        mCache = new IconCache(context);
+        final FeatureFactory factory = FeatureFactory.getFactory(context);
+        mMetricsFeatureProvider = factory.getMetricsFeatureProvider();
+        mSuggestionFeatureProvider = factory.getSuggestionFeatureProvider(context);
+
+        setHasStableIds(true);
+    }
+
+    @Override
+    public DashboardItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        return new DashboardItemHolder(LayoutInflater.from(parent.getContext()).inflate(
+                viewType, parent, false));
+    }
+
+    @Override
+    public void onBindViewHolder(DashboardItemHolder holder, int position) {
+        final Tile suggestion = (Tile) mSuggestions.get(position);
+        final String suggestionId = mSuggestionFeatureProvider.getSuggestionIdentifier(
+            mContext, suggestion);
+        // This is for cases when a suggestion is dismissed and the next one comes to view
+        if (!mSuggestionsShownLogged.contains(suggestionId)) {
+            mMetricsFeatureProvider.action(
+                mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, suggestionId);
+            mSuggestionsShownLogged.add(suggestionId);
+        }
+        if (suggestion.remoteViews != null) {
+            final ViewGroup itemView = (ViewGroup) holder.itemView;
+            itemView.removeAllViews();
+            itemView.addView(suggestion.remoteViews.apply(itemView.getContext(), itemView));
+        } else {
+            holder.icon.setImageDrawable(mCache.getIcon(suggestion.icon));
+            holder.title.setText(suggestion.title);
+            if (!TextUtils.isEmpty(suggestion.summary)) {
+                holder.summary.setText(suggestion.summary);
+                holder.summary.setVisibility(View.VISIBLE);
+            } else {
+                holder.summary.setVisibility(View.GONE);
+            }
+        }
+        final View divider = holder.itemView.findViewById(R.id.divider);
+        if (divider != null) {
+            divider.setVisibility(position < mSuggestions.size() - 1 ? View.VISIBLE : View.GONE);
+        }
+        View clickHandler = holder.itemView;
+        // If a view with @android:id/primary is defined, use that as the click handler
+        // instead.
+        final View primaryAction = holder.itemView.findViewById(android.R.id.primary);
+        if (primaryAction != null) {
+            clickHandler = primaryAction;
+            // set the item view to disabled to remove any touch effects
+            holder.itemView.setEnabled(false);
+        }
+        clickHandler.setOnClickListener(v -> {
+            mMetricsFeatureProvider.action(mContext,
+                MetricsEvent.ACTION_SETTINGS_SUGGESTION, suggestionId);
+            ((SettingsActivity) mContext).startSuggestion(suggestion.intent);
+        });
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return Objects.hash(mSuggestions.get(position).title);
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return layout.suggestion_tile_new_ui;
+    }
+
+    @Override
+    public int getItemCount() {
+        return mSuggestions.size();
+    }
+
+    public Tile getSuggestion(int position) {
+        final long itemId = getItemId(position);
+        for (Tile tile: mSuggestions) {
+            if (Objects.hash(tile.title) == itemId) {
+                return tile;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionDismissController.java b/src/com/android/settings/dashboard/suggestions/SuggestionDismissController.java
index 776bd1e..f0a65f6 100644
--- a/src/com/android/settings/dashboard/suggestions/SuggestionDismissController.java
+++ b/src/com/android/settings/dashboard/suggestions/SuggestionDismissController.java
@@ -67,6 +67,7 @@
     public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
         final int layoutId = viewHolder.getItemViewType();
         if (layoutId == R.layout.suggestion_tile
+                || layoutId == R.layout.suggestion_tile_new_ui
                 || layoutId == R.layout.suggestion_tile_card) {
             // Only return swipe direction for suggestion tiles. All other types are not swipeable.
             return super.getSwipeDirs(recyclerView, viewHolder);
diff --git a/tests/robotests/src/com/android/settings/conditional/ConditionAdapterUtilsTest.java b/tests/robotests/src/com/android/settings/conditional/ConditionAdapterUtilsTest.java
index dde291d..bf28d97 100644
--- a/tests/robotests/src/com/android/settings/conditional/ConditionAdapterUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/conditional/ConditionAdapterUtilsTest.java
@@ -36,6 +36,8 @@
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Mockito.when;
 
+// Not needed in new UI as the view is always expanded
+@Deprecated
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class ConditionAdapterUtilsTest{
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java
index 8eae8bc..5799b22 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java
@@ -164,14 +164,6 @@
     }
 
     @Test
-    public void testSetConditions_AfterSetConditions_ExpandedConditionNull() {
-        mDashboardAdapter.onExpandClick(mView);
-        assertThat(mDashboardAdapter.mDashboardData.getExpandedCondition()).isEqualTo(mCondition);
-        mDashboardAdapter.setConditions(null);
-        assertThat(mDashboardAdapter.mDashboardData.getExpandedCondition()).isNull();
-    }
-
-    @Test
     public void testSuggestionsLogs_NotExpanded() {
         setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3"));
         verify(mFactory.metricsFeatureProvider, times(2)).action(
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardDataTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardDataTest.java
index 8bbb15b..23681bc 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardDataTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardDataTest.java
@@ -88,17 +88,21 @@
         mDashboardCategory.tiles.add(mTestCategoryTile);
         categories.add(mDashboardCategory);
 
-        // Build DashboardData 
+        // Build DashboardData
         mDashboardDataWithOneConditions = new DashboardData.Builder()
                 .setConditions(oneItemConditions)
                 .setCategories(categories)
                 .setSuggestions(suggestions)
+                .setSuggestionConditionMode(DashboardData.HEADER_MODE_FULLY_EXPANDED)
+                .setCombineSuggestionAndCondition(true)
                 .build();
 
         mDashboardDataWithTwoConditions = new DashboardData.Builder()
                 .setConditions(twoItemsConditions)
                 .setCategories(categories)
                 .setSuggestions(suggestions)
+                .setSuggestionConditionMode(DashboardData.HEADER_MODE_FULLY_EXPANDED)
+                .setCombineSuggestionAndCondition(true)
                 .build();
 
         mDashboardDataWithNoItems = new DashboardData.Builder()
@@ -110,23 +114,33 @@
 
     @Test
     public void testBuildItemsData_containsAllData() {
-        final DashboardData.SuggestionHeaderData data =
-                new DashboardData.SuggestionHeaderData(false, 1, 0);
-        final Object[] expectedObjects = {null, mTestCondition, null, data, mTestSuggestion,
-                mDashboardCategory, mTestCategoryTile};
+        final DashboardData.SuggestionConditionHeaderData data =
+                new DashboardData.SuggestionConditionHeaderData(
+                    mDashboardDataWithOneConditions.getConditions(), 0);
+        final Object[] expectedObjects = {null, data,
+            mDashboardDataWithOneConditions.getSuggestions(),
+            mDashboardDataWithOneConditions.getConditions(),
+            null, mDashboardCategory, mTestCategoryTile};
         final int expectedSize = expectedObjects.length;
 
         assertThat(mDashboardDataWithOneConditions.getItemList().size())
                 .isEqualTo(expectedSize);
         for (int i = 0; i < expectedSize; i++) {
-            if (mDashboardDataWithOneConditions.getItemEntityByPosition(i)
-                    instanceof DashboardData.SuggestionHeaderData) {
+            final Object item = mDashboardDataWithOneConditions.getItemEntityByPosition(i);
+            if (item instanceof DashboardData.SuggestionHeaderData
+                || item instanceof List) {
                 // SuggestionHeaderData is created inside when build, we can only use isEqualTo
-                assertThat(mDashboardDataWithOneConditions.getItemEntityByPosition(i))
-                        .isEqualTo(expectedObjects[i]);
+                assertThat(item).isEqualTo(expectedObjects[i]);
+            } else if (item instanceof DashboardData.SuggestionConditionHeaderData) {
+                DashboardData.SuggestionConditionHeaderData i1 =
+                    (DashboardData.SuggestionConditionHeaderData)item;
+                DashboardData.SuggestionConditionHeaderData i2 =
+                    (DashboardData.SuggestionConditionHeaderData)expectedObjects[i];
+                assertThat(i1.title).isEqualTo(i2.title);
+                assertThat(i1.conditionCount).isEqualTo(i2.conditionCount);
+                assertThat(i1.hiddenSuggestionCount).isEqualTo(i2.hiddenSuggestionCount);
             } else {
-                assertThat(mDashboardDataWithOneConditions.getItemEntityByPosition(i))
-                        .isSameAs(expectedObjects[i]);
+                assertThat(item).isSameAs(expectedObjects[i]);
             }
         }
     }
@@ -134,7 +148,7 @@
     @Test
     public void testGetPositionByEntity_selfInstance_returnPositionFound() {
         final int position = mDashboardDataWithOneConditions
-                .getPositionByEntity(mTestCondition);
+                .getPositionByEntity(mDashboardDataWithOneConditions.getConditions());
         assertThat(position).isNotEqualTo(DashboardData.POSITION_NOT_FOUND);
     }
 
@@ -176,11 +190,17 @@
     }
 
     @Test
-    public void testDiffUtil_InsertOneCondition_ResultDataOneInserted() {
+    public void testDiffUtil_InsertOneCondition_ResultDataTwoChanged() {
         //Build testResultData
         final List<ListUpdateResult.ResultData> testResultData = new ArrayList<>();
+        // Item in position 1 is the header, which contains the number of conditions, changed from
+        // 1 to 2
         testResultData.add(new ListUpdateResult.ResultData(
-                ListUpdateResult.ResultData.TYPE_OPERATION_INSERT, 2, 1));
+                ListUpdateResult.ResultData.TYPE_OPERATION_CHANGE, 1, 1));
+        // Item in position 3 is the condition container containing the list of conditions, which
+        // gets 1 more item
+        testResultData.add(new ListUpdateResult.ResultData(
+            ListUpdateResult.ResultData.TYPE_OPERATION_CHANGE, 3, 1));
 
         testDiffUtil(mDashboardDataWithOneConditions,
                 mDashboardDataWithTwoConditions, testResultData);
@@ -196,31 +216,6 @@
         testDiffUtil(mDashboardDataWithOneConditions, mDashboardDataWithNoItems, testResultData);
     }
 
-    @Test
-    public void testPayload_ItemConditionCard_returnNotNull() {
-        final DashboardData.ItemsDataDiffCallback callback = new DashboardData
-                .ItemsDataDiffCallback(
-                mDashboardDataWithOneConditions.getItemList(),
-                mDashboardDataWithOneConditions.getItemList());
-
-        // Item in position 1 is condition card, which payload should not be null
-        assertThat(callback.getChangePayload(1, 1)).isNotNull();
-    }
-
-    @Test
-    public void testPayload_ItemNotConditionCard_returnNull() {
-        final DashboardData.ItemsDataDiffCallback callback = new DashboardData
-                .ItemsDataDiffCallback(
-                mDashboardDataWithOneConditions.getItemList(),
-                mDashboardDataWithOneConditions.getItemList());
-
-        // Position 0 is spacer, 1 is condition card, so others' payload should be null
-        for (int i = 2; i < mDashboardDataWithOneConditions.getItemList().size(); i++) {
-            assertThat(callback.getChangePayload(i, i)).isNull();
-        }
-
-    }
-
     /**
      * Test when using the
      * {@link com.android.settings.dashboard.DashboardData.ItemsDataDiffCallback}
diff --git a/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionAdapterTest.java b/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionAdapterTest.java
new file mode 100644
index 0000000..141ef6e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionAdapterTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2017 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.settings.dashboard.conditional;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.dashboard.DashboardAdapter;
+import com.android.settings.dashboard.DashboardData;
+import com.android.settings.dashboard.conditional.Condition;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class ConditionAdapterTest {
+    @Mock
+    private Condition mCondition1;
+    @Mock
+    private Condition mCondition2;
+
+    private Context mContext;
+    private ConditionAdapter mConditionAdapter;
+    private List<Condition> mOneCondition;
+    private List<Condition> mTwoConditions;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        final CharSequence[] actions = new CharSequence[2];
+        when(mCondition1.getActions()).thenReturn(actions);
+        when(mCondition1.shouldShow()).thenReturn(true);
+        mOneCondition = new ArrayList<>();
+        mOneCondition.add(mCondition1);
+        mTwoConditions = new ArrayList<>();
+        mTwoConditions.add(mCondition1);
+        mTwoConditions.add(mCondition2);
+    }
+
+    @Test
+    public void getItemCount_notFullyExpanded_shouldReturn0() {
+        mConditionAdapter = new ConditionAdapter(
+            mContext, mOneCondition, DashboardData.HEADER_MODE_DEFAULT);
+        assertThat(mConditionAdapter.getItemCount()).isEqualTo(0);
+
+        mConditionAdapter = new ConditionAdapter(
+            mContext, mOneCondition, DashboardData.HEADER_MODE_SUGGESTION_EXPANDED);
+        assertThat(mConditionAdapter.getItemCount()).isEqualTo(0);
+
+        mConditionAdapter = new ConditionAdapter(
+            mContext, mOneCondition, DashboardData.HEADER_MODE_COLLAPSED);
+        assertThat(mConditionAdapter.getItemCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void getItemCount_fullyExpanded_shouldReturnListSize() {
+        mConditionAdapter = new ConditionAdapter(
+            mContext, mOneCondition, DashboardData.HEADER_MODE_FULLY_EXPANDED);
+        assertThat(mConditionAdapter.getItemCount()).isEqualTo(1);
+
+        mConditionAdapter = new ConditionAdapter(
+            mContext, mTwoConditions, DashboardData.HEADER_MODE_FULLY_EXPANDED);
+        assertThat(mConditionAdapter.getItemCount()).isEqualTo(2);
+    }
+
+    @Test
+    public void getItemViewType_shouldReturnConditionTile() {
+        mConditionAdapter = new ConditionAdapter(
+            mContext, mTwoConditions, DashboardData.HEADER_MODE_FULLY_EXPANDED);
+        assertThat(mConditionAdapter.getItemViewType(0)).isEqualTo(R.layout.condition_tile_new_ui);
+    }
+
+    @Test
+    public void onBindViewHolder_shouldSetListener() {
+        final View view = LayoutInflater.from(mContext).inflate(
+            R.layout.condition_tile_new_ui, new LinearLayout(mContext), true);
+        final DashboardAdapter.DashboardItemHolder viewHolder =
+            new DashboardAdapter.DashboardItemHolder(view);
+        mConditionAdapter = new ConditionAdapter(
+            mContext, mOneCondition, DashboardData.HEADER_MODE_SUGGESTION_EXPANDED);
+
+        mConditionAdapter.onBindViewHolder(viewHolder, 0);
+        final View card = view.findViewById(R.id.content);
+        assertThat(card.hasOnClickListeners()).isTrue();
+    }
+
+    @Test
+    public void viewClick_shouldInvokeConditionPrimaryClick() {
+        final View view = LayoutInflater.from(mContext).inflate(
+            R.layout.condition_tile_new_ui, new LinearLayout(mContext), true);
+        final DashboardAdapter.DashboardItemHolder viewHolder =
+            new DashboardAdapter.DashboardItemHolder(view);
+        mConditionAdapter = new ConditionAdapter(
+            mContext, mOneCondition, DashboardData.HEADER_MODE_SUGGESTION_EXPANDED);
+
+        mConditionAdapter.onBindViewHolder(viewHolder, 0);
+        final View card = view.findViewById(R.id.content);
+        card.performClick();
+        verify(mCondition1).onPrimaryClick();
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterTest.java b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterTest.java
new file mode 100644
index 0000000..cf45c01
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2017 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.settings.dashboard.suggestions;
+
+import android.content.Context;
+import android.graphics.drawable.Icon;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.dashboard.DashboardAdapter;
+import com.android.settingslib.drawer.Tile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class SuggestionAdapterTest {
+    @Mock
+    private Tile mSuggestion1;
+    @Mock
+    private Tile mSuggestion2;
+
+    private Context mContext;
+    private SuggestionAdapter mSuggestionAdapter;
+    private List<Tile> mOneSuggestion;
+    private List<Tile> mTwoSuggestions;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mSuggestion1.title = "Test Suggestion 1";
+        mSuggestion1.icon = mock(Icon.class);
+        mSuggestion2.title = "Test Suggestion 2";
+        mSuggestion2.icon = mock(Icon.class);
+        mOneSuggestion = new ArrayList<>();
+        mOneSuggestion.add(mSuggestion1);
+        mTwoSuggestions = new ArrayList<>();
+        mTwoSuggestions.add(mSuggestion1);
+        mTwoSuggestions.add(mSuggestion2);
+    }
+
+    @Test
+    public void getItemCount_shouldReturnListSize() {
+        mSuggestionAdapter = new SuggestionAdapter(mContext, mOneSuggestion, new ArrayList<>());
+        assertThat(mSuggestionAdapter.getItemCount()).isEqualTo(1);
+
+        mSuggestionAdapter = new SuggestionAdapter(mContext, mTwoSuggestions, new ArrayList<>());
+        assertThat(mSuggestionAdapter.getItemCount()).isEqualTo(2);
+    }
+
+    @Test
+    public void getItemViewType_shouldReturnSuggestionTile() {
+        mSuggestionAdapter = new SuggestionAdapter(mContext, mOneSuggestion, new ArrayList<>());
+        assertThat(mSuggestionAdapter.getItemViewType(0))
+            .isEqualTo(R.layout.suggestion_tile_new_ui);
+    }
+
+    @Test
+    public void onBindViewHolder_shouldSetListener() {
+        final View view = spy(LayoutInflater.from(mContext).inflate(
+            R.layout.suggestion_tile_new_ui, new LinearLayout(mContext), true));
+        final DashboardAdapter.DashboardItemHolder viewHolder =
+            new DashboardAdapter.DashboardItemHolder(view);
+        mSuggestionAdapter = new SuggestionAdapter(mContext, mOneSuggestion, new ArrayList<>());
+
+        mSuggestionAdapter.onBindViewHolder(viewHolder, 0);
+
+        verify(view).setOnClickListener(any(View.OnClickListener.class));
+    }
+
+}