Restrict secondary users to share Wi-Fi network

- Remove "Share" and "Forget" options from the long press menu

- Add SafetyNet Logging for security report

Bug: 206986392
Test: manual test
make RunSettingsRoboTests \
  ROBOTEST_FILTER=NetworkProviderSettingsTest

Change-Id: Ic434f0583cba557228c72508a501347ffa3141e1
Merged-In: Ic434f0583cba557228c72508a501347ffa3141e1
diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java
index 35a34d4..f7b8893 100644
--- a/src/com/android/settings/network/NetworkProviderSettings.java
+++ b/src/com/android/settings/network/NetworkProviderSettings.java
@@ -33,9 +33,11 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PowerManager;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.EventLog;
 import android.util.FeatureFlagUtils;
 import android.util.Log;
 import android.view.ContextMenu;
@@ -199,6 +201,8 @@
      * by the Test DPC tool in AFW mode.
      */
     protected boolean mIsRestricted;
+    @VisibleForTesting
+    boolean mIsAdmin = true;
 
     @VisibleForTesting
     AirplaneModeEnabler mAirplaneModeEnabler;
@@ -280,6 +284,13 @@
         addPreferences();
 
         mIsRestricted = isUiRestricted();
+        mIsAdmin = isAdminUser();
+    }
+
+    private boolean isAdminUser() {
+        final UserManager userManager = getSystemService(UserManager.class);
+        if (userManager == null) return true;
+        return userManager.isAdminUser();
     }
 
     private void addPreferences() {
@@ -538,7 +549,9 @@
         }
 
         if (mSelectedWifiEntry.canDisconnect()) {
-            menu.add(Menu.NONE, MENU_ID_SHARE, 0 /* order */, R.string.share);
+            if (mSelectedWifiEntry.canShare()) {
+                addShareMenuIfSuitable(menu);
+            }
             menu.add(Menu.NONE, MENU_ID_DISCONNECT, 1 /* order */,
                     R.string.wifi_disconnect_button_text);
         }
@@ -546,7 +559,7 @@
         // "forget" for normal saved network. And "disconnect" for ephemeral network because it
         // could only be disconnected and be put in blocklists so it won't be used again.
         if (canForgetNetwork()) {
-            menu.add(Menu.NONE, MENU_ID_FORGET, 0 /* order */, R.string.forget);
+            addForgetMenuIfSuitable(menu);
         }
 
         WifiConfiguration config = mSelectedWifiEntry.getWifiConfiguration();
@@ -561,6 +574,23 @@
         }
     }
 
