From e7de4a415de1f5f40a6b08caff4d4aa5322e817e Mon Sep 17 00:00:00 2001 From: Bonian Chen Date: Fri, 22 Apr 2022 13:54:54 +0800 Subject: [PATCH] [Settings] Code refactor for monitoring service state This is for monitoring the status of service state when Lifecycle state STARTED or RESUMED. Bug: 229689535 Test: unit test Change-Id: If6bac5c04caae67d6293c5a69e3130789e9e588e --- .../network/helper/ServiceStateStatus.java | 104 ++++++++++++++++++ .../helper/ServiceStateStatusTest.java | 94 ++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 src/com/android/settings/network/helper/ServiceStateStatus.java create mode 100644 tests/unit/src/com/android/settings/network/helper/ServiceStateStatusTest.java diff --git a/src/com/android/settings/network/helper/ServiceStateStatus.java b/src/com/android/settings/network/helper/ServiceStateStatus.java new file mode 100644 index 00000000000..871884d1450 --- /dev/null +++ b/src/com/android/settings/network/helper/ServiceStateStatus.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2022 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.network.helper; + +import android.telephony.ServiceState; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyManager; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LiveData; + +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * A {@link LiveData} as a mapping of allowed network types reported from {@link TelephonyCallback}. + * Only got update when Lifecycle.State is considered as STARTED or RESUMED. + * + * {@code null} when status unknown. Other values are {@link ServiceState}. + */ +@VisibleForTesting +public class ServiceStateStatus extends LiveData { + private static final String TAG = "ServiceStateStatus"; + + @VisibleForTesting + protected ServiceStateProducer mServiceStateProducer; + + @VisibleForTesting + protected LifecycleCallbackTelephonyAdapter mAdapter; + + @VisibleForTesting + protected Consumer mLiveDataUpdater = status -> setValue(status); + + /** + * Constructor + * @param lifecycle {@link Lifecycle} to monitor + * @param telephonyManager {@link TelephonyManager} to interact with + * @param executor {@link Executor} for receiving the notify from telephony framework. + */ + @VisibleForTesting + public ServiceStateStatus(@NonNull Lifecycle lifecycle, + @NonNull TelephonyManager telephonyManager, Executor executor) { + super(); + + mServiceStateProducer = new ServiceStateProducer(this); + + mAdapter = new LifecycleCallbackTelephonyAdapter(lifecycle, + telephonyManager, mServiceStateProducer, executor, mLiveDataUpdater) { + @Override + public void setCallbackActive(boolean isActive) { + super.setCallbackActive(isActive); + if (!isActive) { + /** + * Set to unknown status when no longer actively monitoring + * {@link TelephonyCallback}. + */ + mLiveDataUpdater.accept(null); + } + } + }; + } + + /** + * An implementation of TelephonyCallback. + * + * Change of allowed network type will be forward to + * {@link LifecycleCallbackTelephonyAdapter}. + */ + @VisibleForTesting + protected static class ServiceStateProducer extends TelephonyCallback + implements TelephonyCallback.ServiceStateListener { + private final ServiceStateStatus mStatus; + + /** + * Constructor + * @param status {@link ServiceStateStatus} + */ + public ServiceStateProducer(ServiceStateStatus status) { + mStatus = status; + } + + @Override + public void onServiceStateChanged(ServiceState serviceState) { + mStatus.mAdapter.postResult(serviceState); + } + } +} diff --git a/tests/unit/src/com/android/settings/network/helper/ServiceStateStatusTest.java b/tests/unit/src/com/android/settings/network/helper/ServiceStateStatusTest.java new file mode 100644 index 00000000000..1be24f9dcc3 --- /dev/null +++ b/tests/unit/src/com/android/settings/network/helper/ServiceStateStatusTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2022 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.network.helper; + +import static com.google.common.truth.Truth.assertThat; + +import android.telephony.ServiceState; +import android.telephony.TelephonyManager; + +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LifecycleRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.concurrent.atomic.AtomicReference; + +@RunWith(AndroidJUnit4.class) +public class ServiceStateStatusTest implements LifecycleOwner { + + private final LifecycleRegistry mRegistry = LifecycleRegistry.createUnsafe(this); + + @Mock + private TelephonyManager mTelMgr; + @Mock + private ServiceState mTestData; + + private AtomicReference mStatusStorage; + private ServiceStateStatus mServiceStateStatus; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mStatusStorage = new AtomicReference(); + mServiceStateStatus = new ServiceStateStatus(getLifecycle(), mTelMgr, null) { + @Override + protected void setValue(ServiceState status) { + mStatusStorage.set(status); + } + }; + } + + public Lifecycle getLifecycle() { + return mRegistry; + } + + @Test + public void telephonyCallback_updateStatus_whenActive() { + mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE); + + mServiceStateStatus.mServiceStateProducer.onServiceStateChanged(mTestData); + + assertThat(mStatusStorage.get()).isEqualTo(null); + + mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START); + + mServiceStateStatus.mServiceStateProducer.onServiceStateChanged(mTestData); + + assertThat(mStatusStorage.get()).isEqualTo(mTestData); + } + + @Test + public void telephonyCallback_updateStatusToNull_whenInActive() { + mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE); + mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START); + + mServiceStateStatus.mServiceStateProducer.onServiceStateChanged(mTestData); + + assertThat(mStatusStorage.get()).isEqualTo(mTestData); + + mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP); + + assertThat(mStatusStorage.get()).isEqualTo(null); + } +}