Tethering.java revision c9d5fb7c95f158d9a31d534895373afcfad77806
1d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt/*
2d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt * Copyright (C) 2010 The Android Open Source Project
3d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt *
4d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt * Licensed under the Apache License, Version 2.0 (the "License");
5d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt * you may not use this file except in compliance with the License.
6d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt * You may obtain a copy of the License at
7d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt *
8d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt *      http://www.apache.org/licenses/LICENSE-2.0
9d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt *
10d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt * Unless required by applicable law or agreed to in writing, software
11d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt * distributed under the License is distributed on an "AS IS" BASIS,
12d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt * See the License for the specific language governing permissions and
14d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt * limitations under the License.
15d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt */
16d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
17d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltpackage com.android.server.connectivity;
18d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
19d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.app.Notification;
20d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.app.NotificationManager;
21d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.app.PendingIntent;
22d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.content.BroadcastReceiver;
23d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.content.ContentResolver;
24d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.content.Context;
25d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.content.Intent;
26d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.content.IntentFilter;
272a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwaltimport android.content.pm.PackageManager;
28d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.content.res.Resources;
29d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.net.ConnectivityManager;
3065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwaltimport android.net.InterfaceConfiguration;
312a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwaltimport android.net.IConnectivityManager;
32d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.net.INetworkManagementEventObserver;
332a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwaltimport android.net.NetworkInfo;
341cb3cb1a94342e03b54fabfaf361c9e2e26f23feMike Lockwoodimport android.os.BatteryManager;
352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwaltimport android.os.Binder;
36d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.os.IBinder;
37d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.os.INetworkManagementService;
382a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwaltimport android.os.Message;
39d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.os.RemoteException;
40d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.os.ServiceManager;
41d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.provider.Settings;
42d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport android.util.Log;
43d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
442a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwaltimport com.android.internal.telephony.Phone;
452a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwaltimport com.android.internal.util.HierarchicalState;
462a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwaltimport com.android.internal.util.HierarchicalStateMachine;
472a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
482a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwaltimport java.io.FileDescriptor;
492a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwaltimport java.io.PrintWriter;
50d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltimport java.util.ArrayList;
512a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwaltimport java.util.HashMap;
522a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwaltimport java.util.Set;
53d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt/**
54d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt * @hide
552a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt *
562a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt * Timeout
572a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt * TODO - review error states - they currently are dead-ends with no recovery possible
582a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt *
592a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt * TODO - look for parent classes and code sharing
60d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt */
6165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt
62d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwaltpublic class Tethering extends INetworkManagementEventObserver.Stub {
63d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
64d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    private Notification mTetheringNotification;
65d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    private Context mContext;
66d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    private final String TAG = "Tethering";
67d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
68d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    private boolean mPlaySounds = false;
69c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt    private boolean mBooted = false;
70c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt    //used to remember if we got connected before boot finished
71c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt    private boolean mDeferedUsbConnection = false;
72d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
732a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    // TODO - remove both of these - should be part of interface inspection/selection stuff
742a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    private String[] mTetherableUsbRegexs;
752a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    private String[] mTetherableWifiRegexs;
76c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt    private String[] mUpstreamIfaceRegexs;
772a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
782a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    private HashMap<String, TetherInterfaceSM> mIfaces;
79d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
80d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    private ArrayList<String> mActiveTtys;
81d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
82d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    private BroadcastReceiver mStateReceiver;
83d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
84d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt    private static final String USB_NEAR_IFACE_ADDR      = "169.254.2.1";
85d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt
862a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    private String[] mDhcpRange;
87d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt    private static final String DHCP_DEFAULT_RANGE_START = "169.254.2.10";
88d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt    private static final String DHCP_DEFAULT_RANGE_STOP  = "169.254.2.64";
892a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
902a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    private String[] mDnsServers;
91d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt    private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
92d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt    private static final String DNS_DEFAULT_SERVER2 = "4.2.2.2";
932a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
94c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt    private boolean mDunRequired;
95c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt    private boolean mUseHiPri;
962a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    private String mUpstreamIfaceName;
972a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
982a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    HierarchicalStateMachine mTetherMasterSM;
992a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
100d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    public Tethering(Context context) {
101d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        Log.d(TAG, "Tethering starting");
102d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        mContext = context;
103d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
104d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        // register for notifications from NetworkManagement Service
105d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
106d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
107d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        try {
108d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            service.registerObserver(this);
109d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        } catch (RemoteException e) {
110d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            Log.e(TAG, "Error registering observer :" + e);
111d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
112d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
1132a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        mIfaces = new HashMap<String, TetherInterfaceSM>();
114d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        mActiveTtys = new ArrayList<String>();
115d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
1162a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        mTetherMasterSM = new TetherMasterSM("TetherMaster");
1172a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        mTetherMasterSM.start();
1182a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
119d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        // TODO - remove this hack after real USB connections are detected.
120d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        IntentFilter filter = new IntentFilter();
1211cb3cb1a94342e03b54fabfaf361c9e2e26f23feMike Lockwood        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
1222a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
123c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
1242a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        mStateReceiver = new StateReceiver();
125d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        mContext.registerReceiver(mStateReceiver, filter);
1262a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
1272a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        mDhcpRange = context.getResources().getStringArray(
1282a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                com.android.internal.R.array.config_tether_dhcp_range);
1292a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        if (mDhcpRange.length == 0) {
1302a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mDhcpRange = new String[2];
131d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt            mDhcpRange[0] = DHCP_DEFAULT_RANGE_START;
132d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt            mDhcpRange[1] = DHCP_DEFAULT_RANGE_STOP;
1332a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        } else if(mDhcpRange.length == 1) {
1342a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            String[] tmp = new String[2];
1352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            tmp[0] = mDhcpRange[0];
1362a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            tmp[1] = new String("");
1372a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mDhcpRange = tmp;
1382a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
139c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt        mDunRequired = context.getResources().getBoolean(
140c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                com.android.internal.R.bool.config_tether_dun_required);
1412a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
1422a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        mTetherableUsbRegexs = context.getResources().getStringArray(
1432a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                com.android.internal.R.array.config_tether_usb_regexs);
1442a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        mTetherableWifiRegexs = context.getResources().getStringArray(
1452a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                com.android.internal.R.array.config_tether_wifi_regexs);
146c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt        mUpstreamIfaceRegexs = context.getResources().getStringArray(
147c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                com.android.internal.R.array.config_tether_upstream_regexs);
1482a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
1492a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // TODO - remove and rely on real notifications of the current iface
1502a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        mDnsServers = new String[2];
151d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt        mDnsServers[0] = DNS_DEFAULT_SERVER1;
152d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt        mDnsServers[1] = DNS_DEFAULT_SERVER2;
153d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    }
154d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
1552a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    public void interfaceLinkStatusChanged(String iface, boolean link) {
156d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        Log.d(TAG, "interfaceLinkStatusChanged " + iface + ", " + link);
1572a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        boolean found = false;
15865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        boolean usb = false;
1592a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        for (String regex : mTetherableWifiRegexs) {
1602a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (iface.matches(regex)) {
1612a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                found = true;
1622a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                break;
1632a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
1642a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
1652a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        for (String regex: mTetherableUsbRegexs) {
1662a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (iface.matches(regex)) {
1672a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                found = true;
16865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                usb = true;
1692a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                break;
1702a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
1712a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
1722a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        if (found == false) return;
1732a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
1742a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        synchronized (mIfaces) {
1752a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            TetherInterfaceSM sm = mIfaces.get(iface);
1762a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (link) {
1772a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                if (sm == null) {
17865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                    sm = new TetherInterfaceSM(iface, usb);
1792a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    mIfaces.put(iface, sm);
1802a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    sm.start();
1812a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
1822a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            } else {
1832a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                if (sm != null) {
1842a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN));
1852a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    mIfaces.remove(iface);
1862a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
1872a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
1882a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
189d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    }
190d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
1912a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    public void interfaceAdded(String iface) {
19265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
19365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
1942a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        boolean found = false;
19565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        boolean usb = false;
1962a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        for (String regex : mTetherableWifiRegexs) {
1972a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (iface.matches(regex)) {
1982a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                found = true;
1992a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                break;
2002a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
2012a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
2022a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        for (String regex : mTetherableUsbRegexs) {
2032a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (iface.matches(regex)) {
2042a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                found = true;
20565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                usb = true;
2062a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                break;
2072a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
208d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
2092a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        if (found == false) {
2102a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            Log.d(TAG, iface + " is not a tetherable iface, ignoring");
211d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            return;
212d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
21365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt
2142a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        synchronized (mIfaces) {
2152a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            TetherInterfaceSM sm = mIfaces.get(iface);
2162a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (sm != null) {
2172a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.e(TAG, "active iface (" + iface + ") reported as added, ignoring");
2182a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                return;
2192a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
22065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            sm = new TetherInterfaceSM(iface, usb);
2212a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mIfaces.put(iface, sm);
2222a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            sm.start();
2232a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
224d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        Log.d(TAG, "interfaceAdded :" + iface);
225d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    }
226d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
2272a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    public void interfaceRemoved(String iface) {
2282a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        synchronized (mIfaces) {
2292a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            TetherInterfaceSM sm = mIfaces.get(iface);
2302a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (sm == null) {
2312a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.e(TAG, "attempting to remove unknown iface (" + iface + "), ignoring");
2322a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                return;
2332a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
2342a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN));
2352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mIfaces.remove(iface);
236d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
237d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    }
238d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
2392a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    public boolean tether(String iface) {
240d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        Log.d(TAG, "Tethering " + iface);
2412a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        TetherInterfaceSM sm = null;
2422a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        synchronized (mIfaces) {
2432a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            sm = mIfaces.get(iface);
244d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
2452a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        if (sm == null) {
2462a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
247d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            return false;
248d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
2492a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        if (sm.isErrored()) {
2502a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            Log.e(TAG, "Tried to Tether to an errored iface :" + iface + ", ignoring");
251d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            return false;
252d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
2532a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        if (!sm.isAvailable()) {
2542a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
255d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            return false;
256d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
2572a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED));
258d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        return true;
259d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    }
260d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
2612a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    public boolean untether(String iface) {
262d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        Log.d(TAG, "Untethering " + iface);
2632a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        TetherInterfaceSM sm = null;
2642a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        synchronized (mIfaces) {
2652a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            sm = mIfaces.get(iface);
2662a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
2672a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        if (sm == null) {
2682a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
269d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            return false;
270d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
2712a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        if (sm.isErrored()) {
2722a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            Log.e(TAG, "Tried to Untethered an errored iface :" + iface + ", ignoring");
273d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            return false;
274d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
2752a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_TETHER_UNREQUESTED));
2762a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        return true;
2772a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    }
278d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
2792a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    private void sendTetherStateChangedBroadcast() {
2802a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
2812a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
282d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        try {
2832a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (!service.isTetheringSupported()) return;
2842a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        } catch (RemoteException e) {
2852a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            return;
286d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
287d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
2882a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        ArrayList<String> availableList = new ArrayList<String>();
2892a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        ArrayList<String> activeList = new ArrayList<String>();
2902a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        ArrayList<String> erroredList = new ArrayList<String>();
2912a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
2922a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        synchronized (mIfaces) {
2932a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            Set ifaces = mIfaces.keySet();
2942a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            for (Object iface : ifaces) {
2952a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                TetherInterfaceSM sm = mIfaces.get(iface);
2962a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                if (sm != null) {
2972a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    if(sm.isErrored()) {
2982a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        erroredList.add((String)iface);
2992a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    } else if (sm.isAvailable()) {
3002a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        availableList.add((String)iface);
3012a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    } else if (sm.isTethered()) {
3022a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        activeList.add((String)iface);
3032a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    }
3042a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
305d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            }
306d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
307d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
308d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
3092a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER,
3102a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                availableList);
3112a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList);
3122a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
3132a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                erroredList);
3142a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        mContext.sendStickyBroadcast(broadcast);
315d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt        Log.d(TAG, "sendTetherStateChangedBroadcast " + availableList.size() + ", " +
316d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                activeList.size() + ", " + erroredList.size());
3172a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // check if we need to send a USB notification
3182a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // Check if the user wants to be bothered
3192a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        boolean tellUser = (Settings.Secure.getInt(mContext.getContentResolver(),
3202a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Settings.Secure.TETHER_NOTIFY, 0) == 1);
3212a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        for (Object o : activeList) {
3222a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            String s = (String)o;
3232a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            for (Object regexObject : mTetherableUsbRegexs) {
3242a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                if (s.matches((String)regexObject)) {
3252a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    showTetheredNotification();
3262a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    return;
3272a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
3282a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
3292a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
3302a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        if (tellUser) {
3312a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            for (Object o : availableList) {
3322a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                String s = (String)o;
33365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                for (String match : mTetherableUsbRegexs) {
33465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                    if (s.matches(match)) {
3352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        showTetherAvailableNotification();
3362a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        return;
3372a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    }
3382a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
3392a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
340d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
3412a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        clearNotification();
342d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    }
343d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
344d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    private void showTetherAvailableNotification() {
345d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        NotificationManager notificationManager = (NotificationManager)mContext.
346d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                getSystemService(Context.NOTIFICATION_SERVICE);
347d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        if (notificationManager == null) {
348d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            return;
349d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
350d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        Intent intent = new Intent();
351d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        intent.setClass(mContext, com.android.internal.app.TetherActivity.class);
352d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
353d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
354d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
355d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
356d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        Resources r = Resources.getSystem();
357d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        CharSequence title = r.getText(com.android.internal.R.string.
358d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                tether_available_notification_title);
359d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        CharSequence message = r.getText(com.android.internal.R.string.
360d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                tether_available_notification_message);
361d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
362d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        if(mTetheringNotification == null) {
363d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            mTetheringNotification = new Notification();
364d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            mTetheringNotification.when = 0;
365d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
366d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        mTetheringNotification.icon = com.android.internal.R.drawable.stat_sys_tether_usb;
367d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
368d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        boolean playSounds = false;
369d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        //playSounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1");
370d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        if (playSounds) {
371d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            mTetheringNotification.defaults |= Notification.DEFAULT_SOUND;
372d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        } else {
373d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            mTetheringNotification.defaults &= ~Notification.DEFAULT_SOUND;
374d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
375d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
376d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        mTetheringNotification.flags = Notification.FLAG_ONGOING_EVENT;
377d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        mTetheringNotification.tickerText = title;
378d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        mTetheringNotification.setLatestEventInfo(mContext, title, message, pi);
379d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
380d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        notificationManager.notify(mTetheringNotification.icon, mTetheringNotification);
381d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
382d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    }
383d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
384d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    private void showTetheredNotification() {
385d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        NotificationManager notificationManager = (NotificationManager)mContext.
386d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                getSystemService(Context.NOTIFICATION_SERVICE);
387d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        if (notificationManager == null) {
388d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            return;
389d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
390d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
391d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        Intent intent = new Intent();
392d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        intent.setClass(mContext, com.android.internal.app.TetherActivity.class);
393d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
394d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
395d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
396d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
397d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        Resources r = Resources.getSystem();
398d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        CharSequence title = r.getText(com.android.internal.R.string.
399d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                tether_stop_notification_title);
400d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        CharSequence message = r.getText(com.android.internal.R.string.
401d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                tether_stop_notification_message);
402d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
403d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        if(mTetheringNotification == null) {
404d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            mTetheringNotification = new Notification();
405d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            mTetheringNotification.when = 0;
406d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
407d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        mTetheringNotification.icon = com.android.internal.R.drawable.stat_sys_tether_usb;
408d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
409d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        boolean playSounds = false;
410d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        //playSounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1");
411d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        if (playSounds) {
412d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            mTetheringNotification.defaults |= Notification.DEFAULT_SOUND;
413d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        } else {
414d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            mTetheringNotification.defaults &= ~Notification.DEFAULT_SOUND;
415d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
416d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
417d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        mTetheringNotification.flags = Notification.FLAG_ONGOING_EVENT;
418d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        mTetheringNotification.tickerText = title;
419d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        mTetheringNotification.setLatestEventInfo(mContext, title, message, pi);
420d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
421d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        notificationManager.notify(mTetheringNotification.icon, mTetheringNotification);
422d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    }
423d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
424d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    private void clearNotification() {
425d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        NotificationManager notificationManager = (NotificationManager)mContext.
426d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                getSystemService(Context.NOTIFICATION_SERVICE);
427d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        if (notificationManager != null && mTetheringNotification != null) {
428d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            notificationManager.cancel(mTetheringNotification.icon);
429d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            mTetheringNotification = null;
430d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
431d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    }
432d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
4332a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    private class StateReceiver extends BroadcastReceiver {
434d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        public void onReceive(Context content, Intent intent) {
4352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            String action = intent.getAction();
4361cb3cb1a94342e03b54fabfaf361c9e2e26f23feMike Lockwood            if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
4371cb3cb1a94342e03b54fabfaf361c9e2e26f23feMike Lockwood                boolean usbConnected = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)
4381cb3cb1a94342e03b54fabfaf361c9e2e26f23feMike Lockwood                        == BatteryManager.BATTERY_PLUGGED_USB);
439c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                if (mBooted) {
440c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    Tethering.this.enableUsbIfaces(usbConnected); // add or remove them
441c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                } else {
442c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    mDeferedUsbConnection = usbConnected;
443c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                }
4442a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
4452a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
44665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
4472a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                try {
448c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    int netType = (mUseHiPri ? ConnectivityManager.TYPE_MOBILE_HIPRI:
449c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                               ConnectivityManager.TYPE_MOBILE_DUN);
450c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    NetworkInfo info = service.getNetworkInfo(netType);
4512a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    int msg;
452a4437fc93a993c7ab326b592d22c05be2f11b543Mike Lockwood                    if (info != null && info.isConnected() == true) {
4532a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        msg = TetherMasterSM.CMD_CELL_DUN_ENABLED;
4542a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    } else {
4552a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        msg = TetherMasterSM.CMD_CELL_DUN_DISABLED;
4562a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    }
4572a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    mTetherMasterSM.sendMessage(mTetherMasterSM.obtainMessage(msg));
4582a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                } catch (RemoteException e) {}
459c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt            } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
460c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                mBooted = true;
461c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                if (mDeferedUsbConnection) {
462c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    Tethering.this.enableUsbIfaces(true);
463c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                }
464d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            }
465d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
466d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    }
467d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
46865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt    // used on cable insert/remove
469d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt    private void enableUsbIfaces(boolean enable) {
47065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
47165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
47265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        String[] ifaces = new String[0];
47365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        try {
47465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            ifaces = service.listInterfaces();
47565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        } catch (Exception e) {
47665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            Log.e(TAG, "Error listing Interfaces :" + e);
47765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            return;
47865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        }
47965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        for (String iface : ifaces) {
48065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            for (String regex : mTetherableUsbRegexs) {
48165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                if (iface.matches(regex)) {
482d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    if (enable) {
48365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        interfaceAdded(iface);
48465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                    } else {
48565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        interfaceRemoved(iface);
48665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                    }
48765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                }
48865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            }
48965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        }
49065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt    }
49165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt
49265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt    // toggled when we enter/leave the fully teathered state
493d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt    private boolean enableUsbRndis(boolean enabled) {
494d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt        Log.d(TAG, "enableUsbRndis(" + enabled + ")");
49565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
49665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
49765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt
49865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        try {
49965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            if (enabled) {
50065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                synchronized (this) {
50165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                    if (!service.isUsbRNDISStarted()) {
50265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        service.startUsbRNDIS();
50365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                    }
50465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                }
50565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            } else {
50665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                if (service.isUsbRNDISStarted()) {
50765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                    service.stopUsbRNDIS();
50865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                }
50965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            }
51065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        } catch (Exception e) {
51165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            Log.e(TAG, "Error toggling usb RNDIS :" + e);
51265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            return false;
51365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        }
51465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        return true;
51565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt    }
51665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt
51765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt    // configured when we start tethering and unconfig'd on error or conclusion
518d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt    private boolean configureUsbIface(boolean enabled) {
519d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt        Log.d(TAG, "configureUsbIface(" + enabled + ")");
52065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt
52165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
52265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
52365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt
52465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        // bring toggle the interfaces
52565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        String[] ifaces = new String[0];
52665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        try {
52765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            ifaces = service.listInterfaces();
52865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        } catch (Exception e) {
52965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            Log.e(TAG, "Error listing Interfaces :" + e);
53065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            return false;
53165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        }
53265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        for (String iface : ifaces) {
53365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            for (String regex : mTetherableUsbRegexs) {
53465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                if (iface.matches(regex)) {
53565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                    InterfaceConfiguration ifcg = null;
53665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                    try {
53765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        ifcg = service.getInterfaceConfig(iface);
53865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        if (ifcg != null) {
53965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                            ifcg.ipAddr = (169 << 24) + (254 << 16) + (2 << 8) + 1;
54065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                            ifcg.netmask = (255 << 24) + (255 << 16) + (255 << 8) + 0;
54165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                            if (enabled) {
54265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                                ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up");
54365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                            } else {
54465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                                ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down");
545d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                                // TODO - clean this up - maybe a better regex?
546c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running", "");
547c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                ifcg.interfaceFlags = ifcg.interfaceFlags.replace("  "," ");
54865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                            }
54965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                            service.setInterfaceConfig(iface, ifcg);
55065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        }
55165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                    } catch (Exception e) {
55265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        Log.e(TAG, "Error configuring interface " + iface + ", :" + e);
55365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        return false;
55465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                    }
55565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                }
55665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            }
55765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        }
55865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt
55965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        return true;
56065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt    }
56165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt
5622a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    public String[] getTetherableUsbRegexs() {
5632a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        return mTetherableUsbRegexs;
5642a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    }
5652a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
5662a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    public String[] getTetherableWifiRegexs() {
5672a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        return mTetherableWifiRegexs;
5682a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    }
5692a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
570c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt    public String[] getUpstreamIfaceRegexs() {
571c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt        return mUpstreamIfaceRegexs;
572c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt    }
573c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt
574c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt    public boolean isDunRequired() {
575c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt        return mDunRequired;
576c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt    }
577c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt
5782a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    public String[] getTetheredIfaces() {
5792a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        ArrayList<String> list = new ArrayList<String>();
5802a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        synchronized (mIfaces) {
5812a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            Set keys = mIfaces.keySet();
5822a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            for (Object key : keys) {
5832a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                TetherInterfaceSM sm = mIfaces.get(key);
5842a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                if (sm.isTethered()) {
5852a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    list.add((String)key);
5862a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
5872a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
5882a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
5892a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        String[] retVal = new String[list.size()];
5902a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        for (int i=0; i < list.size(); i++) {
5912a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            retVal[i] = list.get(i);
5922a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
5932a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        return retVal;
5942a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    }
5952a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
5962a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    public String[] getTetherableIfaces() {
5972a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        ArrayList<String> list = new ArrayList<String>();
5982a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        synchronized (mIfaces) {
5992a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            Set keys = mIfaces.keySet();
6002a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            for (Object key : keys) {
6012a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                TetherInterfaceSM sm = mIfaces.get(key);
6022a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                if (sm.isAvailable()) {
6032a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    list.add((String)key);
6042a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
6052a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
6062a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
6072a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        String[] retVal = new String[list.size()];
6082a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        for (int i=0; i < list.size(); i++) {
6092a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            retVal[i] = list.get(i);
6102a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
6112a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        return retVal;
6122a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    }
6132a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
6142a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
6152a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    class TetherInterfaceSM extends HierarchicalStateMachine {
6162a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // notification from the master SM that it's in tether mode
6172a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_TETHER_MODE_ALIVE           =  1;
6182a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // notification from the master SM that it's not in tether mode
6192a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_TETHER_MODE_DEAD            =  2;
6202a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // request from the user that it wants to tether
6212a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_TETHER_REQUESTED            =  3;
6222a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // request from the user that it wants to untether
6232a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_TETHER_UNREQUESTED          =  4;
6242a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // notification that this interface is down
6252a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_INTERFACE_DOWN              =  5;
6262a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // notification that this interface is up
6272a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_INTERFACE_UP                =  6;
6282a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // notification from the master SM that it had an error turning on cellular dun
6292a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_CELL_DUN_ERROR              = 10;
6302a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // notification from the master SM that it had trouble enabling IP Forwarding
6312a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_IP_FORWARDING_ENABLE_ERROR  = 11;
6322a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // notification from the master SM that it had trouble disabling IP Forwarding
6332a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_IP_FORWARDING_DISABLE_ERROR = 12;
6342a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // notification from the master SM that it had trouble staring tethering
6352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_START_TETHERING_ERROR       = 13;
6362a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // notification from the master SM that it had trouble stopping tethering
6372a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_STOP_TETHERING_ERROR        = 14;
6382a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // notification from the master SM that it had trouble setting the DNS forwarders
6392a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_SET_DNS_FORWARDERS_ERROR    = 15;
6402a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // a mechanism to transition self to error state from an enter function
6412a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_TRANSITION_TO_ERROR         = 16;
6422a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
6432a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mDefaultState;
6442a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
6452a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mInitialState;
6462a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mStartingState;
6472a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mTetheredState;
6482a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
6492a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mMasterTetherErrorState;
6502a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mTetherInterfaceErrorState;
6512a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mUntetherInterfaceErrorState;
6522a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mEnableNatErrorState;
6532a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mDisableNatErrorState;
65465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        private HierarchicalState mUsbConfigurationErrorState;
6552a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
6562a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mUnavailableState;
6572a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
6582a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private boolean mAvailable;
6592a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private boolean mErrored;
6602a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private boolean mTethered;
6612a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
6622a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        String mIfaceName;
66365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        boolean mUsb;
6642a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
66565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        TetherInterfaceSM(String name, boolean usb) {
6662a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            super(name);
6672a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mIfaceName = name;
66865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            mUsb = usb;
6692a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
6702a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mInitialState = new InitialState();
6712a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mInitialState);
6722a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mStartingState = new StartingState();
6732a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mStartingState);
6742a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mTetheredState = new TetheredState();
6752a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mTetheredState);
6762a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mMasterTetherErrorState = new MasterTetherErrorState();
6772a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mMasterTetherErrorState);
6782a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mTetherInterfaceErrorState = new TetherInterfaceErrorState();
6792a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mTetherInterfaceErrorState);
6802a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mUntetherInterfaceErrorState = new UntetherInterfaceErrorState();
6812a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mUntetherInterfaceErrorState);
6822a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mEnableNatErrorState = new EnableNatErrorState();
6832a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mEnableNatErrorState);
6842a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mDisableNatErrorState = new DisableNatErrorState();
6852a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mDisableNatErrorState);
68665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            mUsbConfigurationErrorState = new UsbConfigurationErrorState();
68765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            addState(mUsbConfigurationErrorState);
6882a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mUnavailableState = new UnavailableState();
6892a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mUnavailableState);
6902a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
6912a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            setInitialState(mInitialState);
6922a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
6932a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
6942a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        public String toString() {
6952a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            String res = new String();
6962a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            res += mIfaceName + " - ";
6972a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            HierarchicalState current = getCurrentState();
6982a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (current == mInitialState) res += "InitialState";
6992a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (current == mStartingState) res += "StartingState";
7002a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (current == mTetheredState) res += "TetheredState";
7012a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (current == mMasterTetherErrorState) res += "MasterTetherErrorState";
7022a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (current == mTetherInterfaceErrorState) res += "TetherInterfaceErrorState";
7032a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (current == mUntetherInterfaceErrorState) res += "UntetherInterfaceErrorState";
7042a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (current == mEnableNatErrorState) res += "EnableNatErrorState";
7052a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (current == mDisableNatErrorState) res += "DisableNatErrorState";
70665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            if (current == mUsbConfigurationErrorState) res += "UsbConfigurationErrorState";
7072a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (current == mUnavailableState) res += "UnavailableState";
7082a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (mAvailable) res += " - Available";
7092a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (mTethered) res += " - Tethered";
7102a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            if (mErrored) res += " - ERRORED";
7112a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            return res;
7122a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
7132a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
7142a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // synchronized between this getter and the following setter
7152a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        public synchronized boolean isAvailable() {
7162a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            return mAvailable;
7172a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
7182a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
7192a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private synchronized void setAvailable(boolean available) {
7202a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mAvailable = available;
7212a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
7222a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
7232a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // synchronized between this getter and the following setter
7242a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        public synchronized boolean isTethered() {
7252a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            return mTethered;
7262a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
7272a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
7282a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private synchronized void setTethered(boolean tethered) {
7292a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mTethered = tethered;
7302a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
7312a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
7322a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // synchronized between this getter and the following setter
7332a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        public synchronized boolean isErrored() {
7342a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            return mErrored;
7352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
7362a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
73765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        private void setErrored(boolean errored) {
73865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            synchronized (this) {
73965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                mErrored = errored;
74065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            }
74165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            if (errored && mUsb) {
74265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                // note everything's been unwound by this point so nothing to do on
74365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                // further error..
744d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                Tethering.this.configureUsbIface(false);
74565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            }
7462a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
7472a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
7482a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class InitialState extends HierarchicalState {
7492a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
7502a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
7512a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setAvailable(true);
7522a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setTethered(false);
7532a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setErrored(false);
7542a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                sendTetherStateChangedBroadcast();
7552a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
7562a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
7572a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
7582a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public boolean processMessage(Message message) {
7592a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.d(TAG, "InitialState.processMessage what=" + message.what);
7602a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                boolean retValue = true;
7612a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                switch (message.what) {
7622a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_REQUESTED:
7632a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        Message m = mTetherMasterSM.obtainMessage(
7642a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                                TetherMasterSM.CMD_TETHER_MODE_REQUESTED);
7652a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        m.obj = TetherInterfaceSM.this;
7662a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        mTetherMasterSM.sendMessage(m);
7672a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        transitionTo(mStartingState);
7682a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
7692a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_INTERFACE_DOWN:
7702a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        transitionTo(mUnavailableState);
7712a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
7722a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    default:
7732a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        retValue = false;
7742a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
7752a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
7762a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                return retValue;
7772a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
7782a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
7792a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
7802a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class StartingState extends HierarchicalState {
7812a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
7822a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
7832a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setAvailable(false);
78465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                if (mUsb) {
785d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    if (!Tethering.this.configureUsbIface(true)) {
78665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        Message m = mTetherMasterSM.obtainMessage(
78765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                                TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED);
78865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        m.obj = TetherInterfaceSM.this;
78965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        mTetherMasterSM.sendMessage(m);
79065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt
79165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        m = obtainMessage(CMD_TRANSITION_TO_ERROR);
79265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        m.obj = mUsbConfigurationErrorState;
79365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        sendMessageAtFrontOfQueue(m);
79465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        return;
79565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                    }
79665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                }
7972a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                sendTetherStateChangedBroadcast();
7982a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
7992a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
8002a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public boolean processMessage(Message message) {
8012a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.d(TAG, "StartingState.processMessage what=" + message.what);
8022a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                boolean retValue = true;
8032a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                switch (message.what) {
8042a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    // maybe a parent class?
8052a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_UNREQUESTED:
8062a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        Message m = mTetherMasterSM.obtainMessage(
8072a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                                TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED);
8082a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        m.obj = TetherInterfaceSM.this;
8092a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        mTetherMasterSM.sendMessage(m);
81065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        if (mUsb) {
811d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                            if (!Tethering.this.configureUsbIface(false)) {
81265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                                transitionTo(mUsbConfigurationErrorState);
81365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                                break;
81465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                            }
81565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        }
8162a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        transitionTo(mInitialState);
8172a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
8182a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_MODE_ALIVE:
8192a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        transitionTo(mTetheredState);
8202a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
8212a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_CELL_DUN_ERROR:
8222a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_IP_FORWARDING_ENABLE_ERROR:
8232a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_IP_FORWARDING_DISABLE_ERROR:
8242a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_START_TETHERING_ERROR:
8252a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_STOP_TETHERING_ERROR:
8262a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_SET_DNS_FORWARDERS_ERROR:
8272a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        transitionTo(mMasterTetherErrorState);
8282a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
8292a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_INTERFACE_DOWN:
8302a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        m = mTetherMasterSM.obtainMessage(
8312a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                                TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED);
8322a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        m.obj = TetherInterfaceSM.this;
8332a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        mTetherMasterSM.sendMessage(m);
8342a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        transitionTo(mUnavailableState);
8352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
83665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                   case CMD_TRANSITION_TO_ERROR:
83765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                       HierarchicalState s = (HierarchicalState)(message.obj);
83865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                       transitionTo(s);
83965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                       break;
8402a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    default:
8412a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        retValue = false;
8422a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
8432a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                return retValue;
8442a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
8452a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
8462a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
8472a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class TetheredState extends HierarchicalState {
8482a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
8492a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
8502a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
8512a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                INetworkManagementService service =
8522a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        INetworkManagementService.Stub.asInterface(b);
8532a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                try {
8542a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    service.tetherInterface(mIfaceName);
8552a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                } catch (Exception e) {
8562a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    Message m = obtainMessage(CMD_TRANSITION_TO_ERROR);
8572a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    m.obj = mTetherInterfaceErrorState;
8582a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    sendMessageAtFrontOfQueue(m);
8592a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    return;
8602a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
8612a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                try {
8622a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    service.enableNat(mIfaceName, mUpstreamIfaceName);
8632a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                } catch (Exception e) {
8642a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    Message m = obtainMessage(CMD_TRANSITION_TO_ERROR);
8652a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    m.obj = mEnableNatErrorState;
8662a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    sendMessageAtFrontOfQueue(m);
8672a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    return;
8682a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
869d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                if (mUsb) Tethering.this.enableUsbRndis(true);
8702a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.d(TAG, "Tethered " + mIfaceName);
8712a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setAvailable(false);
8722a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setTethered(true);
8732a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                sendTetherStateChangedBroadcast();
8742a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
8752a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
87665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            public void exit() {
877d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                if (mUsb) Tethering.this.enableUsbRndis(false);
87865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            }
87965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            @Override
8802a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public boolean processMessage(Message message) {
8812a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.d(TAG, "TetheredState.processMessage what=" + message.what);
8822a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                boolean retValue = true;
8832a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                boolean error = false;
8842a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                switch (message.what) {
8852a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_UNREQUESTED:
8862a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_INTERFACE_DOWN:
8872a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
8882a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        INetworkManagementService service =
8892a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                                INetworkManagementService.Stub.asInterface(b);
8902a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        try {
8912a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            service.disableNat(mIfaceName, mUpstreamIfaceName);
8922a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        } catch (Exception e) {
8932a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            transitionTo(mDisableNatErrorState);
8942a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            break;
8952a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        }
8962a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        try {
8972a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            service.untetherInterface(mIfaceName);
8982a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        } catch (Exception e) {
8992a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            transitionTo(mUntetherInterfaceErrorState);
9002a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            break;
9012a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        }
9022a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        Message m = mTetherMasterSM.obtainMessage(
9032a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                                TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED);
9042a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        m.obj = TetherInterfaceSM.this;
9052a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        mTetherMasterSM.sendMessage(m);
9062a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        if (message.what == CMD_TETHER_UNREQUESTED) {
90765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                            if (mUsb) {
908d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                                if (!Tethering.this.configureUsbIface(false)) {
90965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                                    transitionTo(mUsbConfigurationErrorState);
91065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                                } else {
9116142a0b68fffb2d9595c364ebf4f8be996f37f77Robert Greenwalt                                    transitionTo(mInitialState);
91265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                                }
9136142a0b68fffb2d9595c364ebf4f8be996f37f77Robert Greenwalt                            } else {
9146142a0b68fffb2d9595c364ebf4f8be996f37f77Robert Greenwalt                                transitionTo(mInitialState);
91565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                            }
9162a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        } else if (message.what == CMD_INTERFACE_DOWN) {
9172a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            transitionTo(mUnavailableState);
9182a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        }
9192a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        Log.d(TAG, "Untethered " + mIfaceName);
9202a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
9212a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_CELL_DUN_ERROR:
9222a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_IP_FORWARDING_ENABLE_ERROR:
9232a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_IP_FORWARDING_DISABLE_ERROR:
9242a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_START_TETHERING_ERROR:
9252a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_STOP_TETHERING_ERROR:
9262a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_SET_DNS_FORWARDERS_ERROR:
9272a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        error = true;
9282a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        // fall through
9292a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_MODE_DEAD:
9302a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
9312a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        service = INetworkManagementService.Stub.asInterface(b);
9322a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        try {
9332a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            service.disableNat(mIfaceName, mUpstreamIfaceName);
9342a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        } catch (Exception e) {
9352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            transitionTo(mDisableNatErrorState);
9362a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            break;
9372a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        }
9382a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        try {
9392a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            service.untetherInterface(mIfaceName);
9402a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        } catch (Exception e) {
9412a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            transitionTo(mUntetherInterfaceErrorState);
9422a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            break;
9432a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        }
9442a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        if (error) {
9452a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            transitionTo(mMasterTetherErrorState);
9462a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            break;
9472a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        }
9482a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
9492a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        sendTetherStateChangedBroadcast();
95065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        if (mUsb) {
951d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                            if (!Tethering.this.configureUsbIface(false)) {
9526142a0b68fffb2d9595c364ebf4f8be996f37f77Robert Greenwalt                                transitionTo(mUsbConfigurationErrorState);
95365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                                break;
95465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                            }
95565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        }
9562a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        transitionTo(mInitialState);
9572a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
9582a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TRANSITION_TO_ERROR:
9592a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        HierarchicalState s = (HierarchicalState)(message.obj);
9602a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        transitionTo(s);
9612a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
9622a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    default:
9632a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        retValue = false;
9642a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
9652a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
9662a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                return retValue;
9672a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
9682a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
9692a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
9702a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class UnavailableState extends HierarchicalState {
9712a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
9722a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
9732a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setAvailable(false);
9742a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setErrored(false);
9752a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setTethered(false);
9762a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                sendTetherStateChangedBroadcast();
9772a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
9782a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
9792a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public boolean processMessage(Message message) {
9802a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                boolean retValue = true;
9812a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                switch (message.what) {
9822a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_INTERFACE_UP:
9832a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        transitionTo(mInitialState);
9842a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
9852a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    default:
9862a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        retValue = false;
9872a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
9882a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
9892a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                return retValue;
9902a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
9912a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
9922a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
9932a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
9942a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class ErrorState extends HierarchicalState {
9952a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            int mErrorNotification;
9962a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
9972a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public boolean processMessage(Message message) {
9982a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                boolean retValue = true;
9992a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                switch (message.what) {
10002a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_REQUESTED:
10012a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        sendTetherStateChangedBroadcast();
10022a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
10032a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    default:
10042a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        retValue = false;
10052a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
10062a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
10072a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                return retValue;
10082a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
10092a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
10102a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
10112a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class MasterTetherErrorState extends ErrorState {
10122a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
10132a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
10142a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.e(TAG, "Error in Master Tether state " + mIfaceName);
10152a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setAvailable(false);
10162a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setErrored(true);
10172a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                sendTetherStateChangedBroadcast();
10182a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
10192a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
10202a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
10212a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class TetherInterfaceErrorState extends ErrorState {
10222a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
10232a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
10242a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.e(TAG, "Error trying to tether " + mIfaceName);
10252a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setAvailable(false);
10262a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setErrored(true);
10272a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                sendTetherStateChangedBroadcast();
10282a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
10292a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
10302a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
10312a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class UntetherInterfaceErrorState extends ErrorState {
10322a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
10332a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
10342a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.e(TAG, "Error trying to untether " + mIfaceName);
10352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setAvailable(false);
10362a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setErrored(true);
10372a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                sendTetherStateChangedBroadcast();
10382a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
10392a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
10402a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
10412a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class EnableNatErrorState extends ErrorState {
10422a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
10432a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
10442a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.e(TAG, "Error trying to enable NAT " + mIfaceName);
10452a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setAvailable(false);
10462a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setErrored(true);
10472a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
10482a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
10492a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
10502a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                try {
10512a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    service.untetherInterface(mIfaceName);
10522a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                } catch (Exception e) {}
10532a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                sendTetherStateChangedBroadcast();
10542a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
10552a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
10562a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
10572a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
10582a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class DisableNatErrorState extends ErrorState {
10592a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
10602a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
10612a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.e(TAG, "Error trying to disable NAT " + mIfaceName);
10622a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setAvailable(false);
10632a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                setErrored(true);
10642a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
10652a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
10662a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
10672a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                try {
10682a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    service.untetherInterface(mIfaceName);
10692a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                } catch (Exception e) {}
10702a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                sendTetherStateChangedBroadcast();
10712a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
10722a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
107365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt
107465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        class UsbConfigurationErrorState extends ErrorState {
107565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            @Override
107665ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            public void enter() {
107765ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                Log.e(TAG, "Error trying to configure USB " + mIfaceName);
107865ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                setAvailable(false);
107965ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                setErrored(true);
108065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt            }
108165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt        }
10822a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    }
10832a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
10842a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    class TetherMasterSM extends HierarchicalStateMachine {
10852a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // an interface SM has requested Tethering
10862a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_TETHER_MODE_REQUESTED   = 1;
10872a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // an interface SM has unrequested Tethering
10882a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_TETHER_MODE_UNREQUESTED = 2;
10892a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // we received notice that the cellular DUN connection is up
10902a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_CELL_DUN_ENABLED        = 3;
10912a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // we received notice that the cellular DUN connection is down
10922a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_CELL_DUN_DISABLED       = 4;
10932a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // we timed out on a cellular DUN toggle
10942a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_CELL_DUN_TIMEOUT        = 5;
10952a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // it's time to renew our cellular DUN reservation
10962a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        static final int CMD_CELL_DUN_RENEW          = 6;
10972a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
10982a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // This indicates what a timeout event relates to.  A state that
10992a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // sends itself a delayed timeout event and handles incoming timeout events
11002a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // should inc this when it is entered and whenever it sends a new timeout event.
11012a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        // We do not flush the old ones.
11022a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private int mSequenceNumber;
11032a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
11042a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mInitialState;
11052a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mCellDunRequestedState;
11062a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mCellDunAliveState;
11072a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mTetherModeAliveState;
11082a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
11092a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mCellDunErrorState;
11102a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mSetIpForwardingEnabledErrorState;
11112a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mSetIpForwardingDisabledErrorState;
11122a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mStartTetheringErrorState;
11132a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mStopTetheringErrorState;
11142a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private HierarchicalState mSetDnsForwardersErrorState;
11152a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
11162a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private ArrayList mNotifyList;
11172a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
11182a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
11192a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private static final int CELL_DUN_TIMEOUT_MS         = 45000;
11202a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private static final int CELL_DISABLE_DUN_TIMEOUT_MS = 3000;
11212a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        private static final int CELL_DUN_RENEW_MS           = 40000;
11222a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
11232a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        TetherMasterSM(String name) {
11242a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            super(name);
11252a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
11262a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            //Add states
11272a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mInitialState = new InitialState();
11282a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mInitialState);
11292a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mCellDunRequestedState = new CellDunRequestedState();
11302a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mCellDunRequestedState);
11312a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mCellDunAliveState = new CellDunAliveState();
11322a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mCellDunAliveState);
11332a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mTetherModeAliveState = new TetherModeAliveState();
11342a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mTetherModeAliveState);
11352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
11362a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mCellDunErrorState = new CellDunErrorState();
11372a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mCellDunErrorState);
11382a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState();
11392a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mSetIpForwardingEnabledErrorState);
11402a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mSetIpForwardingDisabledErrorState = new SetIpForwardingDisabledErrorState();
11412a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mSetIpForwardingDisabledErrorState);
11422a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mStartTetheringErrorState = new StartTetheringErrorState();
11432a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mStartTetheringErrorState);
11442a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mStopTetheringErrorState = new StopTetheringErrorState();
11452a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mStopTetheringErrorState);
11462a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mSetDnsForwardersErrorState = new SetDnsForwardersErrorState();
11472a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            addState(mSetDnsForwardersErrorState);
11482a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
11492a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            mNotifyList = new ArrayList();
11502a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
11512a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            setInitialState(mInitialState);
11522a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
11532a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
1154d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt        class TetherMasterUtilState extends HierarchicalState {
1155d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt            @Override
1156d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt            public boolean processMessage(Message m) {
1157d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                return false;
1158d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt            }
1159d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt            public int turnOnMobileDun() {
1160d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
1161d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
1162d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                int retValue = Phone.APN_REQUEST_FAILED;
1163d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                try {
1164d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    retValue = service.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
1165c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            (mUseHiPri ? Phone.FEATURE_ENABLE_HIPRI : Phone.FEATURE_ENABLE_DUN),
1166c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            new Binder());
1167d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                } catch (Exception e) {
1168d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                }
1169d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                return retValue;
1170d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt            }
1171d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt            public boolean turnOffMobileDun() {
1172d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
1173d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                IConnectivityManager service =
1174d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                        IConnectivityManager.Stub.asInterface(b);
1175d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                try {
1176d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    service.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
1177c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            (mUseHiPri ? Phone.FEATURE_ENABLE_HIPRI : Phone.FEATURE_ENABLE_DUN));
1178d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                } catch (Exception e) {
1179d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    return false;
1180d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                }
1181d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                return true;
1182d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt            }
1183d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt            public boolean turnOnMasterTetherSettings() {
1184d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1185d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                INetworkManagementService service =
1186d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                        INetworkManagementService.Stub.asInterface(b);
1187d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                try {
1188d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    service.setIpForwardingEnabled(true);
1189d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                } catch (Exception e) {
1190d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    transitionTo(mSetIpForwardingEnabledErrorState);
1191d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    return false;
1192d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                }
1193d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                try {
1194d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    service.startTethering(mDhcpRange[0], mDhcpRange[1]);
1195d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                } catch (Exception e) {
1196d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    transitionTo(mStartTetheringErrorState);
1197d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    return false;
1198d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                }
1199d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                try {
1200d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    service.setDnsForwarders(mDnsServers);
1201d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                } catch (Exception e) {
1202d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    transitionTo(mSetDnsForwardersErrorState);
1203d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    return false;
1204d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                }
1205d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                transitionTo(mTetherModeAliveState);
1206d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                return true;
1207d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt            }
1208d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt            public boolean turnOffMasterTetherSettings() {
1209d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1210d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                INetworkManagementService service =
1211d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                        INetworkManagementService.Stub.asInterface(b);
1212d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                try {
1213d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    service.stopTethering();
1214d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                } catch (Exception e) {
1215d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    transitionTo(mStopTetheringErrorState);
1216d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    return false;
1217d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                }
1218d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                try {
1219d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    service.setIpForwardingEnabled(false);
1220d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                } catch (Exception e) {
1221d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    transitionTo(mSetIpForwardingDisabledErrorState);
1222d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                    return false;
1223d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                }
1224d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                transitionTo(mInitialState);
1225d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                return true;
1226d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt            }
1227c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt            public String findActiveUpstreamIface() {
1228c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                // check for what iface we can use - if none found switch to error.
1229c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1230c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
1231c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt
1232c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                String[] ifaces = new String[0];
1233c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                try {
1234c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    ifaces = service.listInterfaces();
1235c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                } catch (Exception e) {
1236c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    Log.e(TAG, "Error listing Interfaces :" + e);
1237c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    return null;
1238c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                }
1239c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                for (String iface : ifaces) {
1240c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    for (String regex : mUpstreamIfaceRegexs) {
1241c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                        if (iface.matches(regex)) {
1242c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            // verify it is up!
1243c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            InterfaceConfiguration ifcg = null;
1244c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            try {
1245c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                ifcg = service.getInterfaceConfig(iface);
1246c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            } catch (Exception e) {
1247c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                Log.e(TAG, "Error getting iface config :" + e);
1248c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                // ignore - try next
1249c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                continue;
1250c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            }
1251c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            if (ifcg.interfaceFlags.contains("up")) {
1252c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                return iface;
1253c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            }
1254c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                        }
1255c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    }
1256c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                }
1257c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                return null;
1258c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt            }
1259d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt        }
12602a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
1261d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt        class InitialState extends TetherMasterUtilState {
12622a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
1263c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt            public void enter() {
1264c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                mUseHiPri = false;
1265c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt            }
1266c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt            @Override
12672a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public boolean processMessage(Message message) {
12682a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
12692a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                boolean retValue = true;
12702a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                switch (message.what) {
12712a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_MODE_REQUESTED:
12722a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
12732a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        Log.d(TAG, "Tether Mode requested by " + who.toString());
12742a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        mNotifyList.add(who);
12752a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        transitionTo(mCellDunRequestedState);
12762a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
12772a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_MODE_UNREQUESTED:
12782a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        who = (TetherInterfaceSM)message.obj;
12792a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        Log.d(TAG, "Tether Mode unrequested by " + who.toString());
12802a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        int index = mNotifyList.indexOf(who);
12812a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        if (index != -1) {
12822a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            mNotifyList.remove(who);
12832a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        }
12842a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
12852a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_CELL_DUN_ENABLED:
12862a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        transitionTo(mCellDunAliveState);
12872a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
12882a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    default:
12892a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        retValue = false;
12902a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
12912a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
12922a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                return retValue;
12932a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
12942a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
1295d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt        class CellDunRequestedState extends TetherMasterUtilState {
12962a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
12972a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
1298c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                mUseHiPri = (findActiveUpstreamIface() == null && !mDunRequired);
1299c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                if (mDunRequired || mUseHiPri) {
1300c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    ++mSequenceNumber;
1301c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    int result = turnOnMobileDun();
1302c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    switch (result) {
1303c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                        case Phone.APN_ALREADY_ACTIVE:
1304c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            Log.d(TAG, "Dun already active");
1305c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            sendMessage(obtainMessage(CMD_CELL_DUN_ENABLED));
1306c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            break;
1307c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                        case Phone.APN_REQUEST_FAILED:
1308c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                        case Phone.APN_TYPE_NOT_AVAILABLE:
1309c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            Log.d(TAG, "Error bringing up Dun connection");
1310c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            Message m = obtainMessage(CMD_CELL_DUN_TIMEOUT);
1311c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            m.arg1 = mSequenceNumber;
1312c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            sendMessage(m);
1313c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            break;
1314c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                        case Phone.APN_REQUEST_STARTED:
1315c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            Log.d(TAG, "Started bringing up Dun connection");
1316c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            m = obtainMessage(CMD_CELL_DUN_TIMEOUT);
1317c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            m.arg1 = mSequenceNumber;
1318c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            sendMessageDelayed(m, CELL_DUN_TIMEOUT_MS);
1319c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            break;
1320c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                        default:
1321c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                            Log.e(TAG, "Unknown return value from startUsingNetworkFeature " +
1322c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                    result);
1323c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    }
1324c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                } else {
1325c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    Log.d(TAG, "no Dun Required.  Skipping to Active");
1326c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    sendMessage(obtainMessage(CMD_CELL_DUN_ENABLED));
13272a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
13282a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
13292a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
13302a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
13312a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public boolean processMessage(Message message) {
13322a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.d(TAG, "CellDunRequestedState.processMessage what=" + message.what);
13332a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                boolean retValue = true;
13342a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                switch (message.what) {
13352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_MODE_REQUESTED:
13362a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
13372a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        mNotifyList.add(who);
13382a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
13392a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_MODE_UNREQUESTED:
13402a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        who = (TetherInterfaceSM)message.obj;
13412a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        int index = mNotifyList.indexOf(who);
13422a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        if (index != -1) {
13432a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            mNotifyList.remove(index);
13442a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            if (mNotifyList.isEmpty()) {
1345c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                if (mDunRequired || mUseHiPri) {
1346c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                    turnOffMobileDun();
1347c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                }
1348d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                                transitionTo(mInitialState);
13492a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            }
13502a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        }
13512a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
13522a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_CELL_DUN_ENABLED:
1353d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                        turnOnMasterTetherSettings();
13542a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
13552a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_CELL_DUN_DISABLED:
13562a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
13572a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_CELL_DUN_TIMEOUT:
13582a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        if (message.arg1 == mSequenceNumber) {
13592a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            transitionTo(mCellDunErrorState);
13602a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        }
13612a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
13622a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    default:
13632a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        retValue = false;
13642a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
13652a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
13662a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                return retValue;
13672a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
13682a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
13692a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
1370d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt        class CellDunAliveState extends TetherMasterUtilState {
13712a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
13722a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
137365ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                Log.d(TAG, "renewing Dun in " + CELL_DUN_RENEW_MS + "ms");
13742a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS);
13752a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
13762a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
13772a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
13782a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public boolean processMessage(Message message) {
13792a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.d(TAG, "CellDunAliveState.processMessage what=" + message.what);
13802a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                boolean retValue = true;
13812a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                switch (message.what) {
13822a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_MODE_REQUESTED:
13832a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
13842a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        mNotifyList.add(who);
1385d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                        turnOnMasterTetherSettings();
13862a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
13872a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_MODE_UNREQUESTED:
13882a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        who = (TetherInterfaceSM)message.obj;
13892a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        int index = mNotifyList.indexOf(who);
13902a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        if (index != -1) {
13912a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            mNotifyList.remove(index);
13922a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            if (mNotifyList.isEmpty()) {
1393c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                if (mDunRequired || mUseHiPri) {
1394c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                    turnOffMobileDun();
1395c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                }
1396d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                                transitionTo(mInitialState);
13972a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            }
13982a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        }
13992a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
14002a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_CELL_DUN_DISABLED:
14012a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        transitionTo(mInitialState);
14022a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
14032a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_CELL_DUN_RENEW:
140465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        Log.d(TAG, "renewing dun connection - requeuing for another " +
140565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                                CELL_DUN_RENEW_MS + "ms");
1406d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                        turnOnMobileDun();
14072a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS);
14082a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
14092a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    default:
14102a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        retValue = false;
14112a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
14122a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
14132a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                return retValue;
14142a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
14152a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
14162a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
1417d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt        class TetherModeAliveState extends TetherMasterUtilState {
14182a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
14192a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
1420c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                if (mDunRequired || mUseHiPri) {
1421c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    Log.d(TAG, "renewing Dun in " + CELL_DUN_RENEW_MS + "ms");
1422c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS);
1423c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                }
1424c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                mUpstreamIfaceName = findActiveUpstreamIface();
1425c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                if (mUpstreamIfaceName == null) {
1426c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    Log.d(TAG, "Erroring our of tether - no upstream ifaces available");
1427c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    sendMessage(obtainMessage(CMD_CELL_DUN_DISABLED));
1428c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                } else {
1429c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    for (Object o : mNotifyList) {
1430c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                        TetherInterfaceSM sm = (TetherInterfaceSM)o;
1431c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                        sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_TETHER_MODE_ALIVE));
1432c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                    }
14332a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
14342a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
14352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
14362a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public boolean processMessage(Message message) {
14372a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what);
14382a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                boolean retValue = true;
14392a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                switch (message.what) {
14402a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_MODE_REQUESTED:
14412a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
14422a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        mNotifyList.add(who);
14432a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        who.sendMessage(who.obtainMessage(TetherInterfaceSM.CMD_TETHER_MODE_ALIVE));
14442a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
14452a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_MODE_UNREQUESTED:
14462a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        who = (TetherInterfaceSM)message.obj;
14472a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        int index = mNotifyList.indexOf(who);
14482a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        if (index != -1) {
14492a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            mNotifyList.remove(index);
14502a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            if (mNotifyList.isEmpty()) {
1451c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                if (mDunRequired || mUseHiPri) {
1452c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                    turnOffMobileDun();
1453c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                }
1454d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                                turnOffMasterTetherSettings(); // transitions appropriately
1455c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                                mUpstreamIfaceName = null;
14562a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            }
14572a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        }
14582a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
14592a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_CELL_DUN_DISABLED:
14602a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        int size = mNotifyList.size();
14612a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        for (int i = 0; i < size; i++) {
14622a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            TetherInterfaceSM sm = (TetherInterfaceSM)mNotifyList.get(i);
14632a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            mNotifyList.remove(i);
14642a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                            sm.sendMessage(sm.obtainMessage(
14652a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                                    TetherInterfaceSM.CMD_TETHER_MODE_DEAD));
14662a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        }
1467d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                        turnOffMasterTetherSettings(); // transitions appropriately
1468c9d5fb7c95f158d9a31d534895373afcfad77806Robert Greenwalt                        mUpstreamIfaceName = null;
14692a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
147065ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                    case CMD_CELL_DUN_RENEW:
147165ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        Log.d(TAG, "renewing dun connection - requeuing for another " +
147265ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                                CELL_DUN_RENEW_MS + "ms");
1473d70a3d4e2d356aab4cac313f1f9d8272a5e3e8d0Robert Greenwalt                        turnOnMobileDun();
147465ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS);
147565ae29bd852ff468ad003af241d5177fe016c74aRobert Greenwalt                        break;
14762a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    default:
14772a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                       retValue = false;
14782a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                       break;
14792a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
14802a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                return retValue;
14812a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
14822a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
14832a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
14842a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class ErrorState extends HierarchicalState {
14852a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            int mErrorNotification;
14862a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
14872a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public boolean processMessage(Message message) {
14882a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                boolean retValue = true;
14892a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                switch (message.what) {
14902a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    case CMD_TETHER_MODE_REQUESTED:
14912a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
14922a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        who.sendMessage(who.obtainMessage(mErrorNotification));
14932a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        break;
14942a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    default:
14952a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                       retValue = false;
14962a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
14972a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                return retValue;
14982a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
14992a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            void notify(int msgType) {
15002a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                mErrorNotification = msgType;
15012a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                for (Object o : mNotifyList) {
15022a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    TetherInterfaceSM sm = (TetherInterfaceSM)o;
15032a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    sm.sendMessage(sm.obtainMessage(msgType));
15042a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                }
15052a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
15062a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
15072a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
15082a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class CellDunErrorState extends ErrorState {
15092a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
15102a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
15112a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.e(TAG, "Error trying to enable Cell DUN");
15122a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                notify(TetherInterfaceSM.CMD_CELL_DUN_ERROR);
15132a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
15142a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
15152a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
15162a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class SetIpForwardingEnabledErrorState extends ErrorState {
15172a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
15182a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
15192a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.e(TAG, "Error in setIpForwardingEnabled");
15202a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                notify(TetherInterfaceSM.CMD_IP_FORWARDING_ENABLE_ERROR);
15212a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
15222a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
15232a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
15242a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class SetIpForwardingDisabledErrorState extends ErrorState {
15252a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
15262a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
15272a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.e(TAG, "Error in setIpForwardingDisabled");
15282a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                notify(TetherInterfaceSM.CMD_IP_FORWARDING_DISABLE_ERROR);
15292a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
15302a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
15312a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
15322a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class StartTetheringErrorState extends ErrorState {
15332a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
15342a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
15352a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.e(TAG, "Error in startTethering");
15362a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                notify(TetherInterfaceSM.CMD_START_TETHERING_ERROR);
15372a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
15382a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                INetworkManagementService service =
15392a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        INetworkManagementService.Stub.asInterface(b);
15402a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                try {
15412a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    service.setIpForwardingEnabled(false);
15422a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                } catch (Exception e) {}
15432a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
15442a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
15452a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
15462a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class StopTetheringErrorState extends ErrorState {
15472a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
15482a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
15492a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.e(TAG, "Error in stopTethering");
15502a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                notify(TetherInterfaceSM.CMD_STOP_TETHERING_ERROR);
15512a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
15522a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                INetworkManagementService service =
15532a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                         INetworkManagementService.Stub.asInterface(b);
15542a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                try {
15552a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    service.setIpForwardingEnabled(false);
15562a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                } catch (Exception e) {}
15572a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
15582a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
15592a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
15602a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        class SetDnsForwardersErrorState extends ErrorState {
15612a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            @Override
15622a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            public void enter() {
15632a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                Log.e(TAG, "Error in setDnsForwarders");
15642a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                notify(TetherInterfaceSM.CMD_SET_DNS_FORWARDERS_ERROR);
15652a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
15662a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                INetworkManagementService service =
15672a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                        INetworkManagementService.Stub.asInterface(b);
15682a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                try {
15692a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    service.stopTethering();
15702a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                } catch (Exception e) {}
15712a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                try {
15722a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    service.setIpForwardingEnabled(false);
15732a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                } catch (Exception e) {}
15742a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
1575d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
1576d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    }
1577d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt
15782a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
15792a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        if (mContext.checkCallingOrSelfPermission(
15802a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
15812a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            pw.println("Permission Denial: can't dump ConnectivityService.Tether " +
15822a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
15832a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    Binder.getCallingUid());
15842a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                    return;
15852a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        }
15862a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt
15872a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        pw.println();
15882a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        pw.println("Tether state:");
15892a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        synchronized (mIfaces) {
15902a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            for (Object o : mIfaces.values()) {
15912a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt                pw.println(" "+o.toString());
15922a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt            }
1593d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt        }
15942a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        pw.println();
15952a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        return;
1596d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    }
1597d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt}
1598