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

Commit 8cb2f42e authored by Wink Saville's avatar Wink Saville Committed by Android Git Automerger
Browse files

am 948282b0: Add support for handling mobile provisioning networks.

* commit '948282b0':
  Add support for handling mobile provisioning networks.
parents 6d3fbd00 948282b0
Loading
Loading
Loading
Loading
+27 −89
Original line number Diff line number Diff line
@@ -58,13 +58,11 @@ public class CaptivePortalTracker extends StateMachine {
    private static final String TAG = "CaptivePortalTracker";

    private static final String DEFAULT_SERVER = "clients3.google.com";
    private static final String NOTIFICATION_ID = "CaptivePortal.Notification";

    private static final int SOCKET_TIMEOUT_MS = 10000;

    private String mServer;
    private String mUrl;
    private boolean mNotificationShown = false;
    private boolean mIsCaptivePortalCheckEnabled = false;
    private IConnectivityManager mConnService;
    private TelephonyManager mTelephonyManager;
@@ -161,12 +159,12 @@ public class CaptivePortalTracker extends StateMachine {
    private class DefaultState extends State {
        @Override
        public void enter() {
            if (DBG) log(getName() + "\n");
            setNotificationOff();
        }

        @Override
        public boolean processMessage(Message message) {
            if (DBG) log(getName() + message.toString() + "\n");
            if (DBG) log(getName() + message.toString());
            switch (message.what) {
                case CMD_DETECT_PORTAL:
                    NetworkInfo info = (NetworkInfo) message.obj;
@@ -188,24 +186,25 @@ public class CaptivePortalTracker extends StateMachine {
    private class NoActiveNetworkState extends State {
        @Override
        public void enter() {
            if (DBG) log(getName() + "\n");
            mNetworkInfo = null;
            /* Clear any previous notification */
            setNotificationVisible(false);
        }

        @Override
        public boolean processMessage(Message message) {
            if (DBG) log(getName() + message.toString() + "\n");
            if (DBG) log(getName() + message.toString());
            InetAddress server;
            NetworkInfo info;
            switch (message.what) {
                case CMD_CONNECTIVITY_CHANGE:
                    info = (NetworkInfo) message.obj;
                    if (info.getType() == ConnectivityManager.TYPE_WIFI) {
                        if (info.isConnected() && isActiveNetwork(info)) {
                            mNetworkInfo = info;
                            transitionTo(mDelayedCaptiveCheckState);
                        }
                    } else {
                        log(getName() + " not a wifi connectivity change, ignore");
                    }
                    break;
                default:
                    return NOT_HANDLED;
@@ -217,7 +216,7 @@ public class CaptivePortalTracker extends StateMachine {
    private class ActiveNetworkState extends State {
        @Override
        public void enter() {
            if (DBG) log(getName() + "\n");
            setNotificationOff();
        }

        @Override
@@ -250,7 +249,6 @@ public class CaptivePortalTracker extends StateMachine {
    private class DelayedCaptiveCheckState extends State {
        @Override
        public void enter() {
            if (DBG) log(getName() + "\n");
            Message message = obtainMessage(CMD_DELAYED_CAPTIVE_CHECK, ++mDelayedCheckToken, 0);
            if (mDeviceProvisioned) {
                sendMessageDelayed(message, DELAYED_CHECK_INTERVAL_MS);
@@ -261,7 +259,7 @@ public class CaptivePortalTracker extends StateMachine {

        @Override
        public boolean processMessage(Message message) {
            if (DBG) log(getName() + message.toString() + "\n");
            if (DBG) log(getName() + message.toString());
            switch (message.what) {
                case CMD_DELAYED_CAPTIVE_CHECK:
                    if (message.arg1 == mDelayedCheckToken) {
@@ -277,7 +275,12 @@ public class CaptivePortalTracker extends StateMachine {
                            if (captive) {
                                // Setup Wizard will assist the user in connecting to a captive
                                // portal, so make the notification visible unless during setup
                                setNotificationVisible(true);
                                try {
                                    mConnService.setProvisioningNotificationVisible(true,
                                        mNetworkInfo.getType(), mNetworkInfo.getExtraInfo(), mUrl);
                                } catch(RemoteException e) {
                                    e.printStackTrace();
                                }
                            }
                        } else {
                            Intent intent = new Intent(
@@ -335,6 +338,15 @@ public class CaptivePortalTracker extends StateMachine {
        return false;
    }

    private void setNotificationOff() {
        try {
            mConnService.setProvisioningNotificationVisible(false, ConnectivityManager.TYPE_NONE,
                    null, null);
        } catch (RemoteException e) {
            log("setNotificationOff: " + e);
        }
    }

    /**
     * Do a URL fetch on a known server to see if we get the data we expect
     */
@@ -354,9 +366,6 @@ public class CaptivePortalTracker extends StateMachine {
            urlConnection.getInputStream();
            // we got a valid response, but not from the real google
            return urlConnection.getResponseCode() != 204;
        } catch (SocketTimeoutException e) {
            if (DBG) log("Probably a portal: exception " + e);
            return true;
        } catch (IOException e) {
            if (DBG) log("Probably not a portal: exception " + e);
            return false;
@@ -380,75 +389,4 @@ public class CaptivePortalTracker extends StateMachine {
        }
        return null;
    }

    private void setNotificationVisible(boolean visible) {
        // if it should be hidden and it is already hidden, then noop
        if (!visible && !mNotificationShown) {
            if (DBG) log("setNotivicationVisible: false and not shown, so noop");
            return;
        }

        Resources r = Resources.getSystem();
        NotificationManager notificationManager = (NotificationManager) mContext
            .getSystemService(Context.NOTIFICATION_SERVICE);

        if (visible) {
            CharSequence title;
            CharSequence details;
            int icon;
            String url = null;
            switch (mNetworkInfo.getType()) {
                case ConnectivityManager.TYPE_WIFI:
                    title = r.getString(R.string.wifi_available_sign_in, 0);
                    details = r.getString(R.string.network_available_sign_in_detailed,
                            mNetworkInfo.getExtraInfo());
                    icon = R.drawable.stat_notify_wifi_in_range;
                    url = mUrl;
                    break;
                case ConnectivityManager.TYPE_MOBILE:
                    title = r.getString(R.string.network_available_sign_in, 0);
                    // TODO: Change this to pull from NetworkInfo once a printable
                    // name has been added to it
                    details = mTelephonyManager.getNetworkOperatorName();
                    icon = R.drawable.stat_notify_rssi_in_range;
                    try {
                        url = mConnService.getMobileProvisioningUrl();
                        if (TextUtils.isEmpty(url)) {
                            url = mConnService.getMobileRedirectedProvisioningUrl();
                        }
                    } catch(RemoteException e) {
                        e.printStackTrace();
                    }
                    if (TextUtils.isEmpty(url)) {
                        url = mUrl;
                    }
                    break;
                default:
                    title = r.getString(R.string.network_available_sign_in, 0);
                    details = r.getString(R.string.network_available_sign_in_detailed,
                            mNetworkInfo.getExtraInfo());
                    icon = R.drawable.stat_notify_rssi_in_range;
                    url = mUrl;
                    break;
            }

            Notification notification = new Notification();
            notification.when = 0;
            notification.icon = icon;
            notification.flags = Notification.FLAG_AUTO_CANCEL;
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
                    Intent.FLAG_ACTIVITY_NEW_TASK);
            notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
            notification.tickerText = title;
            notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);

            if (DBG) log("setNotivicationVisible: make visible");
            notificationManager.notify(NOTIFICATION_ID, 1, notification);
        } else {
            if (DBG) log("setNotivicationVisible: cancel notification");
            notificationManager.cancel(NOTIFICATION_ID, 1);
        }
        mNotificationShown = visible;
    }
}
+42 −47
Original line number Diff line number Diff line
@@ -582,6 +582,29 @@ public class ConnectivityManager {
        }
    }

    /**
     * Returns details about the Provisioning or currently active default data network. When
     * connected, this network is the default route for outgoing connections.
     * You should always check {@link NetworkInfo#isConnected()} before initiating
     * network traffic. This may return {@code null} when there is no default
     * network.
     *
     * @return a {@link NetworkInfo} object for the current default network
     *        or {@code null} if no network default network is currently active
     *
     * <p>This method requires the call to hold the permission
     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
     *
     * {@hide}
     */
    public NetworkInfo getProvisioningOrActiveNetworkInfo() {
        try {
            return mService.getProvisioningOrActiveNetworkInfo();
        } catch (RemoteException e) {
            return null;
        }
    }

    /**
     * Returns the IP information for the current default network.
     *
@@ -1316,63 +1339,19 @@ public class ConnectivityManager {
    }

    /**
     * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE)
     */

    /**
     * No connection was possible to the network.
     * {@hide}
     */
    public static final int CMP_RESULT_CODE_NO_CONNECTION = 0;

    /**
     * A connection was made to the internet, all is well.
     * {@hide}
     */
    public static final int CMP_RESULT_CODE_CONNECTABLE = 1;

    /**
     * A connection was made but there was a redirection, we appear to be in walled garden.
     * This is an indication of a warm sim on a mobile network.
     * {@hide}
     */
    public static final int CMP_RESULT_CODE_REDIRECTED = 2;

    /**
     * A connection was made but no dns server was available to resolve a name to address.
     * This is an indication of a warm sim on a mobile network.
     * Check mobile provisioning.
     *
     * {@hide}
     */
    public static final int CMP_RESULT_CODE_NO_DNS = 3;

    /**
     * A connection was made but could not open a TCP connection.
     * This is an indication of a warm sim on a mobile network.
     * {@hide}
     */
    public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4;

    /**
     * Check mobile provisioning. The resultCode passed to
     * onReceiveResult will be one of the CMP_RESULT_CODE_xxxx values above.
     * This may take a minute or more to complete.
     *
     * @param sendNotificaiton, when true a notification will be sent to user.
     * @param suggestedTimeOutMs, timeout in milliseconds
     * @param resultReceiver needs to  be supplied to receive the result
     *
     * @return time out that will be used, maybe less that suggestedTimeOutMs
     * -1 if an error.
     *
     * {@hide}
     */
    public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs,
            ResultReceiver resultReceiver) {
    public int checkMobileProvisioning(int suggestedTimeOutMs) {
        int timeOutMs = -1;
        try {
            timeOutMs = mService.checkMobileProvisioning(sendNotification, suggestedTimeOutMs,
                    resultReceiver);
            timeOutMs = mService.checkMobileProvisioning(suggestedTimeOutMs);
        } catch (RemoteException e) {
        }
        return timeOutMs;
@@ -1401,4 +1380,20 @@ public class ConnectivityManager {
        }
        return null;
    }

    /**
     * Set sign in error notification to visible or in visible
     *
     * @param visible
     * @param networkType
     *
     * {@hide}
     */
    public void setProvisioningNotificationVisible(boolean visible, int networkType,
            String extraInfo, String url) {
        try {
            mService.setProvisioningNotificationVisible(visible, networkType, extraInfo, url);
        } catch (RemoteException e) {
        }
    }
}
+5 −1
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@ interface IConnectivityManager
    NetworkInfo getNetworkInfo(int networkType);
    NetworkInfo[] getAllNetworkInfo();

    NetworkInfo getProvisioningOrActiveNetworkInfo();

    boolean isNetworkSupported(int networkType);

    LinkProperties getActiveLinkProperties();
@@ -135,9 +137,11 @@ interface IConnectivityManager

    int findConnectionTypeForIface(in String iface);

    int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver);
    int checkMobileProvisioning(int suggestedTimeOutMs);

    String getMobileProvisioningUrl();

    String getMobileRedirectedProvisioningUrl();

    void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url);
}
+74 −26
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class MobileDataStateTracker implements NetworkStateTracker {

    private static final String TAG = "MobileDataStateTracker";
    private static final boolean DBG = false;
    private static final boolean DBG = true;
    private static final boolean VDBG = false;

    private PhoneConstants.DataState mMobileDataState;
@@ -104,6 +104,7 @@ public class MobileDataStateTracker implements NetworkStateTracker {

        IntentFilter filter = new IntentFilter();
        filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
        filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN);
        filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);

        mContext.registerReceiver(new MobileDataStateReceiver(), filter);
@@ -171,20 +172,49 @@ public class MobileDataStateTracker implements NetworkStateTracker {
    public void releaseWakeLock() {
    }

    private void updateLinkProperitesAndCapatilities(Intent intent) {
        mLinkProperties = intent.getParcelableExtra(
                PhoneConstants.DATA_LINK_PROPERTIES_KEY);
        if (mLinkProperties == null) {
            loge("CONNECTED event did not supply link properties.");
            mLinkProperties = new LinkProperties();
        }
        mLinkCapabilities = intent.getParcelableExtra(
                PhoneConstants.DATA_LINK_CAPABILITIES_KEY);
        if (mLinkCapabilities == null) {
            loge("CONNECTED event did not supply link capabilities.");
            mLinkCapabilities = new LinkCapabilities();
        }
    }

    private class MobileDataStateReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(TelephonyIntents.
                    ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
                    ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN)) {
                String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
                String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
                if (VDBG) {
                    log(String.format("Broadcast received: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED"
                        + "mApnType=%s %s received apnType=%s", mApnType,
                        TextUtils.equals(apnType, mApnType) ? "==" : "!=", apnType));
                if (!TextUtils.equals(mApnType, apnType)) {
                    return;
                }
                if (DBG) {
                    log("Broadcast received: " + intent.getAction() + " apnType=" + apnType
                            + " apnName=" + apnName);
                }

                // Make us in the connecting state until we make a new TYPE_MOBILE_PROVISIONING
                mMobileDataState = PhoneConstants.DataState.CONNECTING;
                updateLinkProperitesAndCapatilities(intent);
                setDetailedState(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, "", apnName);
            } else if (intent.getAction().equals(TelephonyIntents.
                    ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
                String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
                if (!TextUtils.equals(apnType, mApnType)) {
                    return;
                }
                if (DBG) {
                    log("Broadcast received: " + intent.getAction() + " apnType=" + apnType);
                }

                int oldSubtype = mNetworkInfo.getSubtype();
                int newSubType = TelephonyManager.getDefault().getNetworkType();
@@ -202,7 +232,7 @@ public class MobileDataStateTracker implements NetworkStateTracker {
                String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
                mNetworkInfo.setRoaming(intent.getBooleanExtra(
                        PhoneConstants.DATA_NETWORK_ROAMING_KEY, false));
                if (VDBG) {
                if (DBG) {
                    log(mApnType + " setting isAvailable to " +
                            intent.getBooleanExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY,false));
                }
@@ -236,18 +266,7 @@ public class MobileDataStateTracker implements NetworkStateTracker {
                            setDetailedState(DetailedState.SUSPENDED, reason, apnName);
                            break;
                        case CONNECTED:
                            mLinkProperties = intent.getParcelableExtra(
                                    PhoneConstants.DATA_LINK_PROPERTIES_KEY);
                            if (mLinkProperties == null) {
                                loge("CONNECTED event did not supply link properties.");
                                mLinkProperties = new LinkProperties();
                            }
                            mLinkCapabilities = intent.getParcelableExtra(
                                    PhoneConstants.DATA_LINK_CAPABILITIES_KEY);
                            if (mLinkCapabilities == null) {
                                loge("CONNECTED event did not supply link capabilities.");
                                mLinkCapabilities = new LinkCapabilities();
                            }
                            updateLinkProperitesAndCapatilities(intent);
                            setDetailedState(DetailedState.CONNECTED, reason, apnName);
                            break;
                    }
@@ -272,18 +291,13 @@ public class MobileDataStateTracker implements NetworkStateTracker {
                    equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) {
                String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
                if (!TextUtils.equals(apnType, mApnType)) {
                    if (DBG) {
                        log(String.format(
                                "Broadcast received: ACTION_ANY_DATA_CONNECTION_FAILED ignore, " +
                                "mApnType=%s != received apnType=%s", mApnType, apnType));
                    }
                    return;
                }
                String reason = intent.getStringExtra(PhoneConstants.FAILURE_REASON_KEY);
                String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
                if (DBG) {
                    log("Received " + intent.getAction() +
                                " broadcast" + reason == null ? "" : "(" + reason + ")");
                    log("Broadcast received: " + intent.getAction() +
                                " reason=" + reason == null ? "null" : reason);
                }
                setDetailedState(DetailedState.FAILED, reason, apnName);
            } else {
@@ -544,6 +558,40 @@ public class MobileDataStateTracker implements NetworkStateTracker {
        }
    }

    /**
     *  Inform DCT mobile provisioning has started, it ends when provisioning completes.
     */
    public void enableMobileProvisioning(String url) {
        if (DBG) log("enableMobileProvisioning(url=" + url + ")");
        final AsyncChannel channel = mDataConnectionTrackerAc;
        if (channel != null) {
            Message msg = Message.obtain();
            msg.what = DctConstants.CMD_ENABLE_MOBILE_PROVISIONING;
            msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, url));
            channel.sendMessage(msg);
        }
    }

    /**
     * Return if this network is the provisioning network. Valid only if connected.
     * @param met
     */
    public boolean isProvisioningNetwork() {
        boolean retVal;
        try {
            Message msg = Message.obtain();
            msg.what = DctConstants.CMD_IS_PROVISIONING_APN;
            msg.setData(Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType));
            Message result = mDataConnectionTrackerAc.sendMessageSynchronously(msg);
            retVal = result.arg1 == DctConstants.ENABLED;
        } catch (NullPointerException e) {
            loge("isProvisioningNetwork: X " + e);
            retVal = false;
        }
        if (DBG) log("isProvisioningNetwork: retVal=" + retVal);
        return retVal;
    }

    @Override
    public void addStackedLink(LinkProperties link) {
        mLinkProperties.addStackedLink(link);
+7 −0
Original line number Diff line number Diff line
@@ -84,6 +84,12 @@ public class NetworkInfo implements Parcelable {
        VERIFYING_POOR_LINK,
        /** Checking if network is a captive portal */
        CAPTIVE_PORTAL_CHECK,
        /**
         * Network is connected to provisioning network
         * TODO: Probably not needed when we add TYPE_PROVISIONING_NETWORK
         * @hide
         */
        CONNECTED_TO_PROVISIONING_NETWORK
    }

    /**
@@ -108,6 +114,7 @@ public class NetworkInfo implements Parcelable {
        stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED);
        stateMap.put(DetailedState.FAILED, State.DISCONNECTED);
        stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED);
        stateMap.put(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, State.CONNECTED);
    }

    private int mNetworkType;
Loading