diff options
Diffstat (limited to 'services/java/com/android/server/ConnectivityService.java')
-rw-r--r-- | services/java/com/android/server/ConnectivityService.java | 741 |
1 files changed, 741 insertions, 0 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java new file mode 100644 index 0000000..760988d --- /dev/null +++ b/services/java/com/android/server/ConnectivityService.java @@ -0,0 +1,741 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.app.Notification; +import android.app.NotificationManager; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.IConnectivityManager; +import android.net.MobileDataStateTracker; +import android.net.NetworkInfo; +import android.net.NetworkStateTracker; +import android.net.wifi.WifiStateTracker; +import android.os.Binder; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.ServiceManager; +import android.os.SystemProperties; +import android.provider.Settings; +import android.provider.Sync; +import android.util.EventLog; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** + * @hide + */ +public class ConnectivityService extends IConnectivityManager.Stub { + + private static final boolean DBG = false; + private static final String TAG = "ConnectivityService"; + + // Event log tags (must be in sync with event-log-tags) + private static final int EVENTLOG_CONNECTIVITY_STATE_CHANGED = 50020; + + /** + * Sometimes we want to refer to the individual network state + * trackers separately, and sometimes we just want to treat them + * abstractly. + */ + private NetworkStateTracker mNetTrackers[]; + private WifiStateTracker mWifiStateTracker; + private MobileDataStateTracker mMobileDataStateTracker; + private WifiWatchdogService mWifiWatchdogService; + + private Context mContext; + private int mNetworkPreference; + private NetworkStateTracker mActiveNetwork; + + private int mNumDnsEntries; + private static int sDnsChangeCounter; + + private boolean mTestMode; + private static ConnectivityService sServiceInstance; + + private static class ConnectivityThread extends Thread { + private Context mContext; + + private ConnectivityThread(Context context) { + super("ConnectivityThread"); + mContext = context; + } + + @Override + public void run() { + Looper.prepare(); + synchronized (this) { + sServiceInstance = new ConnectivityService(mContext); + notifyAll(); + } + Looper.loop(); + } + + public static ConnectivityService getServiceInstance(Context context) { + ConnectivityThread thread = new ConnectivityThread(context); + thread.start(); + + synchronized (thread) { + while (sServiceInstance == null) { + try { + // Wait until sServiceInstance has been initialized. + thread.wait(); + } catch (InterruptedException ignore) { + Log.e(TAG, + "Unexpected InterruptedException while waiting for ConnectivityService thread"); + } + } + } + + return sServiceInstance; + } + } + + public static ConnectivityService getInstance(Context context) { + return ConnectivityThread.getServiceInstance(context); + } + + private ConnectivityService(Context context) { + if (DBG) Log.v(TAG, "ConnectivityService starting up"); + mContext = context; + mNetTrackers = new NetworkStateTracker[2]; + Handler handler = new MyHandler(); + + mNetworkPreference = getPersistedNetworkPreference(); + + /* + * Create the network state trackers for Wi-Fi and mobile + * data. Maybe this could be done with a factory class, + * but it's not clear that it's worth it, given that + * the number of different network types is not going + * to change very often. + */ + if (DBG) Log.v(TAG, "Starting Wifi Service."); + mWifiStateTracker = new WifiStateTracker(context, handler); + WifiService wifiService = new WifiService(context, mWifiStateTracker); + ServiceManager.addService(Context.WIFI_SERVICE, wifiService); + mNetTrackers[ConnectivityManager.TYPE_WIFI] = mWifiStateTracker; + + mMobileDataStateTracker = new MobileDataStateTracker(context, handler); + mNetTrackers[ConnectivityManager.TYPE_MOBILE] = mMobileDataStateTracker; + + mActiveNetwork = null; + mNumDnsEntries = 0; + + mTestMode = SystemProperties.get("cm.test.mode").equals("true") + && SystemProperties.get("ro.build.type").equals("eng"); + + for (NetworkStateTracker t : mNetTrackers) + t.startMonitoring(); + + // Constructing this starts it too + mWifiWatchdogService = new WifiWatchdogService(context, mWifiStateTracker); + } + + /** + * Sets the preferred network. + * @param preference the new preference + */ + public synchronized void setNetworkPreference(int preference) { + enforceChangePermission(); + if (ConnectivityManager.isNetworkTypeValid(preference)) { + if (mNetworkPreference != preference) { + persistNetworkPreference(preference); + mNetworkPreference = preference; + enforcePreference(); + } + } + } + + public int getNetworkPreference() { + enforceAccessPermission(); + return mNetworkPreference; + } + + private void persistNetworkPreference(int networkPreference) { + final ContentResolver cr = mContext.getContentResolver(); + Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, networkPreference); + } + + private int getPersistedNetworkPreference() { + final ContentResolver cr = mContext.getContentResolver(); + + final int networkPrefSetting = Settings.Secure + .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1); + if (networkPrefSetting != -1) { + return networkPrefSetting; + } + + return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE; + } + + /** + * Make the state of network connectivity conform to the preference settings. + * In this method, we only tear down a non-preferred network. Establishing + * a connection to the preferred network is taken care of when we handle + * the disconnect event from the non-preferred network + * (see {@link #handleDisconnect(NetworkInfo)}). + */ + private void enforcePreference() { + if (mActiveNetwork == null) + return; + + for (NetworkStateTracker t : mNetTrackers) { + if (t == mActiveNetwork) { + int netType = t.getNetworkInfo().getType(); + int otherNetType = ((netType == ConnectivityManager.TYPE_WIFI) ? + ConnectivityManager.TYPE_MOBILE : + ConnectivityManager.TYPE_WIFI); + + if (t.getNetworkInfo().getType() != mNetworkPreference) { + NetworkStateTracker otherTracker = mNetTrackers[otherNetType]; + if (otherTracker.isAvailable()) { + teardown(t); + } + } + } + } + } + + private boolean teardown(NetworkStateTracker netTracker) { + if (netTracker.teardown()) { + netTracker.setTeardownRequested(true); + return true; + } else { + return false; + } + } + + /** + * Return NetworkInfo for the active (i.e., connected) network interface. + * It is assumed that at most one network is active at a time. If more + * than one is active, it is indeterminate which will be returned. + * @return the info for the active network, or {@code null} if none is active + */ + public NetworkInfo getActiveNetworkInfo() { + enforceAccessPermission(); + for (NetworkStateTracker t : mNetTrackers) { + NetworkInfo info = t.getNetworkInfo(); + if (info.isConnected()) { + return info; + } + } + return null; + } + + public NetworkInfo getNetworkInfo(int networkType) { + enforceAccessPermission(); + if (ConnectivityManager.isNetworkTypeValid(networkType)) { + NetworkStateTracker t = mNetTrackers[networkType]; + if (t != null) + return t.getNetworkInfo(); + } + return null; + } + + public NetworkInfo[] getAllNetworkInfo() { + enforceAccessPermission(); + NetworkInfo[] result = new NetworkInfo[mNetTrackers.length]; + int i = 0; + for (NetworkStateTracker t : mNetTrackers) { + result[i++] = t.getNetworkInfo(); + } + return result; + } + + public boolean setRadios(boolean turnOn) { + boolean result = true; + enforceChangePermission(); + for (NetworkStateTracker t : mNetTrackers) { + result = t.setRadio(turnOn) && result; + } + return result; + } + + public boolean setRadio(int netType, boolean turnOn) { + enforceChangePermission(); + if (!ConnectivityManager.isNetworkTypeValid(netType)) { + return false; + } + NetworkStateTracker tracker = mNetTrackers[netType]; + return tracker != null && tracker.setRadio(turnOn); + } + + public int startUsingNetworkFeature(int networkType, String feature) { + enforceChangePermission(); + if (!ConnectivityManager.isNetworkTypeValid(networkType)) { + return -1; + } + NetworkStateTracker tracker = mNetTrackers[networkType]; + if (tracker != null) { + return tracker.startUsingNetworkFeature(feature, getCallingPid(), getCallingUid()); + } + return -1; + } + + public int stopUsingNetworkFeature(int networkType, String feature) { + enforceChangePermission(); + if (!ConnectivityManager.isNetworkTypeValid(networkType)) { + return -1; + } + NetworkStateTracker tracker = mNetTrackers[networkType]; + if (tracker != null) { + return tracker.stopUsingNetworkFeature(feature, getCallingPid(), getCallingUid()); + } + return -1; + } + + /** + * Ensure that a network route exists to deliver traffic to the specified + * host via the specified network interface. + * @param networkType the type of the network over which traffic to the specified + * host is to be routed + * @param hostAddress the IP address of the host to which the route is desired + * @return {@code true} on success, {@code false} on failure + */ + public boolean requestRouteToHost(int networkType, int hostAddress) { + enforceChangePermission(); + if (!ConnectivityManager.isNetworkTypeValid(networkType)) { + return false; + } + NetworkStateTracker tracker = mNetTrackers[networkType]; + /* + * If there's only one connected network, and it's the one requested, + * then we don't have to do anything - the requested route already + * exists. If it's not the requested network, then it's not possible + * to establish the requested route. Finally, if there is more than + * one connected network, then we must insert an entry in the routing + * table. + */ + if (getNumConnectedNetworks() > 1) { + return tracker.requestRouteToHost(hostAddress); + } else { + return tracker.getNetworkInfo().getType() == networkType; + } + } + + /** + * @see ConnectivityManager#getBackgroundDataSetting() + */ + public boolean getBackgroundDataSetting() { + return Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.BACKGROUND_DATA, 1) == 1; + } + + /** + * @see ConnectivityManager#setBackgroundDataSetting(boolean) + */ + public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING, + "ConnectivityService"); + + if (getBackgroundDataSetting() == allowBackgroundDataUsage) return; + + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.BACKGROUND_DATA, allowBackgroundDataUsage ? 1 : 0); + + Intent broadcast = new Intent( + ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); + mContext.sendBroadcast(broadcast); + } + + private int getNumConnectedNetworks() { + int numConnectedNets = 0; + + for (NetworkStateTracker nt : mNetTrackers) { + if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { + ++numConnectedNets; + } + } + return numConnectedNets; + } + + private void enforceAccessPermission() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE, + "ConnectivityService"); + } + + private void enforceChangePermission() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE, + "ConnectivityService"); + + } + + /** + * Handle a {@code DISCONNECTED} event. If this pertains to the non-active network, + * we ignore it. If it is for the active network, we send out a broadcast. + * But first, we check whether it might be possible to connect to a different + * network. + * @param info the {@code NetworkInfo} for the network + */ + private void handleDisconnect(NetworkInfo info) { + + if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName()); + + mNetTrackers[info.getType()].setTeardownRequested(false); + /* + * If the disconnected network is not the active one, then don't report + * this as a loss of connectivity. What probably happened is that we're + * getting the disconnect for a network that we explicitly disabled + * in accordance with network preference policies. + */ + if (mActiveNetwork == null || info.getType() != mActiveNetwork.getNetworkInfo().getType()) + return; + + NetworkStateTracker newNet; + if (info.getType() == ConnectivityManager.TYPE_MOBILE) { + newNet = mWifiStateTracker; + } else /* info().getType() == TYPE_WIFI */ { + newNet = mMobileDataStateTracker; + } + + /** + * See if the other network is available to fail over to. + * If is not available, we enable it anyway, so that it + * will be able to connect when it does become available, + * but we report a total loss of connectivity rather than + * report that we are attempting to fail over. + */ + NetworkInfo switchTo = null; + if (newNet.isAvailable()) { + mActiveNetwork = newNet; + switchTo = newNet.getNetworkInfo(); + switchTo.setFailover(true); + if (!switchTo.isConnectedOrConnecting()) { + newNet.reconnect(); + } + } else { + newNet.reconnect(); + } + + boolean otherNetworkConnected = false; + Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); + if (info.isFailover()) { + intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); + info.setFailover(false); + } + if (info.getReason() != null) { + intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); + } + if (info.getExtraInfo() != null) { + intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); + } + if (switchTo != null) { + otherNetworkConnected = switchTo.isConnected(); + if (DBG) { + if (otherNetworkConnected) { + Log.v(TAG, "Switching to already connected " + switchTo.getTypeName()); + } else { + Log.v(TAG, "Attempting to switch to " + switchTo.getTypeName()); + } + } + intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); + } else { + intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); + } + if (DBG) Log.v(TAG, "Sending DISCONNECT bcast for " + info.getTypeName() + + (switchTo == null ? "" : " other=" + switchTo.getTypeName())); + + mContext.sendStickyBroadcast(intent); + /* + * If the failover network is already connected, then immediately send out + * a followup broadcast indicating successful failover + */ + if (switchTo != null && otherNetworkConnected) + sendConnectedBroadcast(switchTo); + } + + private void sendConnectedBroadcast(NetworkInfo info) { + Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); + if (info.isFailover()) { + intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); + info.setFailover(false); + } + if (info.getReason() != null) { + intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); + } + if (info.getExtraInfo() != null) { + intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); + } + mContext.sendStickyBroadcast(intent); + } + + /** + * Called when an attempt to fail over to another network has failed. + * @param info the {@link NetworkInfo} for the failed network + */ + private void handleConnectionFailure(NetworkInfo info) { + mNetTrackers[info.getType()].setTeardownRequested(false); + if (getActiveNetworkInfo() == null) { + String reason = info.getReason(); + String extraInfo = info.getExtraInfo(); + + if (DBG) { + String reasonText; + if (reason == null) { + reasonText = "."; + } else { + reasonText = " (" + reason + ")."; + } + Log.v(TAG, "Attempt to connect to " + info.getTypeName() + " failed" + reasonText); + } + + Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); + intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); + if (reason != null) { + intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); + } + if (extraInfo != null) { + intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); + } + if (info.isFailover()) { + intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); + info.setFailover(false); + } + mContext.sendStickyBroadcast(intent); + } + } + + private void handleConnect(NetworkInfo info) { + if (DBG) Log.v(TAG, "Handle CONNECT for " + info.getTypeName()); + + // snapshot isFailover, because sendConnectedBroadcast() resets it + boolean isFailover = info.isFailover(); + NetworkStateTracker thisNet = mNetTrackers[info.getType()]; + NetworkStateTracker deadnet = null; + NetworkStateTracker otherNet; + if (info.getType() == ConnectivityManager.TYPE_MOBILE) { + otherNet = mWifiStateTracker; + } else /* info().getType() == TYPE_WIFI */ { + otherNet = mMobileDataStateTracker; + } + /* + * Check policy to see whether we are connected to a non-preferred + * network that now needs to be torn down. + */ + NetworkInfo wifiInfo = mWifiStateTracker.getNetworkInfo(); + NetworkInfo mobileInfo = mMobileDataStateTracker.getNetworkInfo(); + if (wifiInfo.isConnected() && mobileInfo.isConnected()) { + if (mNetworkPreference == ConnectivityManager.TYPE_WIFI) + deadnet = mMobileDataStateTracker; + else + deadnet = mWifiStateTracker; + } + + boolean toredown = false; + thisNet.setTeardownRequested(false); + if (!mTestMode && deadnet != null) { + if (DBG) Log.v(TAG, "Policy requires " + + deadnet.getNetworkInfo().getTypeName() + " teardown"); + toredown = teardown(deadnet); + if (DBG && !toredown) { + Log.d(TAG, "Network declined teardown request"); + } + } + + /* + * Note that if toredown is true, deadnet cannot be null, so there is + * no danger of a null pointer exception here.. + */ + if (!toredown || deadnet.getNetworkInfo().getType() != info.getType()) { + mActiveNetwork = thisNet; + if (DBG) Log.v(TAG, "Sending CONNECT bcast for " + info.getTypeName()); + thisNet.updateNetworkSettings(); + sendConnectedBroadcast(info); + if (isFailover) { + otherNet.releaseWakeLock(); + } + } else { + if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION to torn down network " + + info.getTypeName()); + } + } + + private void handleScanResultsAvailable(NetworkInfo info) { + int networkType = info.getType(); + if (networkType != ConnectivityManager.TYPE_WIFI) { + if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " + info.getTypeName() + " network." + + " Don't know how to handle."); + } + + mNetTrackers[networkType].interpretScanResultsAvailable(); + } + + private void handleNotificationChange(boolean visible, int id, Notification notification) { + NotificationManager notificationManager = (NotificationManager) mContext + .getSystemService(Context.NOTIFICATION_SERVICE); + + if (visible) { + notificationManager.notify(id, notification); + } else { + notificationManager.cancel(id); + } + } + + /** + * After any kind of change in the connectivity state of any network, + * make sure that anything that depends on the connectivity state of + * more than one network is set up correctly. We're mainly concerned + * with making sure that the list of DNS servers is set up according + * to which networks are connected, and ensuring that the right routing + * table entries exist. + */ + private void handleConnectivityChange() { + /* + * If both mobile and wifi are enabled, add the host routes that + * will allow MMS traffic to pass on the mobile network. But + * remove the default route for the mobile network, so that there + * will be only one default route, to ensure that all traffic + * except MMS will travel via Wi-Fi. + */ + int numConnectedNets = handleConfigurationChange(); + if (numConnectedNets > 1) { + mMobileDataStateTracker.addPrivateRoutes(); + mMobileDataStateTracker.removeDefaultRoute(); + } else if (mMobileDataStateTracker.getNetworkInfo().isConnected()) { + mMobileDataStateTracker.removePrivateRoutes(); + mMobileDataStateTracker.restoreDefaultRoute(); + } + } + + private int handleConfigurationChange() { + /* + * Set DNS properties. Always put Wi-Fi entries at the front of + * the list if it is active. + */ + int index = 1; + String lastDns = ""; + int numConnectedNets = 0; + int incrValue = ConnectivityManager.TYPE_MOBILE - ConnectivityManager.TYPE_WIFI; + int stopValue = ConnectivityManager.TYPE_MOBILE + incrValue; + + for (int netType = ConnectivityManager.TYPE_WIFI; netType != stopValue; netType += incrValue) { + NetworkStateTracker nt = mNetTrackers[netType]; + if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { + ++numConnectedNets; + String[] dnsList = nt.getNameServers(); + for (int i = 0; i < dnsList.length && dnsList[i] != null; i++) { + // skip duplicate entries + if (!dnsList[i].equals(lastDns)) { + SystemProperties.set("net.dns" + index++, dnsList[i]); + lastDns = dnsList[i]; + } + } + } + } + // Null out any DNS properties that are no longer used + for (int i = index; i <= mNumDnsEntries; i++) { + SystemProperties.set("net.dns" + i, ""); + } + mNumDnsEntries = index - 1; + // Notify the name resolver library of the change + SystemProperties.set("net.dnschange", String.valueOf(sDnsChangeCounter++)); + return numConnectedNets; + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump ConnectivityService from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + if (mActiveNetwork == null) { + pw.println("No active network"); + } else { + pw.println("Active network: " + mActiveNetwork.getNetworkInfo().getTypeName()); + } + pw.println(); + for (NetworkStateTracker nst : mNetTrackers) { + pw.println(nst.getNetworkInfo()); + pw.println(nst); + pw.println(); + } + } + + private class MyHandler extends Handler { + @Override + public void handleMessage(Message msg) { + NetworkInfo info; + switch (msg.what) { + case NetworkStateTracker.EVENT_STATE_CHANGED: + info = (NetworkInfo) msg.obj; + if (DBG) Log.v(TAG, "ConnectivityChange for " + info.getTypeName() + ": " + + info.getState() + "/" + info.getDetailedState()); + + // Connectivity state changed: + // [31-13] Reserved for future use + // [12-9] Network subtype (for mobile network, as defined by TelephonyManager) + // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState) + // [2-0] Network type (as defined by ConnectivityManager) + int eventLogParam = (info.getType() & 0x7) | + ((info.getDetailedState().ordinal() & 0x3f) << 3) | + (info.getSubtype() << 9); + EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED, eventLogParam); + + if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) { + handleConnectionFailure(info); + } else if (info.getState() == NetworkInfo.State.DISCONNECTED) { + handleDisconnect(info); + } else if (info.getState() == NetworkInfo.State.SUSPENDED) { + // TODO: need to think this over. + // the logic here is, handle SUSPENDED the same as DISCONNECTED. The + // only difference being we are broadcasting an intent with NetworkInfo + // that's suspended. This allows the applications an opportunity to + // handle DISCONNECTED and SUSPENDED differently, or not. + handleDisconnect(info); + } else if (info.getState() == NetworkInfo.State.CONNECTED) { + handleConnect(info); + } + handleConnectivityChange(); + break; + + case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE: + info = (NetworkInfo) msg.obj; + handleScanResultsAvailable(info); + break; + + case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED: + handleNotificationChange(msg.arg1 == 1, msg.arg2, (Notification) msg.obj); + + case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: + handleConfigurationChange(); + break; + + case NetworkStateTracker.EVENT_ROAMING_CHANGED: + // fill me in + break; + + case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: + // fill me in + break; + } + } + } +} |