blob: 83d1bda82100f4b07986fd327962113726163fd0 [file] [log] [blame]
/*
* Copyright (C) 2010 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 android.bluetooth;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.DhcpInfoInternal;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkStateTracker;
import android.net.NetworkUtils;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* This class tracks the data connection associated with Bluetooth
* reverse tethering. This is a singleton class and an instance will be
* created by ConnectivityService. BluetoothService will call into this
* when a reverse tethered connection needs to be activated.
*
* @hide
*/
public class BluetoothTetheringDataTracker implements NetworkStateTracker {
private static final String NETWORKTYPE = "BLUETOOTH_TETHER";
private static final String TAG = "BluetoothTethering";
private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
private LinkProperties mLinkProperties;
private LinkCapabilities mLinkCapabilities;
private NetworkInfo mNetworkInfo;
private BluetoothPan mBluetoothPan;
private BluetoothDevice mDevice;
private static String mIface;
/* For sending events to connectivity service handler */
private Handler mCsHandler;
private Context mContext;
public static BluetoothTetheringDataTracker sInstance;
private BluetoothTetheringDataTracker() {
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORKTYPE, "");
mLinkProperties = new LinkProperties();
mLinkCapabilities = new LinkCapabilities();
mNetworkInfo.setIsAvailable(false);
setTeardownRequested(false);
}
public static synchronized BluetoothTetheringDataTracker getInstance() {
if (sInstance == null) sInstance = new BluetoothTetheringDataTracker();
return sInstance;
}
public Object Clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
public void setTeardownRequested(boolean isRequested) {
mTeardownRequested.set(isRequested);
}
public boolean isTeardownRequested() {
return mTeardownRequested.get();
}
/**
* Begin monitoring connectivity
*/
public void startMonitoring(Context context, Handler target) {
mContext = context;
mCsHandler = target;
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
adapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.PAN);
}
}
private BluetoothProfile.ServiceListener mProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
mBluetoothPan = (BluetoothPan) proxy;
}
public void onServiceDisconnected(int profile) {
mBluetoothPan = null;
}
};
/**
* Disable connectivity to a network
* TODO: do away with return value after making MobileDataStateTracker async
*/
public boolean teardown() {
mTeardownRequested.set(true);
if (mBluetoothPan != null) {
for (BluetoothDevice device: mBluetoothPan.getConnectedDevices()) {
mBluetoothPan.disconnect(device);
}
}
return true;
}
/**
* Re-enable connectivity to a network after a {@link #teardown()}.
*/
public boolean reconnect() {
mTeardownRequested.set(false);
//Ignore
return true;
}
/**
* Turn the wireless radio off for a network.
* @param turnOn {@code true} to turn the radio on, {@code false}
*/
public boolean setRadio(boolean turnOn) {
return true;
}
/**
* @return true - If are we currently tethered with another device.
*/
public synchronized boolean isAvailable() {
return mNetworkInfo.isAvailable();
}
/**
* Tells the underlying networking system that the caller wants to
* begin using the named feature. The interpretation of {@code feature}
* is completely up to each networking implementation.
* @param feature the name of the feature to be used
* @param callingPid the process ID of the process that is issuing this request
* @param callingUid the user ID of the process that is issuing this request
* @return an integer value representing the outcome of the request.
* The interpretation of this value is specific to each networking
* implementation+feature combination, except that the value {@code -1}
* always indicates failure.
* TODO: needs to go away
*/
public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
return -1;
}
/**
* Tells the underlying networking system that the caller is finished
* using the named feature. The interpretation of {@code feature}
* is completely up to each networking implementation.
* @param feature the name of the feature that is no longer needed.
* @param callingPid the process ID of the process that is issuing this request
* @param callingUid the user ID of the process that is issuing this request
* @return an integer value representing the outcome of the request.
* The interpretation of this value is specific to each networking
* implementation+feature combination, except that the value {@code -1}
* always indicates failure.
* TODO: needs to go away
*/
public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
return -1;
}
@Override
public void setUserDataEnable(boolean enabled) {
Log.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
}
@Override
public void setPolicyDataEnable(boolean enabled) {
Log.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")");
}
/**
* Check if private DNS route is set for the network
*/
public boolean isPrivateDnsRouteSet() {
return mPrivateDnsRouteSet.get();
}
/**
* Set a flag indicating private DNS route is set
*/
public void privateDnsRouteSet(boolean enabled) {
mPrivateDnsRouteSet.set(enabled);
}
/**
* Fetch NetworkInfo for the network
*/
public synchronized NetworkInfo getNetworkInfo() {
return mNetworkInfo;
}
/**
* Fetch LinkProperties for the network
*/
public synchronized LinkProperties getLinkProperties() {
return new LinkProperties(mLinkProperties);
}
/**
* A capability is an Integer/String pair, the capabilities
* are defined in the class LinkSocket#Key.
*
* @return a copy of this connections capabilities, may be empty but never null.
*/
public LinkCapabilities getLinkCapabilities() {
return new LinkCapabilities(mLinkCapabilities);
}
/**
* Fetch default gateway address for the network
*/
public int getDefaultGatewayAddr() {
return mDefaultGatewayAddr.get();
}
/**
* Check if default route is set
*/
public boolean isDefaultRouteSet() {
return mDefaultRouteSet.get();
}
/**
* Set a flag indicating default route is set for the network
*/
public void defaultRouteSet(boolean enabled) {
mDefaultRouteSet.set(enabled);
}
/**
* Return the system properties name associated with the tcp buffer sizes
* for this network.
*/
public String getTcpBufferSizesPropName() {
return "net.tcp.buffersize.wifi";
}
public synchronized void startReverseTether(String iface, BluetoothDevice device) {
mIface = iface;
mDevice = device;
Thread dhcpThread = new Thread(new Runnable() {
public void run() {
//TODO(): Add callbacks for failure and success case.
//Currently this thread runs independently.
DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) {
Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
return;
}
mLinkProperties = dhcpInfoInternal.makeLinkProperties();
mLinkProperties.setInterfaceName(mIface);
mNetworkInfo.setIsAvailable(true);
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
msg.sendToTarget();
}
});
dhcpThread.start();
}
public synchronized void stopReverseTether(String iface) {
NetworkUtils.stopDhcp(iface);
mLinkProperties.clear();
mNetworkInfo.setIsAvailable(false);
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
msg.sendToTarget();
}
public void setDependencyMet(boolean met) {
// not supported on this network
}
}