Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d4d235a authored by Lorenzo Colitti's avatar Lorenzo Colitti
Browse files

resolve merge conflicts of b97129ec to master

Change-Id: Ib09134090aa135d88bb807034b262a23c8b40e5f
parents 2c6fe63b b97129ec
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -342,6 +342,15 @@ public class ConnectivityManager {
     */
    public static final String ACTION_PROMPT_UNVALIDATED = "android.net.conn.PROMPT_UNVALIDATED";

    /**
     * Action used to display a dialog that asks the user whether to avoid a network that is no
     * longer validated. This intent is used to start the dialog in settings via startActivity.
     *
     * @hide
     */
    public static final String ACTION_PROMPT_LOST_VALIDATION =
            "android.net.conn.PROMPT_LOST_VALIDATION";

    /**
     * Invalid tethering type.
     * @see #startTethering(int, OnStartTetheringCallback, boolean)
+65 −10
Original line number Diff line number Diff line
@@ -398,6 +398,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
    private static final int EVENT_REQUEST_LINKPROPERTIES  = 32;
    private static final int EVENT_REQUEST_NETCAPABILITIES = 33;

    /**
     * Used internally to (re)configure avoid bad wifi setting.
     */
    private static final int EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI = 34;

    /** Handler thread used for both of the handlers below. */
    @VisibleForTesting
    protected final HandlerThread mHandlerThread;
@@ -902,6 +907,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
        mSettingsObserver.observe(
                Settings.Global.getUriFor(Settings.Global.MOBILE_DATA_ALWAYS_ON),
                EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON);

        // Watch for whether to automatically switch away from wifi networks that lose Internet
        // access.
        mSettingsObserver.observe(
                Settings.Global.getUriFor(Settings.Global.NETWORK_AVOID_BAD_WIFI),
                EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI);
    }

    private synchronized int nextNetworkRequestId() {
@@ -2209,6 +2220,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
                    if (nai != null) {
                        final boolean valid =
                                (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
                        final boolean wasValidated = nai.lastValidated;
                        if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") +
                                (msg.obj == null ? "" : " with redirect to " + (String)msg.obj));
                        if (valid != nai.lastValidated) {
@@ -2227,6 +2239,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
                                NetworkAgent.CMD_REPORT_NETWORK_STATUS,
                                (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
                                0, redirectUrlBundle);
                         if (wasValidated && !nai.lastValidated) {
                             handleNetworkUnvalidated(nai);
                         }
                    }
                    break;
                }
@@ -2745,6 +2760,10 @@ public class ConnectivityService extends IConnectivityManager.Stub

    @VisibleForTesting
    public boolean avoidBadWifi() {
        // There are two modes: either we always automatically avoid unvalidated wifi, or we show a
        // dialog and don't switch to it. The behaviour is controlled by the NETWORK_AVOID_BAD_WIFI
        // setting. If the setting has no value, then the value is taken from the config value,
        // which can be changed via OEM/carrier overlays.
        int defaultAvoidBadWifi =
            mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi);
        int avoid = Settings.Global.getInt(mContext.getContentResolver(),
@@ -2752,6 +2771,31 @@ public class ConnectivityService extends IConnectivityManager.Stub
        return avoid == 1;
    }

    private void showValidationNotification(NetworkAgentInfo nai, NotificationType type) {
        final String action;
        switch (type) {
            case NO_INTERNET:
                action = ConnectivityManager.ACTION_PROMPT_UNVALIDATED;
                break;
            case LOST_INTERNET:
                action = ConnectivityManager.ACTION_PROMPT_LOST_VALIDATION;
                break;
            default:
                Slog.wtf(TAG, "Unknown notification type " + type);
                return;
        }

        Intent intent = new Intent(action);
        intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.netId), null));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setClassName("com.android.settings",
                "com.android.settings.wifi.WifiNoInternetDialog");

        PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
                mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
        mNotifier.showNotification(nai.network.netId, type, nai, null, pendingIntent, true);
    }

    private void handlePromptUnvalidated(Network network) {
        if (VDBG) log("handlePromptUnvalidated " + network);
        NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
@@ -2763,18 +2807,22 @@ public class ConnectivityService extends IConnectivityManager.Stub
                !nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated) {
            return;
        }
        showValidationNotification(nai, NotificationType.NO_INTERNET);
    }

        Intent intent = new Intent(ConnectivityManager.ACTION_PROMPT_UNVALIDATED);
        intent.setData(Uri.fromParts("netId", Integer.toString(network.netId), null));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setClassName("com.android.settings",
                "com.android.settings.wifi.WifiNoInternetDialog");
    // TODO: Delete this like updateMobileDataAlwaysOn above.
    @VisibleForTesting
    void updateNetworkAvoidBadWifi() {
        mHandler.sendEmptyMessage(EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI);
    }

        PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
                mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
    private void handleNetworkUnvalidated(NetworkAgentInfo nai) {
        NetworkCapabilities nc = nai.networkCapabilities;
        if (DBG) log("handleNetworkUnvalidated " + nai.name() + " cap=" + nc);

        mNotifier.showNotification(nai.network.netId, NotificationType.NO_INTERNET, nai, null,
                pendingIntent, true);
        if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && !avoidBadWifi()) {
            showValidationNotification(nai, NotificationType.LOST_INTERNET);
        }
    }

    private class InternalHandler extends Handler {
@@ -2863,6 +2911,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
                    handleMobileDataAlwaysOn();
                    break;
                }
                case EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI: {
                    rematchAllNetworksAndRequests(null, 0);
                    break;
                }
                case EVENT_REQUEST_LINKPROPERTIES:
                    handleRequestLinkProperties((NetworkRequest) msg.obj, msg.arg1);
                    break;
