Merge "Fixed handover not working issue"
diff --git a/src/java/com/android/internal/telephony/TransportManager.java b/src/java/com/android/internal/telephony/TransportManager.java
index 9e1379b..aea1007 100644
--- a/src/java/com/android/internal/telephony/TransportManager.java
+++ b/src/java/com/android/internal/telephony/TransportManager.java
@@ -29,6 +29,7 @@
import android.telephony.data.ApnSetting;
import android.telephony.data.ApnSetting.ApnType;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.dataconnection.AccessNetworksManager.QualifiedNetworks;
import com.android.internal.util.ArrayUtils;
@@ -122,7 +123,11 @@
*/
private final RegistrantList mHandoverNeededEventRegistrants;
- static final class HandoverParams {
+ /**
+ * Handover parameters
+ */
+ @VisibleForTesting
+ public static final class HandoverParams {
public final @ApnType int apnType;
public final int targetTransport;
HandoverParams(int apnType, int targetTransport) {
@@ -134,10 +139,6 @@
public TransportManager(Phone phone) {
mPhone = phone;
mAccessNetworksManager = new AccessNetworksManager(phone);
-
- mAccessNetworksManager.registerForQualifiedNetworksChanged(this,
- EVENT_QUALIFIED_NETWORKS_CHANGED);
-
mCurrentAvailableNetworks = new ConcurrentHashMap<>();
mCurrentTransports = new ConcurrentHashMap<>();
mHandoverNeededEventRegistrants = new RegistrantList();
@@ -147,6 +148,8 @@
// the IWLAN ones.
mAvailableTransports = new int[]{TransportType.WWAN};
} else {
+ mAccessNetworksManager.registerForQualifiedNetworksChanged(this,
+ EVENT_QUALIFIED_NETWORKS_CHANGED);
mAvailableTransports = new int[]{TransportType.WWAN, TransportType.WLAN};
}
}
@@ -211,14 +214,17 @@
log("updateAvailableNetworks: " + networksList);
for (QualifiedNetworks networks : networksList) {
if (areNetworksValid(networks)) {
- mCurrentAvailableNetworks.put(networks.apnType, networks.qualifiedNetworks);
if (isHandoverNeeded(networks)) {
+ mCurrentAvailableNetworks.put(networks.apnType, networks.qualifiedNetworks);
// If handover is needed, perform the handover works. For now we only pick the
// first element because it's the most preferred. In the future we should also
// consider the rest in the list, for example, the first one violates
// carrier/user policy.
int targetTransport = ACCESS_NETWORK_TRANSPORT_TYPE_MAP.get(
networks.qualifiedNetworks[0]);
+ log("Handover needed for APN type: "
+ + ApnSetting.getApnTypeString(networks.apnType) + ", target transport: "
+ + TransportType.toString(targetTransport));
mHandoverNeededEventRegistrants.notifyResult(
new HandoverParams(networks.apnType, targetTransport));
@@ -227,6 +233,7 @@
// transport.
log("Handover not needed for APN type: "
+ ApnSetting.getApnTypeString(networks.apnType));
+ mCurrentAvailableNetworks.put(networks.apnType, networks.qualifiedNetworks);
int transport = TransportType.WWAN;
if (!ArrayUtils.isEmpty(networks.qualifiedNetworks)
&& ACCESS_NETWORK_TRANSPORT_TYPE_MAP.containsKey(
diff --git a/src/java/com/android/internal/telephony/dataconnection/AccessNetworksManager.java b/src/java/com/android/internal/telephony/dataconnection/AccessNetworksManager.java
index 2e95967..96dabd4 100644
--- a/src/java/com/android/internal/telephony/dataconnection/AccessNetworksManager.java
+++ b/src/java/com/android/internal/telephony/dataconnection/AccessNetworksManager.java
@@ -16,16 +16,17 @@
package com.android.internal.telephony.dataconnection;
+import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.os.AsyncResult;
import android.os.Handler;
import android.os.IBinder;
import android.os.PersistableBundle;
+import android.os.Registrant;
import android.os.RegistrantList;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -191,8 +192,7 @@
}
if (!qualifiedNetworksList.isEmpty()) {
- mQualifiedNetworksChangedRegistrants.notifyRegistrants(
- new AsyncResult(null, qualifiedNetworksList, null));
+ mQualifiedNetworksChangedRegistrants.notifyResult(qualifiedNetworksList);
}
}
}
@@ -290,6 +290,17 @@
return packageName;
}
+
+ private @NonNull List<QualifiedNetworks> getQualifiedNetworksList() {
+ List<QualifiedNetworks> qualifiedNetworksList = new ArrayList<>();
+ for (int i = 0; i < mAvailableNetworks.size(); i++) {
+ qualifiedNetworksList.add(new QualifiedNetworks(mAvailableNetworks.keyAt(i),
+ mAvailableNetworks.valueAt(i)));
+ }
+
+ return qualifiedNetworksList;
+ }
+
/**
* Register for qualified networks changed event.
*
@@ -298,7 +309,14 @@
*/
public void registerForQualifiedNetworksChanged(Handler h, int what) {
if (h != null) {
- mQualifiedNetworksChangedRegistrants.addUnique(h, what, null);
+ Registrant r = new Registrant(h, what, null);
+ mQualifiedNetworksChangedRegistrants.add(r);
+
+ // Notify for the first time if there is already something in the available network
+ // list.
+ if (mAvailableNetworks.size() != 0) {
+ r.notifyResult(getQualifiedNetworksList());
+ }
}
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TransportManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TransportManagerTest.java
new file mode 100644
index 0000000..8a30cde
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TransportManagerTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2019 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.internal.telephony.dataconnection;
+
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.AccessNetworkConstants.TransportType;
+import android.telephony.data.ApnSetting;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.dataconnection.AccessNetworksManager.QualifiedNetworks;
+import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class TransportManagerTest extends TelephonyTest {
+ private static final int EVENT_HANDOVER_NEEDED = 1;
+
+ @Mock
+ private Handler mTestHandler;
+
+ private TransportManager mTransportManager;
+
+ private TransportManagerTestHandler mTransportManagerTestHandler;
+
+ private class TransportManagerTestHandler extends HandlerThread {
+
+ private TransportManagerTestHandler(String name) {
+ super(name);
+ }
+
+ @Override
+ public void onLooperPrepared() {
+ mTransportManager = new TransportManager(mPhone);
+ setReady(true);
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp(getClass().getSimpleName());
+ mTransportManagerTestHandler = new TransportManagerTestHandler(TAG);
+ mTransportManagerTestHandler.start();
+ waitUntilReady();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mTransportManagerTestHandler.quit();
+ mTransportManagerTestHandler.join();
+ super.tearDown();
+ }
+
+ @Test
+ @SmallTest
+ public void testHandoverNeeded() throws Exception {
+ mTransportManager.registerForHandoverNeededEvent(mTestHandler, EVENT_HANDOVER_NEEDED);
+
+ // Initial qualified networks
+ List<QualifiedNetworks> networkList = new ArrayList<>(Arrays.asList(
+ new QualifiedNetworks(ApnSetting.TYPE_IMS,
+ new int[]{AccessNetworkType.EUTRAN, AccessNetworkType.UTRAN,
+ AccessNetworkType.IWLAN})));
+ mTransportManager.obtainMessage(1 /* EVENT_QUALIFIED_NETWORKS_CHANGED */,
+ new AsyncResult(null, networkList, null)).sendToTarget();
+ waitForMs(100);
+ // Verify handover needed event was not sent
+ verify(mTestHandler, never()).sendMessageAtTime(any(Message.class), anyLong());
+
+ // Now change the order of qualified networks by putting IWLAN first
+ networkList = new ArrayList<>(Arrays.asList(
+ new QualifiedNetworks(ApnSetting.TYPE_IMS,
+ new int[]{AccessNetworkType.IWLAN, AccessNetworkType.UTRAN,
+ AccessNetworkType.EUTRAN})));
+ mTransportManager.obtainMessage(1 /* EVENT_QUALIFIED_NETWORKS_CHANGED */,
+ new AsyncResult(null, networkList, null)).sendToTarget();
+ waitForMs(100);
+
+ ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+
+ // Verify handover needed event was sent and the the target transport is WLAN.
+ verify(mTestHandler, times(1)).sendMessageAtTime(messageArgumentCaptor.capture(),
+ anyLong());
+ Message message = messageArgumentCaptor.getValue();
+ assertEquals(EVENT_HANDOVER_NEEDED, message.what);
+ AsyncResult ar = (AsyncResult) message.obj;
+ HandoverParams params = (HandoverParams) ar.result;
+ assertEquals(ApnSetting.TYPE_IMS, params.apnType);
+ assertEquals(TransportType.WLAN, params.targetTransport);
+
+ // Now change the order of qualified networks by putting UTRAN first
+ networkList = new ArrayList<>(Arrays.asList(
+ new QualifiedNetworks(ApnSetting.TYPE_IMS,
+ new int[]{AccessNetworkType.UTRAN, AccessNetworkType.EUTRAN,
+ AccessNetworkType.IWLAN})));
+ mTransportManager.obtainMessage(1 /* EVENT_QUALIFIED_NETWORKS_CHANGED */,
+ new AsyncResult(null, networkList, null)).sendToTarget();
+ waitForMs(100);
+
+ messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+
+ // Verify handover needed event was sent and the the target transport is WWAN.
+ verify(mTestHandler, times(2)).sendMessageAtTime(messageArgumentCaptor.capture(),
+ anyLong());
+ message = messageArgumentCaptor.getValue();
+ assertEquals(EVENT_HANDOVER_NEEDED, message.what);
+ ar = (AsyncResult) message.obj;
+ params = (HandoverParams) ar.result;
+ assertEquals(ApnSetting.TYPE_IMS, params.apnType);
+ assertEquals(TransportType.WWAN, params.targetTransport);
+ }
+
+ @Test
+ @SmallTest
+ public void testHandoverNotNeeded() throws Exception {
+ mTransportManager.registerForHandoverNeededEvent(mTestHandler, EVENT_HANDOVER_NEEDED);
+
+ // Initial qualified networks
+ List<QualifiedNetworks> networkList = new ArrayList<>(Arrays.asList(
+ new QualifiedNetworks(ApnSetting.TYPE_IMS,
+ new int[]{AccessNetworkType.EUTRAN, AccessNetworkType.UTRAN,
+ AccessNetworkType.IWLAN})));
+ mTransportManager.obtainMessage(1 /* EVENT_QUALIFIED_NETWORKS_CHANGED */,
+ new AsyncResult(null, networkList, null)).sendToTarget();
+ waitForMs(100);
+ // Verify handover needed event was not sent
+ verify(mTestHandler, never()).sendMessageAtTime(any(Message.class), anyLong());
+
+ // Now change the order of qualified networks by swapping EUTRAN and UTRAN.
+ networkList = new ArrayList<>(Arrays.asList(
+ new QualifiedNetworks(ApnSetting.TYPE_IMS,
+ new int[]{AccessNetworkType.UTRAN, AccessNetworkType.EUTRAN,
+ AccessNetworkType.IWLAN})));
+ mTransportManager.obtainMessage(1 /* EVENT_QUALIFIED_NETWORKS_CHANGED */,
+ new AsyncResult(null, networkList, null)).sendToTarget();
+ waitForMs(100);
+ // Verify handover needed event was not sent
+ verify(mTestHandler, never()).sendMessageAtTime(any(Message.class), anyLong());
+ }
+}