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