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_COARSE_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_COARSE_LOCATION: 77 if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { 78 Log.e(TAG, "Coarse 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_COARSE_LOCATION) 102 != PackageManager.PERMISSION_GRANTED) { 103 requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 104 WiFiDirectActivity.PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_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