org.deviceconnect.android.message.DevicePluginContext.java Source code

Java tutorial

Introduction

Here is the source code for org.deviceconnect.android.message.DevicePluginContext.java

Source

/*
 DevicePluginContext.java
 Copyright (c) 2018 NTT DOCOMO,INC.
 Released under the MIT license
 http://opensource.org/licenses/mit-license.php
 */
package org.deviceconnect.android.message;

import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;

import org.deviceconnect.android.BuildConfig;
import org.deviceconnect.android.IDConnectCallback;
import org.deviceconnect.android.event.Event;
import org.deviceconnect.android.event.EventManager;
import org.deviceconnect.android.event.cache.EventCacheController;
import org.deviceconnect.android.event.cache.MemoryCacheController;
import org.deviceconnect.android.localoauth.CheckAccessTokenResult;
import org.deviceconnect.android.localoauth.DevicePluginXmlProfile;
import org.deviceconnect.android.localoauth.DevicePluginXmlUtil;
import org.deviceconnect.android.localoauth.LocalOAuth2Main;
import org.deviceconnect.android.profile.AuthorizationProfile;
import org.deviceconnect.android.profile.DConnectProfile;
import org.deviceconnect.android.profile.DConnectProfileProvider;
import org.deviceconnect.android.profile.ServiceDiscoveryProfile;
import org.deviceconnect.android.profile.SystemProfile;
import org.deviceconnect.android.profile.spec.DConnectPluginSpec;
import org.deviceconnect.android.service.DConnectService;
import org.deviceconnect.android.service.DConnectServiceManager;
import org.deviceconnect.android.service.DConnectServiceProvider;
import org.deviceconnect.android.ssl.EndPointKeyStoreManager;
import org.deviceconnect.android.ssl.KeyStoreCallback;
import org.deviceconnect.android.ssl.KeyStoreError;
import org.deviceconnect.android.ssl.KeyStoreManager;
import org.deviceconnect.message.DConnectMessage;
import org.deviceconnect.message.intent.message.IntentDConnectMessage;
import org.deviceconnect.profile.AuthorizationProfileConstants;
import org.deviceconnect.profile.AvailabilityProfileConstants;
import org.deviceconnect.profile.ServiceDiscoveryProfileConstants;
import org.deviceconnect.profile.SystemProfileConstants;

import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Logger;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

/**
 * ???.
 *
 * @author NTT DOCOMO, INC.
 */
public abstract class DevicePluginContext implements DConnectProfileProvider, DConnectProfile.Responder {
    /**
     * .
     */
    private Logger mLogger = Logger.getLogger("org.deviceconnect.dplugin");

    /**
     * LocalOAuth??.
     */
    private static final String[] IGNORE_PROFILES = { AuthorizationProfileConstants.PROFILE_NAME.toLowerCase(),
            SystemProfileConstants.PROFILE_NAME.toLowerCase(),
            ServiceDiscoveryProfileConstants.PROFILE_NAME.toLowerCase() };

    /**
     * .
     */
    private Context mContext;

    /**
     * .
     */
    private Map<String, DConnectProfile> mProfileMap = new HashMap<>();

    /**
     * Device Connect Manager ????.
     */
    private IDConnectCallback mIDConnectCallback;

    /**
     * ??.
     */
    private DConnectServiceManager mServiceProvider;

    /**
     * ???.
     */
    private DConnectPluginSpec mPluginSpec;

    /**
     * ??(Local OAuth).
     */
    private LocalOAuth2Main mLocalOAuth2Main;

