code: /*
   * Copyright 2016 Google Inc. All rights reserved.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.physical_web.physicalweb;
  
  import org.physical_web.collection.UrlDevice;
  
  import android.app.ProgressDialog;
  import android.content.BroadcastReceiver;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.content.DialogInterface.OnCancelListener;
  import android.content.Intent;
  import android.content.IntentFilter;
  import android.net.NetworkInfo;
  import android.net.Uri;
  import android.net.wifi.p2p.WifiP2pConfig;
  import android.net.wifi.p2p.WifiP2pGroup;
  import android.net.wifi.p2p.WifiP2pInfo;
  import android.net.wifi.p2p.WifiP2pManager;
  import android.net.wifi.p2p.WifiP2pManager.ActionListener;
  import android.net.wifi.p2p.WifiP2pManager.Channel;
  import android.widget.Toast;
  
  
  /**
   * This class is for using WifiDirect to create a WifiDirect
   * P2P connection with the Physical Web Device.
   */
  class WifiDirectConnect {
    private static final String TAG = WifiDirectConnect.class.getSimpleName();
    private ProgressDialog mProgress;
    private Context mContext;
    private WifiP2pManager mManager;
    private Channel mChannel;
    private UrlDevice mDevice;
    private BroadcastReceiver mReceiver;
    private ConnectionListener mCallback;
  
    public WifiDirectConnect(Context context) {
      mManager = (WifiP2pManager) context.getSystemService(Context.WIFI_P2P_SERVICE);
      mChannel = mManager.initialize(context, context.getMainLooper(), null);
      mContext = context;
      mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
          String action = intent.getAction();
          if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
            if (mManager == null) {
              return;
            }
            NetworkInfo networkInfo = (NetworkInfo) intent
                .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
            if (networkInfo.isConnected()) {
              mManager.requestConnectionInfo(mChannel,
                  new WifiP2pManager.ConnectionInfoListener() {
                    @Override
                    public void onConnectionInfoAvailable(final WifiP2pInfo info) {
                      if (mDevice != null) {
                        Intent intent = new Intent(Intent.ACTION_VIEW);
                        intent.setData(Uri.parse("http:/" + info.groupOwnerAddress + ":" +
                            Integer.toString(Utils.getWifiPort(mDevice))));
                        mContext.startActivity(intent);
                        close();
                      }
                    }
                  });
            }
          }
        }
      };
    }
  
    public void connect(UrlDevice urlDevice, String title) {
      String progressTitle = mContext.getString(R.string.page_loading_title) + " " + title;
      mProgress = new ProgressDialog(mContext);
      mProgress.setCancelable(true);
      mProgress.setOnCancelListener(new OnCancelListener() {
        @Override
        public void onCancel(DialogInterface dialogInterface) {
          Log.i(TAG, "Dialog box canceled");
          mDevice = null;
          mManager.cancelConnect(mChannel, new ActionListener() {
            @Override
            public void onSuccess() {
              Log.d(TAG, "cancel connect call success");
            }
            @Override
            public void onFailure(int reason) {
              Log.d(TAG, "cancel connect call fail " + reason);
            }
          });
        }
      });
      mProgress.setTitle(progressTitle);
      mProgress.setMessage(mContext.getString(R.string.page_loading_message));
      mProgress.show();
      mDevice = urlDevice;
      WifiP2pConfig config = new WifiP2pConfig();
      config.deviceAddress = Utils.getWifiAddress(mDevice);
      config.groupOwnerIntent = 0;
      IntentFilter intentFilter = new IntentFilter();
      intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
      mContext.registerReceiver(mReceiver, intentFilter);
      mManager.requestGroupInfo(mChannel, new WifiP2pManager.GroupInfoListener() {
        public void onGroupInfoAvailable(final WifiP2pGroup group) {
          if (group != null) {
            Log.d(TAG, "group not null");
            if (group.getOwner().deviceAddress.equals(Utils.getWifiAddress(mDevice))) {
              Log.i(TAG, "Already connected");
              mManager.requestConnectionInfo(mChannel,
                new WifiP2pManager.ConnectionInfoListener() {
                  public void onConnectionInfoAvailable(final WifiP2pInfo info) {
                    if (mDevice != null && info.groupOwnerAddress != null) {
                      Intent intent = new Intent(Intent.ACTION_VIEW);
                      intent.setData(Uri.parse("http:/" + info.groupOwnerAddress + ":" +
                          Integer.toString(Utils.getWifiPort(mDevice))));
                      mContext.startActivity(intent);
                    }
                  }
                }
              );
            } else {
              mManager.removeGroup(mChannel, new ActionListener() {
                @Override
                public void onSuccess() {
                  Log.d(TAG, "remove call success");
                  connectHelper(true, config);
                }
  
                @Override
                public void onFailure(int reason) {
                  Log.d(TAG, "remove call fail " + reason);
                }
              });
            }
          } else {
            Log.d(TAG, "group null");
            connectHelper(true, config);
          }
        }
      });
    }
  
    public void connect(UrlDevice urlDevice, String title, ConnectionListener callback) {
      mCallback = callback;
      connect(urlDevice, title);
    }
  
    private void connectHelper(boolean retry, WifiP2pConfig config) {
      mManager.connect(mChannel, config, new ActionListener() {
        @Override
        public void onSuccess() {
          Log.d(TAG, "connect call success");
          Toast.makeText(mContext, R.string.wifi_direct_connection_succeeded, Toast.LENGTH_SHORT)
              .show();
        }
  
        @Override
        public void onFailure(int reason) {
          Log.d(TAG, "connect call fail " + reason);
          if (retry && reason == WifiP2pManager.BUSY) {
            mManager.cancelConnect(mChannel, new ActionListener() {
              @Override
              public void onSuccess() {
                Log.d(TAG, "cancel connect call success");
                connectHelper(false, config);
              }
              @Override
              public void onFailure(int reason) {
                Log.d(TAG, "cancel connect call fail " + reason);
                Toast.makeText(mContext, R.string.wifi_direct_connection_failed, Toast.LENGTH_SHORT)
                    .show();
                close();
              }
            });
          } else {
            Toast.makeText(mContext, R.string.wifi_direct_connection_failed, Toast.LENGTH_SHORT)
                .show();
            close();
          }
        }
      });
    }
  
    private void close() {
      mProgress.dismiss();
      if (mCallback != null) {
        mCallback.onConnectionFinished();
      }
    }
  }
  