Merge "Blame scan request from WifiManager.reconnect()" into oc-mr1-dev
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index d6723ca..bc14278 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -1770,7 +1770,9 @@
                     uid) == PackageManager.PERMISSION_GRANTED) {
                 result.setMacAddress(mWifiInfo.getMacAddress());
             }
-            if (mWifiPermissionsUtil.canAccessScanResults(
+            final WifiConfiguration currentWifiConfiguration = getCurrentWifiConfiguration();
+            if (mWifiPermissionsUtil.canAccessFullConnectionInfo(
+                    currentWifiConfiguration,
                     callingPackage,
                     uid,
                     Build.VERSION_CODES.O)) {
diff --git a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
index 069e5a8..52c9618 100644
--- a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
+++ b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
@@ -17,17 +17,23 @@
 package com.android.server.wifi.util;
 
 import android.Manifest;
+import android.annotation.Nullable;
 import android.app.AppOpsManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.net.ConnectivityManager;
 import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppData;
+import android.net.wifi.WifiConfiguration;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.text.TextUtils;
 
+import com.android.server.wifi.FrameworkFacade;
 import com.android.server.wifi.WifiInjector;
 import com.android.server.wifi.WifiLog;
 import com.android.server.wifi.WifiSettingsStore;
@@ -46,6 +52,7 @@
     private final UserManager mUserManager;
     private final WifiSettingsStore mSettingsStore;
     private final NetworkScoreManager mNetworkScoreManager;
+    private final FrameworkFacade mFrameworkFacade;
     private WifiLog mLog;
 
     public WifiPermissionsUtil(WifiPermissionsWrapper wifiPermissionsWrapper,
@@ -58,6 +65,7 @@
         mSettingsStore = settingsStore;
         mLog = wifiInjector.makeLog(TAG);
         mNetworkScoreManager = networkScoreManager;
+        mFrameworkFacade = wifiInjector.getFrameworkFacade();
     }
 
     /**
@@ -168,7 +176,7 @@
         }
         // If the User or profile is current, permission is granted
         // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
-        if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) {
+        if (!canAccessUserProfile(uid)) {
             mLog.tC("Denied: Profile not permitted");
             return false;
         }
@@ -176,6 +184,77 @@
     }
 
     /**
+     * API to determine if the caller has permissions to get a {@link android.net.wifi.WifiInfo}
+     * instance containing the SSID and BSSID.
+     *
+     *
+     * @param currentConfig the currently connected WiFi config
+     * @param pkgName package name of the application requesting access
+     * @param uid The uid of the package
+     * @param minVersion Minimum app API Version number to enforce location permission
+     * @return boolean true if the SSID/BSSID can be sent to the user, false if they
+     *         should be hidden/removed.
+     */
+    public boolean canAccessFullConnectionInfo(@Nullable WifiConfiguration currentConfig,
+            String pkgName, int uid, int minVersion) throws SecurityException {
+        mAppOps.checkPackage(uid, pkgName);
+
+        // The User or profile must be current or the uid must
+        // have INTERACT_ACROSS_USERS_FULL permission.
+        if (!canAccessUserProfile(uid)) {
+            mLog.tC("Denied: Profile not permitted");
+            return false;
+        }
+
+        // If the caller has scan result access then they can also see the full connection info.
+        // Otherwise the caller must be the active use open wifi package and the current config
+        // must be for an open network.
+        return canAccessScanResults(pkgName, uid, minVersion)
+                || isUseOpenWifiPackageWithConnectionInfoAccess(currentConfig, pkgName);
+
+    }
+
+    /**
+     * Returns true if the given WiFi config is for an open network and the package is the active
+     * use open wifi app.
+     */
+    private boolean isUseOpenWifiPackageWithConnectionInfoAccess(
+            @Nullable WifiConfiguration currentConfig, String pkgName) {
+
+        // Access is only granted for open networks.
+        if (currentConfig == null) {
+            mLog.tC("Denied: WifiConfiguration is NULL.");
+            return false;
+        }
+
+        // Access is only granted for open networks.
+        if (!currentConfig.isOpenNetwork()) {
+            mLog.tC("Denied: The current config is not for an open network.");
+            return false;
+        }
+
+        // The USE_OPEN_WIFI_PACKAGE can access the full connection info details without
+        // scan result access.
+        if (!isUseOpenWifiPackage(pkgName)) {
+            mLog.tC("Denied: caller is not the current USE_OPEN_WIFI_PACKAGE");
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns true if the User or profile is current or the
+     * uid has the INTERACT_ACROSS_USERS_FULL permission.
+     */
+    private boolean canAccessUserProfile(int uid) {
+        if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
      * Returns true if the caller holds PEERS_MAC_ADDRESS permission.
      */
     private boolean checkCallerHasPeersMacAddressPermission(int uid) {
@@ -192,6 +271,43 @@
     }
 
     /**
+     * Returns true if the given package is equal to the setting keyed by
+     * {@link Settings.Global#USE_OPEN_WIFI_PACKAGE} and the NetworkScoreManager
+     * has the package name set as the use open wifi package.
+     */
+    private boolean isUseOpenWifiPackage(String packageName) {
+        if (TextUtils.isEmpty(packageName)) {
+            return false;
+        }
+
+        // When the setting is enabled it's set to the package name of the use open wifi app.
+        final String useOpenWifiPkg =
+                mFrameworkFacade.getStringSetting(mContext, Settings.Global.USE_OPEN_WIFI_PACKAGE);
+        if (packageName.equals(useOpenWifiPkg)) {
+            // If the package name matches the setting then also confirm that the scorer is
+            // active and the package matches the expected use open wifi package from the scorer's
+            // perspective. The scorer can be active when the use open wifi feature is off so we
+            // can't rely on this check alone.
+            // TODO(b/67278755): Refactor this into an API similar to isCallerActiveScorer()
+            final NetworkScorerAppData appData;
+            final long token = Binder.clearCallingIdentity();
+            try {
+                appData = mNetworkScoreManager.getActiveScorer();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            if (appData != null) {
+                final ComponentName enableUseOpenWifiActivity =
+                        appData.getEnableUseOpenWifiActivity();
+                return enableUseOpenWifiActivity != null
+                        && packageName.equals(enableUseOpenWifiActivity.getPackageName());
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * Returns true if Wifi scan operation is allowed for this caller
      * and package.
      */
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index ecb4c95..8f67df4 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -2275,8 +2275,8 @@
             assertEquals(sBSSID, wifiInfo.getBSSID());
             assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
 
-            when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt()))
-                    .thenReturn(false);
+            when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid),
+                    anyInt())).thenReturn(false);
 
             WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
 
@@ -2308,8 +2308,8 @@
             assertEquals(sBSSID, wifiInfo.getBSSID());
             assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
 
-            when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt()))
-                    .thenThrow(new SecurityException());
+            when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid),
+                    anyInt())).thenThrow(new SecurityException());
 
             WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
 
