Loading src/com/android/settings/ResetNetworkConfirm.java +20 −63 Original line number Diff line number Diff line Loading @@ -61,6 +61,7 @@ public class ResetNetworkConfirm extends InstrumentedFragment { @VisibleForTesting ResetNetworkRequest mResetNetworkRequest; private ProgressDialog mProgressDialog; private AlertDialog mAlertDialog; @VisibleForTesting ResetSubscriptionContract mResetSubscriptionContract; private OnSubscriptionsChangedListener mSubscriptionsChangedListener; /** Loading Loading @@ -130,17 +131,12 @@ public class ResetNetworkConfirm extends InstrumentedFragment { } // abandon execution if subscription no longer active int subId = mResetNetworkRequest.getResetApnSubId(); if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { SubscriptionManager mgr = getSubscriptionManager(); // always remove listener stopMonitorSubscriptionChange(mgr); if (!isSubscriptionRemainActive(mgr, subId)) { Log.w(TAG, "subId " + subId + " disappear when confirm"); mActivity.finish(); Integer subId = mResetSubscriptionContract.getAnyMissingSubscriptionId(); if (subId != null) { Log.w(TAG, "subId " + subId + " no longer active"); getActivity().onBackPressed(); return; } } // Should dismiss the progress dialog firstly if it is showing // Or not the progress dialog maybe not dismissed in fast clicking. Loading Loading @@ -186,7 +182,7 @@ public class ResetNetworkConfirm extends InstrumentedFragment { Bundle savedInstanceState) { View view = (new ResetNetworkRestrictionViewBuilder(mActivity)).build(); if (view != null) { stopMonitorSubscriptionChange(getSubscriptionManager()); mResetSubscriptionContract.close(); Log.w(TAG, "Access deny."); return view; } Loading @@ -208,13 +204,15 @@ public class ResetNetworkConfirm extends InstrumentedFragment { mActivity = getActivity(); if (mResetNetworkRequest.getResetApnSubId() == ResetNetworkRequest.INVALID_SUBSCRIPTION_ID) { return; mResetSubscriptionContract = new ResetSubscriptionContract(getContext(), mResetNetworkRequest) { @Override public void onSubscriptionInactive(int subscriptionId) { // close UI if subscription no longer active Log.w(TAG, "subId " + subscriptionId + " no longer active."); getActivity().onBackPressed(); } // close confirmation dialog when reset specific subscription // but removed priori to the confirmation button been pressed startMonitorSubscriptionChange(getSubscriptionManager()); }; } @Override Loading @@ -223,63 +221,22 @@ public class ResetNetworkConfirm extends InstrumentedFragment { mResetNetworkRequest.writeIntoBundle(outState); } private SubscriptionManager getSubscriptionManager() { SubscriptionManager mgr = mActivity.getSystemService(SubscriptionManager.class); if (mgr == null) { Log.w(TAG, "No SubscriptionManager"); } return mgr; } private void startMonitorSubscriptionChange(SubscriptionManager mgr) { if (mgr == null) { return; } // update monitor listener mSubscriptionsChangedListener = new OnSubscriptionsChangedListener( Looper.getMainLooper()) { @Override public void onSubscriptionsChanged() { int subId = mResetNetworkRequest.getResetApnSubId(); SubscriptionManager mgr = getSubscriptionManager(); if (isSubscriptionRemainActive(mgr, subId)) { return; } // close UI if subscription no longer active Log.w(TAG, "subId " + subId + " no longer active."); stopMonitorSubscriptionChange(mgr); mActivity.finish(); } }; mgr.addOnSubscriptionsChangedListener( mActivity.getMainExecutor(), mSubscriptionsChangedListener); } private boolean isSubscriptionRemainActive(SubscriptionManager mgr, int subscriptionId) { return (mgr == null) ? false : (mgr.getActiveSubscriptionInfo(subscriptionId) != null); } private void stopMonitorSubscriptionChange(SubscriptionManager mgr) { if ((mgr == null) || (mSubscriptionsChangedListener == null)) { return; } mgr.removeOnSubscriptionsChangedListener(mSubscriptionsChangedListener); mSubscriptionsChangedListener = null; } @Override public void onDestroy() { if (mResetNetworkTask != null) { mResetNetworkTask.cancel(true /* mayInterruptIfRunning */); mResetNetworkTask = null; } if (mResetSubscriptionContract != null) { mResetSubscriptionContract.close(); mResetSubscriptionContract = null; } if (mProgressDialog != null) { mProgressDialog.dismiss(); } if (mAlertDialog != null) { mAlertDialog.dismiss(); } stopMonitorSubscriptionChange(getSubscriptionManager()); super.onDestroy(); } Loading src/com/android/settings/ResetSubscriptionContract.java 0 → 100644 +157 −0 Original line number Diff line number Diff line /* * 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; import android.content.Context; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.util.Log; import androidx.annotation.VisibleForTesting; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.IntStream; /** * A Class monitoring the availability of subscription IDs provided within reset request. * * This is to detect the situation when user changing SIM card during the presenting of * confirmation UI. */ public class ResetSubscriptionContract implements AutoCloseable { private static final String TAG = "ResetSubscriptionContract"; private final Context mContext; private ExecutorService mExecutorService; private final int [] mResetSubscriptionIds; @VisibleForTesting protected OnSubscriptionsChangedListener mSubscriptionsChangedListener; private AtomicBoolean mSubscriptionsUpdateNotify = new AtomicBoolean(); /** * Constructor * @param context Context * @param resetRequest the request object for perform network reset operation. */ public ResetSubscriptionContract(Context context, ResetNetworkRequest resetRequest) { mContext = context; // Only keeps specific subscription ID required to perform reset operation IntStream subIdStream = IntStream.of( resetRequest.getResetTelephonyAndNetworkPolicyManager() , resetRequest.getResetApnSubId()); mResetSubscriptionIds = subIdStream.sorted().distinct() .filter(id -> SubscriptionManager.isUsableSubscriptionId(id)) .toArray(); if (mResetSubscriptionIds.length <= 0) { return; } // Monitoring callback through background thread mExecutorService = Executors.newSingleThreadExecutor(); startMonitorSubscriptionChange(); } /** * A method for detecting if there's any subscription under monitor no longer active. * @return subscription ID which is no longer active. */ public Integer getAnyMissingSubscriptionId() { if (mResetSubscriptionIds.length <= 0) { return null; } SubscriptionManager mgr = getSubscriptionManager(); if (mgr == null) { Log.w(TAG, "Fail to access subscription manager"); return mResetSubscriptionIds[0]; } for (int idx = 0; idx < mResetSubscriptionIds.length; idx++) { int subId = mResetSubscriptionIds[idx]; if (mgr.getActiveSubscriptionInfo(subId) == null) { Log.w(TAG, "SubId " + subId + " no longer active."); return subId; } } return null; } /** * Async callback when detecting if there's any subscription under monitor no longer active. * @param subscriptionId subscription ID which is no longer active. */ public void onSubscriptionInactive(int subscriptionId) {} @VisibleForTesting protected SubscriptionManager getSubscriptionManager() { return mContext.getSystemService(SubscriptionManager.class); } @VisibleForTesting protected OnSubscriptionsChangedListener getChangeListener() { return new OnSubscriptionsChangedListener() { @Override public void onSubscriptionsChanged() { /** * Reducing the processing time on main UI thread through a flag. * Once flag get into false, which means latest callback has been * processed. */ mSubscriptionsUpdateNotify.set(true); // Back to main UI thread mContext.getMainExecutor().execute(() -> { // Remove notifications and perform checking. if (mSubscriptionsUpdateNotify.getAndSet(false)) { Integer subId = getAnyMissingSubscriptionId(); if (subId != null) { onSubscriptionInactive(subId); } } }); } }; } private void startMonitorSubscriptionChange() { SubscriptionManager mgr = getSubscriptionManager(); if (mgr == null) { return; } // update monitor listener mSubscriptionsChangedListener = getChangeListener(); mgr.addOnSubscriptionsChangedListener( mExecutorService, mSubscriptionsChangedListener); } // Implementation of AutoCloseable public void close() { if (mExecutorService == null) { return; } // Stop monitoring subscription change SubscriptionManager mgr = getSubscriptionManager(); if (mgr != null) { mgr.removeOnSubscriptionsChangedListener(mSubscriptionsChangedListener); } // Release Executor mExecutorService.shutdownNow(); mExecutorService = null; } } tests/robotests/src/com/android/settings/ResetNetworkConfirmTest.java +8 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,14 @@ public class ResetNetworkConfirmTest { public void testResetNetworkData_notResetEsim() { mResetNetworkConfirm.mResetNetworkRequest = new ResetNetworkRequest(ResetNetworkRequest.RESET_NONE); mResetNetworkConfirm.mResetSubscriptionContract = new ResetSubscriptionContract(mActivity, mResetNetworkConfirm.mResetNetworkRequest) { @Override public void onSubscriptionInactive(int subscriptionId) { mActivity.onBackPressed(); } }; mResetNetworkConfirm.mFinalClickListener.onClick(null /* View */); Robolectric.getBackgroundThreadScheduler().advanceToLastPostedRunnable(); Loading tests/unit/src/com/android/settings/ResetSubscriptionContractTest.java 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * 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; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.content.Context; import android.os.Bundle; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import androidx.test.core.app.ApplicationProvider; 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; @RunWith(AndroidJUnit4.class) public class ResetSubscriptionContractTest { private static final int SUB_ID_1 = 3; private static final int SUB_ID_2 = 8; @Mock private SubscriptionManager mSubscriptionManager; @Mock private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener; @Mock private SubscriptionInfo mSubscriptionInfo1; @Mock private SubscriptionInfo mSubscriptionInfo2; private Context mContext; private ResetNetworkRequest mRequestArgs; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(ApplicationProvider.getApplicationContext()); mRequestArgs = new ResetNetworkRequest(new Bundle()); } private ResetSubscriptionContract createTestObject() { return new ResetSubscriptionContract(mContext, mRequestArgs) { @Override protected SubscriptionManager getSubscriptionManager() { return mSubscriptionManager; } @Override protected OnSubscriptionsChangedListener getChangeListener() { return mOnSubscriptionsChangedListener; } }; } @Test public void getAnyMissingSubscriptionId_returnNull_whenNoSubscriptionChange() { mRequestArgs.setResetTelephonyAndNetworkPolicyManager(SUB_ID_1); doReturn(mSubscriptionInfo1).when(mSubscriptionManager) .getActiveSubscriptionInfo(SUB_ID_1); mRequestArgs.setResetApn(SUB_ID_2); doReturn(mSubscriptionInfo2).when(mSubscriptionManager) .getActiveSubscriptionInfo(SUB_ID_2); ResetSubscriptionContract target = createTestObject(); verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), any()); assertNull(target.getAnyMissingSubscriptionId()); } @Test public void getAnyMissingSubscriptionId_returnSubId_whenSubscriptionNotActive() { mRequestArgs.setResetTelephonyAndNetworkPolicyManager(SUB_ID_1); doReturn(mSubscriptionInfo1).when(mSubscriptionManager) .getActiveSubscriptionInfo(SUB_ID_1); mRequestArgs.setResetApn(SUB_ID_2); doReturn(null).when(mSubscriptionManager) .getActiveSubscriptionInfo(SUB_ID_2); ResetSubscriptionContract target = createTestObject(); verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), any()); assertEquals(target.getAnyMissingSubscriptionId(), new Integer(SUB_ID_2)); } } Loading
src/com/android/settings/ResetNetworkConfirm.java +20 −63 Original line number Diff line number Diff line Loading @@ -61,6 +61,7 @@ public class ResetNetworkConfirm extends InstrumentedFragment { @VisibleForTesting ResetNetworkRequest mResetNetworkRequest; private ProgressDialog mProgressDialog; private AlertDialog mAlertDialog; @VisibleForTesting ResetSubscriptionContract mResetSubscriptionContract; private OnSubscriptionsChangedListener mSubscriptionsChangedListener; /** Loading Loading @@ -130,17 +131,12 @@ public class ResetNetworkConfirm extends InstrumentedFragment { } // abandon execution if subscription no longer active int subId = mResetNetworkRequest.getResetApnSubId(); if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { SubscriptionManager mgr = getSubscriptionManager(); // always remove listener stopMonitorSubscriptionChange(mgr); if (!isSubscriptionRemainActive(mgr, subId)) { Log.w(TAG, "subId " + subId + " disappear when confirm"); mActivity.finish(); Integer subId = mResetSubscriptionContract.getAnyMissingSubscriptionId(); if (subId != null) { Log.w(TAG, "subId " + subId + " no longer active"); getActivity().onBackPressed(); return; } } // Should dismiss the progress dialog firstly if it is showing // Or not the progress dialog maybe not dismissed in fast clicking. Loading Loading @@ -186,7 +182,7 @@ public class ResetNetworkConfirm extends InstrumentedFragment { Bundle savedInstanceState) { View view = (new ResetNetworkRestrictionViewBuilder(mActivity)).build(); if (view != null) { stopMonitorSubscriptionChange(getSubscriptionManager()); mResetSubscriptionContract.close(); Log.w(TAG, "Access deny."); return view; } Loading @@ -208,13 +204,15 @@ public class ResetNetworkConfirm extends InstrumentedFragment { mActivity = getActivity(); if (mResetNetworkRequest.getResetApnSubId() == ResetNetworkRequest.INVALID_SUBSCRIPTION_ID) { return; mResetSubscriptionContract = new ResetSubscriptionContract(getContext(), mResetNetworkRequest) { @Override public void onSubscriptionInactive(int subscriptionId) { // close UI if subscription no longer active Log.w(TAG, "subId " + subscriptionId + " no longer active."); getActivity().onBackPressed(); } // close confirmation dialog when reset specific subscription // but removed priori to the confirmation button been pressed startMonitorSubscriptionChange(getSubscriptionManager()); }; } @Override Loading @@ -223,63 +221,22 @@ public class ResetNetworkConfirm extends InstrumentedFragment { mResetNetworkRequest.writeIntoBundle(outState); } private SubscriptionManager getSubscriptionManager() { SubscriptionManager mgr = mActivity.getSystemService(SubscriptionManager.class); if (mgr == null) { Log.w(TAG, "No SubscriptionManager"); } return mgr; } private void startMonitorSubscriptionChange(SubscriptionManager mgr) { if (mgr == null) { return; } // update monitor listener mSubscriptionsChangedListener = new OnSubscriptionsChangedListener( Looper.getMainLooper()) { @Override public void onSubscriptionsChanged() { int subId = mResetNetworkRequest.getResetApnSubId(); SubscriptionManager mgr = getSubscriptionManager(); if (isSubscriptionRemainActive(mgr, subId)) { return; } // close UI if subscription no longer active Log.w(TAG, "subId " + subId + " no longer active."); stopMonitorSubscriptionChange(mgr); mActivity.finish(); } }; mgr.addOnSubscriptionsChangedListener( mActivity.getMainExecutor(), mSubscriptionsChangedListener); } private boolean isSubscriptionRemainActive(SubscriptionManager mgr, int subscriptionId) { return (mgr == null) ? false : (mgr.getActiveSubscriptionInfo(subscriptionId) != null); } private void stopMonitorSubscriptionChange(SubscriptionManager mgr) { if ((mgr == null) || (mSubscriptionsChangedListener == null)) { return; } mgr.removeOnSubscriptionsChangedListener(mSubscriptionsChangedListener); mSubscriptionsChangedListener = null; } @Override public void onDestroy() { if (mResetNetworkTask != null) { mResetNetworkTask.cancel(true /* mayInterruptIfRunning */); mResetNetworkTask = null; } if (mResetSubscriptionContract != null) { mResetSubscriptionContract.close(); mResetSubscriptionContract = null; } if (mProgressDialog != null) { mProgressDialog.dismiss(); } if (mAlertDialog != null) { mAlertDialog.dismiss(); } stopMonitorSubscriptionChange(getSubscriptionManager()); super.onDestroy(); } Loading
src/com/android/settings/ResetSubscriptionContract.java 0 → 100644 +157 −0 Original line number Diff line number Diff line /* * 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; import android.content.Context; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.util.Log; import androidx.annotation.VisibleForTesting; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.IntStream; /** * A Class monitoring the availability of subscription IDs provided within reset request. * * This is to detect the situation when user changing SIM card during the presenting of * confirmation UI. */ public class ResetSubscriptionContract implements AutoCloseable { private static final String TAG = "ResetSubscriptionContract"; private final Context mContext; private ExecutorService mExecutorService; private final int [] mResetSubscriptionIds; @VisibleForTesting protected OnSubscriptionsChangedListener mSubscriptionsChangedListener; private AtomicBoolean mSubscriptionsUpdateNotify = new AtomicBoolean(); /** * Constructor * @param context Context * @param resetRequest the request object for perform network reset operation. */ public ResetSubscriptionContract(Context context, ResetNetworkRequest resetRequest) { mContext = context; // Only keeps specific subscription ID required to perform reset operation IntStream subIdStream = IntStream.of( resetRequest.getResetTelephonyAndNetworkPolicyManager() , resetRequest.getResetApnSubId()); mResetSubscriptionIds = subIdStream.sorted().distinct() .filter(id -> SubscriptionManager.isUsableSubscriptionId(id)) .toArray(); if (mResetSubscriptionIds.length <= 0) { return; } // Monitoring callback through background thread mExecutorService = Executors.newSingleThreadExecutor(); startMonitorSubscriptionChange(); } /** * A method for detecting if there's any subscription under monitor no longer active. * @return subscription ID which is no longer active. */ public Integer getAnyMissingSubscriptionId() { if (mResetSubscriptionIds.length <= 0) { return null; } SubscriptionManager mgr = getSubscriptionManager(); if (mgr == null) { Log.w(TAG, "Fail to access subscription manager"); return mResetSubscriptionIds[0]; } for (int idx = 0; idx < mResetSubscriptionIds.length; idx++) { int subId = mResetSubscriptionIds[idx]; if (mgr.getActiveSubscriptionInfo(subId) == null) { Log.w(TAG, "SubId " + subId + " no longer active."); return subId; } } return null; } /** * Async callback when detecting if there's any subscription under monitor no longer active. * @param subscriptionId subscription ID which is no longer active. */ public void onSubscriptionInactive(int subscriptionId) {} @VisibleForTesting protected SubscriptionManager getSubscriptionManager() { return mContext.getSystemService(SubscriptionManager.class); } @VisibleForTesting protected OnSubscriptionsChangedListener getChangeListener() { return new OnSubscriptionsChangedListener() { @Override public void onSubscriptionsChanged() { /** * Reducing the processing time on main UI thread through a flag. * Once flag get into false, which means latest callback has been * processed. */ mSubscriptionsUpdateNotify.set(true); // Back to main UI thread mContext.getMainExecutor().execute(() -> { // Remove notifications and perform checking. if (mSubscriptionsUpdateNotify.getAndSet(false)) { Integer subId = getAnyMissingSubscriptionId(); if (subId != null) { onSubscriptionInactive(subId); } } }); } }; } private void startMonitorSubscriptionChange() { SubscriptionManager mgr = getSubscriptionManager(); if (mgr == null) { return; } // update monitor listener mSubscriptionsChangedListener = getChangeListener(); mgr.addOnSubscriptionsChangedListener( mExecutorService, mSubscriptionsChangedListener); } // Implementation of AutoCloseable public void close() { if (mExecutorService == null) { return; } // Stop monitoring subscription change SubscriptionManager mgr = getSubscriptionManager(); if (mgr != null) { mgr.removeOnSubscriptionsChangedListener(mSubscriptionsChangedListener); } // Release Executor mExecutorService.shutdownNow(); mExecutorService = null; } }
tests/robotests/src/com/android/settings/ResetNetworkConfirmTest.java +8 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,14 @@ public class ResetNetworkConfirmTest { public void testResetNetworkData_notResetEsim() { mResetNetworkConfirm.mResetNetworkRequest = new ResetNetworkRequest(ResetNetworkRequest.RESET_NONE); mResetNetworkConfirm.mResetSubscriptionContract = new ResetSubscriptionContract(mActivity, mResetNetworkConfirm.mResetNetworkRequest) { @Override public void onSubscriptionInactive(int subscriptionId) { mActivity.onBackPressed(); } }; mResetNetworkConfirm.mFinalClickListener.onClick(null /* View */); Robolectric.getBackgroundThreadScheduler().advanceToLastPostedRunnable(); Loading
tests/unit/src/com/android/settings/ResetSubscriptionContractTest.java 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * 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; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.content.Context; import android.os.Bundle; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import androidx.test.core.app.ApplicationProvider; 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; @RunWith(AndroidJUnit4.class) public class ResetSubscriptionContractTest { private static final int SUB_ID_1 = 3; private static final int SUB_ID_2 = 8; @Mock private SubscriptionManager mSubscriptionManager; @Mock private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener; @Mock private SubscriptionInfo mSubscriptionInfo1; @Mock private SubscriptionInfo mSubscriptionInfo2; private Context mContext; private ResetNetworkRequest mRequestArgs; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(ApplicationProvider.getApplicationContext()); mRequestArgs = new ResetNetworkRequest(new Bundle()); } private ResetSubscriptionContract createTestObject() { return new ResetSubscriptionContract(mContext, mRequestArgs) { @Override protected SubscriptionManager getSubscriptionManager() { return mSubscriptionManager; } @Override protected OnSubscriptionsChangedListener getChangeListener() { return mOnSubscriptionsChangedListener; } }; } @Test public void getAnyMissingSubscriptionId_returnNull_whenNoSubscriptionChange() { mRequestArgs.setResetTelephonyAndNetworkPolicyManager(SUB_ID_1); doReturn(mSubscriptionInfo1).when(mSubscriptionManager) .getActiveSubscriptionInfo(SUB_ID_1); mRequestArgs.setResetApn(SUB_ID_2); doReturn(mSubscriptionInfo2).when(mSubscriptionManager) .getActiveSubscriptionInfo(SUB_ID_2); ResetSubscriptionContract target = createTestObject(); verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), any()); assertNull(target.getAnyMissingSubscriptionId()); } @Test public void getAnyMissingSubscriptionId_returnSubId_whenSubscriptionNotActive() { mRequestArgs.setResetTelephonyAndNetworkPolicyManager(SUB_ID_1); doReturn(mSubscriptionInfo1).when(mSubscriptionManager) .getActiveSubscriptionInfo(SUB_ID_1); mRequestArgs.setResetApn(SUB_ID_2); doReturn(null).when(mSubscriptionManager) .getActiveSubscriptionInfo(SUB_ID_2); ResetSubscriptionContract target = createTestObject(); verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), any()); assertEquals(target.getAnyMissingSubscriptionId(), new Integer(SUB_ID_2)); } }