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