├── .classpath
├── .gitignore
├── .project
├── AndroidManifest.xml
├── README.md
├── assets
└── sample_file.txt
├── project.properties
├── res
├── drawable-hdpi
│ ├── ic_action_discover.png
│ ├── ic_action_on_off.png
│ ├── ic_launcher.png
│ └── icon.png
├── drawable-ldpi
│ ├── ic_action_discover.png
│ ├── ic_action_on_off.png
│ ├── ic_launcher.png
│ └── icon.png
├── drawable-mdpi
│ ├── ic_action_discover.png
│ ├── ic_action_on_off.png
│ ├── ic_launcher.png
│ └── icon.png
├── drawable-xhdpi
│ ├── ic_action_discover.png
│ ├── ic_action_on_off.png
│ └── ic_launcher.png
├── drawable
│ ├── details_view.xml
│ ├── machine.png
│ └── section_header.xml
├── layout-land
│ └── main.xml
├── layout-large
│ └── main.xml
├── layout
│ ├── device_detail.xml
│ ├── device_list.xml
│ ├── main.xml
│ ├── message.xml
│ ├── prompt_password.xml
│ ├── row_devices.xml
│ └── row_peers.xml
├── menu
│ ├── action_items.xml
│ └── message.xml
├── values-w820dp
│ └── dimens.xml
└── values
│ ├── colors.xml
│ ├── dimens.xml
│ └── strings.xml
└── src
└── com
└── ecse414
└── android
└── echo
├── MessageActivity.java
├── WiFiDirectActivity.java
├── config
└── Configuration.java
├── router
├── AllEncompasingP2PClient.java
├── MeshNetworkManager.java
├── Packet.java
├── Receiver.java
├── Sender.java
└── tcp
│ ├── TcpReciever.java
│ └── TcpSender.java
├── ui
├── DeviceDetailFragment.java
├── DeviceListFragment.java
└── PromptPasswordFragment.java
└── wifi
├── WiFiBroadcastReceiver.java
└── WiFiDirectBroadcastReceiver.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | Echo
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
28 |
29 |
33 |
37 | android:launchMode="singleTask" >
38 |
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | echo
2 | ====
3 |
4 | Android Mesh Networking Chat with WiFI-Direct
5 |
6 | Simply build and launch on a Wi-Fi Direct enabled device to become a GO. Open the Group Chat tab. To build, can import this eclipse project and Build As Android Application.
7 |
8 | To connect to the group and have P2P message passing, can use another Wi-Fi Direct enabled device and hit the search icon and then select the other device to connect to it. Or can launch the laptop client. See instructions on the laptop client for how to do that.
9 |
10 | Can get the Wi-Fi password and access point name (SSID) from the logs.
11 |
--------------------------------------------------------------------------------
/assets/sample_file.txt:
--------------------------------------------------------------------------------
1 | This is a sample text file for wifi_direct demo.
2 |
3 | Once the devices are connected, the server i.e. groupOwner will listen for incoming connections and write this file.
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-20
15 |
16 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_action_discover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-hdpi/ic_action_discover.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_action_on_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-hdpi/ic_action_on_off.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/ic_action_discover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-ldpi/ic_action_discover.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/ic_action_on_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-ldpi/ic_action_on_off.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_action_discover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-mdpi/ic_action_discover.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_action_on_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-mdpi/ic_action_on_off.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_action_discover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-xhdpi/ic_action_discover.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_action_on_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-xhdpi/ic_action_on_off.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable/details_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
10 |
15 |
16 |
--------------------------------------------------------------------------------
/res/drawable/machine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Breakend/echo/721b0f520bfcbc3eecf45eb247428616f0e1d42d/res/drawable/machine.png
--------------------------------------------------------------------------------
/res/drawable/section_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
16 |
17 |
--------------------------------------------------------------------------------
/res/layout-land/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
17 |
18 |
19 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/res/layout-large/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
7 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/res/layout/device_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
18 |
19 |
24 |
25 |
30 |
31 |
32 |
36 |
37 |
41 |
42 |
46 |
47 |
51 |
52 |
53 |
61 |
62 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/res/layout/device_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
21 |
22 |
27 |
28 |
34 |
35 |
40 |
41 |
47 |
48 |
55 |
56 |
57 |
58 |
63 |
64 |
69 |
70 |
71 |
72 |
78 |
79 |
85 |
86 |
--------------------------------------------------------------------------------
/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
22 |
23 |
24 |
25 |
26 |
32 |
33 |
--------------------------------------------------------------------------------
/res/layout/message.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
16 |
22 |
23 |
24 |
25 |
26 |
32 |
33 |
--------------------------------------------------------------------------------
/res/layout/prompt_password.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
16 |
17 |
27 |
28 |
--------------------------------------------------------------------------------
/res/layout/row_devices.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
20 |
21 |
27 |
28 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/res/layout/row_peers.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
20 |
21 |
27 |
28 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/res/menu/action_items.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/res/menu/message.xml:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 | 64dp
9 |
10 |
11 |
--------------------------------------------------------------------------------
/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF000000
4 | #FF111111
5 |
6 |
--------------------------------------------------------------------------------
/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | 300dp
20 | 200dp
21 | 16dp
22 | 16dp
23 |
24 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WiFi Direct
5 | P2P On/Off
6 | Discover
7 | Connect
8 | Disconnect
9 | Launch Gallery
10 |
11 | yes
12 | no
13 | This device will act as a client. Click on Gallery button to pick a local(stored) file
14 | No devices found. Turn on P2P and perform discovery from the Action Bar
15 | Enable P2P from action bar button above or system settings
16 | "Am I the Group Owner? "
17 | ME
18 | PEERS
19 | MessageActivity
20 | Hello world!
21 | Settings
22 | Connect
23 | Cancel
24 | Ssid
25 | Group Chat
26 |
27 |
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/MessageActivity.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo;
2 |
3 | import com.ecse414.android.echo.router.AllEncompasingP2PClient;
4 | import com.ecse414.android.echo.router.MeshNetworkManager;
5 | import com.ecse414.android.echo.router.Packet;
6 | import com.ecse414.android.echo.router.Sender;
7 | import com.ecse414.android.echo.wifi.WiFiDirectBroadcastReceiver;
8 | import com.ecse414.android.echo.R;
9 |
10 | import android.app.Activity;
11 | import android.os.Bundle;
12 | import android.view.View;
13 | import android.widget.Button;
14 | import android.widget.EditText;
15 | import android.widget.TextView;
16 |
17 | /**
18 | * Activity for the group chat view
19 | * @author Peter Henderson
20 | *
21 | */
22 | public class MessageActivity extends Activity {
23 | public static AllEncompasingP2PClient RECIPIENT = null;
24 |
25 | private static TextView messageView;
26 |
27 | /**
28 | * Add appropriate listeners on creation
29 | */
30 | @Override
31 | protected void onCreate(Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 | setContentView(R.layout.message);
34 |
35 | messageView = (TextView) findViewById(R.id.message_view);
36 |
37 | final Button button = (Button) findViewById(R.id.btn_send);
38 | final EditText message = (EditText) findViewById(R.id.edit_message);
39 |
40 | this.setTitle("Group Chat");
41 |
42 | button.setOnClickListener(new View.OnClickListener() {
43 | public void onClick(View v) {
44 | String msgStr = message.getText().toString();
45 | addMessage("This phone", msgStr);
46 | message.setText("");
47 |
48 | // Send to other clients as a group chat message
49 | for (AllEncompasingP2PClient c : MeshNetworkManager.routingTable.values()) {
50 | if (c.getMac().equals(MeshNetworkManager.getSelf().getMac()))
51 | continue;
52 | Sender.queuePacket(new Packet(Packet.TYPE.MESSAGE, msgStr.getBytes(), c.getMac(),
53 | WiFiDirectBroadcastReceiver.MAC));
54 | }
55 |
56 | }
57 | });
58 | }
59 |
60 | /**
61 | * Add a message to the view
62 | */
63 | public static void addMessage(String from, String text) {
64 |
65 | messageView.append(from + " says " + text + "\n");
66 | final int scrollAmount = messageView.getLayout().getLineTop(messageView.getLineCount())
67 | - messageView.getHeight();
68 | // if there is no need to scroll, scrollAmount will be <=0
69 | if (scrollAmount > 0)
70 | messageView.scrollTo(0, scrollAmount);
71 | else
72 | messageView.scrollTo(0, 0);
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/WiFiDirectActivity.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo;
2 |
3 | import android.app.Activity;
4 | import android.content.BroadcastReceiver;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.IntentFilter;
8 | import android.net.wifi.WifiConfiguration;
9 | import android.net.wifi.WifiManager;
10 | import android.net.wifi.p2p.WifiP2pConfig;
11 | import android.net.wifi.p2p.WifiP2pDevice;
12 | import android.net.wifi.p2p.WifiP2pManager;
13 | import android.net.wifi.p2p.WifiP2pManager.ActionListener;
14 | import android.net.wifi.p2p.WifiP2pManager.Channel;
15 | import android.net.wifi.p2p.WifiP2pManager.ChannelListener;
16 | import android.os.Bundle;
17 | import android.provider.Settings;
18 | import android.util.Log;
19 | import android.view.Menu;
20 | import android.view.MenuInflater;
21 | import android.view.MenuItem;
22 | import android.view.View;
23 | import android.widget.Button;
24 | import android.widget.Toast;
25 |
26 | import com.ecse414.android.echo.config.Configuration;
27 | import com.ecse414.android.echo.ui.DeviceDetailFragment;
28 | import com.ecse414.android.echo.ui.DeviceListFragment;
29 | import com.ecse414.android.echo.ui.PromptPasswordFragment;
30 | import com.ecse414.android.echo.ui.DeviceListFragment.DeviceActionListener;
31 | import com.ecse414.android.echo.wifi.WiFiBroadcastReceiver;
32 | import com.ecse414.android.echo.wifi.WiFiDirectBroadcastReceiver;
33 | import com.ecse414.android.echo.R;
34 |
35 | /**
36 | * An activity that uses WiFi Direct APIs to discover and connect with available
37 | * devices. WiFi Direct APIs are asynchronous and rely on callback mechanism
38 | * using interfaces to notify the application of operation success or failure.
39 | * The application should also register a BroadcastReceiver for notification of
40 | * WiFi state related events.
41 | *
42 | * Note: much of this is taken from the Wi-Fi P2P example
43 | */
44 | public class WiFiDirectActivity extends Activity implements ChannelListener, DeviceActionListener {
45 |
46 | public static final String TAG = "wifidirectdemo";
47 | private WifiP2pManager manager;
48 | private boolean isWifiP2pEnabled = false;
49 | private boolean retryChannel = false;
50 |
51 | private final IntentFilter intentFilter = new IntentFilter();
52 | private final IntentFilter wifiIntentFilter = new IntentFilter();
53 | private Channel channel;
54 | private BroadcastReceiver receiver = null;
55 |
56 | WifiManager wifiManager;
57 | WiFiBroadcastReceiver receiverWifi;
58 | private boolean isWifiConnected;
59 |
60 | public boolean isVisible = true;
61 |
62 | /**
63 | * @param isWifiP2pEnabled
64 | * the isWifiP2pEnabled to set
65 | */
66 | public void setIsWifiP2pEnabled(boolean isWifiP2pEnabled) {
67 | this.isWifiP2pEnabled = isWifiP2pEnabled;
68 | }
69 |
70 | /**
71 | * On create start running listeners and try Wi-Fi bridging if possible
72 | */
73 | @Override
74 | public void onCreate(Bundle savedInstanceState) {
75 | super.onCreate(savedInstanceState);
76 | setContentView(R.layout.main);
77 |
78 | // add necessary intent values to be matched.
79 | intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
80 | intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
81 | intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
82 | intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
83 |
84 | manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
85 | channel = manager.initialize(this, getMainLooper(), null);
86 |
87 | if (Configuration.isDeviceBridgingEnabled) {
88 | // Initiate wifi service manager
89 | wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
90 |
91 | // Check for wifi is disabled
92 | if (wifiManager.isWifiEnabled() == false) {
93 | // If wifi disabled then enable it
94 | Toast.makeText(getApplicationContext(), "wifi is disabled..making it enabled", Toast.LENGTH_LONG)
95 | .show();
96 | wifiManager.setWifiEnabled(true);
97 | }
98 |
99 | // wifi scaned value broadcast receiver
100 | receiverWifi = new WiFiBroadcastReceiver(wifiManager, this, this.isWifiConnected);
101 |
102 | // Register broadcast receiver
103 | // Broacast receiver will automatically call when number of wifi
104 | // connections changed
105 | wifiIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
106 | wifiIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
107 | wifiIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
108 |
109 | registerReceiver(receiverWifi, wifiIntentFilter);
110 |
111 | /*
112 | * This shouldn't be hard coded, but for our purposes we wanted to
113 | * demonstrate bridging.
114 | */
115 | this.connectToAccessPoint("DIRECT-Sq-Android_ca89", "c5umx0mw");
116 | // connectToAccessPoint(String ssid, String passphrase)
117 | }
118 |
119 | final Button button = (Button) findViewById(R.id.btn_switch);
120 | button.setOnClickListener(new View.OnClickListener() {
121 | public void onClick(View v) {
122 | Intent i = new Intent(getApplicationContext(), MessageActivity.class);
123 | startActivity(i);
124 | }
125 | });
126 |
127 | }
128 |
129 | /** register the BroadcastReceiver with the intent values to be matched */
130 | @Override
131 | public void onResume() {
132 | super.onResume();
133 | receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
134 | registerReceiver(receiver, intentFilter);
135 | this.isVisible = true;
136 | }
137 |
138 | @Override
139 | public void onPause() {
140 | super.onPause();
141 | unregisterReceiver(receiver);
142 | this.isVisible = false;
143 | }
144 |
145 | /**
146 | * Remove all peers and clear all fields. This is called on
147 | * BroadcastReceiver receiving a state change event.
148 | */
149 | public void resetData() {
150 | DeviceListFragment fragmentList = (DeviceListFragment) getFragmentManager().findFragmentById(R.id.frag_list);
151 | DeviceDetailFragment fragmentDetails = (DeviceDetailFragment) getFragmentManager().findFragmentById(
152 | R.id.frag_detail);
153 | if (fragmentList != null) {
154 | fragmentList.clearPeers();
155 | }
156 | if (fragmentDetails != null) {
157 | fragmentDetails.resetViews();
158 | }
159 | }
160 |
161 | @Override
162 | public boolean onCreateOptionsMenu(Menu menu) {
163 | MenuInflater inflater = getMenuInflater();
164 | inflater.inflate(R.menu.action_items, menu);
165 | return true;
166 | }
167 |
168 |
169 | /**
170 | * Peer discover and state transitions based on capabilities
171 | */
172 | @Override
173 | public boolean onOptionsItemSelected(MenuItem item) {
174 | switch (item.getItemId()) {
175 | case R.id.atn_direct_enable:
176 | if (manager != null && channel != null) {
177 |
178 | // Since this is the system wireless settings activity, it's
179 | // not going to send us a result. We will be notified by
180 | // WiFiDeviceBroadcastReceiver instead.
181 |
182 | startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
183 | } else {
184 | Log.e(TAG, "channel or manager is null");
185 | }
186 | return true;
187 |
188 | case R.id.atn_direct_discover:
189 | if (!isWifiP2pEnabled) {
190 | // If p2p not enabled try to connect as a legacy device
191 | wifiManager.startScan();
192 | Toast.makeText(WiFiDirectActivity.this, R.string.p2p_off_warning, Toast.LENGTH_SHORT).show();
193 | return true;
194 | }
195 | final DeviceListFragment fragment = (DeviceListFragment) getFragmentManager().findFragmentById(
196 | R.id.frag_list);
197 | fragment.onInitiateDiscovery();
198 | manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
199 |
200 | @Override
201 | public void onSuccess() {
202 | Toast.makeText(WiFiDirectActivity.this, "Discovery Initiated", Toast.LENGTH_SHORT).show();
203 | }
204 |
205 | @Override
206 | public void onFailure(int reasonCode) {
207 | Toast.makeText(WiFiDirectActivity.this, "Discovery Failed : " + reasonCode, Toast.LENGTH_SHORT)
208 | .show();
209 | }
210 | });
211 | return true;
212 | default:
213 | return super.onOptionsItemSelected(item);
214 | }
215 | }
216 |
217 | @Override
218 | public void showDetails(WifiP2pDevice device) {
219 | DeviceDetailFragment fragment = (DeviceDetailFragment) getFragmentManager().findFragmentById(R.id.frag_detail);
220 | fragment.showDetails(device);
221 | }
222 |
223 | /**
224 | * Try to connect through a callback to a given device
225 | */
226 | @Override
227 | public void connect(WifiP2pConfig config) {
228 | manager.connect(channel, config, new ActionListener() {
229 |
230 | @Override
231 | public void onSuccess() {
232 | // WiFiDirectBroadcastReceiver will notify us. Ignore for now.
233 | }
234 |
235 | @Override
236 | public void onFailure(int reason) {
237 | Toast.makeText(WiFiDirectActivity.this, "Connect failed. Retry.", Toast.LENGTH_SHORT).show();
238 | }
239 | });
240 | }
241 |
242 | @Override
243 | public void disconnect() {
244 | // TODO: again here it should also include the other wifi hotspot thing
245 | final DeviceDetailFragment fragment = (DeviceDetailFragment) getFragmentManager().findFragmentById(
246 | R.id.frag_detail);
247 | fragment.resetViews();
248 | manager.removeGroup(channel, new ActionListener() {
249 |
250 | @Override
251 | public void onFailure(int reasonCode) {
252 | Log.d(TAG, "Disconnect failed. Reason :" + reasonCode);
253 |
254 | }
255 |
256 | @Override
257 | public void onSuccess() {
258 | fragment.getView().setVisibility(View.GONE);
259 | }
260 |
261 | });
262 | }
263 |
264 | @Override
265 | public void onChannelDisconnected() {
266 | // we will try once more
267 | if (manager != null && !retryChannel) {
268 | Toast.makeText(this, "Channel lost. Trying again", Toast.LENGTH_LONG).show();
269 | resetData();
270 | retryChannel = true;
271 | manager.initialize(this, getMainLooper(), this);
272 | } else {
273 | Toast.makeText(this, "Severe! Channel is probably lost premanently. Try Disable/Re-Enable P2P.",
274 | Toast.LENGTH_LONG).show();
275 | }
276 | }
277 |
278 | @Override
279 | public void cancelDisconnect() {
280 |
281 | /*
282 | * A cancel abort request by user. Disconnect i.e. removeGroup if
283 | * already connected. Else, request WifiP2pManager to abort the ongoing
284 | * request
285 | */
286 | if (manager != null) {
287 | final DeviceListFragment fragment = (DeviceListFragment) getFragmentManager().findFragmentById(
288 | R.id.frag_list);
289 | if (fragment.getDevice() == null || fragment.getDevice().status == WifiP2pDevice.CONNECTED) {
290 | disconnect();
291 | } else if (fragment.getDevice().status == WifiP2pDevice.AVAILABLE
292 | || fragment.getDevice().status == WifiP2pDevice.INVITED) {
293 |
294 | manager.cancelConnect(channel, new ActionListener() {
295 |
296 | @Override
297 | public void onSuccess() {
298 | Toast.makeText(WiFiDirectActivity.this, "Aborting connection", Toast.LENGTH_SHORT).show();
299 | }
300 |
301 | @Override
302 | public void onFailure(int reasonCode) {
303 | Toast.makeText(WiFiDirectActivity.this,
304 | "Connect abort request failed. Reason Code: " + reasonCode, Toast.LENGTH_SHORT).show();
305 | }
306 | });
307 | }
308 | }
309 |
310 | }
311 |
312 | public void displayConnectDialog(String ssid) {
313 |
314 | PromptPasswordFragment ppf = new PromptPasswordFragment(this, ssid);
315 | ppf.show(this.getFragmentManager(), ppf.getTag());
316 |
317 | }
318 |
319 | public void connectToAccessPoint(String ssid, String passphrase) {
320 |
321 | Log.d(WiFiDirectActivity.TAG, "Trying to connect to AP : (" + ssid + "," + passphrase + ")");
322 |
323 | WifiConfiguration wc = new WifiConfiguration();
324 | wc.SSID = "\"" + ssid + "\"";
325 | wc.preSharedKey = "\"" + passphrase + "\""; // "\""+passphrase+"\"";
326 | wc.status = WifiConfiguration.Status.ENABLED;
327 | wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
328 | wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
329 | wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
330 | wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
331 | wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
332 | wc.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
333 | // connect to and enable the connection
334 | int netId = wifiManager.addNetwork(wc);
335 | wifiManager.enableNetwork(netId, true);
336 | wifiManager.setWifiEnabled(true);
337 |
338 | Log.d(WiFiDirectActivity.TAG, "Connected? ip = " + wifiManager.getConnectionInfo().getIpAddress());
339 | Log.d(WiFiDirectActivity.TAG, "Connected? bssid = " + wifiManager.getConnectionInfo().getBSSID());
340 | Log.d(WiFiDirectActivity.TAG, "Connected? ssid = " + wifiManager.getConnectionInfo().getSSID());
341 |
342 | if (wifiManager.getConnectionInfo().getIpAddress() != 0) {
343 | this.isWifiConnected = true;
344 | Toast.makeText(this, "Connected!!! ip = " + wifiManager.getConnectionInfo().getIpAddress(),
345 | Toast.LENGTH_LONG).show();
346 | } else {
347 | Toast.makeText(
348 | this,
349 | "WiFi AP connection failed... ip = " + wifiManager.getConnectionInfo().getIpAddress() + "(" + ssid
350 | + "," + passphrase + ")", Toast.LENGTH_LONG).show();
351 | }
352 |
353 | }
354 | }
355 |
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/config/Configuration.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo.config;
2 |
3 | /**
4 | * Contains configuration settings related to the WiFi Direct implementation
5 | * @author Peter Henderson
6 | *
7 | */
8 | public class Configuration {
9 | /**
10 | * The default ports that all clients receive at
11 | */
12 | public static final int RECEIVE_PORT = 8888;
13 |
14 | /**
15 | * The default GO IP address for initial connections
16 | */
17 | public static final String GO_IP = "192.168.49.1";
18 |
19 | /**
20 | * This only works on certain devices where multiple simultaneous
21 | * connections are available (infrastructure & ad-hoc) (multiroll)
22 | */
23 | public static final boolean isDeviceBridgingEnabled = false;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/router/AllEncompasingP2PClient.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo.router;
2 |
3 | /**
4 | * This is an alternative representation the Android P2P library's WiFiP2PDevice class
5 | * it contains information about any client connected to the mesh and is stored in
6 | * the routing table
7 | *
8 | * @author Peter Henderson
9 | *
10 | */
11 | public class AllEncompasingP2PClient {
12 |
13 | /**
14 | * The client's mac address
15 | */
16 | private String mac;
17 |
18 | /**
19 | * The client's name (i.e. Joe)
20 | */
21 | private String name;
22 |
23 | /**
24 | * The client's GO mac address, for routing
25 | */
26 | private String groupOwnerMac;
27 |
28 | /**
29 | * The client's IP address
30 | */
31 | private String ip;
32 |
33 | /**
34 | * Whether it is a direct link or not, this could help with making routing more efficient
35 | */
36 | private boolean isDirectLink;
37 |
38 | /**
39 | * Constructor
40 | */
41 | public AllEncompasingP2PClient(String mac_address, String ip, String name, String groupOwner) {
42 | this.setMac(mac_address);
43 | this.setName(name);
44 | this.setIp(ip);
45 | this.setGroupOwnerMac(groupOwner);
46 | this.isDirectLink = true;
47 | }
48 |
49 | /**
50 | * Change this if we don't have a direct link
51 | *
52 | * @param d
53 | */
54 | public void setIsDirectLink(boolean d) {
55 | this.isDirectLink = d;
56 | }
57 |
58 | /**
59 | * Get if have a direct link to this client from the current running client
60 | * @return
61 | */
62 | public boolean getIsDirectLink() {
63 | return this.isDirectLink;
64 | }
65 |
66 | /**
67 | * Get GO MAC
68 | * @return
69 | */
70 | public String getGroupOwnerMac() {
71 | return groupOwnerMac;
72 | }
73 |
74 | /**
75 | * Set GO MAC
76 | * @param groupOwnerMac
77 | */
78 | public void setGroupOwnerMac(String groupOwnerMac) {
79 | this.groupOwnerMac = groupOwnerMac;
80 | }
81 |
82 | /**
83 | * Get the client's name
84 | * Note: here we don't currently use this so much, and just refer to client's as MAC addresses
85 | * @return
86 | */
87 | public String getName() {
88 | return name;
89 | }
90 |
91 | /**
92 | * Set a client's name (like a nickname or something for future use)
93 | * @param name
94 | */
95 | public void setName(String name) {
96 | this.name = name;
97 | }
98 |
99 | /**
100 | * Get the client's mac address
101 | * @return
102 | */
103 | public String getMac() {
104 | return mac;
105 | }
106 |
107 | /**
108 | * Set the client's mac address
109 | * @param mac
110 | */
111 | public void setMac(String mac) {
112 | this.mac = mac;
113 | }
114 |
115 | /**
116 | * Get the client's IP as a string
117 | * (i.e. 124.12.124.15)
118 | * @return
119 | */
120 | public String getIp() {
121 | return ip;
122 | }
123 |
124 | /**
125 | * Set the client's IP as a string
126 | * @param ip
127 | */
128 | public void setIp(String ip) {
129 | this.ip = ip;
130 | }
131 |
132 | /**
133 | * Serialize this client's information into a comma delimited form
134 | */
135 | @Override
136 | public String toString() {
137 | return getIp() + "," + getMac() + "," + getName() + "," + getGroupOwnerMac();
138 | }
139 |
140 | /**
141 | * Generate a client object from a serializerd string
142 | * @param serialized
143 | * @return
144 | */
145 | public static AllEncompasingP2PClient fromString(String serialized) {
146 | String[] divided = serialized.split(",");
147 | return new AllEncompasingP2PClient(divided[1], divided[0], divided[2], divided[3]);
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/router/MeshNetworkManager.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo.router;
2 |
3 | import java.util.concurrent.ConcurrentHashMap;
4 |
5 | import com.ecse414.android.echo.config.Configuration;
6 |
7 | /**
8 | * A manager for keeping track of a mesh and handling routing
9 | *
10 | * @author Peter Henderson
11 | *
12 | */
13 | public class MeshNetworkManager {
14 | /**
15 | * Your routing table
16 | */
17 | public static ConcurrentHashMap routingTable = new ConcurrentHashMap();
18 |
19 | /**
20 | * Need to know yourself
21 | */
22 | private static AllEncompasingP2PClient self;
23 |
24 | /**
25 | * Introduce a new client into the routing table
26 | * @param c
27 | */
28 | public static void newClient(AllEncompasingP2PClient c) {
29 | routingTable.put(c.getMac(), c);
30 | }
31 |
32 | /**
33 | * A client has left the routing table
34 | * @param c
35 | */
36 | public static void clientGone(AllEncompasingP2PClient c) {
37 | routingTable.remove(c.getMac());
38 | }
39 |
40 | /**
41 | * Get yourself
42 | * @return
43 | */
44 | public static AllEncompasingP2PClient getSelf() {
45 | return self;
46 | }
47 |
48 | /**
49 | * Set yourself
50 | * @param self
51 | */
52 | public static void setSelf(AllEncompasingP2PClient self) {
53 | MeshNetworkManager.self = self;
54 | newClient(self);
55 | }
56 |
57 | /**
58 | * Either returns the IP in the current net if on the same one, or sends to
59 | * the relevant Group Owner or sends to all group owners if group owner not
60 | * in mesh
61 | *
62 | * @param c
63 | */
64 | public static String getIPForClient(AllEncompasingP2PClient c) {
65 |
66 | /*
67 | * This is part of the same Group so its okay to use its IP
68 | */
69 | if (self.getGroupOwnerMac() == c.getGroupOwnerMac()) {
70 | // share the same GO then just give its IP
71 | System.out.println("Have the same group owner, sending to :" + c.getIp());
72 | return c.getIp();
73 | }
74 |
75 | AllEncompasingP2PClient go = routingTable.get(c.getGroupOwnerMac());
76 |
77 |
78 | // I am the group owner so can propagate
79 | if (self.getGroupOwnerMac() == self.getMac()) {
80 | if (self.getGroupOwnerMac() != c.getGroupOwnerMac() && go.getIsDirectLink()) {
81 | // not the same group owner, but we have the group owner as a
82 | // direct link
83 | return c.getIp();
84 | } else if (go != null && self.getGroupOwnerMac() != c.getGroupOwnerMac() && !go.getIsDirectLink()) {
85 | for(AllEncompasingP2PClient aclient : routingTable.values()){
86 | if(aclient.getGroupOwnerMac().equals(aclient.getMac())){
87 | //try sending it to a random group owner
88 | //can also expand this to all group owners
89 | return aclient.getIp();
90 | }
91 | }
92 | //no other group owners, don't know who to send it to
93 | return "0.0.0.0";
94 | }
95 | } else if (go != null) { // I am not the group owner - need to sent it to my GO
96 | return Configuration.GO_IP;
97 | }
98 |
99 | //Will drop the packet
100 | return "0.0.0.0";
101 |
102 | }
103 |
104 | /**
105 | * Serialize the routing table, one serialized AllEncompasingP2PClient per line
106 | * @return
107 | */
108 | public static byte[] serializeRoutingTable() {
109 | StringBuilder serialized = new StringBuilder();
110 |
111 | for (AllEncompasingP2PClient v : routingTable.values()) {
112 | serialized.append(v.toString());
113 | serialized.append("\n");
114 | }
115 |
116 | return serialized.toString().getBytes();
117 | }
118 |
119 | /**
120 | * De serialize a routing table and populate the existing one with the data
121 | * @param rtable
122 | */
123 | public static void deserializeRoutingTableAndAdd(byte[] rtable) {
124 | String rstring = new String(rtable);
125 |
126 | String[] div = rstring.split("\n");
127 | for (String s : div) {
128 | AllEncompasingP2PClient a = AllEncompasingP2PClient.fromString(s);
129 | routingTable.put(a.getMac(), a);
130 | }
131 | }
132 |
133 | /**
134 | * Either returns the IP in the current net if on the same one, or sends to
135 | * the relevant Group Owner or sends to all group owners if group owner not
136 | * in mesh
137 | *
138 | * @param c
139 | */
140 | public static String getIPForClient(String mac) {
141 |
142 | AllEncompasingP2PClient c = routingTable.get(mac);
143 | if (c == null) {
144 | System.out.println("NULL ENTRY in ROUTING TABLE FOR MAC");
145 | return Configuration.GO_IP;
146 | }
147 |
148 | return getIPForClient(c);
149 |
150 | }
151 |
152 | }
153 |
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/router/Packet.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo.router;
2 |
3 | /**
4 | * The echo packet structure
5 | * @author Peter Henderson
6 | *
7 | */
8 | public class Packet {
9 |
10 | /**
11 | * Different types of echo packets
12 | * @author Peter Henderson
13 | *
14 | */
15 | public enum TYPE {
16 | HELLO, HELLO_ACK, BYE, MESSAGE, UPDATE
17 | };
18 |
19 | private byte[] data;
20 | private Packet.TYPE type;
21 | private String receiverMac;
22 | private String senderMac;
23 | private String senderIP;
24 | private int ttl;
25 |
26 | /**
27 | * constructor default TTL (3)
28 | * @param type
29 | * @param extraData
30 | * @param receiverMac
31 | * @param senderMac
32 | */
33 | public Packet(Packet.TYPE type, byte[] extraData, String receiverMac, String senderMac) {
34 | this.setData(extraData);
35 | this.setType(type);
36 | this.receiverMac = receiverMac;
37 | this.setTtl(3);
38 | if (receiverMac == null)
39 | this.receiverMac = "00:00:00:00:00:00";
40 | this.senderMac = senderMac;
41 | }
42 |
43 | /**
44 | * constructor custom ttl
45 | * @param type2
46 | * @param eData
47 | * @param receivermac
48 | * @param senderMac
49 | * @param timetolive
50 | */
51 | public Packet(TYPE type2, byte[] eData, String receivermac, String senderMac, int timetolive) {
52 | this.setData(eData);
53 | this.setType(type2);
54 | this.receiverMac = receivermac;
55 | if (receiverMac == null)
56 | this.receiverMac = "00:00:00:00:00:00";
57 | this.senderMac = senderMac;
58 | this.ttl = timetolive;
59 | }
60 |
61 | /**
62 | * get the data (message body)
63 | * @return
64 | */
65 | public byte[] getData() {
66 | return data;
67 | }
68 |
69 | /**
70 | * set the data (message body)
71 | * @param data
72 | */
73 | public void setData(byte[] data) {
74 | this.data = data;
75 | }
76 |
77 | /**
78 | * the type of packet
79 | * @return
80 | */
81 | public Packet.TYPE getType() {
82 | return type;
83 | }
84 |
85 | /**
86 | * set the type of packets
87 | * @param type
88 | */
89 | public void setType(Packet.TYPE type) {
90 | this.type = type;
91 | }
92 |
93 | /**
94 | * Helper function to get a mac address string as bytes
95 | * @param maca
96 | * @return
97 | */
98 | public static byte[] getMacAsBytes(String maca) {
99 | String[] mac = maca.split(":");
100 | byte[] macAddress = new byte[6]; // mac.length == 6 bytes
101 | for (int i = 0; i < mac.length; i++) {
102 | macAddress[i] = Integer.decode("0x" + mac[i]).byteValue();
103 | }
104 | return macAddress;
105 | }
106 |
107 | /**
108 | * Helper function to get a byte array of data with an
109 | * offset and use the next six bytes to make a MAC address string
110 | * @param data
111 | * @param startOffset
112 | * @return
113 | */
114 | public static String getMacBytesAsString(byte[] data, int startOffset) {
115 | StringBuilder sb = new StringBuilder(18);
116 | for (int i = startOffset; i < startOffset + 6; i++) {
117 | byte b = data[i];
118 | if (sb.length() > 0)
119 | sb.append(':');
120 | sb.append(String.format("%02x", b));
121 | }
122 | return sb.toString();
123 | }
124 |
125 | /**
126 | * Serialize a packet according to the predefined structure
127 | * @return
128 | */
129 | public byte[] serialize() {
130 |
131 | // 6 bytes for mac
132 | byte[] serialized = new byte[1 + data.length + 13];
133 | serialized[0] = (byte) type.ordinal();
134 |
135 | serialized[1] = (byte) ttl;
136 |
137 | byte[] mac = getMacAsBytes(this.receiverMac);
138 |
139 | for (int i = 2; i <= 7; i++) {
140 | serialized[i] = mac[i - 2];
141 | }
142 | mac = getMacAsBytes(this.senderMac);
143 |
144 | for (int i = 8; i <= 13; i++) {
145 | serialized[i] = mac[i - 8];
146 | }
147 | for (int i = 14; i < serialized.length; i++) {
148 | serialized[i] = data[i - 14];
149 | }
150 | return serialized;
151 | }
152 |
153 | /**
154 | * Deserialize a packet according to a predefined structure
155 | * @param inputData
156 | * @return
157 | */
158 | public static Packet deserialize(byte[] inputData) {
159 | Packet.TYPE type = TYPE.values()[(int) inputData[0]];
160 |
161 | byte[] data = new byte[inputData.length - 14];
162 | int timetolive = (int) inputData[1];
163 | String mac = getMacBytesAsString(inputData, 2);
164 | String receivermac = getMacBytesAsString(inputData, 8);
165 |
166 | for (int i = 14; i < inputData.length; i++) {
167 | data[i - 14] = inputData[i];
168 | }
169 | return new Packet(type, data, mac, receivermac, timetolive);
170 | }
171 |
172 | /**
173 | * Get the receivers mac
174 | * @return
175 | */
176 | public String getMac() {
177 | return receiverMac;
178 | }
179 |
180 | /**
181 | * Set the receivers mac
182 | * @param mac
183 | */
184 | public void setMac(String mac) {
185 | this.receiverMac = mac;
186 | }
187 |
188 | /**
189 | * Get the sender's MAC
190 | * @return
191 | */
192 | public String getSenderMac() {
193 | return this.senderMac;
194 | }
195 |
196 | /**
197 | * get the sender's IP
198 | * @return
199 | */
200 | public String getSenderIP() {
201 | return senderIP;
202 | }
203 |
204 | /**
205 | * Set the sender's IP
206 | * @param senderIP
207 | */
208 | public void setSenderIP(String senderIP) {
209 | this.senderIP = senderIP;
210 | }
211 |
212 | /**
213 | * Stringify a packet
214 | */
215 | @Override
216 | public String toString() {
217 | return "Type" + getType().toString() + "receiver:" + getMac() + "sender:" + getSenderMac();
218 | }
219 |
220 | /**
221 | * Get the TTL
222 | * @return
223 | */
224 | public int getTtl() {
225 | return ttl;
226 | }
227 |
228 | /**
229 | * Set the TTL
230 | * @param ttl
231 | */
232 | public void setTtl(int ttl) {
233 | this.ttl = ttl;
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/router/Receiver.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo.router;
2 |
3 | import java.util.concurrent.ConcurrentLinkedQueue;
4 |
5 | import com.ecse414.android.echo.MessageActivity;
6 | import com.ecse414.android.echo.WiFiDirectActivity;
7 | import com.ecse414.android.echo.config.Configuration;
8 | import com.ecse414.android.echo.router.tcp.TcpReciever;
9 | import com.ecse414.android.echo.ui.DeviceDetailFragment;
10 |
11 | import android.widget.Toast;
12 |
13 | /**
14 | * The main receiver class
15 | * @author Matthew Vertescher
16 | * @author Peter Henderson
17 | */
18 | public class Receiver implements Runnable {
19 |
20 | /**
21 | * Flag if the receiver has been running to prevent overzealous thread spawning
22 | */
23 | public static boolean running = false;
24 |
25 | /**
26 | * A ref to the activity
27 | */
28 | static WiFiDirectActivity activity;
29 |
30 | /**
31 | * Constructor with activity
32 | * @param a
33 | */
34 | public Receiver(WiFiDirectActivity a) {
35 | Receiver.activity = a;
36 | running = true;
37 | }
38 |
39 | /**
40 | * Main thread runner
41 | */
42 | public void run() {
43 | /*
44 | * A queue for received packets
45 | */
46 | ConcurrentLinkedQueue packetQueue = new ConcurrentLinkedQueue();
47 |
48 | /*
49 | * Receiver thread
50 | */
51 | new Thread(new TcpReciever(Configuration.RECEIVE_PORT, packetQueue)).start();
52 |
53 | Packet p;
54 |
55 | /*
56 | * Keep going through packets
57 | */
58 | while (true) {
59 | /*
60 | * If the queue is empty, sleep to give up CPU cycles
61 | */
62 | while (packetQueue.isEmpty()) {
63 | try {
64 | Thread.sleep(2000);
65 | } catch (InterruptedException e) {
66 | e.printStackTrace();
67 | }
68 | }
69 |
70 | /*
71 | * Pop a packet off the queue
72 | */
73 | p = packetQueue.remove();
74 |
75 |
76 | /*
77 | * If it's a hello, this is special and need to go through the connection mechanism for any node receiving this
78 | */
79 | if (p.getType().equals(Packet.TYPE.HELLO)) {
80 | // Put it in your routing table
81 | for (AllEncompasingP2PClient c : MeshNetworkManager.routingTable.values()) {
82 | if (c.getMac().equals(MeshNetworkManager.getSelf().getMac()) || c.getMac().equals(p.getSenderMac()))
83 | continue;
84 | Packet update = new Packet(Packet.TYPE.UPDATE, Packet.getMacAsBytes(p.getSenderMac()), c.getMac(),
85 | MeshNetworkManager.getSelf().getMac());
86 | Sender.queuePacket(update);
87 | }
88 |
89 | MeshNetworkManager.routingTable.put(p.getSenderMac(),
90 | new AllEncompasingP2PClient(p.getSenderMac(), p.getSenderIP(), p.getSenderMac(),
91 | MeshNetworkManager.getSelf().getMac()));
92 |
93 | // Send routing table back as HELLO_ACK
94 | byte[] rtable = MeshNetworkManager.serializeRoutingTable();
95 |
96 | Packet ack = new Packet(Packet.TYPE.HELLO_ACK, rtable, p.getSenderMac(), MeshNetworkManager.getSelf()
97 | .getMac());
98 | Sender.queuePacket(ack);
99 | somebodyJoined(p.getSenderMac());
100 | updatePeerList();
101 | } else {
102 | // If you're the intended target for a non hello message
103 | if (p.getMac().equals(MeshNetworkManager.getSelf().getMac())) {
104 | //if we get a hello ack populate the table
105 | if (p.getType().equals(Packet.TYPE.HELLO_ACK)) {
106 | MeshNetworkManager.deserializeRoutingTableAndAdd(p.getData());
107 | MeshNetworkManager.getSelf().setGroupOwnerMac(p.getSenderMac());
108 | somebodyJoined(p.getSenderMac());
109 | updatePeerList();
110 | } else if (p.getType().equals(Packet.TYPE.UPDATE)) {
111 | //if it's an update, add to the table
112 | String emb_mac = Packet.getMacBytesAsString(p.getData(), 0);
113 | MeshNetworkManager.routingTable.put(emb_mac,
114 | new AllEncompasingP2PClient(emb_mac, p.getSenderIP(), p.getMac(), MeshNetworkManager
115 | .getSelf().getMac()));
116 |
117 | final String message = emb_mac + " joined the conversation";
118 | final String name = p.getSenderMac();
119 | activity.runOnUiThread(new Runnable() {
120 |
121 | @Override
122 | public void run() {
123 | if (activity.isVisible) {
124 | Toast.makeText(activity, message, Toast.LENGTH_LONG).show();
125 | } else {
126 | MessageActivity.addMessage(name, message);
127 | }
128 | }
129 | });
130 | updatePeerList();
131 |
132 | } else if (p.getType().equals(Packet.TYPE.MESSAGE)) {
133 | //If it's a message display the message and update the table if they're not there
134 | // for whatever reason
135 | final String message = p.getSenderMac() + " says:\n" + new String(p.getData());
136 | final String msg = new String(p.getData());
137 | final String name = p.getSenderMac();
138 |
139 | if (!MeshNetworkManager.routingTable.contains(p.getSenderMac())) {
140 | /*
141 | * Update your routing table if for some reason this
142 | * guy isn't in it
143 | */
144 | MeshNetworkManager.routingTable.put(p.getSenderMac(),
145 | new AllEncompasingP2PClient(p.getSenderMac(), p.getSenderIP(), p.getSenderMac(),
146 | MeshNetworkManager.getSelf().getGroupOwnerMac()));
147 | }
148 |
149 | activity.runOnUiThread(new Runnable() {
150 |
151 | @Override
152 | public void run() {
153 | if (activity.isVisible) {
154 | Toast.makeText(activity, message, Toast.LENGTH_LONG).show();
155 | } else {
156 | MessageActivity.addMessage(name, msg);
157 | }
158 | }
159 | });
160 | updatePeerList();
161 | }
162 | } else {
163 | // otherwise forward it if you're not the recipient
164 | int ttl = p.getTtl();
165 | // Have a ttl so that they don't bounce around forever
166 | ttl--;
167 | if (ttl > 0) {
168 | Sender.queuePacket(p);
169 | p.setTtl(ttl);
170 | }
171 | }
172 | }
173 |
174 | }
175 | }
176 |
177 | /**
178 | * GUI thread to send somebody joined notification
179 | * @param smac
180 | */
181 | public static void somebodyJoined(String smac) {
182 |
183 | final String message;
184 | final String msg;
185 | message = msg = smac + " has joined.";
186 | final String name = smac;
187 | activity.runOnUiThread(new Runnable() {
188 |
189 | @Override
190 | public void run() {
191 | if (activity.isVisible) {
192 | Toast.makeText(activity, message, Toast.LENGTH_LONG).show();
193 | } else {
194 | MessageActivity.addMessage(name, msg);
195 | }
196 | }
197 | });
198 | }
199 |
200 | /**
201 | * Somebody left notification on the UI thread
202 | * @param smac
203 | */
204 | public static void somebodyLeft(String smac) {
205 |
206 | final String message;
207 | final String msg;
208 | message = msg = smac + " has left.";
209 | final String name = smac;
210 | activity.runOnUiThread(new Runnable() {
211 |
212 | @Override
213 | public void run() {
214 | if (activity.isVisible) {
215 | Toast.makeText(activity, message, Toast.LENGTH_LONG).show();
216 | } else {
217 | MessageActivity.addMessage(name, msg);
218 | }
219 | }
220 | });
221 | }
222 |
223 | /**
224 | * Update the list of peers on the front page
225 | */
226 | public static void updatePeerList() {
227 | if (activity == null)
228 | return;
229 | activity.runOnUiThread(new Runnable() {
230 | @Override
231 | public void run() {
232 | DeviceDetailFragment.updateGroupChatMembersMessage();
233 | }
234 |
235 | });
236 | }
237 |
238 | }
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/router/Sender.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo.router;
2 |
3 | import java.util.concurrent.ConcurrentLinkedQueue;
4 |
5 | import com.ecse414.android.echo.config.Configuration;
6 | import com.ecse414.android.echo.router.tcp.TcpSender;
7 |
8 | /**
9 | * Responsible for sending all packets that appear in the queue
10 | *
11 | * @author Matthew Vertescher
12 | */
13 | public class Sender implements Runnable {
14 |
15 | /**
16 | * Queue for packets to send
17 | */
18 | private static ConcurrentLinkedQueue ccl;
19 |
20 | /**
21 | * Constructor
22 | */
23 | public Sender() {
24 | if (ccl == null)
25 | ccl = new ConcurrentLinkedQueue();
26 | }
27 |
28 | /**
29 | * Enqueue a packet to send
30 | * @param p
31 | * @return
32 | */
33 | public static boolean queuePacket(Packet p) {
34 | if (ccl == null)
35 | ccl = new ConcurrentLinkedQueue();
36 | return ccl.add(p);
37 | }
38 |
39 | @Override
40 | public void run() {
41 | TcpSender packetSender = new TcpSender();
42 |
43 | while (true) {
44 | //Sleep to give up CPU cycles
45 | while (ccl.isEmpty()) {
46 | try {
47 | Thread.sleep(2000);
48 | } catch (InterruptedException e) {
49 | e.printStackTrace();
50 | }
51 | }
52 |
53 | Packet p = ccl.remove();
54 | String ip = MeshNetworkManager.getIPForClient(p.getMac());
55 | packetSender.sendPacket(ip, Configuration.RECEIVE_PORT, p);
56 |
57 | }
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/router/tcp/TcpReciever.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo.router.tcp;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.net.ServerSocket;
7 | import java.net.Socket;
8 | import java.util.concurrent.ConcurrentLinkedQueue;
9 |
10 | import com.ecse414.android.echo.router.Packet;
11 |
12 | /**
13 | * Receives packets on a server socket threads and enqueues them to a receiver runner
14 | *
15 | * @author Matthew Vertescher
16 | *
17 | */
18 | public class TcpReciever implements Runnable {
19 |
20 | private ServerSocket serverSocket;
21 | private ConcurrentLinkedQueue packetQueue;
22 |
23 | /**
24 | * Constructor with the queue
25 | * @param port
26 | * @param queue
27 | */
28 | public TcpReciever(int port, ConcurrentLinkedQueue queue) {
29 | try {
30 | this.serverSocket = new ServerSocket(port);
31 | } catch (IOException e) {
32 | System.err.println("Server socket on port " + port + " could not be created. ");
33 | e.printStackTrace();
34 | }
35 | this.packetQueue = queue;
36 | }
37 |
38 | /**
39 | * Thread runner
40 | */
41 | @Override
42 | public void run() {
43 | Socket socket;
44 | while (!Thread.currentThread().isInterrupted()) {
45 | try {
46 | socket = this.serverSocket.accept();
47 | InputStream in = socket.getInputStream();
48 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
49 |
50 | byte[] buf = new byte[1024];
51 | while (true) {
52 | int n = in.read(buf);
53 | if (n < 0)
54 | break;
55 | baos.write(buf, 0, n);
56 | }
57 |
58 | byte trimmedBytes[] = baos.toByteArray();
59 | Packet p = Packet.deserialize(trimmedBytes);
60 | p.setSenderIP(socket.getInetAddress().getHostAddress());
61 | this.packetQueue.add(p);
62 | socket.close();
63 | } catch (IOException e) {
64 | e.printStackTrace();
65 | }
66 | }
67 | }
68 |
69 | }
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/router/tcp/TcpSender.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo.router.tcp;
2 |
3 | import java.io.OutputStream;
4 | import java.net.InetAddress;
5 | import java.net.InetSocketAddress;
6 | import java.net.Socket;
7 |
8 | import com.ecse414.android.echo.router.MeshNetworkManager;
9 | import com.ecse414.android.echo.router.Packet;
10 | import com.ecse414.android.echo.router.Receiver;
11 |
12 | /**
13 | * Runner for dequeueing packets from packets to send, and issues the TCP connection to send them
14 | *
15 | * @author Matthew Vertescher
16 | * @author Peter Henderson
17 | *
18 | */
19 | public class TcpSender {
20 |
21 | Socket tcpSocket = null;
22 |
23 | public boolean sendPacket(String ip, int port, Packet data) {
24 | // Try to connect, otherwise remove from table
25 | try {
26 | System.out.println("IP: " + ip);
27 | InetAddress serverAddr = InetAddress.getByName(ip);
28 | tcpSocket = new Socket();
29 | tcpSocket.bind(null);
30 | tcpSocket.connect(new InetSocketAddress(serverAddr, port), 5000);
31 |
32 | } catch (Exception e) {
33 | /*
34 | * If can't connect assume that they left the chat and remove them
35 | */
36 | MeshNetworkManager.routingTable.remove(data.getMac());
37 | Receiver.somebodyLeft(data.getMac());
38 | Receiver.updatePeerList();
39 | e.printStackTrace();
40 | return false;
41 | }
42 |
43 | OutputStream os = null;
44 |
45 | //try to send otherwise remove from table
46 | try {
47 | os = tcpSocket.getOutputStream();
48 | os.write(data.serialize());
49 | os.close();
50 | tcpSocket.close();
51 |
52 | } catch (Exception e) {
53 | MeshNetworkManager.routingTable.remove(data.getMac());
54 | Receiver.somebodyLeft(data.getMac());
55 | Receiver.updatePeerList();
56 | e.printStackTrace();
57 | }
58 |
59 | return true;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/ui/DeviceDetailFragment.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo.ui;
2 |
3 | import android.app.Fragment;
4 | import android.app.ProgressDialog;
5 | import android.content.Intent;
6 | import android.net.Uri;
7 | import android.net.wifi.WpsInfo;
8 | import android.net.wifi.p2p.WifiP2pConfig;
9 | import android.net.wifi.p2p.WifiP2pDevice;
10 | import android.net.wifi.p2p.WifiP2pInfo;
11 | import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
12 | import android.os.Bundle;
13 | import android.util.Log;
14 | import android.view.LayoutInflater;
15 | import android.view.View;
16 | import android.view.ViewGroup;
17 | import android.widget.TextView;
18 |
19 | import com.ecse414.android.echo.WiFiDirectActivity;
20 | import com.ecse414.android.echo.router.AllEncompasingP2PClient;
21 | import com.ecse414.android.echo.router.MeshNetworkManager;
22 | import com.ecse414.android.echo.router.Packet;
23 | import com.ecse414.android.echo.router.Sender;
24 | import com.ecse414.android.echo.ui.DeviceListFragment.DeviceActionListener;
25 | import com.ecse414.android.echo.wifi.WiFiDirectBroadcastReceiver;
26 | import com.ecse414.android.echo.R;
27 |
28 | /**
29 | * A fragment that manages a particular peer and allows interaction with device
30 | * i.e. setting up network connection and transferring data.
31 | *
32 | * NOTE: much of this was taken from the Android example on P2P networking
33 | */
34 | public class DeviceDetailFragment extends Fragment implements ConnectionInfoListener {
35 |
36 | private static View mContentView = null;
37 | private WifiP2pDevice device;
38 | ProgressDialog progressDialog = null;
39 |
40 | /**
41 | * Update who is in the chat from the routing table
42 | */
43 | public static void updateGroupChatMembersMessage() {
44 | TextView view = (TextView) mContentView.findViewById(R.id.device_address);
45 | if (view != null) {
46 | String s = "Currently in the network chatting: \n";
47 | for (AllEncompasingP2PClient c : MeshNetworkManager.routingTable.values()) {
48 | s += c.getMac() + "\n";
49 | }
50 | view.setText(s);
51 | }
52 | }
53 |
54 | /**
55 | * Once the activity is created make sure to call the super constructor
56 | */
57 | @Override
58 | public void onActivityCreated(Bundle savedInstanceState) {
59 | super.onActivityCreated(savedInstanceState);
60 | }
61 |
62 | /**
63 | * Handle the view setup and callbacks
64 | */
65 | @Override
66 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
67 |
68 | mContentView = inflater.inflate(R.layout.device_detail, null);
69 | mContentView.findViewById(R.id.btn_connect).setOnClickListener(new View.OnClickListener() {
70 |
71 | @Override
72 | public void onClick(View v) {
73 | WifiP2pConfig config = new WifiP2pConfig();
74 | config.deviceAddress = device.deviceAddress;
75 | config.wps.setup = WpsInfo.PBC;
76 | if (progressDialog != null && progressDialog.isShowing()) {
77 | progressDialog.dismiss();
78 | }
79 | progressDialog = ProgressDialog.show(getActivity(), "Press back to cancel", "Connecting to :"
80 | + device.deviceAddress, true, true);
81 | ((DeviceActionListener) getActivity()).connect(config);
82 |
83 | }
84 | });
85 |
86 | mContentView.findViewById(R.id.btn_disconnect).setOnClickListener(new View.OnClickListener() {
87 |
88 | @Override
89 | public void onClick(View v) {
90 | ((DeviceActionListener) getActivity()).disconnect();
91 | }
92 | });
93 |
94 | return mContentView;
95 | }
96 |
97 | /**
98 | * This is mostly for debugging
99 | */
100 | @Override
101 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
102 |
103 | // User has picked an image. Transfer it to group owner i.e peer using
104 | // FileTransferService.
105 | Uri uri = data.getData();
106 | TextView statusText = (TextView) mContentView.findViewById(R.id.status_text);
107 | statusText.setText("Sending: " + uri);
108 | Log.d(WiFiDirectActivity.TAG, "Intent----------- " + uri);
109 | }
110 |
111 | /**
112 | * If you aren't the group owner and a connection has been established, send a hello packet to set up the connection
113 | */
114 | @Override
115 | public void onConnectionInfoAvailable(final WifiP2pInfo info) {
116 | if (progressDialog != null && progressDialog.isShowing()) {
117 | progressDialog.dismiss();
118 | }
119 | this.getView().setVisibility(View.VISIBLE);
120 |
121 | if (!info.isGroupOwner) {
122 | Sender.queuePacket(new Packet(Packet.TYPE.HELLO, new byte[0], null, WiFiDirectBroadcastReceiver.MAC));
123 | }
124 |
125 | // hide the connect button
126 | mContentView.findViewById(R.id.btn_connect).setVisibility(View.GONE);
127 | }
128 |
129 | /**
130 | * Updates the UI with device data
131 | *
132 | * @param device
133 | * the device to be displayed
134 | */
135 | public void showDetails(WifiP2pDevice device) {
136 | this.device = device;
137 | this.getView().setVisibility(View.VISIBLE);
138 | TextView view = (TextView) mContentView.findViewById(R.id.device_address);
139 | String s = "Currently in the network chatting: \n";
140 | for (AllEncompasingP2PClient c : MeshNetworkManager.routingTable.values()) {
141 | s += c.getMac() + "\n";
142 | }
143 | view.setText(s);
144 | }
145 |
146 | /**
147 | * Clears the UI fields after a disconnect or direct mode disable operation.
148 | */
149 | public void resetViews() {
150 | mContentView.findViewById(R.id.btn_connect).setVisibility(View.VISIBLE);
151 | TextView view = (TextView) mContentView.findViewById(R.id.device_address);
152 | view.setText(R.string.empty);
153 | view = (TextView) mContentView.findViewById(R.id.device_info);
154 | view.setText(R.string.empty);
155 | view = (TextView) mContentView.findViewById(R.id.group_owner);
156 | view.setText(R.string.empty);
157 | view = (TextView) mContentView.findViewById(R.id.status_text);
158 | view.setText(R.string.empty);
159 | this.getView().setVisibility(View.GONE);
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/ui/DeviceListFragment.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo.ui;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import com.ecse414.android.echo.WiFiDirectActivity;
7 | import com.ecse414.android.echo.R;
8 |
9 | import android.app.ListFragment;
10 | import android.app.ProgressDialog;
11 | import android.content.Context;
12 | import android.content.DialogInterface;
13 | import android.net.wifi.p2p.WifiP2pConfig;
14 | import android.net.wifi.p2p.WifiP2pDevice;
15 | import android.net.wifi.p2p.WifiP2pDeviceList;
16 | import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
17 | import android.os.Bundle;
18 | import android.util.Log;
19 | import android.view.LayoutInflater;
20 | import android.view.View;
21 | import android.view.ViewGroup;
22 | import android.widget.ArrayAdapter;
23 | import android.widget.ListView;
24 | import android.widget.TextView;
25 |
26 | /**
27 | * A ListFragment that displays available peers on discovery and requests the
28 | * parent activity to handle user interaction events
29 | *
30 | * NOTE: much of this was taken from the example in the Android P2P networking library
31 | */
32 | public class DeviceListFragment extends ListFragment implements PeerListListener {
33 |
34 | /**
35 | * A list of Wi-Fi Direct enabled ppers
36 | */
37 | private List peers = new ArrayList();
38 | ProgressDialog progressDialog = null;
39 | View mContentView = null;
40 | private WifiP2pDevice device;
41 |
42 | /**
43 | * Once the activity is created make sure that an adapter is fit to the fragment to update on finding new peers
44 | */
45 | @Override
46 | public void onActivityCreated(Bundle savedInstanceState) {
47 | super.onActivityCreated(savedInstanceState);
48 | this.setListAdapter(new WiFiPeerListAdapter(getActivity(), R.layout.row_devices, peers));
49 | }
50 |
51 | /**
52 | * Inflate the devices list view
53 | */
54 | @Override
55 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
56 | mContentView = inflater.inflate(R.layout.device_list, null);
57 | return mContentView;
58 | }
59 |
60 | /**
61 | * @return this device
62 | */
63 | public WifiP2pDevice getDevice() {
64 | return device;
65 | }
66 |
67 | /**
68 | * For a given device see if it's connected to a group, pending a connection, etc.
69 | * @param deviceStatus
70 | * @return
71 | */
72 | private static String getDeviceStatus(int deviceStatus) {
73 | Log.d(WiFiDirectActivity.TAG, "Peer status :" + deviceStatus);
74 | switch (deviceStatus) {
75 | case WifiP2pDevice.AVAILABLE:
76 | return "Available";
77 | case WifiP2pDevice.INVITED:
78 | return "Invited";
79 | case WifiP2pDevice.CONNECTED:
80 | return "Connected";
81 | case WifiP2pDevice.FAILED:
82 | return "Failed";
83 | case WifiP2pDevice.UNAVAILABLE:
84 | return "Unavailable";
85 | default:
86 | return "Unknown";
87 |
88 | }
89 | }
90 |
91 | /**
92 | * Initiate a connection with the peer.
93 | */
94 | @Override
95 | public void onListItemClick(ListView l, View v, int position, long id) {
96 | WifiP2pDevice device = (WifiP2pDevice) getListAdapter().getItem(position);
97 | ((DeviceActionListener) getActivity()).showDetails(device);
98 | }
99 |
100 | /**
101 | * Array adapter for ListFragment that maintains WifiP2pDevice list.
102 | */
103 | private class WiFiPeerListAdapter extends ArrayAdapter {
104 |
105 | private List items;
106 |
107 | /**
108 | * @param context
109 | * @param textViewResourceId
110 | * @param objects
111 | */
112 | public WiFiPeerListAdapter(Context context, int textViewResourceId, List objects) {
113 | super(context, textViewResourceId, objects);
114 | items = objects;
115 |
116 | }
117 |
118 | @Override
119 | public View getView(int position, View convertView, ViewGroup parent) {
120 | View v = convertView;
121 | if (v == null) {
122 | LayoutInflater vi = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
123 | v = vi.inflate(R.layout.row_devices, null);
124 | }
125 | WifiP2pDevice device = items.get(position);
126 | if (device != null) {
127 | TextView top = (TextView) v.findViewById(R.id.device_name);
128 | TextView bottom = (TextView) v.findViewById(R.id.device_details);
129 | if (top != null) {
130 | top.setText(device.deviceName);
131 | }
132 | if (bottom != null) {
133 | bottom.setText(getDeviceStatus(device.status));
134 | }
135 | }
136 |
137 | return v;
138 |
139 | }
140 | }
141 |
142 | /**
143 | * Update UI for this device.
144 | *
145 | * @param device
146 | * WifiP2pDevice object
147 | */
148 | public void updateThisDevice(WifiP2pDevice device) {
149 | this.device = device;
150 | TextView view = (TextView) mContentView.findViewById(R.id.my_name);
151 | view.setText(device.deviceName);
152 | view = (TextView) mContentView.findViewById(R.id.my_status);
153 | view.setText(getDeviceStatus(device.status));
154 | }
155 |
156 | /**
157 | * Callback for async peer searching
158 | */
159 | @Override
160 | public void onPeersAvailable(WifiP2pDeviceList peerList) {
161 | if (progressDialog != null && progressDialog.isShowing()) {
162 | progressDialog.dismiss();
163 | }
164 | peers.clear();
165 | peers.addAll(peerList.getDeviceList());
166 | ((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
167 | if (peers.size() == 0) {
168 | Log.d(WiFiDirectActivity.TAG, "No devices found");
169 | return;
170 | }
171 |
172 | }
173 |
174 | /**
175 | * Remove the peers
176 | */
177 | public void clearPeers() {
178 | peers.clear();
179 | ((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
180 | }
181 |
182 | /**
183 | * Callback to bring up searching modal
184 | */
185 | public void onInitiateDiscovery() {
186 | if (progressDialog != null && progressDialog.isShowing()) {
187 | progressDialog.dismiss();
188 | }
189 | progressDialog = ProgressDialog.show(getActivity(), "Press back to cancel", "finding peers", true, true,
190 | new DialogInterface.OnCancelListener() {
191 |
192 | @Override
193 | public void onCancel(DialogInterface dialog) {
194 |
195 | }
196 | });
197 | }
198 |
199 | /**
200 | * An interface-callback for the activity to listen to fragment interaction
201 | * events.
202 | */
203 | public interface DeviceActionListener {
204 |
205 | void showDetails(WifiP2pDevice device);
206 | void cancelDisconnect();
207 | void connect(WifiP2pConfig config);
208 | void disconnect();
209 | }
210 |
211 | }
212 |
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/ui/PromptPasswordFragment.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo.ui;
2 |
3 | import com.ecse414.android.echo.WiFiDirectActivity;
4 | import com.ecse414.android.echo.R;
5 |
6 | import android.annotation.SuppressLint;
7 | import android.app.AlertDialog;
8 | import android.app.Dialog;
9 | import android.app.DialogFragment;
10 | import android.content.DialogInterface;
11 | import android.os.Bundle;
12 | import android.view.LayoutInflater;
13 | import android.view.View;
14 | import android.widget.TextView;
15 |
16 | /**
17 | * A password prompt for legacy connections or GO bridging connections
18 | *
19 | * @author Matthew Vertescher
20 | *
21 | */
22 | @SuppressLint("ValidFragment")
23 | public class PromptPasswordFragment extends DialogFragment {
24 |
25 | private WiFiDirectActivity activty;
26 | private View mContentView;
27 | private String ssid;
28 |
29 | public PromptPasswordFragment() {
30 | }
31 |
32 | /**
33 | * constructor with activity and SSID for the wifi hotspot
34 | * @param activty
35 | * @param ssid
36 | */
37 | public PromptPasswordFragment(WiFiDirectActivity activty, String ssid) {
38 | this.activty = activty;
39 | this.ssid = ssid;
40 | }
41 |
42 | @Override
43 | public Dialog onCreateDialog(Bundle savedInstanceState) {
44 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
45 | // Get the layout inflater
46 | LayoutInflater inflater = getActivity().getLayoutInflater();
47 |
48 | mContentView = inflater.inflate(R.layout.prompt_password, null);
49 | ((TextView) mContentView.findViewById(R.id.ssid)).setText("Enter password for (" + this.ssid + ")");
50 |
51 | // Inflate and set the layout for the dialog
52 | // Pass null as the parent view because its going in the dialog layout
53 | builder.setView(mContentView)
54 | // Add action buttons
55 | .setPositiveButton(R.string.label_connect, new DialogInterface.OnClickListener() {
56 |
57 | @Override
58 | public void onClick(DialogInterface dialog, int id) {
59 | String ssid = PromptPasswordFragment.this.ssid;
60 | String password = ((TextView) PromptPasswordFragment.this.mContentView
61 | .findViewById(R.id.password)).getText().toString();
62 |
63 | PromptPasswordFragment.this.activty.connectToAccessPoint(ssid, password);
64 |
65 | }
66 | }).setNegativeButton(R.string.label_cancel, new DialogInterface.OnClickListener() {
67 | public void onClick(DialogInterface dialog, int id) {
68 | PromptPasswordFragment.this.getDialog().cancel();
69 | }
70 | });
71 | return builder.create();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/wifi/WiFiBroadcastReceiver.java:
--------------------------------------------------------------------------------
1 | package com.ecse414.android.echo.wifi;
2 |
3 | import java.math.BigInteger;
4 | import java.net.InetAddress;
5 | import java.net.UnknownHostException;
6 | import java.nio.ByteOrder;
7 | import java.util.List;
8 |
9 | import com.ecse414.android.echo.WiFiDirectActivity;
10 | import com.ecse414.android.echo.config.Configuration;
11 | import com.ecse414.android.echo.router.AllEncompasingP2PClient;
12 | import com.ecse414.android.echo.router.MeshNetworkManager;
13 | import com.ecse414.android.echo.router.Receiver;
14 | import com.ecse414.android.echo.router.Sender;
15 |
16 | import android.content.BroadcastReceiver;
17 | import android.content.Context;
18 | import android.content.Intent;
19 | import android.net.NetworkInfo;
20 | import android.net.NetworkInfo.DetailedState;
21 | import android.net.wifi.ScanResult;
22 | import android.net.wifi.WifiManager;
23 | import android.util.Log;
24 | import android.widget.Toast;
25 |
26 | /**
27 | * Used for bridging or legacy wifi connections
28 | *
29 | * @author Matthew Vertescher
30 | *
31 | */
32 | public class WiFiBroadcastReceiver extends BroadcastReceiver {
33 |
34 | private WifiManager wifiManager;
35 | private WiFiDirectActivity activity;
36 | private boolean isWifiConnected;
37 | private List wifiList;
38 | private StringBuilder sb = new StringBuilder();
39 |
40 | public WiFiBroadcastReceiver(WifiManager wifiManager, WiFiDirectActivity activity, boolean isWifiConnected) {
41 | super();
42 | this.wifiManager = wifiManager;
43 | this.activity = activity;
44 | this.isWifiConnected = isWifiConnected;
45 | }
46 |
47 | /**
48 | * This method call when number of wifi connections changed
49 | */
50 | public void onReceive(Context context, Intent intent) {
51 |
52 | String action = intent.getAction();
53 |
54 | if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
55 |
56 | String wfdSsid = null;
57 |
58 | sb = new StringBuilder();
59 | wifiList = this.wifiManager.getScanResults();
60 | sb.append("\n Number Of Wifi connections :" + wifiList.size() + "\n\n");
61 |
62 | for (int i = 0; i < wifiList.size(); i++) {
63 |
64 | if (wifiList.get(i).SSID.contains("DIRECT")) {
65 | wfdSsid = wifiList.get(i).SSID;
66 | }
67 |
68 | sb.append(Integer.valueOf(i + 1) + ". ");
69 | sb.append((wifiList.get(i)).toString());
70 | sb.append("\n\n");
71 | }
72 |
73 | if (wfdSsid != null && !this.isWifiConnected) {
74 | // this.activity.displayConnectDialog(wfdSsid);
75 | } else {
76 | Toast.makeText(activity, "Found no WiFi direct network to connect to using wlan0", Toast.LENGTH_LONG)
77 | .show();
78 | }
79 | } else if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
80 | Log.d("WiFiBroadcastReceiver", "WIFI_STATE_CHANGED_ACTION");
81 | int iTemp = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN);
82 | checkState(iTemp);
83 | } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
84 | Log.d("WiFiBroadcastReceiver", "NETWORK_STATE_CHANGED_ACTION");
85 | NetworkInfo netInfo = (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
86 | DetailedState state = netInfo.getDetailedState();
87 | Log.d("WiFiBroadcastReceiver", " state = " + state.name());
88 | changeState(state, context);
89 |
90 | }
91 | }
92 |
93 | private void changeState(DetailedState aState, Context context) {
94 | if (aState == DetailedState.SCANNING) {
95 | Log.d("WiFiBroadcastReceiver", "SCANNING");
96 | } else if (aState == DetailedState.CONNECTING) {
97 | Log.d("WiFiBroadcastReceiver", "CONNECTING");
98 | } else if (aState == DetailedState.OBTAINING_IPADDR) {
99 | Log.d("WiFiBroadcastReceiver", "OBTAINING_IPADDR");
100 | } else if (aState == DetailedState.CONNECTED) {
101 | Log.d("WiFiBroadcastReceiver", "CONNECTED");
102 | Log.d("WiFiBroadcastReceiver", " bssid=" + wifiManager.getConnectionInfo().getBSSID());
103 | Log.d("WiFiBroadcastReceiver", " ip=" + this.parseIpAddress(wifiManager.getConnectionInfo().getIpAddress()));
104 | Log.d("WiFiBroadcastReceiver", " ssid=" + wifiManager.getConnectionInfo().getSSID());
105 | Log.d("WiFiBroadcastReceiver", " dhcpGtw=" + this.parseIpAddress(wifiManager.getDhcpInfo().gateway));
106 | Log.d("WiFiBroadcastReceiver", " MAC=" + wifiManager.getConnectionInfo().getMacAddress());
107 | Log.d("WiFiBroadcastReceiver",
108 | " dhcpServer=" + this.parseIpAddress(wifiManager.getDhcpInfo().serverAddress));
109 | Log.d("WiFiBroadcastReceiver", " netmask=" + this.parseIpAddress(wifiManager.getDhcpInfo().netmask));
110 |
111 | MeshNetworkManager.setSelf(new AllEncompasingP2PClient(wifiManager.getConnectionInfo().getMacAddress(),
112 | Configuration.GO_IP, wifiManager.getConnectionInfo().getMacAddress(), wifiManager
113 | .getConnectionInfo().getMacAddress()));
114 |
115 | if (!Receiver.running) {
116 | Receiver r = new Receiver(this.activity);
117 | new Thread(r).start();
118 | Sender s = new Sender();
119 | new Thread(s).start();
120 | }
121 | } else if (aState == DetailedState.DISCONNECTING) {
122 | Log.d("WiFiBroadcastReceiver", "DISCONNECTING");
123 | } else if (aState == DetailedState.DISCONNECTED) {
124 | Log.d("WiFiBroadcastReceiver", "DISCONNECTED");
125 | } else if (aState == DetailedState.FAILED) {
126 | // TODO
127 | }
128 | }
129 |
130 | public void checkState(int aInt) {
131 | if (aInt == WifiManager.WIFI_STATE_ENABLING) {
132 | Log.d("WiFiBroadcastReceiver", "WIFI_STATE_ENABLING");
133 | } else if (aInt == WifiManager.WIFI_STATE_ENABLED) {
134 | Log.d("WiFiBroadcastReceiver", "WIFI_STATE_ENABLED");
135 | } else if (aInt == WifiManager.WIFI_STATE_DISABLING) {
136 | Log.d("WiFiBroadcastReceiver", "WIFI_STATE_DISABLING");
137 | } else if (aInt == WifiManager.WIFI_STATE_DISABLED) {
138 | Log.d("WiFiBroadcastReceiver", "WIFI_STATE_DISABLED");
139 | }
140 | }
141 |
142 | private String parseIpAddress(int ipAddress) {
143 |
144 | // Convert little-endian to big-endian if needed
145 | if (ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN)) {
146 | ipAddress = Integer.reverseBytes(ipAddress);
147 | }
148 |
149 | byte[] ipByteArray = BigInteger.valueOf(ipAddress).toByteArray();
150 |
151 | String ipAddressString;
152 | try {
153 | ipAddressString = InetAddress.getByAddress(ipByteArray).getHostAddress();
154 | } catch (UnknownHostException ex) {
155 | Log.e("WIFIIP", "Unable to get host address.");
156 | ipAddressString = null;
157 | }
158 |
159 | return ipAddressString;
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/src/com/ecse414/android/echo/wifi/WiFiDirectBroadcastReceiver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ecse414.android.echo.wifi;
18 |
19 | import com.ecse414.android.echo.WiFiDirectActivity;
20 | import com.ecse414.android.echo.config.Configuration;
21 | import com.ecse414.android.echo.router.AllEncompasingP2PClient;
22 | import com.ecse414.android.echo.router.MeshNetworkManager;
23 | import com.ecse414.android.echo.router.Receiver;
24 | import com.ecse414.android.echo.router.Sender;
25 | import com.ecse414.android.echo.ui.DeviceDetailFragment;
26 | import com.ecse414.android.echo.ui.DeviceListFragment;
27 | import com.ecse414.android.echo.R;
28 |
29 | import android.content.BroadcastReceiver;
30 | import android.content.Context;
31 | import android.content.Intent;
32 | import android.net.NetworkInfo;
33 | import android.net.wifi.p2p.WifiP2pDevice;
34 | import android.net.wifi.p2p.WifiP2pGroup;
35 | import android.net.wifi.p2p.WifiP2pManager;
36 | import android.net.wifi.p2p.WifiP2pManager.ActionListener;
37 | import android.net.wifi.p2p.WifiP2pManager.Channel;
38 | import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
39 | import android.util.Log;
40 |
41 | /**
42 | * A BroadcastReceiver that notifies of important wifi p2p events.
43 | */
44 | public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {
45 |
46 | private WifiP2pManager manager;
47 | private Channel channel;
48 | private WiFiDirectActivity activity;
49 |
50 | public static String MAC;
51 |
52 | /**
53 | * @param manager
54 | * WifiP2pManager system service
55 | * @param channel
56 | * Wifi p2p channel
57 | * @param activity
58 | * activity associated with the receiver
59 | */
60 | public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel, WiFiDirectActivity activity) {
61 | super();
62 | this.manager = manager;
63 | this.channel = channel;
64 | this.activity = activity;
65 | }
66 |
67 | /**
68 | * State transitions based on connection and state information, callback based on P2P library
69 | */
70 | @Override
71 | public void onReceive(Context context, Intent intent) {
72 | String action = intent.getAction();
73 |
74 | if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
75 |
76 | // UI update to indicate wifi p2p status.
77 | int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
78 |
79 | if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
80 | // Wifi Direct mode is enabled
81 | activity.setIsWifiP2pEnabled(true);
82 |
83 | manager.createGroup(channel, new ActionListener() {
84 |
85 | @Override
86 | public void onSuccess() {
87 | Log.d(WiFiDirectActivity.TAG, "P2P Group created");
88 | }
89 |
90 | @Override
91 | public void onFailure(int reason) {
92 | Log.d(WiFiDirectActivity.TAG, "P2P Group failed");
93 | }
94 | });
95 | } else {
96 | activity.setIsWifiP2pEnabled(false);
97 | activity.resetData();
98 |
99 | }
100 |
101 | Log.d(WiFiDirectActivity.TAG, "P2PACTION : WIFI_P2P_STATE_CHANGED_ACTION state = " + state);
102 | } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
103 |
104 | // request available peers from the wifi p2p manager. This is an
105 | // asynchronous call and the calling activity is notified with a
106 | // callback on PeerListListener.onPeersAvailable()
107 | if (manager != null) {
108 | manager.requestPeers(channel,
109 | (PeerListListener) activity.getFragmentManager().findFragmentById(R.id.frag_list));
110 | }
111 | Log.d(WiFiDirectActivity.TAG, "P2PACTION : WIFI_P2P_PEERS_CHANGED_ACTION");
112 | } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
113 |
114 | if (manager == null) {
115 | return;
116 | }
117 |
118 | NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
119 |
120 | if (networkInfo.isConnected()) {
121 | // we are connected with the other device, request connection
122 | // info to find group owner IP
123 | DeviceDetailFragment fragment = (DeviceDetailFragment) activity.getFragmentManager().findFragmentById(
124 | R.id.frag_detail);
125 | manager.requestConnectionInfo(channel, fragment);
126 | } else {
127 | // It's a disconnect
128 | Log.d(WiFiDirectActivity.TAG, "P2PACTION : WIFI_P2P_CONNECTION_CHANGED_ACTION -- DISCONNECT");
129 | activity.resetData();
130 | }
131 | } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
132 | DeviceListFragment fragment = (DeviceListFragment) activity.getFragmentManager().findFragmentById(
133 | R.id.frag_list);
134 | fragment.updateThisDevice((WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
135 |
136 | MAC = ((WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)).deviceAddress;
137 |
138 | //Set yourself on connection
139 | MeshNetworkManager.setSelf(new AllEncompasingP2PClient(((WifiP2pDevice) intent
140 | .getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)).deviceAddress, Configuration.GO_IP,
141 | ((WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)).deviceName,
142 | ((WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)).deviceAddress));
143 |
144 | //Launch receiver and sender once connected to someone
145 | if (!Receiver.running) {
146 | Receiver r = new Receiver(this.activity);
147 | new Thread(r).start();
148 | Sender s = new Sender();
149 | new Thread(s).start();
150 | }
151 |
152 | manager.requestGroupInfo(channel, new WifiP2pManager.GroupInfoListener() {
153 | @Override
154 | public void onGroupInfoAvailable(WifiP2pGroup group) {
155 | if (group != null) {
156 | // clients require these
157 | String ssid = group.getNetworkName();
158 | String passphrase = group.getPassphrase();
159 |
160 | Log.d(WiFiDirectActivity.TAG, "GROUP INFO AVALABLE");
161 | Log.d(WiFiDirectActivity.TAG, " SSID : " + ssid + "\n Passphrase : " + passphrase);
162 |
163 | }
164 | }
165 | });
166 | }
167 | }
168 | }
169 |
--------------------------------------------------------------------------------