@@ -4849,7 +4901,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
            } else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) {
                // If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
                // mark it as no longer satisfying "nri".  Because networks are processed by
                // rematchAllNetworkAndRequests() in descending score order, "currentNetwork" will
                // rematchAllNetworksAndRequests() in descending score order, "currentNetwork" will
                // match "newNetwork" before this loop will encounter a "currentNetwork" with higher
                // score than "newNetwork" and where "currentNetwork" no longer satisfies "nri".
                // This means this code doesn't have to handle the case where "currentNetwork" no
@@ -5409,6 +5461,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
                }
            }
        }

        Settings.Global.putString(mContext.getContentResolver(),
                Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
    }

    @VisibleForTesting
+7 −3
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ import static android.net.NetworkCapabilities.*;

public class NetworkNotificationManager {

    public static enum NotificationType { SIGN_IN, NO_INTERNET, NETWORK_SWITCH };
    public static enum NotificationType { SIGN_IN, NO_INTERNET, LOST_INTERNET, NETWORK_SWITCH };

    private static final String NOTIFICATION_ID = "Connectivity.Notification";

@@ -91,8 +91,8 @@ public class NetworkNotificationManager {
     * @param id an identifier that uniquely identifies this notification.  This must match
     *         between show and hide calls.  We use the NetID value but for legacy callers
     *         we concatenate the range of types with the range of NetIDs.
     * @param nai the network with which the notification is associated. For a SIGN_IN or
     *         NO_INTERNET notification, this is the network we're connecting to. For a
     * @param nai the network with which the notification is associated. For a SIGN_IN, NO_INTERNET,
     *         or LOST_INTERNET notification, this is the network we're connecting to. For a
     *         NETWORK_SWITCH notification it's the network that we switched from. When this network
     *         disconnects the notification is removed.
     * @param switchToNai for a NETWORK_SWITCH notification, the network we are switching to. Null
@@ -126,6 +126,10 @@ public class NetworkNotificationManager {
        if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
            title = r.getString(R.string.wifi_no_internet, 0);
            details = r.getString(R.string.wifi_no_internet_detailed);
        } else if (notifyType == NotificationType.LOST_INTERNET &&
                transportType == TRANSPORT_WIFI) {
            title = r.getString(R.string.wifi_no_internet, 0);
            details = r.getString(R.string.wifi_no_internet_detailed);
        } else if (notifyType == NotificationType.SIGN_IN) {
            switch (transportType) {
                case TRANSPORT_WIFI:
+76 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static android.net.NetworkCapabilities.*;

import static org.mockito.Mockito.mock;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -137,7 +138,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {

        @Override
        public Object getSystemService(String name) {
            if (name == Context.CONNECTIVITY_SERVICE) return mCm;
            if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
            if (Context.NOTIFICATION_SERVICE.equals(name)) return mock(NotificationManager.class);
            return super.getSystemService(name);
        }

@@ -2037,6 +2039,79 @@ public class ConnectivityServiceTest extends AndroidTestCase {
        handlerThread.quit();
    }

    @SmallTest
    public void testAvoidBadWifiSetting() throws Exception {
        ContentResolver cr = mServiceContext.getContentResolver();

        // File a request for cell to ensure it doesn't go down.
        final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
        final NetworkRequest cellRequest = new NetworkRequest.Builder()
                .addTransportType(TRANSPORT_CELLULAR).build();
        mCm.requestNetwork(cellRequest, cellNetworkCallback);

        TestNetworkCallback defaultCallback = new TestNetworkCallback();
        mCm.registerDefaultNetworkCallback(defaultCallback);

        NetworkRequest validatedWifiRequest = new NetworkRequest.Builder()
                .addTransportType(TRANSPORT_WIFI)
                .addCapability(NET_CAPABILITY_VALIDATED)
                .build();
        TestNetworkCallback validatedWifiCallback = new TestNetworkCallback();
        mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);

        // Takes effect on every rematch.
        Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);

        // Bring up validated cell.
        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
        mCellNetworkAgent.connect(true);
        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
        Network cellNetwork = mCellNetworkAgent.getNetwork();

        // Bring up validated wifi.
        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
        mWiFiNetworkAgent.connect(true);
        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
        validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
        Network wifiNetwork = mWiFiNetworkAgent.getNetwork();

        // Fail validation on wifi.
        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
        mCm.reportNetworkConnectivity(wifiNetwork, false);
        validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);

        // Because avoid bad wifi is off, we don't switch to cellular.
        defaultCallback.assertNoCallback();
        assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
                NET_CAPABILITY_VALIDATED));
        assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
                NET_CAPABILITY_VALIDATED));
        assertEquals(mCm.getActiveNetwork(), wifiNetwork);

        // Simulate the user selecting "switch" on the dialog.
        Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
        mService.updateNetworkAvoidBadWifi();

        // We now switch to cell.
        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
        assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
                NET_CAPABILITY_VALIDATED));
        assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
                NET_CAPABILITY_VALIDATED));
        assertEquals(mCm.getActiveNetwork(), cellNetwork);

        // If cell goes down, we switch to wifi.
        mCellNetworkAgent.disconnect();
        defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
        validatedWifiCallback.assertNoCallback();

        mCm.unregisterNetworkCallback(cellNetworkCallback);
        mCm.unregisterNetworkCallback(validatedWifiCallback);
        mCm.unregisterNetworkCallback(defaultCallback);
    }

    /**
     * Validate that a satisfied network request does not trigger onUnavailable() once the
     * time-out period expires.