    /**
     * Wi-Fi?????????.
     * <p>
     * IP ????????????????
     * </p>
     */
    private BroadcastReceiver mWiFiBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            // 
            requestAndNotifyKeyStore();
        }
    };

    /**
     * ??.
     */
    private KeyStoreManager mKeyStoreMgr;

    /**
     * Local OAuth.
     * <p>
     * ?? true ????????
     * </p>
     */
    private boolean mUseLocalOAuth = true;

    /**
     * ?.
     */
    private boolean mIsEnabled;

    /**
     * .
     * @param context 
     */
    public DevicePluginContext(final Context context) {
        if (context == null) {
            throw new IllegalArgumentException("context is null.");
        }
        mContext = context;

        // ???
        EventManager.INSTANCE.setController(createEventCacheController());

        // LocalOAuth??
        mLocalOAuth2Main = new LocalOAuth2Main(context);

        try {
            // SPEC??
            mPluginSpec = DConnectProfileHelper.loadPluginSpec(context, createSupportedProfiles());
        } catch (Exception e) {
            if (BuildConfig.DEBUG) {
                mLogger.warning("Failed to load a profile spec.");
            }
        }

        // ???
        mKeyStoreMgr = new EndPointKeyStoreManager(context, getKeyStoreFileName(), getCertificateAlias());
        if (usesAutoCertificateRequest()) {
            requestAndNotifyKeyStore();
            IntentFilter filter = new IntentFilter();
            filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
            context.registerReceiver(mWiFiBroadcastReceiver, filter);
        }

        // ?
        mServiceProvider = new DConnectServiceManager();
        mServiceProvider.setContext(context);
        mServiceProvider.setPluginContext(this);
        mServiceProvider.setPluginSpec(mPluginSpec);

        // 
        addProfile(new AuthorizationProfile(this, mLocalOAuth2Main));
        addProfile(new ServiceDiscoveryProfile(mServiceProvider));
        addProfile(getSystemProfile());
    }

    /**
     * ????.
     * <p>
     * ??????????<br>
     * ???????????<br>
     * </p>
     * <p>
     * ??????????super.release(); ????
     * </p>
     */
    public void release() {
        if (mLocalOAuth2Main != null) {
            mLocalOAuth2Main.destroy();
            mLocalOAuth2Main = null;
        }
        if (usesAutoCertificateRequest()) {
            mContext.unregisterReceiver(mWiFiBroadcastReceiver);
        }

    }

    /**
     * ????.
     * @return 
     */
    public Context getContext() {
        return mContext;
    }

    /**
     * ????.
     *
     * @return ?
     */
    public DConnectServiceProvider getServiceProvider() {
        return mServiceProvider;
    }

    /**
     * ??????????.
     *
     * @return ?
     */
    public DConnectPluginSpec getPluginSpec() {
        return mPluginSpec;
    }

    /**
     * Device Connect Manager ?????????.
     *
     * @param callback ?
     */
    public void setIDConnectCallback(final IDConnectCallback callback) {
        mIDConnectCallback = callback;
    }

    /**
     * LocalOAuth?????.
     * @return LocalOAuth
     */
    public LocalOAuth2Main getLocalOAuth2Main() {
        return mLocalOAuth2Main;
    }

    /**
     * ??????.
     *
     * @return ??
     */
    private Map<String, DevicePluginXmlProfile> createSupportedProfiles() {
        return DevicePluginXmlUtil.getSupportProfiles(getContext(), getPluginXmlResId());
    }

    /**
     * ?????xml??ID????.
     *
     * @return ??
     */
    protected int getPluginXmlResId() {
        return DevicePluginXmlUtil.getPluginXmlResourceId(getContext(), getContext().getPackageName());
    }

    /**
     * SystemProfile??.
     * <p>
     * SystemProfile???????SystemProfile????<br>
     * ??????SystemProfile???
     * </p>
     * @return SystemProfile?
     */
    protected abstract SystemProfile getSystemProfile();

    /**
     * ??????.
     *
     * @param message ???????Intent
     */
    public void handleMessage(final Intent message) {
        String action = message.getAction();
        try {
            if (checkRequestAction(action)) {
                // Device Connect ????????????
                MessageConverterHelper.convert(message);
                onRequest(message, MessageUtils.createResponseIntent(message));
            } else if (checkManagerUninstall(message)) {
                onManagerUninstalled();
            } else if (checkManagerLaunched(action)) {
                onManagerLaunched();
            } else if (checkManagerTerminated(action)) {
                onManagerTerminated();
            } else if (checkManagerEventTransmitDisconnect(action)) {
                onManagerEventTransmitDisconnected(message.getStringExtra(IntentDConnectMessage.EXTRA_ORIGIN));
            } else if (checkDevicePluginReset(action)) {
                onDevicePluginReset();
            } else if (checkDevicePluginEnabled(action)) {
                mIsEnabled = true;
                onDevicePluginEnabled();
            } else if (checkDevicePluginDisabled(action)) {
                mIsEnabled = false;
                onDevicePluginDisabled();
            } else {
                if (BuildConfig.DEBUG) {
                    mLogger.warning("action is unknown type. " + action);
                }
            }
        } catch (Exception e) {
            if (BuildConfig.DEBUG) {
                e.printStackTrace();
                mLogger.severe("DevicePluginContext#handleMessage : error=" + e.getMessage());
            }
        }
    }

    /**
     * EventCacheController??.
     *
     * <p>
     * ??MemoryCacheController?.<br>
     * ?????????.
     * </p>
     *
     * @return EventCacheController?
     */
    protected EventCacheController getEventCacheController() {
        return new MemoryCacheController();
    }

    /**
     * EventCacheController?????.
     * <p>
     * ???MemoryCacheController????
     * </p>
     * @return EventCacheController?
     */
    private EventCacheController createEventCacheController() {
        EventCacheController ctrl = getEventCacheController();
        if (ctrl == null) {
            ctrl = new MemoryCacheController();
        }
        return ctrl;
    }

    /**
     * Device Connect Manager??????????????.
     * @return ???????<code>true</code>, ????????<code>false</code>
     */
    protected boolean isEnabled() {
        return mIsEnabled;
    }

    /**
     * Local OAuth?.
     * <p>
     * ??false??????LocalOAuth?OFF????????<br>
     * ???true????????LocalOAuth??????
     * </p>
     * @param use 
     */
    public void setUseLocalOAuth(final boolean use) {
        mUseLocalOAuth = use;
    }

    /**
     * Local OAuth??.
     *
     * @return ????true????false
     */
    public boolean isUseLocalOAuth() {
        return mUseLocalOAuth;
    }

    /**
     * LocalOAuth??.
     * ?????????????????.
     *
     * @return LocalOAuth??
     */
    public String[] getIgnoredProfiles() {
        return IGNORE_PROFILES;
    }

    /**
     * ???Local OAuth???????.
     *
     * @param profileName ??
     * @return ?????true????false
     */
    public boolean isIgnoredProfile(final String profileName) {
        for (String name : getIgnoredProfiles()) {
            if (name.equalsIgnoreCase(profileName)) { // MEMO ??
                return true;
            }
        }
        return false;
    }

    /// DConnectProfile#Responder Method

    /**
     * Device Connect Manager???????.
     *
     * @param response ?
     * @return ????true????false
     */
    @Override
    public boolean sendResponse(final Intent response) {
        if (response == null) {
            throw new IllegalArgumentException("response is null.");
        }

        // TODO ?????????

        if (BuildConfig.DEBUG) {
            mLogger.info("sendResponse: " + response);
            mLogger.info("sendResponse Extra: " + response.getExtras());
        }

        return sendMessage(response);
    }

    /**
     * Device Connect???.
     *
     * @param event 
     * @param accessToken ??
     * @return ????true????false?
     */
    @Override
    public boolean sendEvent(final Intent event, final String accessToken) {
        // TODO ????????
        if (event == null) {
            throw new IllegalArgumentException("Event is null.");
        }

        if (isUseLocalOAuth()) {
            CheckAccessTokenResult result = mLocalOAuth2Main.checkAccessToken(accessToken,
                    event.getStringExtra(DConnectMessage.EXTRA_PROFILE), getIgnoredProfiles());
            if (!result.checkResult()) {
                return false;
            }
        }

        if (BuildConfig.DEBUG) {
            mLogger.info("sendEvent: " + event);
            mLogger.info("sendEvent Extra: " + event.getExtras());
        }

        return sendMessage(event);
    }

    /**
     * Device Connect???.
     *
     * @param event 
     * @param bundle 
     * @return ????true????false?
     */
    @Override
    public boolean sendEvent(final Event event, final Bundle bundle) {
        Intent intent = EventManager.createEventMessage(event);
        Bundle original = intent.getExtras();
        if (original != null) {
            original.putAll(bundle);
            intent.putExtras(original);
        }
        return sendEvent(intent, event.getAccessToken());
    }

    /// DConnectProfileProvider Method

    @Override
    public List<DConnectProfile> getProfileList() {
        return new ArrayList<>(mProfileMap.values());
    }

    @Override
    public DConnectProfile getProfile(final String name) {
        // XXXX ??
        return name == null ? null : mProfileMap.get(name.toLowerCase());
    }

    @Override
    public void addProfile(final DConnectProfile profile) {
        if (profile != null) {
            profile.setContext(mContext);
            profile.setPluginContext(this);
            profile.setResponder(this);
            // XXXX ??
            mProfileMap.put(profile.getProfileName().toLowerCase(), profile);
        }
    }

    @Override
    public void removeProfile(final DConnectProfile profile) {
        if (profile != null) {
            // XXXX ??
            mProfileMap.remove(profile.getProfileName().toLowerCase());
        }
    }

    /**
     * ??????.
     *
     * @param request 
     * @param response ?
     */
    protected void onRequest(final Intent request, final Intent response) {
        if (BuildConfig.DEBUG) {
            mLogger.info("request: " + request);
            mLogger.info("request extras: " + request.getExtras());
        }

        // ????
        String profileName = request.getStringExtra(DConnectMessage.EXTRA_PROFILE);
        if (profileName == null) {
            MessageUtils.setNotSupportProfileError(response);
            sendResponse(response);
            return;
        }

        boolean send = true;
        if (isUseLocalOAuth()) {
            String accessToken = request.getStringExtra(AuthorizationProfile.PARAM_ACCESS_TOKEN);
            CheckAccessTokenResult result = mLocalOAuth2Main.checkAccessToken(accessToken,
                    profileName.toLowerCase(), getIgnoredProfiles());
            if (result.checkResult()) {
                send = executeRequest(profileName, request, response);
            } else {
                if (accessToken == null) {
                    MessageUtils.setEmptyAccessTokenError(response);
                } else if (!result.isExistAccessToken()) {
                    MessageUtils.setNotFoundClientId(response);
                } else if (!result.isExistClientId()) {
                    MessageUtils.setNotFoundClientId(response);
                } else if (!result.isExistScope()) {
                    MessageUtils.setScopeError(response);
                } else if (!result.isNotExpired()) {
                    MessageUtils.setExpiredAccessTokenError(response);
                } else {
                    MessageUtils.setAuthorizationError(response);
                }
            }
        } else {
            send = executeRequest(profileName, request, response);
        }

        if (send) {
            sendResponse(response);
        }
    }

    /**
     * ??????.
     * <p>
     * ????????????????????
     * </p>
     * @param profileName ??
     * @param request 
     * @param response ?
     * @return true?????????????????????
     */
    protected boolean executeRequest(final String profileName, final Intent request, final Intent response) {
        DConnectProfile profile = getProfile(profileName);
        if (profile == null) {
            String serviceId = DConnectProfile.getServiceID(request);
            DConnectService service = getServiceProvider().getService(serviceId);
            if (service != null) {
                return service.onRequest(request, response);
            } else {
                MessageUtils.setNotFoundServiceError(response);
                return true;
            }
        } else {
            return profile.onRequest(request, response);
        }
    }

    /**
     * Intent  Device Connect Manager ?????.
     *
     * @param intent ??Intent
     * @return ??????true????false
     */
    private boolean sendMessage(final Intent intent) {
        if (mIDConnectCallback == null) {
            if (BuildConfig.DEBUG) {
                mLogger.severe("sendMessage: IDConnectCallback is not set.");
            }
            return false;
        }

        try {
            mIDConnectCallback.sendMessage(intent);
        } catch (Exception e) {
            if (BuildConfig.DEBUG) {
                mLogger.severe("sendMessage: exception occurred.");
            }
            return false;
        }
        return true;
    }

    /**
     * ???Device Connect??????.
     * @param action ??
     * @return Device Connect????true????false
     */
    private boolean checkRequestAction(String action) {
        return IntentDConnectMessage.ACTION_GET.equals(action) || IntentDConnectMessage.ACTION_POST.equals(action)
                || IntentDConnectMessage.ACTION_PUT.equals(action)
                || IntentDConnectMessage.ACTION_DELETE.equals(action);
    }

    /**
     * Device Connect Manager????????.
     * @param intent intent
     * @return ?true????false
     */
    private boolean checkManagerUninstall(final Intent intent) {
        return Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(intent.getAction())
                && intent.getExtras().getBoolean(Intent.EXTRA_DATA_REMOVED)
                && intent.getDataString().contains("package:org.deviceconnect.android.manager");
    }

    /**
     * Device Connect Manager ????????.
     * @param action ??
     * @return Manager ?true????false
     */
    private boolean checkManagerLaunched(String action) {
        return IntentDConnectMessage.ACTION_MANAGER_LAUNCHED.equals(action);
    }

    /**
     * Device Connect Manager ????????.
     * @param action ??
     * @return Manager ?true????false
     */
    private boolean checkManagerTerminated(String action) {
        return IntentDConnectMessage.ACTION_MANAGER_TERMINATED.equals(action);
    }

    /**
     * Device Connect Manager ?Event ?????????.
     * @param action ??
     * @return ??true????false
     */
    private boolean checkManagerEventTransmitDisconnect(String action) {
        return IntentDConnectMessage.ACTION_EVENT_TRANSMIT_DISCONNECT.equals(action);
    }

    /**
     * Device Plug-in??Reset?????????.
     * @param action ??
     * @return Reset???true????false
     */
    private boolean checkDevicePluginReset(String action) {
        return IntentDConnectMessage.ACTION_DEVICEPLUGIN_RESET.equals(action);
    }

    /**
     * ????????.
     * @param action ??
     * @return ?true????false
     */
    private boolean checkDevicePluginEnabled(String action) {
        return IntentDConnectMessage.ACTION_DEVICEPLUGIN_ENABLED.equals(action);
    }

    /**
     * ????????.
     * @param action ??
     * @return ?true????false
     */
    private boolean checkDevicePluginDisabled(String action) {
        return IntentDConnectMessage.ACTION_DEVICEPLUGIN_DISABLED.equals(action);
    }

    /**
     * Device Connect Manager??????.
     * <p>
     * Device Connect Manager?????????????
     * ????????
     * </p>
     */
    protected void onManagerUninstalled() {
        if (BuildConfig.DEBUG) {
            mLogger.info("SDK : onManagerUninstalled");
        }
    }

    /**
     * Device Connect Manager???????.
     * <p>
     * Device Connect Manager???????????????????
     * </p>
     */
    protected void onManagerLaunched() {
        if (BuildConfig.DEBUG) {
            mLogger.info("SDK : onManagerLaunched");
        }
    }

    /**
     * Device Connect Manager???????.
     * <p>
     * Device Connect Manager???????????????????
     * </p>
     */
    protected void onManagerTerminated() {
        if (BuildConfig.DEBUG) {
            mLogger.info("SDK : onManagerTerminated");
        }
    }

    /**
     * Device Connect Manager?Event???????.
     * <p>
     * Device Connect Manager?WebSocket?????????????????
     * ??????????????
     * </p>
     * @param origin ?????
     */
    protected void onManagerEventTransmitDisconnected(final String origin) {
        if (BuildConfig.DEBUG) {
            mLogger.info("SDK : onManagerEventTransmitDisconnected: " + origin);
        }
    }

    /**
     * Device Plug-in??Reset???????.
     * <p>
     * Device Connect Manager??????????????
     * ???????????
     * </p>
     */
    protected void onDevicePluginReset() {
        if (BuildConfig.DEBUG) {
            mLogger.info("SDK : onDevicePluginReset");
        }
    }

    /**
     * Device Connect Manager???????.
     */
    protected void onDevicePluginEnabled() {
        if (BuildConfig.DEBUG) {
            mLogger.info("SDK : onEnabled");
        }
    }

    /**
     * Device Connect Manager???????.
     */
    protected void onDevicePluginDisabled() {
        if (BuildConfig.DEBUG) {
            mLogger.info("SDK : onDisabled");
        }
    }

    // ??????

    /**
     * ????????.
     * <p>
     * ???????????true????
     * </p>
     * @return ????true????false
     */
    protected boolean usesAutoCertificateRequest() {
        return false;
    }

    /**
     * ?????????.
     * <p>
     * ???keystore.p12 ???
     * </p>
     * <p>
     * ????????????????
     * </p>
     * @return ???
     */
    protected String getKeyStoreFileName() {
        return "keystore.p12";
    }

    /**
     * ????????.
     * <p>
     * ?????????
     * </p>
     * <p>
     * ???????????????
     * </p>
     * @return ??
     */
    protected String getCertificateAlias() {
        return getContext().getPackageName();
    }

    /**
     * ??????.
     *
     * @param ipAddress IP
     * @param callback ???
     */
    public void requestKeyStore(final String ipAddress, final KeyStoreCallback callback) {
        mKeyStoreMgr.requestKeyStore(ipAddress, callback);
    }

    /**
     * ??????.
     */
    private void requestAndNotifyKeyStore() {
        requestAndNotifyKeyStore(getCurrentIPAddress());
    }

    /**
     * ??????.
     *
     * @param ipAddress IP
     */
    private void requestAndNotifyKeyStore(final String ipAddress) {
        requestKeyStore(ipAddress, new KeyStoreCallback() {
            @Override
            public void onSuccess(final KeyStore keyStore, final Certificate cert, final Certificate rootCert) {
                onKeyStoreUpdated(keyStore, cert, rootCert);
            }

            @Override
            public void onError(final KeyStoreError error) {
                onKeyStoreUpdateError(error);
            }
        });
    }

    /**
     * ??IP????.
     *
     * @return IP
     */
    private String getCurrentIPAddress() {
        Context appContext = getContext().getApplicationContext();
        int state = ContextCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_WIFI_STATE);
        if (state != PackageManager.PERMISSION_GRANTED) {
            return null;
        }

        // TODO IPv6 ?????
        // TODO Wi-Fi ???????

        WifiManager wifiManager = (WifiManager) appContext.getSystemService(Context.WIFI_SERVICE);
        if (wifiManager != null) {
            int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
            return String.format(Locale.getDefault(), "%d.%d.%d.%d", (ipAddress & 0xff), (ipAddress >> 8 & 0xff),
                    (ipAddress >> 16 & 0xff), (ipAddress >> 24 & 0xff));
        }
        return null;
    }

    /**
     * ?????????.
     * <p>
     * ???????????????????
     * </p>
     * @param keyStore 
     * @param cert 
     * @param rootCert 
     */
    protected void onKeyStoreUpdated(final KeyStore keyStore, final Certificate cert, final Certificate rootCert) {
    }

    /**
     * ??????????.
     * <p>
     * ????????????????????
     * </p>
     * @param error 
     */
    protected void onKeyStoreUpdateError(final KeyStoreError error) {
    }

    /**
     * SSLContext ?????.
     * <p>
     * ? Web ?????Manager???????????SSLContext ???
     * </p>
     * @param keyStore 
     * @return SSLContext?
     * @throws GeneralSecurityException SSLContext???????
     */
    protected SSLContext createSSLContext(final KeyStore keyStore) throws GeneralSecurityException {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        KeyManagerFactory keyManagerFactory = KeyManagerFactory
                .getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(keyStore, "0000".toCharArray());
        TrustManagerFactory trustManagerFactory = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);
        sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(),
                new SecureRandom());
        return sslContext;
    }

    public void regsiterChangeIpAddress() {
        if (usesAutoCertificateRequest()) {
            IntentFilter filter = new IntentFilter();
            mContext.registerReceiver(mWiFiBroadcastReceiver, filter);
        }
    }

    public void unregsiterChangeIpAddress() {
        if (usesAutoCertificateRequest()) {
            try {
                mContext.unregisterReceiver(mWiFiBroadcastReceiver);
            } catch (Exception e) {
                // ignore.
            }
        }
    }
}