@@ -2338,8 +2338,8 @@
             assertEquals(sBSSID, wifiInfo.getBSSID());
             assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
 
-            when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt()))
-                    .thenReturn(true);
+            when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid),
+                    anyInt())).thenReturn(true);
 
             WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
 
diff --git a/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java b/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java
index 308e267..7f5a66d 100644
--- a/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doAnswer;
@@ -27,12 +28,15 @@
 
 import android.Manifest;
 import android.app.AppOpsManager;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppData;
+import android.net.wifi.WifiConfiguration;
 import android.os.Build;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -41,6 +45,7 @@
 
 import com.android.server.wifi.BinderUtil;
 import com.android.server.wifi.FakeWifiLog;
+import com.android.server.wifi.FrameworkFacade;
 import com.android.server.wifi.WifiInjector;
 import com.android.server.wifi.WifiSettingsStore;
 
@@ -72,8 +77,10 @@
     @Mock private UserManager mMockUserManager;
     @Mock private WifiSettingsStore mMockWifiSettingsStore;
     @Mock private ContentResolver mMockContentResolver;
-    @Mock private NetworkScoreManager mNetworkScoreManager;
-    @Mock private WifiInjector mWifiInjector;
+    @Mock private NetworkScoreManager mMockNetworkScoreManager;
+    @Mock private WifiInjector mMockWifiInjector;
+    @Mock private FrameworkFacade mMockFrameworkFacade;
+    @Mock private WifiConfiguration mMockWifiConfig;
     @Spy private FakeWifiLog mWifiLog;
 
     private static final String TEST_PACKAGE_NAME = "com.google.somePackage";
@@ -101,6 +108,10 @@
     private boolean mActiveNwScorer;
     private Answer<Integer> mReturnPermission;
     private HashMap<String, Integer> mPermissionsList = new HashMap<String, Integer>();
