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

Commit 0c76907f authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "resolve merge conflicts of b97129ec to master"

parents b7c00598 8d4d235a
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.