OSDN Git Service

Update SettingsPanel UI
authorMatthew Fritze <mfritze@google.com>
Wed, 28 Nov 2018 21:05:43 +0000 (13:05 -0800)
committerMatthew Fritze <mfritze@google.com>
Fri, 30 Nov 2018 21:26:50 +0000 (13:26 -0800)
UI changes include:
- RecyclerView to host slices
- Font family to headline font
- Title is now centered
- Added SeeMore & Done buttons
- Horizontal Dividers between slices
- Indented Slices
- Landscape layout is fullscreen

Change-Id: I3549c847fc88edd81f670ddfa2907dd3741441e0
Screenshot: https://screenshot.googleplex.com/RzWktzOZJkc
Test: Robolectric
Test: Manual app
Bug: 118622007

14 files changed:
res/layout-land/panel_layout.xml [new file with mode: 0644]
res/layout/panel_buttons.xml [new file with mode: 0644]
res/layout/panel_layout.xml
res/layout/panel_slice_row.xml [new file with mode: 0644]
res/values/themes.xml
src/com/android/settings/panel/InternetConnectivityPanel.java
src/com/android/settings/panel/PanelFragment.java
src/com/android/settings/panel/PanelSlicesAdapter.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/panel/FakePanelContent.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/panel/FakeSettingsPanelActivity.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/panel/InternetConnectivityPanelTest.java
tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java

diff --git a/res/layout-land/panel_layout.xml b/res/layout-land/panel_layout.xml
new file mode 100644 (file)
index 0000000..3975bfe
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2018 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="match_parent"
+              android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:paddingBottom="24dp"
+        android:paddingTop="18dp"
+        android:textColor="?android:attr/colorPrimary"
+        android:textSize="20sp"/>
+
+    <include layout="@layout/horizontal_divider"/>
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/panel_parent_layout"
+        android:scrollbars="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"/>
+
+    <include layout="@layout/panel_buttons"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/panel_buttons.xml b/res/layout/panel_buttons.xml
new file mode 100644 (file)
index 0000000..1bb3898
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2018 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:paddingTop="14dp"
+    android:paddingBottom="14dp"
+    android:orientation="horizontal">
+
+    <Button
+        android:id="@+id/see_more"
+        style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="20dp"
+        android:text="@string/see_more"/>
+
+    <Space
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent" />
+
+    <Button
+        android:id="@+id/done"
+        style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="20dp"
+        android:text="@string/done"/>
+</LinearLayout>
\ No newline at end of file
index cbdd53f..a6f62a4 100644 (file)
     See the License for the specific language governing permissions and
     limitations under the License
   -->
+
+<!-- Note: There is a landscape version of this layout. -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/panel_parent_layout"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/title"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:paddingLeft="24dp"
-        android:paddingRight="24dp"
-        android:paddingBottom="8dp"
-        android:layout_margin="4dp"
-        android:orientation="vertical">
+        android:gravity="center"
+        android:paddingBottom="24dp"
+        android:paddingTop="18dp"
+        android:textColor="?android:attr/colorPrimary"
+        android:textSize="20sp"/>
+
+    <include layout="@layout/horizontal_divider"/>
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/panel_parent_layout"
+        android:scrollbars="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+
+    <include layout="@layout/panel_buttons"/>
 </LinearLayout>
\ No newline at end of file
diff --git a/res/layout/panel_slice_row.xml b/res/layout/panel_slice_row.xml
new file mode 100644 (file)
index 0000000..4ce3494
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2018 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">
+
+    <androidx.slice.widget.SliceView
+        android:id="@+id/slice_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="20dp"
+        android:paddingEnd="20dp" />
+
+    <include layout="@layout/horizontal_divider"/>
+</LinearLayout>
\ No newline at end of file
index 873216d..b172b21 100644 (file)
 
     <style name="Theme.BottomDialog" parent="@*android:style/Theme.DeviceDefault.Settings.Dialog">
         <item name="android:windowBackground">@drawable/settings_panel_background</item>
+        <item name="android:dividerHorizontal">@*android:drawable/list_divider_material</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
     </style>
 
 </resources>
index 1e01e71..5b7bc32 100644 (file)
@@ -19,6 +19,7 @@ package com.android.settings.panel;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.provider.Settings;
 
 import com.android.settings.R;
 import com.android.settings.slices.CustomSliceRegistry;
@@ -60,6 +61,6 @@ public class InternetConnectivityPanel implements PanelContent {
 
     @Override
     public Intent getSeeMoreIntent() {
-        return null;
+        return new Intent(Settings.ACTION_WIRELESS_SETTINGS);
     }
 }
