Snap for 6405781 from 4bb98285c99112a8b48a9890d1f91be05aba9c0c to sdk-release

Change-Id: Ib739f62a48a32ffdf0382e6a97b36ed5af933df3
diff --git a/Android.bp b/Android.bp
index e79a55d..fe7c040 100644
--- a/Android.bp
+++ b/Android.bp
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 //
-// Mms service
+// Opportunistic Network Service
 //
 android_app {
     name: "ONS",
diff --git a/src/com/android/ons/ONSProfileSelector.java b/src/com/android/ons/ONSProfileSelector.java
index 029eb8a..d92e2bd 100644
--- a/src/com/android/ons/ONSProfileSelector.java
+++ b/src/com/android/ons/ONSProfileSelector.java
@@ -93,6 +93,8 @@
     protected SubscriptionManager mSubscriptionManager;
     @VisibleForTesting
     protected List<SubscriptionInfo> mOppSubscriptionInfos;
+    @VisibleForTesting
+    protected List<SubscriptionInfo> mStandaloneOppSubInfos;
     private ONSProfileSelectionCallback mProfileSelectionCallback;
     private int mSequenceId;
     private int mSubId;
@@ -584,7 +586,8 @@
         return false;
     }
 
-    private int retrieveBestSubscription(List<CellInfo> results) {
+    @VisibleForTesting
+    protected int retrieveBestSubscription(List<CellInfo> results) {
         /* sort the results according to signal strength level */
         Collections.sort(results, new Comparator<CellInfo>() {
             @Override
@@ -729,6 +732,24 @@
         return false;
     }
 
+    public boolean containStandaloneOppSubs(ArrayList<AvailableNetworkInfo> availableNetworks) {
+        if (mStandaloneOppSubInfos == null) {
+            logDebug("received null subscription infos");
+            return false;
+        }
+        if (mStandaloneOppSubInfos.size() > 0) {
+            logDebug("Standalone opportunistic subInfos size " + mStandaloneOppSubInfos.size());
+            ArrayList<AvailableNetworkInfo> filteredAvailableNetworks =
+                    getFilteredAvailableNetworks(
+                            (ArrayList<AvailableNetworkInfo>) availableNetworks,
+                            mStandaloneOppSubInfos);
+            if (filteredAvailableNetworks.size() > 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public boolean isOpportunisticSubActive() {
         if (mOppSubscriptionInfos == null) {
             logDebug("received null subscription infos");
@@ -842,9 +863,14 @@
     protected void updateOpportunisticSubscriptions() {
         synchronized (mLock) {
             mOppSubscriptionInfos = mSubscriptionManager
-                .getOpportunisticSubscriptions().stream()
-                .filter(subInfo -> subInfo.isGroupDisabled() != true)
-                .collect(Collectors.toList());
+                    .getOpportunisticSubscriptions().stream()
+                    .filter(subInfo -> subInfo.isGroupDisabled() != true)
+                    .collect(Collectors.toList());
+            if (mOppSubscriptionInfos != null) {
+                mStandaloneOppSubInfos = mOppSubscriptionInfos.stream()
+                        .filter(subInfo -> subInfo.getGroupUuid() == null)
+                        .collect(Collectors.toList());
+            }
         }
     }
 
diff --git a/src/com/android/ons/OpportunisticNetworkService.java b/src/com/android/ons/OpportunisticNetworkService.java
index 7cb3238..62e292b 100644
--- a/src/com/android/ons/OpportunisticNetworkService.java
+++ b/src/com/android/ons/OpportunisticNetworkService.java
@@ -59,7 +59,7 @@
 
     private final Object mLock = new Object();
     @VisibleForTesting protected boolean mIsEnabled;
-    private ONSProfileSelector mProfileSelector;
+    @VisibleForTesting protected ONSProfileSelector mProfileSelector;
     private SharedPreferences mSharedPref;
     @VisibleForTesting protected HashMap<String, ONSConfigInput> mONSConfigInputHashMap;
 
@@ -441,6 +441,14 @@
                     onsConfigInput.setPreferredDataSub(availableNetworks.get(0).getSubId());
                     mONSConfigInputHashMap.put(CARRIER_APP_CONFIG_NAME, onsConfigInput);
                 }
+                /* standalone opportunistic subscription should be handled in priority. */
+                if (mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME) != null) {
+                    if (mProfileSelector.containStandaloneOppSubs(mONSConfigInputHashMap.get(
+                            SYSTEM_APP_CONFIG_NAME).getAvailableNetworkInfos())) {
+                        log("standalone opportunistic subscription is using.");
+                        return;
+                    }
+                }
 
                 if (mIsEnabled) {
                     /*  if carrier is reporting availability, then it takes higher priority. */
@@ -527,9 +535,11 @@
                 mONSConfigInputHashMap.put(SYSTEM_APP_CONFIG_NAME,
                         new ONSConfigInput(availableNetworks, callbackStub));
 
-                /* reporting availability. proceed if carrier app has not requested any */
+                /* reporting availability. proceed if carrier app has not requested any, but
+                   standalone opportunistic subscription should be handled in priority. */
                 if (mIsEnabled) {
-                    if (mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME) == null) {
+                    if (mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME) == null
+                            || mProfileSelector.containStandaloneOppSubs(availableNetworks)) {
                         mProfileSelector.startProfileSelection(availableNetworks, callbackStub);
                     }
                 } else {
@@ -549,10 +559,20 @@
                         TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
                     return;
                 }
-                /* reporting unavailability */
+                /* if system is reporting unavailability, then decide whether to start
+                   carrier app request or not. */
                 mONSConfigInputHashMap.put(SYSTEM_APP_CONFIG_NAME, null);
                 if (mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME) == null) {
                     mProfileSelector.stopProfileSelection(callbackStub);
+                } else {
+                    sendUpdateNetworksCallbackHelper(callbackStub,
+                            TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
+                    log("Try to start carrier app request");
+                    mProfileSelector.startProfileSelection(
+                            mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME)
+                                    .getAvailableNetworkInfos(),
+                            mONSConfigInputHashMap.get(
+                                    CARRIER_APP_CONFIG_NAME).getAvailableNetworkCallback());
                 }
             }
         } finally {
diff --git a/tests/src/com/android/ons/ONSProfileSelectorTest.java b/tests/src/com/android/ons/ONSProfileSelectorTest.java
index c979f4a..4816ec6 100644
--- a/tests/src/com/android/ons/ONSProfileSelectorTest.java
+++ b/tests/src/com/android/ons/ONSProfileSelectorTest.java
@@ -247,6 +247,81 @@
     }
 
     @Test
+    public void testStartProfileSelectionWithDifferentPrioritySubInfo() {
+        int PRIORITY_HIGH = 1;
+        int PRIORITY_MED = 2;
+
+        List<SubscriptionInfo> subscriptionInfoList = new ArrayList<SubscriptionInfo>();
+        SubscriptionInfo subscriptionInfo = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1,
+                "123", 1, null, "310", "210", "", false, null, "1");
+        subscriptionInfoList.add(subscriptionInfo);
+        SubscriptionInfo subscriptionInfo_2 = new SubscriptionInfo(8, "", 1, "Vzw", "Vzw", 1, 1,
+                "123", 1, null, "311", "480", "", false, null, "1");
+        subscriptionInfoList.add(subscriptionInfo_2);
+
+        List<CellInfo> results2 = new ArrayList<CellInfo>();
+        CellIdentityLte cellIdentityLte = new CellIdentityLte(310, 210, 1, 1, 1);
+        CellInfoLte cellInfoLte = new CellInfoLte();
+        cellInfoLte.setCellIdentity(cellIdentityLte);
+        results2.add((CellInfo) cellInfoLte);
+        CellIdentityLte cellIdentityLte_2 = new CellIdentityLte(311, 480, 1, 1, 1);
+        CellInfoLte cellInfoLte_2 = new CellInfoLte();
+        cellInfoLte_2.setCellIdentity(cellIdentityLte_2);
+        results2.add((CellInfo) cellInfoLte_2);
+
+        ArrayList<String> mccMncs = new ArrayList<>();
+        mccMncs.add("310210");
+        AvailableNetworkInfo availableNetworkInfo = new AvailableNetworkInfo(5, PRIORITY_MED,
+                mccMncs, new ArrayList<Integer>());
+        ArrayList<AvailableNetworkInfo> availableNetworkInfos = new ArrayList<>();
+        availableNetworkInfos.add(availableNetworkInfo);
+        ArrayList<String> mccMncs_2 = new ArrayList<>();
+        mccMncs_2.add("311480");
+        AvailableNetworkInfo availableNetworkInfo_2 = new AvailableNetworkInfo(8, PRIORITY_HIGH,
+                mccMncs_2, new ArrayList<Integer>());
+        availableNetworkInfos.add(availableNetworkInfo_2);
+
+        IUpdateAvailableNetworksCallback mCallback = new IUpdateAvailableNetworksCallback.Stub() {
+            @Override
+            public void onComplete(int result) {
+                mResult = result;
+            }
+        };
+
+        mResult = -1;
+        mReady = false;
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                Looper.prepare();
+                doReturn(subscriptionInfoList).when(mSubscriptionManager)
+                        .getOpportunisticSubscriptions();
+                doReturn(true).when(mSubscriptionManager).isActiveSubId(anyInt());
+                doReturn(true).when(mSubscriptionBoundTelephonyManager).enableModemForSlot(
+                        anyInt(), anyBoolean());
+                mONSProfileSelector = new MyONSProfileSelector(mContext,
+                        new MyONSProfileSelector.ONSProfileSelectionCallback() {
+                            public void onProfileSelectionDone() {
+                                setReady(true);
+                            }
+                        });
+                mONSProfileSelector.updateOppSubs();
+                mONSProfileSelector.startProfileSelection(availableNetworkInfos, mCallback);
+                mLooper = Looper.myLooper();
+                setReady(true);
+                Looper.loop();
+            }
+        }).start();
+        waitUntilReady();
+        waitForMs(500);
+        // get high priority subId
+        int retrieveSubId = mONSProfileSelector.retrieveBestSubscription(results2);
+        mONSProfileSelector.mNetworkAvailableCallBackCpy.onNetworkAvailability(results2);
+        assertEquals(8, retrieveSubId);
+        assertEquals(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS, mResult);
+    }
+
+    @Test
     public void testStartProfileSelectionWithActivePrimarySimOnESim() {
         List<SubscriptionInfo> opportunisticSubscriptionInfoList = new ArrayList<SubscriptionInfo>();
         List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>();
diff --git a/tests/src/com/android/ons/OpportunisticNetworkServiceTest.java b/tests/src/com/android/ons/OpportunisticNetworkServiceTest.java
index d382450..05a7f17 100644
--- a/tests/src/com/android/ons/OpportunisticNetworkServiceTest.java
+++ b/tests/src/com/android/ons/OpportunisticNetworkServiceTest.java
@@ -60,6 +60,8 @@
 
     @Mock
     private HashMap<String, ONSConfigInput> mockONSConfigInputHashMap;
+    @Mock
+    private ONSProfileSelector mockProfileSelector;
 
     @Before
     public void setUp() throws Exception {
@@ -286,6 +288,76 @@
         assertEquals(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS, mResult);
     }
 
+    @Test
+    public void testPriorityRuleOfActivatingAvailableNetworks() {
+        ArrayList<String> mccMncs = new ArrayList<>();
+        mccMncs.add("310210");
+        AvailableNetworkInfo availableNetworkInfo = new AvailableNetworkInfo(1, 1, mccMncs,
+                new ArrayList<Integer>());
+        ArrayList<AvailableNetworkInfo> availableNetworkInfos =
+                new ArrayList<AvailableNetworkInfo>();
+        availableNetworkInfos.add(availableNetworkInfo);
+        mResult = -1;
+        IUpdateAvailableNetworksCallback mCallback = new IUpdateAvailableNetworksCallback.Stub() {
+            @Override
+            public void onComplete(int result) {
+                mResult = result;
+                Log.d(TAG, "result: " + result);
+            }
+        };
+        ONSConfigInput onsConfigInput = new ONSConfigInput(availableNetworkInfos, mCallback);
+        onsConfigInput.setPrimarySub(1);
+        onsConfigInput.setPreferredDataSub(availableNetworkInfos.get(0).getSubId());
+        doReturn(onsConfigInput).when(mockONSConfigInputHashMap).get(CARRIER_APP_CONFIG_NAME);
+        doReturn(true).when(mockProfileSelector).hasOpprotunisticSub(any());
+        doReturn(false).when(mockProfileSelector).containStandaloneOppSubs(any());
+        mOpportunisticNetworkService.mIsEnabled = true;
+        mOpportunisticNetworkService.mONSConfigInputHashMap = mockONSConfigInputHashMap;
+        mOpportunisticNetworkService.mProfileSelector = mockProfileSelector;
+
+        // Assume carrier app has updated available networks at first.
+        // Then system app updated available networks which is not standalone.
+        try {
+            IOns onsBinder = (IOns) mOpportunisticNetworkService.onBind(null);
+            onsBinder.updateAvailableNetworks(availableNetworkInfos, mCallback, pkgForDebug);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "RemoteException", ex);
+        }
+        verify(mockProfileSelector, never()).startProfileSelection(any(), any());
+
+        // System app updated available networks which contain standalone network.
+        doReturn(true).when(mockProfileSelector).containStandaloneOppSubs(any());
+        try {
+            IOns onsBinder = (IOns) mOpportunisticNetworkService.onBind(null);
+            onsBinder.updateAvailableNetworks(availableNetworkInfos, mCallback, pkgForDebug);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "RemoteException", ex);
+        }
+        verify(mockProfileSelector, times(1)).startProfileSelection(any(), any());
+
+        // System app updated available networks which equal to null.
+        // Case1: start carrier app request, if there is a carrier app request.
+        availableNetworkInfos.clear();
+        try {
+            IOns onsBinder = (IOns) mOpportunisticNetworkService.onBind(null);
+            onsBinder.updateAvailableNetworks(availableNetworkInfos, mCallback, pkgForDebug);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "RemoteException", ex);
+        }
+        verify(mockProfileSelector, times(2)).startProfileSelection(any(), any());
+
+        // System app updated available networks which equal to null.
+        // Case2: stop profile selection, if there is no any carrier app request.
+        doReturn(null).when(mockONSConfigInputHashMap).get(CARRIER_APP_CONFIG_NAME);
+        try {
+            IOns onsBinder = (IOns) mOpportunisticNetworkService.onBind(null);
+            onsBinder.updateAvailableNetworks(availableNetworkInfos, mCallback, pkgForDebug);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "RemoteException", ex);
+        }
+        verify(mockProfileSelector, times(1)).stopProfileSelection(any());
+    }
+
     private IOns getIOns() {
         return IOns.Stub.asInterface(ServiceManager.getService("ions"));
     }