1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.panel;
18 
19 import static com.android.settings.panel.PanelContent.VIEW_TYPE_SLIDER;
20 import static com.android.settings.panel.PanelSlicesAdapter.MAX_NUM_OF_SLICES;
21 import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_INDICATOR_SLICE_URI;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.ArgumentMatchers.eq;
27 import static org.mockito.Mockito.doReturn;
28 import static org.mockito.Mockito.mock;
29 import static org.mockito.Mockito.spy;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
32 
33 import android.content.Context;
34 import android.net.Uri;
35 import android.view.LayoutInflater;
36 import android.view.ViewGroup;
37 import android.widget.FrameLayout;
38 
39 import androidx.lifecycle.LiveData;
40 import androidx.slice.Slice;
41 
42 import com.android.settings.R;
43 import com.android.settings.panel.PanelSlicesAdapter.SliceRowViewHolder;
44 import com.android.settings.testutils.FakeFeatureFactory;
45 
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.junit.runner.RunWith;
49 import org.mockito.ArgumentCaptor;
50 import org.mockito.MockitoAnnotations;
51 import org.robolectric.Robolectric;
52 import org.robolectric.RobolectricTestRunner;
53 import org.robolectric.RuntimeEnvironment;
54 import org.robolectric.android.controller.ActivityController;
55 import org.robolectric.annotation.Config;
56 import org.robolectric.annotation.Implementation;
57 import org.robolectric.annotation.Implements;
58 
59 import java.util.LinkedHashMap;
60 import java.util.Map;
61 
62 @RunWith(RobolectricTestRunner.class)
63 @Config(shadows = PanelSlicesAdapterTest.ShadowLayoutInflater.class)
64 public class PanelSlicesAdapterTest {
65 
66     private static LayoutInflater sLayoutInflater;
67 
68     private Context mContext;
69     private PanelFragment mPanelFragment;
70     private PanelFeatureProvider mPanelFeatureProvider;
71     private FakeFeatureFactory mFakeFeatureFactory;
72     private FakePanelContent mFakePanelContent;
73     private Map<Uri, LiveData<Slice>> mData = new LinkedHashMap<>();
74 
75     @Before
setUp()76     public void setUp() {
77         MockitoAnnotations.initMocks(this);
78         mContext = RuntimeEnvironment.application;
79 
80         mPanelFeatureProvider = spy(new PanelFeatureProviderImpl());
81         mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
82         mFakeFeatureFactory.panelFeatureProvider = mPanelFeatureProvider;
83         mFakePanelContent = new FakePanelContent();
84         doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any());
85 
86         ActivityController<FakeSettingsPanelActivity> activityController =
87                 Robolectric.buildActivity(FakeSettingsPanelActivity.class);
88         activityController.setup();
89 
90         mPanelFragment =
91                 spy((PanelFragment)
92                         activityController
93                                 .get()
94                                 .getSupportFragmentManager()
95                                 .findFragmentById(R.id.main_content));
96 
97     }
98 
addTestLiveData(Uri uri)99     private void addTestLiveData(Uri uri) {
100         // Create a slice to return for the LiveData
101         final Slice slice = spy(new Slice());
102         doReturn(uri).when(slice).getUri();
103         final LiveData<Slice> liveData = mock(LiveData.class);
104         when(liveData.getValue()).thenReturn(slice);
105         mData.put(uri, liveData);
106     }
107 
108     @Test
sizeOfAdapter_shouldNotExceedMaxNum()109     public void sizeOfAdapter_shouldNotExceedMaxNum() {
110         for (int i = 0; i < MAX_NUM_OF_SLICES + 2; i++) {
111             addTestLiveData(Uri.parse("uri" + i));
112         }
113 
114         assertThat(mData.size()).isEqualTo(MAX_NUM_OF_SLICES + 2);
115 
116         final PanelSlicesAdapter adapter =
117                 new PanelSlicesAdapter(mPanelFragment, mData, 0 /* metrics category */);
118         final ViewGroup view = new FrameLayout(mContext);
119         final SliceRowViewHolder viewHolder =
120                 adapter.onCreateViewHolder(view, 0);
121 
122         assertThat(adapter.getItemCount()).isEqualTo(MAX_NUM_OF_SLICES);
123         assertThat(adapter.getData().size()).isEqualTo(MAX_NUM_OF_SLICES);
124     }
125 
126     @Test
mediaOutputIndicatorSlice_notSliderPanel_noSliderLayout()127     public void mediaOutputIndicatorSlice_notSliderPanel_noSliderLayout() {
128         addTestLiveData(MEDIA_OUTPUT_INDICATOR_SLICE_URI);
129 
130         final PanelSlicesAdapter adapter =
131                 new PanelSlicesAdapter(mPanelFragment, mData, 0 /* metrics category */);
132         final int position = 0;
133         final ViewGroup view = new FrameLayout(mContext);
134         final SliceRowViewHolder viewHolder =
135                 adapter.onCreateViewHolder(view, 0 /* view type*/);
136 
137         adapter.onBindViewHolder(viewHolder, position);
138 
139         assertThat(viewHolder.mSliceSliderLayout).isNull();
140     }
141 
142     @Test
onCreateViewHolder_viewTypeSlider_verifyLayout()143     public void onCreateViewHolder_viewTypeSlider_verifyLayout() {
144         final PanelSlicesAdapter adapter =
145                 new PanelSlicesAdapter(mPanelFragment, mData, 0);
146         final ViewGroup view = new FrameLayout(mContext);
147         final ArgumentCaptor<Integer> intArgumentCaptor = ArgumentCaptor.forClass(Integer.class);
148 
149         adapter.onCreateViewHolder(view, VIEW_TYPE_SLIDER);
150 
151         verify(sLayoutInflater).inflate(intArgumentCaptor.capture(), eq(view), eq(false));
152         assertThat(intArgumentCaptor.getValue()).isEqualTo(R.layout.panel_slice_slider_row);
153     }
154 
155     @Test
onCreateViewHolder_viewTypeDefault_verifyLayout()156     public void onCreateViewHolder_viewTypeDefault_verifyLayout() {
157         final PanelSlicesAdapter adapter =
158                 new PanelSlicesAdapter(mPanelFragment, mData, 0);
159         final ViewGroup view = new FrameLayout(mContext);
160         final ArgumentCaptor<Integer> intArgumentCaptor = ArgumentCaptor.forClass(Integer.class);
161 
162         adapter.onCreateViewHolder(view, 0);
163 
164         verify(sLayoutInflater).inflate(intArgumentCaptor.capture(), eq(view), eq(false));
165         assertThat(intArgumentCaptor.getValue()).isEqualTo(R.layout.panel_slice_row);
166     }
167 
168     @Implements(LayoutInflater.class)
169     public static class ShadowLayoutInflater {
170 
171         @Implementation
from(Context context)172         public static LayoutInflater from(Context context) {
173             final LayoutInflater inflater =
174                     (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
175             if (inflater == null) {
176                 throw new AssertionError("LayoutInflater not found.");
177             }
178             sLayoutInflater = spy(inflater);
179             return sLayoutInflater;
180         }
181     }
182 }
183