index bbdaec3..e61b8f8 100644 (file)
 
 package com.android.settings.panel;
 
-import android.net.Uri;
+import android.content.Intent;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
-import android.widget.LinearLayout;
+import android.widget.Button;
+import android.widget.TextView;
 
-import androidx.lifecycle.LiveData;
-import androidx.slice.Slice;
-import androidx.slice.widget.SliceLiveData;
-import androidx.slice.widget.SliceView;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
 
 import androidx.annotation.NonNull;
@@ -38,20 +39,24 @@ import androidx.fragment.app.FragmentActivity;
 
 import com.android.settings.overlay.FeatureFactory;
 
-import java.util.ArrayList;
-import java.util.List;
-
 public class PanelFragment extends Fragment {
 
     private static final String TAG = "PanelFragment";
 
-    private List<SliceView> mSliceViewList;
-    private List<LiveData<Slice>> mSliceDataList;
-    private LinearLayout mPanelLayout;
+    private TextView mTitleView;
+    private Button mSeeMoreButton;
+    private Button mDoneButton;
+    private RecyclerView mPanelSlices;
+
+    @VisibleForTesting
+    PanelSlicesAdapter mAdapter;
+
+    private View.OnClickListener mDoneButtonListener = (v) -> {
+        Log.d(TAG, "Closing dialog");
+        getActivity().finish();
+    };
 
     public PanelFragment() {
-        mSliceViewList = new ArrayList<>();
-        mSliceDataList = new ArrayList<>();
     }
 
     @Nullable
@@ -61,28 +66,37 @@ public class PanelFragment extends Fragment {
         final FragmentActivity activity = getActivity();
         final View view = inflater.inflate(R.layout.panel_layout, container, false);
 
-        mPanelLayout = view.findViewById(R.id.panel_parent_layout);
-        final Bundle arguments = getArguments();
+        mPanelSlices = view.findViewById(R.id.panel_parent_layout);
+        mSeeMoreButton = view.findViewById(R.id.see_more);
+        mDoneButton = view.findViewById(R.id.done);
+        mTitleView = view.findViewById(R.id.title);
 
+        final Bundle arguments = getArguments();
         final String panelType = arguments.getString(SettingsPanelActivity.KEY_PANEL_TYPE_ARGUMENT);
 
         final PanelContent panel = FeatureFactory.getFactory(activity)
                 .getPanelFeatureProvider()
                 .getPanel(activity, panelType);
 
-        activity.setTitle(panel.getTitle());
+        mAdapter = new PanelSlicesAdapter(this, panel.getSlices());
 
+        mPanelSlices.setHasFixedSize(true);
+        mPanelSlices.setLayoutManager(new LinearLayoutManager((activity)));
+        mPanelSlices.setAdapter(mAdapter);
 
-        for (Uri uri : panel.getSlices()) {
-            final SliceView sliceView = new SliceView(activity);
-            mPanelLayout.addView(sliceView);
-            final LiveData<Slice> liveData = SliceLiveData.fromUri(activity, uri);
-            liveData.observe(this /* lifecycleOwner */, sliceView);
+        mTitleView.setText(panel.getTitle());
 
-            mSliceDataList.add(liveData);
-            mSliceViewList.add(sliceView);
-        }
+        mSeeMoreButton.setOnClickListener(getSeeMoreListener(panel.getSeeMoreIntent()));
+        mDoneButton.setOnClickListener(mDoneButtonListener);
 
         return view;
     }
+
+    private View.OnClickListener getSeeMoreListener(final Intent intent) {
+        return (v) -> {
+            final FragmentActivity activity = getActivity();
+            activity.startActivity(intent);
+            activity.finish();
+        };
+    }
 }
