Home | History | Annotate | Download | only in bluetooth
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.bluetooth;
     18 
     19 import android.content.Context;
     20 import android.net.ConnectivityManager;
     21 import android.net.DhcpInfoInternal;
     22 import android.net.LinkCapabilities;
     23 import android.net.LinkProperties;
     24 import android.net.NetworkInfo;
     25 import android.net.NetworkInfo.DetailedState;
     26 import android.net.NetworkStateTracker;
     27 import android.net.NetworkUtils;
     28 import android.os.Handler;
     29 import android.os.Message;
     30 import android.util.Log;
     31 
     32 import java.util.concurrent.atomic.AtomicBoolean;
     33 import java.util.concurrent.atomic.AtomicInteger;
     34 
     35 /**
     36  * This class tracks the data connection associated with Bluetooth
     37  * reverse tethering. This is a singleton class and an instance will be
     38  * created by ConnectivityService. BluetoothService will call into this
     39  * when a reverse tethered connection needs to be activated.
     40  *
     41  * @hide
     42  */
     43 public class BluetoothTetheringDataTracker implements NetworkStateTracker {
     44     private static final String NETWORKTYPE = "BLUETOOTH_TETHER";
     45     private static final String TAG = "BluetoothTethering";
     46 
     47     private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
     48     private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
     49     private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
     50     private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
     51 
     52     private LinkProperties mLinkProperties;
     53     private LinkCapabilities mLinkCapabilities;
     54     private NetworkInfo mNetworkInfo;
     55 
     56     private BluetoothPan mBluetoothPan;
     57     private BluetoothDevice mDevice;
     58     private static String mIface;
     59 
     60     /* For sending events to connectivity service handler */
     61     private Handler mCsHandler;
     62     private Context mContext;
     63     public static BluetoothTetheringDataTracker sInstance;
     64 
     65     private BluetoothTetheringDataTracker() {
     66         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORKTYPE, "");
     67         mLinkProperties = new LinkProperties();
     68         mLinkCapabilities = new LinkCapabilities();
     69 
     70         mNetworkInfo.setIsAvailable(false);
     71         setTeardownRequested(false);
     72     }
     73 
     74     public static synchronized BluetoothTetheringDataTracker getInstance() {
     75         if (sInstance == null) sInstance = new BluetoothTetheringDataTracker();
     76         return sInstance;
     77     }
     78 
     79     public Object Clone() throws CloneNotSupportedException {
     80         throw new CloneNotSupportedException();
     81     }
     82 
     83     public void setTeardownRequested(boolean isRequested) {
     84         mTeardownRequested.set(isRequested);
     85     }
     86 
     87     public boolean isTeardownRequested() {
     88         return mTeardownRequested.get();
     89     }
     90 
     91     /**
     92      * Begin monitoring connectivity
     93      */
     94     public void startMonitoring(Context context, Handler target) {
     95         mContext = context;
     96         mCsHandler = target;
     97         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
     98         if (adapter != null) {
     99             adapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.PAN);
    100         }
    101     }
    102 
    103     private BluetoothProfile.ServiceListener mProfileServiceListener =
    104         new BluetoothProfile.ServiceListener() {
    105         public void onServiceConnected(int profile, BluetoothProfile proxy) {
    106             mBluetoothPan = (BluetoothPan) proxy;
    107         }
    108         public void onServiceDisconnected(int profile) {
    109             mBluetoothPan = null;
    110         }
    111     };
    112 
    113     /**
    114      * Disable connectivity to a network
    115      * TODO: do away with return value after making MobileDataStateTracker async
    116      */
    117     public boolean teardown() {
    118         mTeardownRequested.set(true);
    119         if (mBluetoothPan != null) {
    120             for (BluetoothDevice device: mBluetoothPan.getConnectedDevices()) {
    121                 mBluetoothPan.disconnect(device);
    122             }
    123         }
    124         return true;
    125     }
    126 
    127     /**
    128      * Re-enable connectivity to a network after a {@link #teardown()}.
    129      */
    130     public boolean reconnect() {
    131         mTeardownRequested.set(false);
    132         //Ignore
    133         return true;
    134     }
    135 
    136     /**
    137      * Turn the wireless radio off for a network.
    138      * @param turnOn {@code true} to turn the radio on, {@code false}
    139      */
    140     public boolean setRadio(boolean turnOn) {
    141         return true;
    142     }
    143 
    144     /**
    145      * @return true - If are we currently tethered with another device.
    146      */
    147     public synchronized boolean isAvailable() {
    148         return mNetworkInfo.isAvailable();
    149     }
    150 
    151     /**
    152      * Tells the underlying networking system that the caller wants to
    153      * begin using the named feature. The interpretation of {@code feature}
    154      * is completely up to each networking implementation.
    155      * @param feature the name of the feature to be used
    156      * @param callingPid the process ID of the process that is issuing this request
    157      * @param callingUid the user ID of the process that is issuing this request
    158      * @return an integer value representing the outcome of the request.
    159      * The interpretation of this value is specific to each networking
    160      * implementation+feature combination, except that the value {@code -1}
    161      * always indicates failure.
    162      * TODO: needs to go away
    163      */
    164     public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
    165         return -1;
    166     }
    167 
    168     /**
    169      * Tells the underlying networking system that the caller is finished
    170      * using the named feature. The interpretation of {@code feature}
    171      * is completely up to each networking implementation.
    172      * @param feature the name of the feature that is no longer needed.
    173      * @param callingPid the process ID of the process that is issuing this request
    174      * @param callingUid the user ID of the process that is issuing this request
    175      * @return an integer value representing the outcome of the request.
    176      * The interpretation of this value is specific to each networking
    177      * implementation+feature combination, except that the value {@code -1}
    178      * always indicates failure.
    179      * TODO: needs to go away
    180      */
    181     public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
    182         return -1;
    183     }
    184 
    185     @Override
    186     public void setUserDataEnable(boolean enabled) {
    187         Log.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
    188     }
    189 
    190     @Override
    191     public void setPolicyDataEnable(boolean enabled) {
    192         Log.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")");
    193     }
    194 
    195     /**
    196      * Check if private DNS route is set for the network
    197      */
    198     public boolean isPrivateDnsRouteSet() {
    199         return mPrivateDnsRouteSet.get();
    200     }
    201 
    202     /**
    203      * Set a flag indicating private DNS route is set
    204      */
    205     public void privateDnsRouteSet(boolean enabled) {
    206         mPrivateDnsRouteSet.set(enabled);
    207     }
    208 
    209     /**
    210      * Fetch NetworkInfo for the network
    211      */
    212     public synchronized NetworkInfo getNetworkInfo() {
    213         return mNetworkInfo;
    214     }
    215 
    216     /**
    217      * Fetch LinkProperties for the network
    218      */
    219     public synchronized LinkProperties getLinkProperties() {
    220         return new LinkProperties(mLinkProperties);
    221     }
    222 
    223    /**
    224      * A capability is an Integer/String pair, the capabilities
    225      * are defined in the class LinkSocket#Key.
    226      *
    227      * @return a copy of this connections capabilities, may be empty but never null.
    228      */
    229     public LinkCapabilities getLinkCapabilities() {
    230         return new LinkCapabilities(mLinkCapabilities);
    231     }
    232 
    233     /**
    234      * Fetch default gateway address for the network
    235      */
    236     public int getDefaultGatewayAddr() {
    237         return mDefaultGatewayAddr.get();
    238     }
    239 
    240     /**
    241      * Check if default route is set
    242      */
    243     public boolean isDefaultRouteSet() {
    244         return mDefaultRouteSet.get();
    245     }
    246 
    247     /**
    248      * Set a flag indicating default route is set for the network
    249      */
    250     public void defaultRouteSet(boolean enabled) {
    251         mDefaultRouteSet.set(enabled);
    252     }
    253 
    254     /**
    255      * Return the system properties name associated with the tcp buffer sizes
    256      * for this network.
    257      */
    258     public String getTcpBufferSizesPropName() {
    259         return "net.tcp.buffersize.wifi";
    260     }
    261 
    262 
    263     public synchronized void startReverseTether(String iface, BluetoothDevice device) {
    264         mIface = iface;
    265         mDevice = device;
    266         Thread dhcpThread = new Thread(new Runnable() {
    267             public void run() {
    268                 //TODO(): Add callbacks for failure and success case.
    269                 //Currently this thread runs independently.
    270                 DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
    271                 if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) {
    272                     Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
    273                     return;
    274                 }
    275                 mLinkProperties = dhcpInfoInternal.makeLinkProperties();
    276                 mLinkProperties.setInterfaceName(mIface);
    277 
    278                 mNetworkInfo.setIsAvailable(true);
    279                 mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
    280 
    281                 Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
    282                 msg.sendToTarget();
    283 
    284                 msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
    285                 msg.sendToTarget();
    286             }
    287         });
    288         dhcpThread.start();
    289     }
    290 
    291     public synchronized void stopReverseTether(String iface) {
    292         NetworkUtils.stopDhcp(iface);
    293 
    294         mLinkProperties.clear();
    295         mNetworkInfo.setIsAvailable(false);
    296         mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
    297 
    298         Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
    299         msg.sendToTarget();
    300 
    301         msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
    302         msg.sendToTarget();
    303     }
    304 
    305     public void setDependencyMet(boolean met) {
    306         // not supported on this network
    307     }
    308 }
    309