/*
* 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 android.annotation.TargetApi;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.IBinder;
import android.support.v4.app.NotificationManagerCompat;
import android.widget.Toast;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Shares URLs via bluetooth.
* Also interfaces with PWS to shorten URLs that are too long for Eddystone URLs.
* Lastly, it surfaces a persistent notification whenever a URL is currently being broadcast.
**/
@TargetApi(21)
public class FileBroadcastService extends Service {
private static final String TAG = FileBroadcastService.class.getSimpleName();
private static final int BROADCASTING_NOTIFICATION_ID = 7;
public static final String FILE_KEY = "file";
public static final String MIME_TYPE_KEY = "type";
public static final String TITLE_KEY = "title";
private static final String DEFAULT_DEVICE_NAME = "PW-Share-";
private static final int MAX_DEVICE_NAME_LENGTH = 30;
private int mPort;
private NotificationManagerCompat mNotificationManager;
private Uri mUri;
private String mType;
private String mTitle;
private byte[] mFile;
private FileBroadcastServer mFileBroadcastServer;
/////////////////////////////////
// callbacks
/////////////////////////////////
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mFileBroadcastServer != null) {
mFileBroadcastServer.stop();
}
mType = intent.getStringExtra(MIME_TYPE_KEY);
Log.d(TAG, mType);
mUri = Uri.parse(intent.getStringExtra(FILE_KEY));
Log.d(TAG, mUri.toString());
mTitle = intent.getStringExtra(TITLE_KEY);
mTitle = mTitle == null ? "Share" : mTitle;
mPort = Utils.getWifiDirectPort(this);
try {
mFile = Utils.getBytes(getContentResolver().openInputStream(mUri));
} catch (FileNotFoundException e) {
Log.d(TAG, e.getMessage());
stopSelf();
return START_STICKY;
} catch (IOException e) {
Log.d(TAG, e.getMessage());
stopSelf();
return START_STICKY;
}
mNotificationManager = NotificationManagerCompat.from(this);
mFileBroadcastServer = new FileBroadcastServer(mPort, mType, mFile);
try {
mFileBroadcastServer.start();
Utils.createBroadcastNotification(this, stopServiceReceiver, BROADCASTING_NOTIFICATION_ID,
getString(R.string.wifi_direct_notification_title), Integer.toString(mPort),
"myFilter2");
} catch (IOException e) {
Log.d(TAG, e.getMessage());
stopSelf();
return START_STICKY;
}
sendBroadcast(new Intent("server"));
WifiP2pManager mManager = (WifiP2pManager) this.getSystemService(Context.WIFI_P2P_SERVICE);
WifiP2pManager.Channel mChannel = mManager.initialize(this, this.getMainLooper(), null);
changeWifiName();
mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.d(TAG, "discovering");
}
@Override
public void onFailure(int reasonCode) {
Log.d(TAG, "discovery failed " + reasonCode);
}
});
Toast.makeText(this, R.string.wifi_direct_broadcasting_confirmation, Toast.LENGTH_SHORT)
.show();
return START_STICKY;
}
@Override
public void onDestroy() {
Log.d(TAG, "SERVICE onDestroy");
unregisterReceiver(stopServiceReceiver);
mFileBroadcastServer.stop();
mNotificationManager.cancel(BROADCASTING_NOTIFICATION_ID);
super.onDestroy();
}
protected BroadcastReceiver stopServiceReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, context.toString());
stopSelf();
}
};
private void changeWifiName() {
String deviceName = "PW-" + mTitle + "-" + mPort;
if (deviceName.length() > MAX_DEVICE_NAME_LENGTH) {
deviceName = DEFAULT_DEVICE_NAME + mPort;
}
try {
WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
WifiP2pManager.Channel channel = manager.initialize(this, getMainLooper(), null);
Class[] paramTypes = new Class[3];
paramTypes[0] = WifiP2pManager.Channel.class;
paramTypes[1] = String.class;
paramTypes[2] = WifiP2pManager.ActionListener.class;
Method setDeviceName = manager.getClass().getMethod(
"setDeviceName", paramTypes);
setDeviceName.setAccessible(true);
Object arglist[] = new Object[3];
arglist[0] = channel;
arglist[1] = deviceName;
arglist[2] = new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.d(TAG, "setDeviceName succeeded");
}
@Override
public void onFailure(int reason) {
Log.d(TAG, "setDeviceName failed");
}
};
setDeviceName.invoke(manager, arglist);
} catch (NoSuchMethodException e) {
Log.d(TAG, e.getMessage());
} catch (IllegalAccessException e) {
Log.d(TAG, e.getMessage());
} catch (IllegalArgumentException e) {
Log.d(TAG, e.getMessage());
} catch (InvocationTargetException e) {
Log.d(TAG, e.getMessage());
}
}
}