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.example.android.wifidirect;
18 
19 import android.Manifest;
20 import android.app.Activity;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.content.pm.PackageManager;
26 import android.net.wifi.p2p.WifiP2pConfig;
27 import android.net.wifi.p2p.WifiP2pDevice;
28 import android.net.wifi.p2p.WifiP2pManager;
29 import android.net.wifi.p2p.WifiP2pManager.ActionListener;
30 import android.net.wifi.p2p.WifiP2pManager.Channel;
31 import android.net.wifi.p2p.WifiP2pManager.ChannelListener;
32 import android.os.Build;
33 import android.os.Bundle;
34 import android.provider.Settings;
35 import android.util.Log;
36 import android.view.Menu;
37 import android.view.MenuInflater;
38 import android.view.MenuItem;
39 import android.view.View;
40 import android.widget.Toast;
41 
42 import com.example.android.wifidirect.DeviceListFragment.DeviceActionListener;
43 
44 /**
45  * An activity that uses WiFi Direct APIs to discover and connect with available
46  * devices. WiFi Direct APIs are asynchronous and rely on callback mechanism
47  * using interfaces to notify the application of operation success or failure.
48  * The application should also register a BroadcastReceiver for notification of
49  * WiFi state related events.
50  */
51 public class WiFiDirectActivity extends Activity implements ChannelListener, DeviceActionListener {
52 
53     public static final String TAG = "wifidirectdemo";
54 
55     private static final int PERMISSIONS_REQUEST_CODE_ACCESS_FINE_LOCATION = 1001;
56 
57     private WifiP2pManager manager;
58     private boolean isWifiP2pEnabled = false;
59     private boolean retryChannel = false;
60 
61     private final IntentFilter intentFilter = new IntentFilter();
62     private Channel channel;
63     private BroadcastReceiver receiver = null;
64 
65     /**
66      * @param isWifiP2pEnabled the isWifiP2pEnabled to set
67      */
setIsWifiP2pEnabled(boolean isWifiP2pEnabled)68     public void setIsWifiP2pEnabled(boolean isWifiP2pEnabled) {
69         this.isWifiP2pEnabled = isWifiP2pEnabled;
70     }
71 
72     @Override
onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)73     public void onRequestPermissionsResult(int requestCode, String[] permissions,
74             int[] grantResults) {
75         switch (requestCode) {
76         case PERMISSIONS_REQUEST_CODE_ACCESS_FINE_LOCATION:
77             if  (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
78                 Log.e(TAG, "Fine location permission is not granted!");
79                 finish();
80             }
81             break;
82         }
83     }
84 
85     @Override
onCreate(Bundle savedInstanceState)86     public void onCreate(Bundle savedInstanceState) {
87         super.onCreate(savedInstanceState);
88         setContentView(R.layout.main);
89 
90         // add necessary intent values to be matched.
91 
92         intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
93         intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
94         intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
95         intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
96 
97         manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
98         channel = manager.initialize(this, getMainLooper(), null);
99 
100         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
101                     && checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
102                     != PackageManager.PERMISSION_GRANTED) {
103             requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
104                     WiFiDirectActivity.PERMISSIONS_REQUEST_CODE_ACCESS_FINE_LOCATION);
105             // After this point you wait for callback in
106             // onRequestPermissionsResult(int, String[], int[]) overridden method
107         }
108     }
109 
110     /** register the BroadcastReceiver with the intent values to be matched */
111     @Override
onResume()112     public void onResume() {
113         super.onResume();
114         receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
115         registerReceiver(receiver, intentFilter);
116     }
117 
118     @Override
onPause()119     public void onPause() {
120         super.onPause();
121         unregisterReceiver(receiver);
122     }
123 
124     /**
125      * Remove all peers and clear all fields. This is called on
126      * BroadcastReceiver receiving a state change event.
127      */
resetData()128     public void resetData() {
129         DeviceListFragment fragmentList = (DeviceListFragment) getFragmentManager()
130                 .findFragmentById(R.id.frag_list);
131         DeviceDetailFragment fragmentDetails = (DeviceDetailFragment) getFragmentManager()
132                 .findFragmentById(R.id.frag_detail);
133         if (fragmentList != null) {
134             fragmentList.clearPeers();
135         }
136         if (fragmentDetails != null) {
137             fragmentDetails.resetViews();
138         }
139     }
140 
141     @Override
onCreateOptionsMenu(Menu menu)142     public boolean onCreateOptionsMenu(Menu menu) {
143         MenuInflater inflater = getMenuInflater();
144         inflater.inflate(R.menu.action_items, menu);
145         return true;
146     }
147 
148     /*
149      * (non-Javadoc)
150      * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
151      */
152     @Override
onOptionsItemSelected(MenuItem item)153     public boolean onOptionsItemSelected(MenuItem item) {
154         switch (item.getItemId()) {
155             case R.id.atn_direct_enable:
156                 if (manager != null && channel != null) {
157 
158                     // Since this is the system wireless settings activity, it's
159                     // not going to send us a result. We will be notified by
160                     // WiFiDeviceBroadcastReceiver instead.
161 
162                     startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
163                 } else {
164                     Log.e(TAG, "channel or manager is null");
165                 }
166                 return true;
167 
168             case R.id.atn_direct_discover:
169                 if (!isWifiP2pEnabled) {
170                     Toast.makeText(WiFiDirectActivity.this, R.string.p2p_off_warning,
171                             Toast.LENGTH_SHORT).show();
172                     return true;
173                 }
174                 final DeviceListFragment fragment = (DeviceListFragment) getFragmentManager()
175                         .findFragmentById(R.id.frag_list);
176                 fragment.onInitiateDiscovery();
177                 manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
178 
179                     @Override
180                     public void onSuccess() {
181                         Toast.makeText(WiFiDirectActivity.this, "Discovery Initiated",
182                                 Toast.LENGTH_SHORT).show();
183                     }
184 
185                     @Override
186                     public void onFailure(int reasonCode) {
187                         Toast.makeText(WiFiDirectActivity.this, "Discovery Failed : " + reasonCode,
188                                 Toast.LENGTH_SHORT).show();
189                     }
190                 });
191                 return true;
192             default:
193                 return super.onOptionsItemSelected(item);
194         }
195     }
196 
197     @Override
showDetails(WifiP2pDevice device)198     public void showDetails(WifiP2pDevice device) {
199         DeviceDetailFragment fragment = (DeviceDetailFragment) getFragmentManager()
200                 .findFragmentById(R.id.frag_detail);
201         fragment.showDetails(device);
202 
203     }
204 
205     @Override
connect(WifiP2pConfig config)206     public void connect(WifiP2pConfig config) {
207         manager.connect(channel, config, new ActionListener() {
208 
209             @Override
210             public void onSuccess() {
211                 // WiFiDirectBroadcastReceiver will notify us. Ignore for now.
212             }
213 
214             @Override
215             public void onFailure(int reason) {
216                 Toast.makeText(WiFiDirectActivity.this, "Connect failed. Retry.",
217                         Toast.LENGTH_SHORT).show();
218             }
219         });
220     }
221 
222     @Override
disconnect()223     public void disconnect() {
224         final DeviceDetailFragment fragment = (DeviceDetailFragment) getFragmentManager()
225                 .findFragmentById(R.id.frag_detail);
226         fragment.resetViews();
227         manager.removeGroup(channel, new ActionListener() {
228 
229             @Override
230             public void onFailure(int reasonCode) {
231                 Log.d(TAG, "Disconnect failed. Reason :" + reasonCode);
232 
233             }
234 
235             @Override
236             public void onSuccess() {
237                 fragment.getView().setVisibility(View.GONE);
238             }
239 
240         });
241     }
242 
243     @Override
onChannelDisconnected()244     public void onChannelDisconnected() {
245         // we will try once more
246         if (manager != null && !retryChannel) {
247             Toast.makeText(this, "Channel lost. Trying again", Toast.LENGTH_LONG).show();
248             resetData();
249             retryChannel = true;
250             manager.initialize(this, getMainLooper(), this);
251         } else {
252             Toast.makeText(this,
253                     "Severe! Channel is probably lost premanently. Try Disable/Re-Enable P2P.",
254                     Toast.LENGTH_LONG).show();
255         }
256     }
257 
258     @Override
cancelDisconnect()259     public void cancelDisconnect() {
260 
261         /*
262          * A cancel abort request by user. Disconnect i.e. removeGroup if
263          * already connected. Else, request WifiP2pManager to abort the ongoing
264          * request
265          */
266         if (manager != null) {
267             final DeviceListFragment fragment = (DeviceListFragment) getFragmentManager()
268                     .findFragmentById(R.id.frag_list);
269             if (fragment.getDevice() == null
270                     || fragment.getDevice().status == WifiP2pDevice.CONNECTED) {
271                 disconnect();
272             } else if (fragment.getDevice().status == WifiP2pDevice.AVAILABLE
273                     || fragment.getDevice().status == WifiP2pDevice.INVITED) {
274 
275                 manager.cancelConnect(channel, new ActionListener() {
276 
277                     @Override
278                     public void onSuccess() {
279                         Toast.makeText(WiFiDirectActivity.this, "Aborting connection",
280                                 Toast.LENGTH_SHORT).show();
281                     }
282 
283                     @Override
284                     public void onFailure(int reasonCode) {
285                         Toast.makeText(WiFiDirectActivity.this,
286                                 "Connect abort request failed. Reason Code: " + reasonCode,
287                                 Toast.LENGTH_SHORT).show();
288                     }
289                 });
290             }
291         }
292 
293     }
294 }
295