+    private String mUseOpenWifiPackage;
+    private NetworkScorerAppData mNetworkScorerAppData;
+    private boolean mGetActiveScorerThrowsSecurityException;
+    private boolean mConfigIsOpen;
 
     /**
     * Set up Mockito tests
@@ -124,8 +135,8 @@
         mUid = MANAGED_PROFILE_UID;  // do not really care about this value
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         when(mMockPermissionsWrapper.getOverrideWifiConfigPermission(anyInt()))
                 .thenReturn(PackageManager.PERMISSION_GRANTED);
         assertTrue(codeUnderTest.checkConfigOverridePermission(mUid));
@@ -139,8 +150,8 @@
         mUid = OTHER_USER_UID;  // do not really care about this value
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         when(mMockPermissionsWrapper.getOverrideWifiConfigPermission(anyInt()))
                 .thenReturn(PackageManager.PERMISSION_DENIED);
         assertFalse(codeUnderTest.checkConfigOverridePermission(mUid));
@@ -154,8 +165,8 @@
         mUid = OTHER_USER_UID;  // do not really care about this value
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         doThrow(new RemoteException("Failed to check permissions for " + mUid))
                 .when(mMockPermissionsWrapper).getOverrideWifiConfigPermission(mUid);
         assertFalse(codeUnderTest.checkConfigOverridePermission(mUid));
@@ -179,8 +190,8 @@
         mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         try {
             output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
         } catch (SecurityException e) {
@@ -207,8 +218,8 @@
         mMockUserInfo.id = mCallingUser;
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         try {
             output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
         } catch (SecurityException e) {
@@ -230,8 +241,8 @@
         mPermissionsList.put(mMacAddressPermission, mUid);
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         try {
             output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
         } catch (SecurityException e) {
@@ -259,8 +270,8 @@
         mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid);
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         try {
             output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
         } catch (SecurityException e) {
@@ -286,8 +297,8 @@
         mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         try {
             output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
         } catch (SecurityException e) {
@@ -312,8 +323,8 @@
         mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         try {
             output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
         } catch (SecurityException e) {
@@ -323,6 +334,354 @@
     }
 
     /**
+     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+     *                    User is current
+     *                    The current config is for an open network.
+     * Validate result is true
+     */
+    @Test
+    public void testCanAccessFullConnectionInfo_PackageIsUseOpenWifiPackage() throws Exception {
+        final boolean output;
+        mThrowSecurityException = false;
+        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+        ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
+        mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
+                null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
+                useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
+        setupTestCase();
+        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
+
+        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+                mUid, mTargetVersion);
+
+        assertEquals(true, output);
+    }
+
+    /**
+     * Test case setting: Package is valid because the caller has access to scan results.
+     *                    Location mode is ON
+     *                    User is current
+     *                    The current config is not for an open network.
+     * Validate result is true
+     */
+    @Test
+    public void testCanAccessFullConnectionInfo_HasAccessToScanResults() throws Exception {
+        final boolean output;
+        mThrowSecurityException = false;
+        mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.GINGERBREAD;
+        mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
+        mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED;
+        mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED;
+        mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
+        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+        mConfigIsOpen = false;
+
+        setupTestCase();
+        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
+
+        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+                mUid, mTargetVersion);
+
+        assertEquals(true, output);
+    }
+
+    /**
+     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+     *                    User or profile is not current but the uid has
+     *                    permission to INTERACT_ACROSS_USERS_FULL
+     *                    The current config is for an open network.
+     * Validate result is true
+     */
+    @Test
+    public void testCanAccessFullConnectionInfo_UserNotCurrentButHasInteractAcrossUsers()
+            throws Exception {
+        final boolean output;
+        mThrowSecurityException = false;
+        mUid = MANAGED_PROFILE_UID;
+        mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid);
+        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+        ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
+        mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
+                null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
+                useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
+        setupTestCase();
+        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
+
+        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+                mUid, mTargetVersion);
+
+        assertEquals(true, output);
+    }
+
+    /**
+     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+     *                    User or profile is NOT current
+     *                    INTERACT_ACROSS_USERS_FULL NOT granted
+     *                    The current config is for an open network.
+     * Validate result is false
+     */
+    @Test
+    public void testCanAccessFullConnectionInfo_UserNotCurrentNoInteractAcrossUsers()
+            throws Exception {
+        final boolean output;
+        mThrowSecurityException = false;
+        mUid = MANAGED_PROFILE_UID;
+        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+        setupTestCase();
+        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
+
+        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+                mUid, mTargetVersion);
+
+        assertEquals(false, output);
+    }
+
+    /**
+     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+     *                    User is current
+     *                    The current config is NULL.
+     * Validate result is false
+     */
+    @Test
+    public void testCanAccessFullConnectionInfo_WiFiConfigIsNull() throws Exception {
+        final boolean output;
+        mThrowSecurityException = false;
+        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+        ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
+        mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
+                null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
+                useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
+        setupTestCase();
+        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
+
+        output = codeUnderTest.canAccessFullConnectionInfo(null /*config*/, TEST_PACKAGE_NAME,
+                mUid, mTargetVersion);
+
+        assertEquals(false, output);
+    }
+
+    /**
+     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+     *                    User is current
+     *                    The current config is not for an open network.
+     * Validate result is false
+     */
+    @Test
+    public void testCanAccessFullConnectionInfo_WiFiConfigIsNotOpen() throws Exception {
+        final boolean output;
+        mThrowSecurityException = false;
+        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+        ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
+        mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
+                null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
+                useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
+        mConfigIsOpen = false;
+        setupTestCase();
+        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
+
+        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+                mUid, mTargetVersion);
+
+        assertEquals(false, output);
+    }
+
+    /**
+     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+     *                    User is current
+     *                    The current config is for an open network.
+     *                    There is no active scorer
+     * Validate result is false
+     */
+    @Test
+    public void testCanAccessFullConnectionInfo_UseOpenWifiPackageIsSetButNoActiveScorer()
+            throws Exception {
+        final boolean output;
+        mThrowSecurityException = false;
+        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+        mNetworkScorerAppData = null; // getActiveScorer() will return null
+        setupTestCase();
+        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
+
+        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+                mUid, mTargetVersion);
+
+        assertEquals(false, output);
+    }
+
+    /**
+     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+     *                    User is current
+     *                    The current config is for an open network.
+     *                    The scorer is active but the useOpenWiFi component name doesn't match
+     *                    the provided package.
+     * Validate result is false
+     */
+    @Test
+    public void testCanAccessFullConnectionInfo_MismatchBetweenUseOpenWifiPackages()
+            throws Exception {
+        final boolean output;
+        mThrowSecurityException = false;
+        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+        ComponentName useOpenWifiComponent =
+                new ComponentName(mUseOpenWifiPackage + ".nomatch", "TestClass");
+        mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
+                null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
+                useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
+        setupTestCase();
+        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
+
+        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+                mUid, mTargetVersion);
+
+        assertEquals(false, output);
+    }
+
+    /**
+     * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
+     *                    User is current
+     *                    The current config is for an open network.
+     *                    The scorer is active but the useOpenWiFi component name is null.
+     * Validate result is false
+     */
+    @Test
+    public void testCanAccessFullConnectionInfo_UseOpenWifiPackageFromScorerIsNull()
+            throws Exception {
+        final boolean output;
+        mThrowSecurityException = false;
+        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+        mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
+                null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
+                null /*useOpenWifiComponent*/, null /*networkAvailableNotificationChannelId*/);
+        setupTestCase();
+        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
+
+        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+                mUid, mTargetVersion);
+
+        assertEquals(false, output);
+    }
+
+    /**
+     * Test case setting: Package is invalid because USE_OPEN_WIFI_PACKAGE is an empty string.
+     *                    Location mode is ON
+     *                    User is current
+     *                    The current config is for an open network.
+     * Validate result is false
+     */
+    @Test
+    public void testCanAccessFullConnectionInfo_UseOpenWifiPackageIsEmpty() throws Exception {
+        final boolean output;
+        mThrowSecurityException = false;
+        mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
+        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+        mUseOpenWifiPackage = "";
+        setupTestCase();
+        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
+
+        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+                mUid, mTargetVersion);
+
+        assertEquals(false, output);
+    }
+
+    /**
+     * Test case setting: Package is invalid because it does not match the USE_OPEN_WIFI_PACKAGE.
+     *                    User is current
+     *                    The current config is for an open network.
+     * Validate result is false
+     */
+    @Test
+    public void testCanAccessFullConnectionInfo_DoesNotMatchUseOpenWifiPackage() throws Exception {
+        final boolean output;
+        mThrowSecurityException = false;
+        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+        mUseOpenWifiPackage = TEST_PACKAGE_NAME + ".nomatch";
+        setupTestCase();
+        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
+
+        output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
+                mUid, mTargetVersion);
+
+        assertEquals(false, output);
+    }
+
+    /**
+     * Test case setting: The caller is invalid because its UID does not match the provided package.
+     *
+     * Validate a SecurityException is thrown.
+     */
+    @Test
+    public void testCanAccessFullConnectionInfo_UidPackageCheckFails() throws Exception {
+        mThrowSecurityException = true;
+        setupTestCase();
+        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
+
+        try {
+            codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, mUid,
+                    mTargetVersion);
+            fail("SecurityException not thrown.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Test case setting: The getActiveScorer() call fails with a SecurityException.
+     *
+     * Validate a SecurityException is thrown.
+     */
+    @Test
+    public void testCanAccessFullConnectionInfo_GetActiveScorerFails() throws Exception {
+        mThrowSecurityException = false;
+        mGetActiveScorerThrowsSecurityException = true;
+        mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
+        mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
+        mUseOpenWifiPackage = TEST_PACKAGE_NAME;
+        setupTestCase();
+        WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
+
+        try {
+            codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, mUid,
+                    mTargetVersion);
+            fail("SecurityException not thrown.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
      * Test case Setting: Package is valid
      *                    Legacy App
      *                    Foreground
@@ -341,8 +700,8 @@
         mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         try {
             output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
         } catch (SecurityException e) {
@@ -373,8 +732,8 @@
         mMockUserInfo.id = mCallingUser;
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         try {
             output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
         } catch (SecurityException e) {
@@ -400,8 +759,8 @@
         mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         try {
             output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
         } catch (SecurityException e) {
@@ -419,8 +778,8 @@
         boolean output = false;
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         try {
             output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
         } catch (SecurityException e) {
@@ -444,8 +803,8 @@
         mMockUserInfo.id = mCallingUser;
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         codeUnderTest.enforceLocationPermission(TEST_PACKAGE_NAME, mUid);
     }
 
@@ -457,8 +816,8 @@
     public void testEnforceLocationPermissionExpectSecurityException() throws Exception {
         setupTestCase();
         WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
-                mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
-                mWifiInjector);
+                mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
+                mMockWifiInjector);
         codeUnderTest.enforceLocationPermission(TEST_PACKAGE_NAME, mUid);
     }
 
@@ -500,7 +859,15 @@
         when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
         when(mMockContext.getSystemService(Context.USER_SERVICE))
             .thenReturn(mMockUserManager);
-        when(mWifiInjector.makeLog(anyString())).thenReturn(mWifiLog);
+        when(mMockWifiInjector.makeLog(anyString())).thenReturn(mWifiLog);
+        when(mMockWifiInjector.getFrameworkFacade()).thenReturn(mMockFrameworkFacade);
+        if (mGetActiveScorerThrowsSecurityException) {
+            when(mMockNetworkScoreManager.getActiveScorer()).thenThrow(
+                    new SecurityException("Caller is neither the system process nor a "
+                            + "score requester."));
+        } else {
+            when(mMockNetworkScoreManager.getActiveScorer()).thenReturn(mNetworkScorerAppData);
+        }
     }
 
     private void initTestVars() {
@@ -518,6 +885,10 @@
         mCoarseLocationPermission = PackageManager.PERMISSION_DENIED;
         mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED;
         mActiveNwScorer = false;
+        mUseOpenWifiPackage = null;
+        mNetworkScorerAppData = null;
+        mGetActiveScorerThrowsSecurityException = false;
+        mConfigIsOpen = true;
     }
 
     private void setupMockInterface() {
@@ -528,11 +899,14 @@
                         anyString(), anyInt());
         when(mMockPermissionsWrapper.getCallingUserId(mUid)).thenReturn(mCallingUser);
         when(mMockPermissionsWrapper.getCurrentUser()).thenReturn(mCurrentUser);
-        when(mNetworkScoreManager.isCallerActiveScorer(mUid)).thenReturn(mActiveNwScorer);
+        when(mMockNetworkScoreManager.isCallerActiveScorer(mUid)).thenReturn(mActiveNwScorer);
         when(mMockPermissionsWrapper.getUidPermission(mManifestStringCoarse, mUid))
             .thenReturn(mCoarseLocationPermission);
         when(mMockWifiSettingsStore.getLocationModeSetting(mMockContext))
             .thenReturn(mLocationModeSetting);
         when(mMockPermissionsWrapper.getTopPkgName()).thenReturn(mPkgNameOfTopActivity);
+        when(mMockFrameworkFacade.getStringSetting(mMockContext,
+                Settings.Global.USE_OPEN_WIFI_PACKAGE)).thenReturn(mUseOpenWifiPackage);
+        when(mMockWifiConfig.isOpenNetwork()).thenReturn(mConfigIsOpen);
     }
 }