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 package com.android.settings.datausage;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 
20 import static org.mockito.Mockito.mock;
21 import static org.mockito.Mockito.spy;
22 import static org.mockito.Mockito.verify;
23 
24 import android.app.Activity;
25 import android.util.SparseIntArray;
26 import android.view.LayoutInflater;
27 import android.view.View;
28 import android.widget.TextView;
29 
30 import androidx.preference.PreferenceViewHolder;
31 
32 import com.android.settings.R;
33 import com.android.settings.datausage.ChartDataUsagePreference.DataUsageSummaryNode;
34 import com.android.settings.widget.UsageView;
35 import com.android.settingslib.net.NetworkCycleChartData;
36 import com.android.settingslib.net.NetworkCycleData;
37 
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 import org.mockito.ArgumentCaptor;
42 import org.mockito.MockitoAnnotations;
43 import org.robolectric.Robolectric;
44 import org.robolectric.RobolectricTestRunner;
45 
46 import java.util.ArrayList;
47 import java.util.List;
48 import java.util.concurrent.TimeUnit;
49 
50 @RunWith(RobolectricTestRunner.class)
51 public class ChartDataUsagePreferenceTest {
52 
53     // Test cycle start date, 20 Mar 2018 22:00: GMT
54     private static final long TIMESTAMP_START = 1521583200000L;
55     // Test bucket end date, 22 Mar 2018 00:00:00
56     private static final long TIMESTAMP_END = 1521676800000L;
57 
58     private List<NetworkCycleData> mNetworkCycleData;
59     private NetworkCycleChartData mNetworkCycleChartData;
60     private ChartDataUsagePreference mPreference;
61     private Activity mActivity;
62     private PreferenceViewHolder mHolder;
63 
64     @Before
setUp()65     public void setUp() {
66         MockitoAnnotations.initMocks(this);
67 
68         mActivity = spy(Robolectric.setupActivity(Activity.class));
69         mPreference = new ChartDataUsagePreference(mActivity, null /* attrs */);
70         LayoutInflater inflater = LayoutInflater.from(mActivity);
71         View view = inflater.inflate(mPreference.getLayoutResource(), null /* root */,
72                 false /* attachToRoot */);
73         mHolder = spy(PreferenceViewHolder.createInstanceForTests(view));
74     }
75 
76     @Test
calcPoints_dataAvailableFromCycleStart_shouldAddDataPointsOnly()77     public void calcPoints_dataAvailableFromCycleStart_shouldAddDataPointsOnly() {
78         final UsageView usageView = mock(UsageView.class);
79         final ArgumentCaptor<SparseIntArray> pointsCaptor =
80                 ArgumentCaptor.forClass(SparseIntArray.class);
81         createTestNetworkData();
82         mPreference.setNetworkCycleData(mNetworkCycleChartData);
83 
84         mPreference.calcPoints(usageView, mNetworkCycleData.subList(0, 5));
85 
86         verify(usageView).addPath(pointsCaptor.capture());
87         final SparseIntArray points = pointsCaptor.getValue();
88         // the point should be normal usage data
89         assertThat(points.valueAt(1)).isNotEqualTo(-1);
90     }
91 
92     @Test
calcPoints_dataNotAvailableAtCycleStart_shouldIndicateStartOfData()93     public void calcPoints_dataNotAvailableAtCycleStart_shouldIndicateStartOfData() {
94         final UsageView usageView = mock(UsageView.class);
95         final ArgumentCaptor<SparseIntArray> pointsCaptor =
96                 ArgumentCaptor.forClass(SparseIntArray.class);
97         createTestNetworkData();
98         mPreference.setNetworkCycleData(mNetworkCycleChartData);
99 
100         mPreference.calcPoints(usageView, mNetworkCycleData.subList(2, 7));
101 
102         verify(usageView).addPath(pointsCaptor.capture());
103         final SparseIntArray points = pointsCaptor.getValue();
104         // indicator that no data is available
105         assertThat(points.keyAt(1)).isEqualTo(points.keyAt(2) - 1);
106         assertThat(points.valueAt(1)).isEqualTo(-1);
107     }
108 
109     @Test
calcPoints_shouldNotDrawPointForFutureDate()110     public void calcPoints_shouldNotDrawPointForFutureDate() {
111         final UsageView usageView = mock(UsageView.class);
112         final ArgumentCaptor<SparseIntArray> pointsCaptor =
113             ArgumentCaptor.forClass(SparseIntArray.class);
114         final long tonight = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(12);
115         mNetworkCycleData = new ArrayList<>();
116         // add test usage data for last 5 days
117         mNetworkCycleData.add(createNetworkCycleData(
118             tonight - TimeUnit.DAYS.toMillis(5), tonight - TimeUnit.DAYS.toMillis(4), 743823454L));
119         mNetworkCycleData.add(createNetworkCycleData(
120             tonight - TimeUnit.DAYS.toMillis(4), tonight - TimeUnit.DAYS.toMillis(3), 64396L));
121         mNetworkCycleData.add(createNetworkCycleData(
122             tonight - TimeUnit.DAYS.toMillis(3), tonight - TimeUnit.DAYS.toMillis(2), 2832L));
123         mNetworkCycleData.add(createNetworkCycleData(
124             tonight - TimeUnit.DAYS.toMillis(2), tonight - TimeUnit.DAYS.toMillis(1), 83849690L));
125         mNetworkCycleData.add(createNetworkCycleData(
126             tonight - TimeUnit.DAYS.toMillis(1), tonight, 1883657L));
127         // add dummy usage data for next 5 days
128         mNetworkCycleData.add(createNetworkCycleData(
129             tonight, tonight + TimeUnit.DAYS.toMillis(1), 0L));
130         mNetworkCycleData.add(createNetworkCycleData(
131             tonight + TimeUnit.DAYS.toMillis(1), tonight + TimeUnit.DAYS.toMillis(2), 0L));
132         mNetworkCycleData.add(createNetworkCycleData(
133             tonight + TimeUnit.DAYS.toMillis(2), tonight + TimeUnit.DAYS.toMillis(3), 0L));
134         mNetworkCycleData.add(createNetworkCycleData(
135             tonight + TimeUnit.DAYS.toMillis(3), tonight + TimeUnit.DAYS.toMillis(4), 0L));
136         mNetworkCycleData.add(createNetworkCycleData(
137             tonight + TimeUnit.DAYS.toMillis(4), tonight + TimeUnit.DAYS.toMillis(5), 0L));
138         mNetworkCycleData.add(createNetworkCycleData(
139             tonight + TimeUnit.DAYS.toMillis(5), tonight + TimeUnit.DAYS.toMillis(6), 0L));
140 
141         final NetworkCycleChartData.Builder builder = new NetworkCycleChartData.Builder();
142         builder.setUsageBuckets(mNetworkCycleData)
143             .setStartTime(tonight - TimeUnit.DAYS.toMillis(5))
144             .setEndTime(tonight + TimeUnit.DAYS.toMillis(6));
145         mNetworkCycleChartData = builder.build();
146         mPreference.setNetworkCycleData(mNetworkCycleChartData);
147 
148         mPreference.calcPoints(usageView, mNetworkCycleData);
149 
150         verify(usageView).addPath(pointsCaptor.capture());
151         final SparseIntArray points = pointsCaptor.getValue();
152         // should only have 7 points: 1 dummy point indicating the start of data, starting point 0,
153         // and 5 actual data point for each day
154         assertThat(points.size()).isEqualTo(7);
155         assertThat(points.keyAt(0)).isEqualTo(-1);
156         assertThat(points.keyAt(1)).isEqualTo(0);
157         assertThat(points.keyAt(2)).isEqualTo(TimeUnit.DAYS.toMinutes(1));
158         assertThat(points.keyAt(3)).isEqualTo(TimeUnit.DAYS.toMinutes(2));
159         assertThat(points.keyAt(4)).isEqualTo(TimeUnit.DAYS.toMinutes(3));
160         assertThat(points.keyAt(5)).isEqualTo(TimeUnit.DAYS.toMinutes(4));
161         assertThat(points.keyAt(6)).isEqualTo(TimeUnit.DAYS.toMinutes(5));
162     }
163 
164     @Test
notifyChange_nonEmptyDataUsage_shouldHaveSingleContentDescription()165     public void notifyChange_nonEmptyDataUsage_shouldHaveSingleContentDescription() {
166         final UsageView chart = (UsageView) mHolder.findViewById(R.id.data_usage);
167         final TextView labelTop = (TextView) mHolder.findViewById(R.id.label_top);
168         final TextView labelMiddle = (TextView) mHolder.findViewById(R.id.label_middle);
169         final TextView labelBottom = (TextView) mHolder.findViewById(R.id.label_bottom);
170         final TextView labelStart = (TextView) mHolder.findViewById(R.id.label_start);
171         final TextView labelEnd = (TextView) mHolder.findViewById(R.id.label_end);
172         createTestNetworkData();
173         mPreference.setNetworkCycleData(mNetworkCycleChartData);
174 
175         mPreference.onBindViewHolder(mHolder);
176 
177         assertThat(chart.getContentDescription()).isNotNull();
178         assertThat(labelTop.getContentDescription()).isNull();
179         assertThat(labelMiddle.getContentDescription()).isNull();
180         assertThat(labelBottom.getContentDescription()).isNull();
181         assertThat(labelStart.getContentDescription()).isNull();
182         assertThat(labelEnd.getContentDescription()).isNull();
183     }
184 
185     @Test
getDensedStatsData_someSamePercentageNodes_getDifferentPercentageNodes()186     public void getDensedStatsData_someSamePercentageNodes_getDifferentPercentageNodes() {
187         createSomeSamePercentageNetworkData();
188         final List<DataUsageSummaryNode> densedStatsData =
189                 mPreference.getDensedStatsData(mNetworkCycleData);
190 
191         assertThat(mNetworkCycleData.size()).isEqualTo(8);
192         assertThat(densedStatsData.size()).isEqualTo(3);
193         assertThat(densedStatsData.get(0).getDataUsagePercentage()).isEqualTo(33);
194         assertThat(densedStatsData.get(1).getDataUsagePercentage()).isEqualTo(99);
195         assertThat(densedStatsData.get(2).getDataUsagePercentage()).isEqualTo(100);
196     }
197 
createTestNetworkData()198     private void createTestNetworkData() {
199         mNetworkCycleData = new ArrayList<>();
200         // create 10 arbitrary network data
201         mNetworkCycleData.add(createNetworkCycleData(1521583200000L, 1521586800000L, 743823454L));
202         mNetworkCycleData.add(createNetworkCycleData(1521586800000L, 1521590400000L, 64396L));
203         mNetworkCycleData.add(createNetworkCycleData(1521590400000L, 1521655200000L, 2832L));
204         mNetworkCycleData.add(createNetworkCycleData(1521655200000L, 1521658800000L, 83849690L));
205         mNetworkCycleData.add(createNetworkCycleData(1521658800000L, 1521662400000L, 1883657L));
206         mNetworkCycleData.add(createNetworkCycleData(1521662400000L, 1521666000000L, 705259L));
207         mNetworkCycleData.add(createNetworkCycleData(1521666000000L, 1521669600000L, 216169L));
208         mNetworkCycleData.add(createNetworkCycleData(1521669600000L, 1521673200000L, 6069175L));
209         mNetworkCycleData.add(createNetworkCycleData(1521673200000L, 1521676800000L, 120389L));
210         mNetworkCycleData.add(createNetworkCycleData(1521676800000L, 1521678800000L, 29947L));
211 
212         final NetworkCycleChartData.Builder builder = new NetworkCycleChartData.Builder();
213         builder.setUsageBuckets(mNetworkCycleData)
214             .setStartTime(TIMESTAMP_START)
215             .setEndTime(TIMESTAMP_END);
216         mNetworkCycleChartData = builder.build();
217     }
218 
createSomeSamePercentageNetworkData()219     private void createSomeSamePercentageNetworkData() {
220         mNetworkCycleData = new ArrayList<>();
221         mNetworkCycleData.add(createNetworkCycleData(1521583200000L, 1521586800000L, 100));//33%
222         mNetworkCycleData.add(createNetworkCycleData(1521586800000L, 1521590400000L, 1));  //33%
223         mNetworkCycleData.add(createNetworkCycleData(1521590400000L, 1521655200000L, 0));  //33%
224         mNetworkCycleData.add(createNetworkCycleData(1521655200000L, 1521658800000L, 0));  //33%
225         mNetworkCycleData.add(createNetworkCycleData(1521658800000L, 1521662400000L, 200));//99%
226         mNetworkCycleData.add(createNetworkCycleData(1521662400000L, 1521666000000L, 1));  //99%
227         mNetworkCycleData.add(createNetworkCycleData(1521666000000L, 1521669600000L, 1));  //100
228         mNetworkCycleData.add(createNetworkCycleData(1521669600000L, 1521673200000L, 0));  //100%
229     }
230 
createNetworkCycleData(long start, long end, long usage)231     private NetworkCycleData createNetworkCycleData(long start, long end, long usage) {
232         return new NetworkCycleData.Builder()
233             .setStartTime(start).setEndTime(end).setTotalUsage(usage).build();
234     }
235 }
236