+    @VisibleForTesting
+    void addShareMenuIfSuitable(ContextMenu menu) {
+        if (mIsAdmin) {
+            menu.add(Menu.NONE, MENU_ID_SHARE, 0 /* order */, R.string.share);
+            return;
+        }
+        Log.w(TAG, "Don't add the Wi-Fi share menu because the user is not an admin.");
+        EventLog.writeEvent(0x534e4554, "206986392", -1 /* UID */, "User is not an admin");
+    }
+
+    @VisibleForTesting
+    void addForgetMenuIfSuitable(ContextMenu menu) {
+        if (mIsAdmin) {
+            menu.add(Menu.NONE, MENU_ID_FORGET, 0 /* order */, R.string.forget);
+        }
+    }
+
     private boolean canForgetNetwork() {
         return mSelectedWifiEntry.canForget() && !WifiUtils.isNetworkLockedDown(getActivity(),
                 mSelectedWifiEntry.getWifiConfiguration());
diff --git a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
index 19b044b..38472c5 100644
--- a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
@@ -15,6 +15,9 @@
  */
 package com.android.settings.network;
 
+import static com.android.settings.network.NetworkProviderSettings.MENU_ID_DISCONNECT;
+import static com.android.settings.network.NetworkProviderSettings.MENU_ID_FORGET;
+import static com.android.settings.network.NetworkProviderSettings.MENU_ID_SHARE;
 import static com.android.settings.wifi.WifiConfigUiBase2.MODE_CONNECT;
 import static com.android.settings.wifi.WifiConfigUiBase2.MODE_MODIFY;
 
@@ -76,6 +79,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
@@ -105,6 +109,8 @@
     @Mock
     private WifiPickerTracker mMockWifiPickerTracker;
     @Mock
+    private WifiEntry mWifiEntry;
+    @Mock
     private PreferenceManager mPreferenceManager;
     @Mock
     private InternetResetHelper mInternetResetHelper;
@@ -113,6 +119,8 @@
     @Mock
     private LayoutPreference mResetInternetPreference;
     @Mock
+    private ContextMenu mContextMenu;
+    @Mock
     private MenuItem mMenuItem;
     @Mock
     InternetUpdater mInternetUpdater;
@@ -317,12 +325,54 @@
         final View view = mock(View.class);
         when(view.getTag()).thenReturn(connectedWifiEntryPreference);
 
-        final ContextMenu menu = mock(ContextMenu.class);
-        mNetworkProviderSettings.onCreateContextMenu(menu, view, null /* info */);
+        mNetworkProviderSettings.onCreateContextMenu(mContextMenu, view, null /* info */);
 
-        verify(menu).add(anyInt(), eq(NetworkProviderSettings.MENU_ID_FORGET), anyInt(), anyInt());
-        verify(menu).add(anyInt(), eq(NetworkProviderSettings.MENU_ID_DISCONNECT), anyInt(),
-                anyInt());
+        verify(mContextMenu).add(anyInt(), eq(MENU_ID_FORGET), anyInt(), anyInt());
+        verify(mContextMenu).add(anyInt(), eq(MENU_ID_DISCONNECT), anyInt(), anyInt());
+    }
+
+    @Test
+    public void onCreateContextMenu_canShare_shouldHaveShareMenuForConnectedWifiEntry() {
+        final FragmentActivity activity = mock(FragmentActivity.class);
+        when(activity.getApplicationContext()).thenReturn(mContext);
+        when(mNetworkProviderSettings.getActivity()).thenReturn(activity);
+
+        when(mWifiEntry.canDisconnect()).thenReturn(true);
+        when(mWifiEntry.canShare()).thenReturn(true);
+        when(mWifiEntry.canForget()).thenReturn(true);
+        when(mWifiEntry.isSaved()).thenReturn(true);
+        when(mWifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
+
+        final LongPressWifiEntryPreference connectedWifiEntryPreference =
+                mNetworkProviderSettings.createLongPressWifiEntryPreference(mWifiEntry);
+        final View view = mock(View.class);
+        when(view.getTag()).thenReturn(connectedWifiEntryPreference);
+
+        mNetworkProviderSettings.onCreateContextMenu(mContextMenu, view, null /* info */);
+
+        verify(mContextMenu).add(anyInt(), eq(MENU_ID_SHARE), anyInt(), anyInt());
+    }
+
+    @Test
+    public void onCreateContextMenu_canNotShare_shouldDisappearShareMenuForConnectedWifiEntry() {
+        final FragmentActivity activity = mock(FragmentActivity.class);
+        when(activity.getApplicationContext()).thenReturn(mContext);
+        when(mNetworkProviderSettings.getActivity()).thenReturn(activity);
+
+        when(mWifiEntry.canDisconnect()).thenReturn(true);
+        when(mWifiEntry.canShare()).thenReturn(false);
+        when(mWifiEntry.canForget()).thenReturn(true);
+        when(mWifiEntry.isSaved()).thenReturn(true);
+        when(mWifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
+
+        final LongPressWifiEntryPreference connectedWifiEntryPreference =
+                mNetworkProviderSettings.createLongPressWifiEntryPreference(mWifiEntry);
+        final View view = mock(View.class);
+        when(view.getTag()).thenReturn(connectedWifiEntryPreference);
+
+        mNetworkProviderSettings.onCreateContextMenu(mContextMenu, view, null /* info */);
+
+        verify(mContextMenu, never()).add(anyInt(), eq(MENU_ID_SHARE), anyInt(), anyInt());
     }
 
     @Test
@@ -546,6 +596,46 @@
         verify(mAirplaneModeEnabler).stop();
     }
 
+    @Test
+    public void addShareMenuIfSuitable_isAdmin_addMenu() {
+        mNetworkProviderSettings.mIsAdmin = true;
+        Mockito.reset(mContextMenu);
+
+        mNetworkProviderSettings.addShareMenuIfSuitable(mContextMenu);
+
+        verify(mContextMenu).add(anyInt(), eq(MENU_ID_SHARE), anyInt(), anyInt());
+    }
+
+    @Test
+    public void addShareMenuIfSuitable_isNotAdmin_notAddMenu() {
+        mNetworkProviderSettings.mIsAdmin = false;
+        Mockito.reset(mContextMenu);
+
+        mNetworkProviderSettings.addShareMenuIfSuitable(mContextMenu);
+
+        verify(mContextMenu, never()).add(anyInt(), eq(MENU_ID_SHARE), anyInt(), anyInt());
+    }
+
+    @Test
+    public void addForgetMenuIfSuitable_isAdmin_addMenu() {
+        mNetworkProviderSettings.mIsAdmin = true;
+        Mockito.reset(mContextMenu);
+
+        mNetworkProviderSettings.addForgetMenuIfSuitable(mContextMenu);
+
+        verify(mContextMenu).add(anyInt(), eq(MENU_ID_FORGET), anyInt(), anyInt());
+    }
+
+    @Test
+    public void addForgetMenuIfSuitable_isNotAdmin_notAddMenu() {
+        mNetworkProviderSettings.mIsAdmin = false;
+        Mockito.reset(mContextMenu);
+
+        mNetworkProviderSettings.addForgetMenuIfSuitable(mContextMenu);
+
+        verify(mContextMenu, never()).add(anyInt(), eq(MENU_ID_FORGET), anyInt(), anyInt());
+    }
+
     @Implements(PreferenceFragmentCompat.class)
     public static class ShadowPreferenceFragmentCompat {