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.app.Fragment; 20 import android.app.ProgressDialog; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.net.Uri; 24 import android.net.wifi.WpsInfo; 25 import android.net.wifi.p2p.WifiP2pConfig; 26 import android.net.wifi.p2p.WifiP2pDevice; 27 import android.net.wifi.p2p.WifiP2pInfo; 28 import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener; 29 import android.os.AsyncTask; 30 import android.os.Bundle; 31 import android.support.v4.content.FileProvider; 32 import android.util.Log; 33 import android.view.LayoutInflater; 34 import android.view.View; 35 import android.view.ViewGroup; 36 import android.widget.TextView; 37 38 import com.example.android.wifidirect.DeviceListFragment.DeviceActionListener; 39 40 import java.io.File; 41 import java.io.FileOutputStream; 42 import java.io.IOException; 43 import java.io.InputStream; 44 import java.io.OutputStream; 45 import java.net.ServerSocket; 46 import java.net.Socket; 47 48 /** 49 * A fragment that manages a particular peer and allows interaction with device 50 * i.e. setting up network connection and transferring data. 51 */ 52 public class DeviceDetailFragment extends Fragment implements ConnectionInfoListener { 53 54 protected static final int CHOOSE_FILE_RESULT_CODE = 20; 55 private View mContentView = null; 56 private WifiP2pDevice device; 57 private WifiP2pInfo info; 58 ProgressDialog progressDialog = null; 59 60 @Override onActivityCreated(Bundle savedInstanceState)61 public void onActivityCreated(Bundle savedInstanceState) { 62 super.onActivityCreated(savedInstanceState); 63 } 64 65 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)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", 80 "Connecting to :" + device.deviceAddress, true, true 81 // new DialogInterface.OnCancelListener() { 82 // 83 // @Override 84 // public void onCancel(DialogInterface dialog) { 85 // ((DeviceActionListener) getActivity()).cancelDisconnect(); 86 // } 87 // } 88 ); 89 ((DeviceActionListener) getActivity()).connect(config); 90 91 } 92 }); 93 94 mContentView.findViewById(R.id.btn_disconnect).setOnClickListener( 95 new View.OnClickListener() { 96 97 @Override 98 public void onClick(View v) { 99 ((DeviceActionListener) getActivity()).disconnect(); 100 } 101 }); 102 103 mContentView.findViewById(R.id.btn_start_client).setOnClickListener( 104 new View.OnClickListener() { 105 106 @Override 107 public void onClick(View v) { 108 // Allow user to pick an image from Gallery or other 109 // registered apps 110 Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 111 intent.setType("image/*"); 112 startActivityForResult(intent, CHOOSE_FILE_RESULT_CODE); 113 } 114 }); 115 116 return mContentView; 117 } 118 119 @Override onActivityResult(int requestCode, int resultCode, Intent data)120 public void onActivityResult(int requestCode, int resultCode, Intent data) { 121 122 // User has picked an image. Transfer it to group owner i.e peer using 123 // FileTransferService. 124 Uri uri = data.getData(); 125 TextView statusText = (TextView) mContentView.findViewById(R.id.status_text); 126 statusText.setText("Sending: " + uri); 127 Log.d(WiFiDirectActivity.TAG, "Intent----------- " + uri); 128 Intent serviceIntent = new Intent(getActivity(), FileTransferService.class); 129 serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE); 130 serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_PATH, uri.toString()); 131 serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS, 132 info.groupOwnerAddress.getHostAddress()); 133 serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT, 8988); 134 getActivity().startService(serviceIntent); 135 } 136 137 @Override onConnectionInfoAvailable(final WifiP2pInfo info)138 public void onConnectionInfoAvailable(final WifiP2pInfo info) { 139 if (progressDialog != null && progressDialog.isShowing()) { 140 progressDialog.dismiss(); 141 } 142 this.info = info; 143 this.getView().setVisibility(View.VISIBLE); 144 145 // The owner IP is now known. 146 TextView view = (TextView) mContentView.findViewById(R.id.group_owner); 147 view.setText(getResources().getString(R.string.group_owner_text) 148 + ((info.isGroupOwner == true) ? getResources().getString(R.string.yes) 149 : getResources().getString(R.string.no))); 150 151 // InetAddress from WifiP2pInfo struct. 152 view = (TextView) mContentView.findViewById(R.id.device_info); 153 view.setText("Group Owner IP - " + info.groupOwnerAddress.getHostAddress()); 154 155 // After the group negotiation, we assign the group owner as the file 156 // server. The file server is single threaded, single connection server 157 // socket. 158 if (info.groupFormed && info.isGroupOwner) { 159 new FileServerAsyncTask(getActivity(), mContentView.findViewById(R.id.status_text)) 160 .execute(); 161 } else if (info.groupFormed) { 162 // The other device acts as the client. In this case, we enable the 163 // get file button. 164 mContentView.findViewById(R.id.btn_start_client).setVisibility(View.VISIBLE); 165 ((TextView) mContentView.findViewById(R.id.status_text)).setText(getResources() 166 .getString(R.string.client_text)); 167 } 168 169 // hide the connect button 170 mContentView.findViewById(R.id.btn_connect).setVisibility(View.GONE); 171 } 172 173 /** 174 * Updates the UI with device data 175 * 176 * @param device the device to be displayed 177 */ showDetails(WifiP2pDevice device)178 public void showDetails(WifiP2pDevice device) { 179 this.device = device; 180 this.getView().setVisibility(View.VISIBLE); 181 TextView view = (TextView) mContentView.findViewById(R.id.device_address); 182 view.setText(device.deviceAddress); 183 view = (TextView) mContentView.findViewById(R.id.device_info); 184 view.setText(device.toString()); 185 186 } 187 188 /** 189 * Clears the UI fields after a disconnect or direct mode disable operation. 190 */ resetViews()191 public void resetViews() { 192 mContentView.findViewById(R.id.btn_connect).setVisibility(View.VISIBLE); 193 TextView view = (TextView) mContentView.findViewById(R.id.device_address); 194 view.setText(R.string.empty); 195 view = (TextView) mContentView.findViewById(R.id.device_info); 196 view.setText(R.string.empty); 197 view = (TextView) mContentView.findViewById(R.id.group_owner); 198 view.setText(R.string.empty); 199 view = (TextView) mContentView.findViewById(R.id.status_text); 200 view.setText(R.string.empty); 201 mContentView.findViewById(R.id.btn_start_client).setVisibility(View.GONE); 202 this.getView().setVisibility(View.GONE); 203 } 204 205 /** 206 * A simple server socket that accepts connection and writes some data on 207 * the stream. 208 */ 209 public static class FileServerAsyncTask extends AsyncTask<Void, Void, String> { 210 211 private Context context; 212 private TextView statusText; 213 214 /** 215 * @param context 216 * @param statusText 217 */ FileServerAsyncTask(Context context, View statusText)218 public FileServerAsyncTask(Context context, View statusText) { 219 this.context = context; 220 this.statusText = (TextView) statusText; 221 } 222 223 @Override doInBackground(Void... params)224 protected String doInBackground(Void... params) { 225 try { 226 ServerSocket serverSocket = new ServerSocket(8988); 227 Log.d(WiFiDirectActivity.TAG, "Server: Socket opened"); 228 Socket client = serverSocket.accept(); 229 Log.d(WiFiDirectActivity.TAG, "Server: connection done"); 230 final File f = new File(context.getExternalFilesDir("received"), 231 "wifip2pshared-" + System.currentTimeMillis() 232 + ".jpg"); 233 234 File dirs = new File(f.getParent()); 235 if (!dirs.exists()) 236 dirs.mkdirs(); 237 f.createNewFile(); 238 239 Log.d(WiFiDirectActivity.TAG, "server: copying files " + f.toString()); 240 InputStream inputstream = client.getInputStream(); 241 copyFile(inputstream, new FileOutputStream(f)); 242 serverSocket.close(); 243 return f.getAbsolutePath(); 244 } catch (IOException e) { 245 Log.e(WiFiDirectActivity.TAG, e.getMessage()); 246 return null; 247 } 248 } 249 250 /* 251 * (non-Javadoc) 252 * @see android.os.AsyncTask#onPostExecute(java.lang.Object) 253 */ 254 @Override onPostExecute(String result)255 protected void onPostExecute(String result) { 256 if (result != null) { 257 statusText.setText("File copied - " + result); 258 259 File recvFile = new File(result); 260 Uri fileUri = FileProvider.getUriForFile( 261 context, 262 "com.example.android.wifidirect.fileprovider", 263 recvFile); 264 Intent intent = new Intent(); 265 intent.setAction(android.content.Intent.ACTION_VIEW); 266 intent.setDataAndType(fileUri, "image/*"); 267 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 268 context.startActivity(intent); 269 } 270 271 } 272 273 /* 274 * (non-Javadoc) 275 * @see android.os.AsyncTask#onPreExecute() 276 */ 277 @Override onPreExecute()278 protected void onPreExecute() { 279 statusText.setText("Opening a server socket"); 280 } 281 282 } 283 copyFile(InputStream inputStream, OutputStream out)284 public static boolean copyFile(InputStream inputStream, OutputStream out) { 285 byte buf[] = new byte[1024]; 286 int len; 287 try { 288 while ((len = inputStream.read(buf)) != -1) { 289 out.write(buf, 0, len); 290 291 } 292 out.close(); 293 inputStream.close(); 294 } catch (IOException e) { 295 Log.d(WiFiDirectActivity.TAG, e.toString()); 296 return false; 297 } 298 return true; 299 } 300 301 } 302