[Settings] Code refactor for SIM change detection
Code refactor for maintainance: Move subscription change monitor out of ResetnetworkConfirm Bug: 259611847 Test: local test, auto testing Change-Id: I97a251ced4435d0cc390b40028edef07fd71e24f
This commit is contained in:
@@ -61,6 +61,7 @@ public class ResetNetworkConfirm extends InstrumentedFragment {
|
|||||||
@VisibleForTesting ResetNetworkRequest mResetNetworkRequest;
|
@VisibleForTesting ResetNetworkRequest mResetNetworkRequest;
|
||||||
private ProgressDialog mProgressDialog;
|
private ProgressDialog mProgressDialog;
|
||||||
private AlertDialog mAlertDialog;
|
private AlertDialog mAlertDialog;
|
||||||
|
@VisibleForTesting ResetSubscriptionContract mResetSubscriptionContract;
|
||||||
private OnSubscriptionsChangedListener mSubscriptionsChangedListener;
|
private OnSubscriptionsChangedListener mSubscriptionsChangedListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -130,16 +131,11 @@ public class ResetNetworkConfirm extends InstrumentedFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// abandon execution if subscription no longer active
|
// abandon execution if subscription no longer active
|
||||||
int subId = mResetNetworkRequest.getResetApnSubId();
|
Integer subId = mResetSubscriptionContract.getAnyMissingSubscriptionId();
|
||||||
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
if (subId != null) {
|
||||||
SubscriptionManager mgr = getSubscriptionManager();
|
Log.w(TAG, "subId " + subId + " no longer active");
|
||||||
// always remove listener
|
getActivity().onBackPressed();
|
||||||
stopMonitorSubscriptionChange(mgr);
|
return;
|
||||||
if (!isSubscriptionRemainActive(mgr, subId)) {
|
|
||||||
Log.w(TAG, "subId " + subId + " disappear when confirm");
|
|
||||||
mActivity.finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should dismiss the progress dialog firstly if it is showing
|
// Should dismiss the progress dialog firstly if it is showing
|
||||||
@@ -186,7 +182,7 @@ public class ResetNetworkConfirm extends InstrumentedFragment {
|
|||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
View view = (new ResetNetworkRestrictionViewBuilder(mActivity)).build();
|
View view = (new ResetNetworkRestrictionViewBuilder(mActivity)).build();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
stopMonitorSubscriptionChange(getSubscriptionManager());
|
mResetSubscriptionContract.close();
|
||||||
Log.w(TAG, "Access deny.");
|
Log.w(TAG, "Access deny.");
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
@@ -208,13 +204,15 @@ public class ResetNetworkConfirm extends InstrumentedFragment {
|
|||||||
|
|
||||||
mActivity = getActivity();
|
mActivity = getActivity();
|
||||||
|
|
||||||
if (mResetNetworkRequest.getResetApnSubId()
|
mResetSubscriptionContract = new ResetSubscriptionContract(getContext(),
|
||||||
== ResetNetworkRequest.INVALID_SUBSCRIPTION_ID) {
|
mResetNetworkRequest) {
|
||||||
return;
|
@Override
|
||||||
}
|
public void onSubscriptionInactive(int subscriptionId) {
|
||||||
// close confirmation dialog when reset specific subscription
|
// close UI if subscription no longer active
|
||||||
// but removed priori to the confirmation button been pressed
|
Log.w(TAG, "subId " + subscriptionId + " no longer active.");
|
||||||
startMonitorSubscriptionChange(getSubscriptionManager());
|
getActivity().onBackPressed();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -223,63 +221,22 @@ public class ResetNetworkConfirm extends InstrumentedFragment {
|
|||||||
mResetNetworkRequest.writeIntoBundle(outState);
|
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
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
if (mResetNetworkTask != null) {
|
if (mResetNetworkTask != null) {
|
||||||
mResetNetworkTask.cancel(true /* mayInterruptIfRunning */);
|
mResetNetworkTask.cancel(true /* mayInterruptIfRunning */);
|
||||||
mResetNetworkTask = null;
|
mResetNetworkTask = null;
|
||||||
}
|
}
|
||||||
|
if (mResetSubscriptionContract != null) {
|
||||||
|
mResetSubscriptionContract.close();
|
||||||
|
mResetSubscriptionContract = null;
|
||||||
|
}
|
||||||
if (mProgressDialog != null) {
|
if (mProgressDialog != null) {
|
||||||
mProgressDialog.dismiss();
|
mProgressDialog.dismiss();
|
||||||
}
|
}
|
||||||
if (mAlertDialog != null) {
|
if (mAlertDialog != null) {
|
||||||
mAlertDialog.dismiss();
|
mAlertDialog.dismiss();
|
||||||
}
|
}
|
||||||
stopMonitorSubscriptionChange(getSubscriptionManager());
|
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
157
src/com/android/settings/ResetSubscriptionContract.java
Normal file
157
src/com/android/settings/ResetSubscriptionContract.java
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
@@ -74,6 +74,14 @@ public class ResetNetworkConfirmTest {
|
|||||||
public void testResetNetworkData_notResetEsim() {
|
public void testResetNetworkData_notResetEsim() {
|
||||||
mResetNetworkConfirm.mResetNetworkRequest =
|
mResetNetworkConfirm.mResetNetworkRequest =
|
||||||
new ResetNetworkRequest(ResetNetworkRequest.RESET_NONE);
|
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 */);
|
mResetNetworkConfirm.mFinalClickListener.onClick(null /* View */);
|
||||||
Robolectric.getBackgroundThreadScheduler().advanceToLastPostedRunnable();
|
Robolectric.getBackgroundThreadScheduler().advanceToLastPostedRunnable();
|
||||||
|
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* 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));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user