diff --git a/src/com/android/settings/panel/PanelSlicesAdapter.java b/src/com/android/settings/panel/PanelSlicesAdapter.java
new file mode 100644 (file)
index 0000000..f688512
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 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.panel;
+
+import android.content.Context;
+import android.net.Uri;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.LiveData;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.slice.Slice;
+import androidx.slice.widget.SliceLiveData;
+import androidx.slice.widget.SliceView;
+
+import com.android.settings.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * RecyclerView adapter for Slices in Settings Panels.
+ */
+public class PanelSlicesAdapter
+        extends RecyclerView.Adapter<PanelSlicesAdapter.SliceRowViewHolder> {
+
+    private final List<Uri> mSliceUris;
+    private final PanelFragment mPanelFragment;
+
+    public PanelSlicesAdapter(PanelFragment fragment, List<Uri> sliceUris) {
+        mPanelFragment = fragment;
+        mSliceUris = new ArrayList<>(sliceUris);
+    }
+
+    @NonNull
+    @Override
+    public SliceRowViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
+        final Context context = viewGroup.getContext();
+        final LayoutInflater inflater = LayoutInflater.from(context);
+        final View view = inflater.inflate(R.layout.panel_slice_row, viewGroup, false);
+
+        return new SliceRowViewHolder(view);
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull SliceRowViewHolder sliceRowViewHolder, int position) {
+        sliceRowViewHolder.onBind(mPanelFragment, mSliceUris.get(position));
+    }
+
+    @Override
+    public int getItemCount() {
+        return mSliceUris.size();
+    }
+
+    @VisibleForTesting
+    List<Uri> getData() {
+        return mSliceUris;
+    }
+
+    /**
+     * ViewHolder for binding Slices to SliceViews.
+     */
+    public static class SliceRowViewHolder extends RecyclerView.ViewHolder {
+
+        @VisibleForTesting
+        LiveData<Slice> sliceLiveData;
+
+        @VisibleForTesting
+        final SliceView sliceView;
+
+        public SliceRowViewHolder(View view) {
+            super(view);
+            sliceView = view.findViewById(R.id.slice_view);
+            sliceView.setMode(SliceView.MODE_LARGE);
+        }
+
+        public void onBind(PanelFragment fragment, Uri sliceUri) {
+            final Context context = sliceView.getContext();
+            sliceLiveData = SliceLiveData.fromUri(context, sliceUri);
+            sliceLiveData.observe(fragment.getViewLifecycleOwner(), sliceView);
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/panel/FakePanelContent.java b/tests/robotests/src/com/android/settings/panel/FakePanelContent.java
new file mode 100644 (file)
index 0000000..60f0d5d
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 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.panel;
+
+import static com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI;
+
+import android.content.Intent;
+import android.net.Uri;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Fake PanelContent for testing.
+ */
+public class FakePanelContent implements PanelContent {
+
+    public static final String FAKE_KEY = "fake_key";
+
+    public static final CharSequence TITLE = "title";
+
+    public static final List<Uri> SLICE_URIS = Arrays.asList(
+        WIFI_SLICE_URI
+    );
+
+    public static final Intent INTENT = new Intent();
+
+    @Override
+    public CharSequence getTitle() {
+        return TITLE;
+    }
+
+    @Override
+    public List<Uri> getSlices() {
+        return SLICE_URIS;
+    }
+
+    @Override
+    public Intent getSeeMoreIntent() {
+        return INTENT;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/panel/FakeSettingsPanelActivity.java b/tests/robotests/src/com/android/settings/panel/FakeSettingsPanelActivity.java
new file mode 100644 (file)
index 0000000..afd0bec
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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.panel;
+
+import android.content.ComponentName;
+import android.content.Intent;
+
+public class FakeSettingsPanelActivity extends SettingsPanelActivity {
+    @Override
+    public ComponentName getCallingActivity() {
+        return new ComponentName("fake-package", "fake-class");
+    }
+
+    @Override
+    public Intent getIntent() {
+        final Intent intent = new Intent();
+        intent.putExtra(SettingsPanelActivity.EXTRA_PANEL_TYPE, FakePanelContent.FAKE_KEY);
+        return intent;
+    }
+}
\ No newline at end of file
index 243c19b..aae85ab 100644 (file)
@@ -49,4 +49,9 @@ public class InternetConnectivityPanelTest {
         assertThat(uris).containsExactly(CustomSliceRegistry.WIFI_SLICE_URI,
                 CustomSliceRegistry.AIRPLANE_URI);
     }
+
+    @Test
+    public void getSeeMoreIntent_notNull() {
+        assertThat(mPanel.getSeeMoreIntent()).isNotNull();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java b/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
new file mode 100644 (file)
index 0000000..9b29d48
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 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.panel;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.widget.LinearLayout;
+
+import com.android.settings.R;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.android.controller.ActivityController;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class PanelFragmentTest {
+
+    private Context mContext;
+    private PanelFragment mPanelFragment;
+    private FakeFeatureFactory mFakeFeatureFactory;
+    private PanelFeatureProvider mPanelFeatureProvider;
+    private FakePanelContent mFakePanelContent;
+
+    private final String FAKE_EXTRA = "fake_extra";
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+
+        mPanelFeatureProvider = spy(new PanelFeatureProviderImpl());
+        mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+        mFakeFeatureFactory.panelFeatureProvider = mPanelFeatureProvider;
+        mFakePanelContent = new FakePanelContent();
+        doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any());
+
+
+        ActivityController<FakeSettingsPanelActivity> activityController =
+                Robolectric.buildActivity(FakeSettingsPanelActivity.class);
+        activityController.setup();
+
+        mPanelFragment =
+                spy((PanelFragment)
+                        activityController
+                                .get()
+                                .getSupportFragmentManager()
+                                .findFragmentById(R.id.main_content));
+    }
+
+    @Test
+    public void onCreateView_adapterGetsDataset() {
+        final Bundle bundle = new Bundle();
+        bundle.putString(SettingsPanelActivity.KEY_PANEL_TYPE_ARGUMENT, FAKE_EXTRA);
+        doReturn(bundle).when(mPanelFragment).getArguments();
+        mPanelFragment.onCreateView(LayoutInflater.from(mContext),
+                new LinearLayout(mContext), null);
+        PanelSlicesAdapter adapter = mPanelFragment.mAdapter;
+
+        assertThat(adapter.getData()).containsAllIn(mFakePanelContent.getSlices());
+    }
+
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java b/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java
new file mode 100644 (file)
index 0000000..bfd7863
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 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.panel;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.settings.R;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+
+import org.junit.Test;
+
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.android.controller.ActivityController;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class PanelSlicesAdapterTest {
+
+    private Context mContext;
+    private PanelFragment mPanelFragment;
+    private FakePanelContent mFakePanelContent;
+    private FakeFeatureFactory mFakeFeatureFactory;
+    private PanelFeatureProvider mPanelFeatureProvider;
+
+    private PanelSlicesAdapter mAdapter;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+
+        final ActivityController<FakeSettingsPanelActivity> activityController =
+                Robolectric.buildActivity(FakeSettingsPanelActivity.class);
+        activityController.setup();
+
+        mPanelFragment =
+                spy((PanelFragment)
+                        activityController
+                                .get()
+                                .getSupportFragmentManager()
+                                .findFragmentById(R.id.main_content));
+
+        mPanelFeatureProvider = spy(new PanelFeatureProviderImpl());
+        mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+        mFakeFeatureFactory.panelFeatureProvider = mPanelFeatureProvider;
+        mFakePanelContent = new FakePanelContent();
+        doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any());
+
+        mAdapter = new PanelSlicesAdapter(mPanelFragment, mFakePanelContent.getSlices());
+    }
+
+    @Test
+    public void onCreateViewHolder_returnsSliceRowViewHolder() {
+        final ViewGroup view = new FrameLayout(mContext);
+        final PanelSlicesAdapter.SliceRowViewHolder viewHolder =
+                mAdapter.onCreateViewHolder(view, 0);
+
+        assertThat(viewHolder.sliceView).isNotNull();
+    }
+
+    @Test
+    public void onBindViewHolder_bindsSlice() {
+        final int position = 0;
+        final ViewGroup view = new FrameLayout(mContext);
+        final PanelSlicesAdapter.SliceRowViewHolder viewHolder =
+                mAdapter.onCreateViewHolder(view, 0 /* view type*/);
+
+        mAdapter.onBindViewHolder(viewHolder, position);
+
+        assertThat(viewHolder.sliceLiveData).isNotNull();
+    }
+}
\ No newline at end of file
index 978dd7d..bb475f3 100644 (file)
@@ -63,9 +63,9 @@ public class FakeFeatureFactory extends FeatureFactory {
     public final UserFeatureProvider userFeatureProvider;
     public final AssistGestureFeatureProvider assistGestureFeatureProvider;
     public final AccountFeatureProvider mAccountFeatureProvider;
-    public final PanelFeatureProvider mPanelFeatureProvider;
     public final ContextualCardFeatureProvider mContextualCardFeatureProvider;
 
+    public PanelFeatureProvider panelFeatureProvider;
     public SlicesFeatureProvider slicesFeatureProvider;
     public SearchFeatureProvider searchFeatureProvider;
 
@@ -106,8 +106,8 @@ public class FakeFeatureFactory extends FeatureFactory {
         assistGestureFeatureProvider = mock(AssistGestureFeatureProvider.class);
         slicesFeatureProvider = mock(SlicesFeatureProvider.class);
         mAccountFeatureProvider = mock(AccountFeatureProvider.class);
-        mPanelFeatureProvider = mock(PanelFeatureProvider.class);
         mContextualCardFeatureProvider = mock(ContextualCardFeatureProvider.class);
+        panelFeatureProvider = mock(PanelFeatureProvider.class);
     }
 
     @Override
@@ -192,7 +192,7 @@ public class FakeFeatureFactory extends FeatureFactory {
 
     @Override
     public PanelFeatureProvider getPanelFeatureProvider() {
-        return mPanelFeatureProvider;
+        return panelFeatureProvider;
     }
 
     public ContextualCardFeatureProvider getContextualCardFeatureProvider() {