Merge "Avoid settingslib.widget.preference.radio" into main
diff --git a/src/com/android/settings/datausage/AppDataUsage.java b/src/com/android/settings/datausage/AppDataUsage.java
index 1645586..c3be0aa 100644
--- a/src/com/android/settings/datausage/AppDataUsage.java
+++ b/src/com/android/settings/datausage/AppDataUsage.java
@@ -310,7 +310,7 @@
private void initCycle() {
mCycle = findPreference(KEY_CYCLE);
- mCycleAdapter = new CycleAdapter(mContext, mCycle, mCycleListener);
+ mCycleAdapter = new CycleAdapter(mContext, mCycle);
if (mCycles != null) {
// If coming from a page like DataUsageList where already has a selected cycle, display
// that before loading to reduce flicker.
@@ -435,7 +435,7 @@
return SettingsEnums.APP_DATA_USAGE;
}
- private AdapterView.OnItemSelectedListener mCycleListener =
+ private final AdapterView.OnItemSelectedListener mCycleListener =
new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
@@ -471,6 +471,7 @@
public void onLoadFinished(@NonNull Loader<List<NetworkCycleDataForUid>> loader,
List<NetworkCycleDataForUid> data) {
mUsageData = data;
+ mCycle.setOnItemSelectedListener(mCycleListener);
mCycleAdapter.updateCycleList(data);
if (mSelectedCycle > 0L) {
final int numCycles = data.size();
diff --git a/src/com/android/settings/datausage/ChartDataUsagePreference.java b/src/com/android/settings/datausage/ChartDataUsagePreference.java
index e2a103e..fa467d2 100644
--- a/src/com/android/settings/datausage/ChartDataUsagePreference.java
+++ b/src/com/android/settings/datausage/ChartDataUsagePreference.java
@@ -294,14 +294,6 @@
notifyChanged();
}
- public long getInspectStart() {
- return mStart;
- }
-
- public long getInspectEnd() {
- return mEnd;
- }
-
public void setNetworkCycleData(NetworkCycleChartData data) {
mNetworkCycleChartData = data;
mStart = data.getStartTime();
diff --git a/src/com/android/settings/datausage/CycleAdapter.java b/src/com/android/settings/datausage/CycleAdapter.java
index 2af4012..90a2035 100644
--- a/src/com/android/settings/datausage/CycleAdapter.java
+++ b/src/com/android/settings/datausage/CycleAdapter.java
@@ -14,7 +14,6 @@
package com.android.settings.datausage;
import android.content.Context;
-import android.widget.AdapterView;
import com.android.settings.Utils;
import com.android.settingslib.net.NetworkCycleData;
@@ -25,13 +24,10 @@
public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem> {
private final SpinnerInterface mSpinner;
- private final AdapterView.OnItemSelectedListener mListener;
- public CycleAdapter(Context context, SpinnerInterface spinner,
- AdapterView.OnItemSelectedListener listener) {
+ public CycleAdapter(Context context, SpinnerInterface spinner) {
super(context);
mSpinner = spinner;
- mListener = listener;
mSpinner.setAdapter(this);
}
@@ -67,7 +63,6 @@
* updating the inspection range on chartData.
*/
public void updateCycleList(List<? extends NetworkCycleData> cycleData) {
- mSpinner.setOnItemSelectedListener(mListener);
// stash away currently selected cycle to try restoring below
final CycleAdapter.CycleItem previousItem = (CycleAdapter.CycleItem)
mSpinner.getSelectedItem();
@@ -122,8 +117,6 @@
public interface SpinnerInterface {
void setAdapter(CycleAdapter cycleAdapter);
- void setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener);
-
Object getSelectedItem();
void setSelection(int position);
diff --git a/src/com/android/settings/datausage/DataUsageList.java b/src/com/android/settings/datausage/DataUsageList.java
index 15a5603..f48aacd 100644
--- a/src/com/android/settings/datausage/DataUsageList.java
+++ b/src/com/android/settings/datausage/DataUsageList.java
@@ -28,11 +28,6 @@
import android.util.EventLog;
import android.util.Log;
import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.Spinner;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -43,8 +38,6 @@
import androidx.preference.Preference;
import com.android.settings.R;
-import com.android.settings.core.SubSettingLauncher;
-import com.android.settings.datausage.CycleAdapter.SpinnerInterface;
import com.android.settings.datausage.lib.BillingCycleRepository;
import com.android.settings.network.MobileDataEnabledListener;
import com.android.settings.network.MobileNetworkRepository;
@@ -58,6 +51,8 @@
import java.util.Objects;
import java.util.Optional;
+import kotlin.Unit;
+
/**
* Panel showing data usage history across various networks, including options
* to inspect based on usage cycle and control through {@link NetworkPolicy}.
@@ -90,8 +85,6 @@
@VisibleForTesting
int mNetworkType;
@VisibleForTesting
- Spinner mCycleSpinner;
- @VisibleForTesting
LoadingViewController mLoadingViewController;
private ChartDataUsagePreference mChart;
@@ -102,13 +95,15 @@
// Spinner will keep the selected cycle even after paused, this only keeps the displayed cycle,
// which need be cleared when resumed.
private CycleAdapter.CycleItem mLastDisplayedCycle;
- private CycleAdapter mCycleAdapter;
private Preference mUsageAmount;
- private View mHeader;
private MobileNetworkRepository mMobileNetworkRepository;
private SubscriptionInfoEntity mSubscriptionInfoEntity;
private DataUsageListAppsController mDataUsageListAppsController;
private BillingCycleRepository mBillingCycleRepository;
+ @VisibleForTesting
+ DataUsageListHeaderController mDataUsageListHeaderController;
+
+ private boolean mIsBillingCycleModifiable = false;
@Override
public int getMetricsCategory() {
@@ -158,50 +153,15 @@
public void onViewCreated(@NonNull View v, Bundle savedInstanceState) {
super.onViewCreated(v, savedInstanceState);
- mHeader = setPinnedHeaderView(R.layout.apps_filter_spinner);
- mHeader.findViewById(R.id.filter_settings).setOnClickListener(btn -> {
- final Bundle args = new Bundle();
- args.putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, mTemplate);
- new SubSettingLauncher(getContext())
- .setDestination(BillingCycleSettings.class.getName())
- .setTitleRes(R.string.billing_cycle)
- .setSourceMetricsCategory(getMetricsCategory())
- .setArguments(args)
- .launch();
- });
- mCycleSpinner = mHeader.findViewById(R.id.filter_spinner);
- mCycleSpinner.setVisibility(View.GONE);
- mCycleAdapter = new CycleAdapter(mCycleSpinner.getContext(), new SpinnerInterface() {
- @Override
- public void setAdapter(CycleAdapter cycleAdapter) {
- mCycleSpinner.setAdapter(cycleAdapter);
- }
-
- @Override
- public void setOnItemSelectedListener(OnItemSelectedListener listener) {
- mCycleSpinner.setOnItemSelectedListener(listener);
- }
-
- @Override
- public Object getSelectedItem() {
- return mCycleSpinner.getSelectedItem();
- }
-
- @Override
- public void setSelection(int position) {
- mCycleSpinner.setSelection(position);
- }
- }, mCycleListener);
- mCycleSpinner.setAccessibilityDelegate(new AccessibilityDelegate() {
- @Override
- public void sendAccessibilityEvent(View host, int eventType) {
- if (eventType == AccessibilityEvent.TYPE_VIEW_SELECTED) {
- // Ignore TYPE_VIEW_SELECTED or TalkBack will speak for it at onResume.
- return;
+ mDataUsageListHeaderController = new DataUsageListHeaderController(
+ setPinnedHeaderView(R.layout.apps_filter_spinner),
+ mTemplate,
+ getMetricsCategory(),
+ (cycle, position) -> {
+ updateSelectedCycle(cycle, position);
+ return Unit.INSTANCE;
}
- super.sendAccessibilityEvent(host, eventType);
- }
- });
+ );
mLoadingViewController = new LoadingViewController(
getView().findViewById(R.id.loading_container), getListView());
@@ -213,6 +173,7 @@
mLoadingViewController.showLoadingViewDelayed();
mDataStateListener.start(mSubId);
mLastDisplayedCycle = null;
+ updatePolicy();
// kick off loader for network history
// TODO: consider chaining two loaders together instead of reloading
@@ -291,36 +252,31 @@
*/
@VisibleForTesting
void updatePolicy() {
- final NetworkPolicy policy = services.mPolicyEditor.getPolicy(mTemplate);
- final View configureButton = mHeader.findViewById(R.id.filter_settings);
- //SUB SELECT
- if (policy != null && isMobileDataAvailable()) {
- mChart.setNetworkPolicy(policy);
- configureButton.setVisibility(View.VISIBLE);
+ mIsBillingCycleModifiable = isBillingCycleModifiable();
+ if (mIsBillingCycleModifiable) {
+ mChart.setNetworkPolicy(services.mPolicyEditor.getPolicy(mTemplate));
} else {
- // controls are disabled; don't bind warning/limit sweeps
- mChart.setNetworkPolicy(null);
- configureButton.setVisibility(View.GONE);
+ mChart.setNetworkPolicy(null); // don't bind warning / limit sweeps
}
-
- // generate cycle list based on policy and available history
- if (mCycleData != null) {
- mCycleAdapter.updateCycleList(mCycleData);
- }
- mDataUsageListAppsController.setCycleData(mCycleData);
- updateSelectedCycle();
+ updateConfigButtonVisibility();
}
- private boolean isMobileDataAvailable() {
+ @VisibleForTesting
+ boolean isBillingCycleModifiable() {
return mBillingCycleRepository.isModifiable(mSubId)
&& SubscriptionManager.from(requireContext())
.getActiveSubscriptionInfo(mSubId) != null;
}
+ private void updateConfigButtonVisibility() {
+ mDataUsageListHeaderController.setConfigButtonVisible(
+ mIsBillingCycleModifiable && mCycleData != null);
+ }
+
/**
* Updates the chart and detail data when initial loaded or selected cycle changed.
*/
- private void updateSelectedCycle() {
+ private void updateSelectedCycle(CycleAdapter.CycleItem cycle, int position) {
// Avoid from updating UI after #onStop.
if (!getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
return;
@@ -332,11 +288,6 @@
return;
}
- final int position = mCycleSpinner.getSelectedItemPosition();
- if (mCycleAdapter.getCount() == 0 || position < 0) {
- return;
- }
- final CycleAdapter.CycleItem cycle = mCycleAdapter.getItem(position);
if (Objects.equals(cycle, mLastDisplayedCycle)) {
// Avoid duplicate update to avoid page flash.
return;
@@ -350,9 +301,10 @@
// update chart to show selected cycle, and update detail data
// to match updated sweep bounds.
- mChart.setNetworkCycleData(mCycleData.get(position));
+ NetworkCycleChartData cycleChartData = mCycleData.get(position);
+ mChart.setNetworkCycleData(cycleChartData);
- updateDetailData();
+ updateDetailData(cycleChartData);
}
/**
@@ -360,34 +312,21 @@
* current mode. Updates {@link #mAdapter} with sorted list
* of applications data usage.
*/
- private void updateDetailData() {
+ private void updateDetailData(NetworkCycleChartData cycleChartData) {
if (LOGD) Log.d(TAG, "updateDetailData()");
// kick off loader for detailed stats
mDataUsageListAppsController.update(
mSubscriptionInfoEntity == null ? null : mSubscriptionInfoEntity.carrierId,
- mChart.getInspectStart(),
- mChart.getInspectEnd()
+ cycleChartData.getStartTime(),
+ cycleChartData.getEndTime()
);
- final long totalBytes = mCycleData != null && !mCycleData.isEmpty()
- ? mCycleData.get(mCycleSpinner.getSelectedItemPosition()).getTotalUsage() : 0;
+ final long totalBytes = cycleChartData.getTotalUsage();
final CharSequence totalPhrase = DataUsageUtils.formatDataUsage(getActivity(), totalBytes);
mUsageAmount.setTitle(getString(R.string.data_used_template, totalPhrase));
}
- private final OnItemSelectedListener mCycleListener = new OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- updateSelectedCycle();
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- // ignored
- }
- };
-
@VisibleForTesting
final LoaderCallbacks<List<NetworkCycleChartData>> mNetworkCycleDataCallbacks =
new LoaderCallbacks<>() {
@@ -404,9 +343,9 @@
List<NetworkCycleChartData> data) {
mLoadingViewController.showContent(false /* animate */);
mCycleData = data;
- // calculate policy cycles based on available data
- updatePolicy();
- mCycleSpinner.setVisibility(View.VISIBLE);
+ mDataUsageListHeaderController.updateCycleData(mCycleData);
+ updateConfigButtonVisibility();
+ mDataUsageListAppsController.setCycleData(mCycleData);
}
@Override
diff --git a/src/com/android/settings/datausage/DataUsageListHeaderController.kt b/src/com/android/settings/datausage/DataUsageListHeaderController.kt
new file mode 100644
index 0000000..e295a4c
--- /dev/null
+++ b/src/com/android/settings/datausage/DataUsageListHeaderController.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2023 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.datausage
+
+import android.net.NetworkTemplate
+import android.os.Bundle
+import android.view.View
+import android.view.accessibility.AccessibilityEvent
+import android.widget.AdapterView
+import android.widget.Spinner
+import androidx.annotation.OpenForTesting
+import com.android.settings.R
+import com.android.settings.core.SubSettingLauncher
+import com.android.settings.datausage.CycleAdapter.CycleItem
+import com.android.settings.datausage.CycleAdapter.SpinnerInterface
+import com.android.settingslib.net.NetworkCycleChartData
+
+@OpenForTesting
+open class DataUsageListHeaderController(
+ header: View,
+ template: NetworkTemplate,
+ sourceMetricsCategory: Int,
+ private val onItemSelected: (cycleItem: CycleItem, position: Int) -> Unit,
+) {
+ private val context = header.context
+ private val configureButton: View = header.requireViewById(R.id.filter_settings)
+ private val cycleSpinner: Spinner = header.requireViewById(R.id.filter_spinner)
+ private val cycleAdapter = CycleAdapter(context, object : SpinnerInterface {
+ override fun setAdapter(cycleAdapter: CycleAdapter) {
+ cycleSpinner.adapter = cycleAdapter
+ }
+
+ override fun getSelectedItem() = cycleSpinner.selectedItem
+
+ override fun setSelection(position: Int) {
+ cycleSpinner.setSelection(position)
+ }
+ })
+
+ private val cycleListener = object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
+ if (0 <= position && position < cycleAdapter.count) {
+ cycleAdapter.getItem(position)?.let { cycleItem ->
+ onItemSelected(cycleItem, position)
+ }
+ }
+ }
+
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+ // ignored
+ }
+ }
+
+ init {
+ configureButton.setOnClickListener {
+ val args = Bundle().apply {
+ putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, template)
+ }
+ SubSettingLauncher(context).apply {
+ setDestination(BillingCycleSettings::class.java.name)
+ setTitleRes(R.string.billing_cycle)
+ setSourceMetricsCategory(sourceMetricsCategory)
+ setArguments(args)
+ }.launch()
+ }
+ cycleSpinner.visibility = View.GONE
+ cycleSpinner.accessibilityDelegate = object : View.AccessibilityDelegate() {
+ override fun sendAccessibilityEvent(host: View, eventType: Int) {
+ if (eventType == AccessibilityEvent.TYPE_VIEW_SELECTED) {
+ // Ignore TYPE_VIEW_SELECTED or TalkBack will speak for it at onResume.
+ return
+ }
+ super.sendAccessibilityEvent(host, eventType)
+ }
+ }
+ }
+
+ open fun setConfigButtonVisible(visible: Boolean) {
+ configureButton.visibility = if (visible) View.VISIBLE else View.GONE
+ }
+
+ open fun updateCycleData(cycleData: List<NetworkCycleChartData>) {
+ cycleSpinner.onItemSelectedListener = cycleListener
+ // calculate policy cycles based on available data
+ // generate cycle list based on policy and available history
+ cycleAdapter.updateCycleList(cycleData)
+ cycleSpinner.visibility = View.VISIBLE
+ }
+}
diff --git a/src/com/android/settings/datausage/SpinnerPreference.java b/src/com/android/settings/datausage/SpinnerPreference.java
index c6b5f9f..a705079 100644
--- a/src/com/android/settings/datausage/SpinnerPreference.java
+++ b/src/com/android/settings/datausage/SpinnerPreference.java
@@ -47,7 +47,6 @@
notifyChanged();
}
- @Override
public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) {
mListener = listener;
}
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
index 5eee615..cb2b278 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
@@ -34,17 +34,12 @@
import android.os.Bundle;
import android.os.UserManager;
import android.provider.Settings;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.Spinner;
import androidx.annotation.NonNull;
-import androidx.fragment.app.FragmentActivity;
import androidx.loader.app.LoaderManager;
+import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
-import com.android.settings.R;
import com.android.settings.datausage.lib.BillingCycleRepository;
import com.android.settings.network.MobileDataEnabledListener;
import com.android.settings.testutils.FakeFeatureFactory;
@@ -52,6 +47,7 @@
import com.android.settingslib.NetworkPolicyEditor;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
+import com.android.settingslib.net.NetworkCycleChartData;
import org.junit.Before;
import org.junit.Rule;
@@ -69,7 +65,11 @@
import org.robolectric.annotation.Implements;
import org.robolectric.util.ReflectionHelpers;
+import java.util.Collections;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = DataUsageListTest.ShadowDataUsageBaseFragment.class)
public class DataUsageListTest {
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@@ -84,6 +84,8 @@
private UserManager mUserManager;
@Mock
private BillingCycleRepository mBillingCycleRepository;
+ @Mock
+ private DataUsageListHeaderController mDataUsageListHeaderController;
private Activity mActivity;
@@ -98,7 +100,6 @@
mActivity = spy(mActivityController.get());
mNetworkServices.mPolicyEditor = mock(NetworkPolicyEditor.class);
mDataUsageList.mDataStateListener = mMobileDataEnabledListener;
- mDataUsageList.mTemplate = mock(NetworkTemplate.class);
doReturn(mActivity).when(mDataUsageList).getContext();
doReturn(mUserManager).when(mActivity).getSystemService(UserManager.class);
@@ -110,11 +111,12 @@
mDataUsageList.mLoadingViewController = mock(LoadingViewController.class);
doNothing().when(mDataUsageList).updateSubscriptionInfoEntity();
when(mBillingCycleRepository.isBandwidthControlEnabled()).thenReturn(true);
+ mDataUsageList.mDataUsageListHeaderController = mDataUsageListHeaderController;
}
@Test
- @Config(shadows = ShadowDataUsageBaseFragment.class)
public void onCreate_isNotGuestUser_shouldNotFinish() {
+ mDataUsageList.mTemplate = mock(NetworkTemplate.class);
doReturn(false).when(mUserManager).isGuestUser();
doNothing().when(mDataUsageList).processArgument();
@@ -124,7 +126,6 @@
}
@Test
- @Config(shadows = ShadowDataUsageBaseFragment.class)
public void onCreate_isGuestUser_shouldFinish() {
doReturn(true).when(mUserManager).isGuestUser();
@@ -135,6 +136,7 @@
@Test
public void resume_shouldListenDataStateChange() {
+ mDataUsageList.onCreate(null);
ReflectionHelpers.setField(
mDataUsageList, "mVisibilityLoggerMixin", mock(VisibilityLoggerMixin.class));
ReflectionHelpers.setField(
@@ -149,6 +151,7 @@
@Test
public void pause_shouldUnlistenDataStateChange() {
+ mDataUsageList.onCreate(null);
ReflectionHelpers.setField(
mDataUsageList, "mVisibilityLoggerMixin", mock(VisibilityLoggerMixin.class));
ReflectionHelpers.setField(
@@ -187,12 +190,10 @@
@Test
public void processArgument_fromIntent_shouldGetTemplateFromIntent() {
- final FragmentActivity activity = mock(FragmentActivity.class);
final Intent intent = new Intent();
intent.putExtra(Settings.EXTRA_NETWORK_TEMPLATE, mock(NetworkTemplate.class));
intent.putExtra(Settings.EXTRA_SUB_ID, 3);
- when(activity.getIntent()).thenReturn(intent);
- doReturn(activity).when(mDataUsageList).getActivity();
+ doReturn(intent).when(mDataUsageList).getIntent();
mDataUsageList.processArgument();
@@ -201,30 +202,16 @@
}
@Test
- public void onViewCreated_shouldHideCycleSpinner() {
- final View view = new View(mActivity);
- final View header = getHeader();
- final Spinner spinner = getSpinner(header);
- spinner.setVisibility(View.VISIBLE);
- doReturn(header).when(mDataUsageList).setPinnedHeaderView(anyInt());
- doReturn(view).when(mDataUsageList).getView();
-
- mDataUsageList.onViewCreated(view, null);
-
- assertThat(spinner.getVisibility()).isEqualTo(View.GONE);
- }
-
- @Test
public void onLoadFinished_networkCycleDataCallback_shouldShowCycleSpinner() {
- final Spinner spinner = getSpinner(getHeader());
- spinner.setVisibility(View.INVISIBLE);
- mDataUsageList.mCycleSpinner = spinner;
- assertThat(spinner.getVisibility()).isEqualTo(View.INVISIBLE);
- doNothing().when(mDataUsageList).updatePolicy();
+ mDataUsageList.mTemplate = mock(NetworkTemplate.class);
+ mDataUsageList.onCreate(null);
+ mDataUsageList.updatePolicy();
+ List<NetworkCycleChartData> mockData = Collections.emptyList();
- mDataUsageList.mNetworkCycleDataCallbacks.onLoadFinished(null, null);
+ mDataUsageList.mNetworkCycleDataCallbacks.onLoadFinished(null, mockData);
- assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE);
+ verify(mDataUsageListHeaderController).updateCycleData(mockData);
+ verify(mDataUsageListHeaderController).setConfigButtonVisible(true);
}
@Test
@@ -234,19 +221,6 @@
verify(mLoaderManager).destroyLoader(DataUsageList.LOADER_CHART_DATA);
}
- private View getHeader() {
- final View rootView = LayoutInflater.from(mActivity)
- .inflate(R.layout.preference_list_fragment, null, false);
- final FrameLayout pinnedHeader = rootView.findViewById(R.id.pinned_header);
-
- return mActivity.getLayoutInflater()
- .inflate(R.layout.apps_filter_spinner, pinnedHeader, false);
- }
-
- private Spinner getSpinner(View header) {
- return header.findViewById(R.id.filter_spinner);
- }
-
@Implements(DataUsageBaseFragment.class)
public static class ShadowDataUsageBaseFragment {
@Implementation
@@ -261,10 +235,28 @@
return mock(clazz);
}
+ @Override
+ public <T extends Preference> T findPreference(CharSequence key) {
+ if (key.toString().equals("chart_data")) {
+ return (T) mock(ChartDataUsagePreference.class);
+ }
+ return (T) mock(Preference.class);
+ }
+
+ @Override
+ public Intent getIntent() {
+ return new Intent();
+ }
+
@NonNull
@Override
BillingCycleRepository createBillingCycleRepository() {
return mBillingCycleRepository;
}
+
+ @Override
+ boolean isBillingCycleModifiable() {
+ return true;
+ }
}
}
diff --git a/tests/spa_unit/src/com/android/settings/datausage/DataUsageListHeaderControllerTest.kt b/tests/spa_unit/src/com/android/settings/datausage/DataUsageListHeaderControllerTest.kt
new file mode 100644
index 0000000..a1eebe7
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/datausage/DataUsageListHeaderControllerTest.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 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.datausage
+
+import android.content.Context
+import android.net.NetworkTemplate
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.Spinner
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.whenever
+
+@RunWith(AndroidJUnit4::class)
+class DataUsageListHeaderControllerTest {
+
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+ doNothing().whenever(mock).startActivity(any())
+ }
+
+ private val header =
+ LayoutInflater.from(context).inflate(R.layout.apps_filter_spinner, null, false)
+
+ private val configureButton: View = header.requireViewById(R.id.filter_settings)
+
+ private val spinner: Spinner = header.requireViewById(R.id.filter_spinner)
+
+ private val controller = DataUsageListHeaderController(
+ header = header,
+ template = mock<NetworkTemplate>(),
+ sourceMetricsCategory = 0,
+ onItemSelected = { _, _ -> },
+ )
+
+ @Test
+ fun onViewCreated_shouldHideCycleSpinner() {
+ assertThat(spinner.visibility).isEqualTo(View.GONE)
+ }
+
+ @Test
+ fun updateCycleData_shouldShowCycleSpinner() {
+ controller.updateCycleData(emptyList())
+
+ assertThat(spinner.visibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ fun setConfigButtonVisible_setToTrue_shouldShowConfigureButton() {
+ controller.setConfigButtonVisible(true)
+
+ assertThat(configureButton.visibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ fun setConfigButtonVisible_setToFalse_shouldHideConfigureButton() {
+ controller.setConfigButtonVisible(false)
+
+ assertThat(configureButton.visibility).isEqualTo(View.GONE)
+ }
+}