package com.talent.allshare.server; import java.io.File; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.List; import org.teleal.cling.android.AndroidUpnpService; import org.teleal.cling.support.model.DIDLObject; import org.teleal.cling.support.model.PersonWithRole; import org.teleal.cling.support.model.Res; import org.teleal.cling.support.model.WriteStatus; import org.teleal.cling.support.model.container.Container; import org.teleal.cling.support.model.item.ImageItem; import org.teleal.cling.support.model.item.MusicTrack; import org.teleal.cling.support.model.item.TextItem; import org.teleal.cling.support.model.item.VideoItem; import org.teleal.common.util.MimeType; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.util.Log; import com.talent.allshare.util.FileFilterUtil; import com.talent.allshare.util.IOHelper; import com.wireme.activity.WireUpnpService; import com.wireme.mediaserver.ContentNode; import com.wireme.mediaserver.ContentTree; import com.wireme.mediaserver.MediaServer; public class ShareService extends Service { private boolean mbstarted; private boolean mbsharevideo=true; private boolean mbsharemusic=true; private boolean mbsharepicture=true; private boolean mbsharedoc=true; private String mdevicename="MacroDisk"; private final static String TAG = "ShareService"; private AndroidUpnpService upnpService=null; private MediaServer mediaServer; private static boolean serverPrepared = false; protected static final int UPDATE_VIDEO = 0x10001; protected static final int UPDATE_MUISC = 0x10002; protected static final int UPDATE_PIC = 0x10003; protected static final int UPDATE_FILE = 0x10004; protected static final int LOADSTEP_IDLE = 0; protected static final int LOADSTEP_STOPPENDING = 1; protected static final int LOADSTEP_BEGIN = 2; protected static final int LOADSTEP_VIDEO = 3; protected static final int LOADSTEP_MUISC = 4; protected static final int LOADSTEP_PIC = 5; protected static final int LOADSTEP_FILE = 6; private int mloadstep=LOADSTEP_IDLE; private Handler handler; @Override public IBinder onBind(Intent intent) { Log.i(TAG, "onBind"); return mBinder; } @Override public void onCreate() { super.onCreate(); Log.i(TAG,"ShareService oncreat"); handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case UPDATE_VIDEO: if(mbstarted==true){ List<File> files=(List<File>) msg.obj; ContentNode rootNode = ContentTree.getRootNode(); // Video Container Container videoContainer = new Container(); videoContainer.setClazz(new DIDLObject.Class("object.container")); videoContainer.setId(ContentTree.VIDEO_ID); videoContainer.setParentID(ContentTree.ROOT_ID); videoContainer.setTitle("Videos"); videoContainer.setRestricted(true); videoContainer.setWriteStatus(WriteStatus.NOT_WRITABLE); videoContainer.setChildCount(0); rootNode.getContainer().addContainer(videoContainer); rootNode.getContainer().setChildCount( rootNode.getContainer().getChildCount() + 1); ContentTree.addNode(ContentTree.VIDEO_ID, new ContentNode( ContentTree.VIDEO_ID, videoContainer)); for(int i=0;i<files.size();i++){ String id = ContentTree.VIDEO_PREFIX+i; String title = files.get(i).getName(); String creator ="system"; String filePath =files.get(i).getPath()+""; String mimeType = IOHelper.getMIMEType(title); long size = 50*1024*1024; long duration =60*60*1000; String resolution =null; Res res = new Res(new MimeType(mimeType.substring(0, mimeType.indexOf('/')), mimeType.substring(mimeType .indexOf('/') + 1)), size, "http://" + mediaServer.getAddress() + "/" + id); res.setDuration(duration / (1000 * 60 * 60) + ":" + (duration % (1000 * 60 * 60)) / (1000 * 60) + ":" + (duration % (1000 * 60)) / 1000); res.setResolution(resolution); VideoItem videoItem = new VideoItem(id, ContentTree.VIDEO_ID, title, creator, res); videoContainer.addItem(videoItem); videoContainer .setChildCount(videoContainer.getChildCount() + 1); ContentTree.addNode(id, new ContentNode(id, videoItem, filePath)); //Log.i(TAG, "added video item " + title + "from " + filePath); } } dosearch(); break; case UPDATE_MUISC: if(mbstarted==true){ List<File> files=(List<File>) msg.obj; ContentNode rootNode = ContentTree.getRootNode(); // Audio Container Container audioContainer = new Container(ContentTree.AUDIO_ID, ContentTree.ROOT_ID, "Audios", "GNaP MediaServer", new DIDLObject.Class("object.container"), 0); audioContainer.setRestricted(true); audioContainer.setWriteStatus(WriteStatus.NOT_WRITABLE); rootNode.getContainer().addContainer(audioContainer); rootNode.getContainer().setChildCount( rootNode.getContainer().getChildCount() + 1); ContentTree.addNode(ContentTree.AUDIO_ID, new ContentNode( ContentTree.AUDIO_ID, audioContainer)); for(int i=0;i<files.size();i++){ String id = ContentTree.AUDIO_PREFIX+i; String title = files.get(i).getName(); String creator ="system"; String filePath =files.get(i).getPath()+""; String mimeType = IOHelper.getMIMEType(title); long size = 50*1024*1024; long duration =60*60*1000; String album ="system"; Res res = new Res(new MimeType(mimeType.substring(0, mimeType.indexOf('/')), mimeType.substring(mimeType .indexOf('/') + 1)), size, "http://" + mediaServer.getAddress() + "/" + id); res.setDuration(duration / (1000 * 60 * 60) + ":" + (duration % (1000 * 60 * 60)) / (1000 * 60) + ":" + (duration % (1000 * 60)) / 1000); // Music Track must have `artist' with role field, or // DIDLParser().generate(didl) will throw nullpointException MusicTrack musicTrack = new MusicTrack(id, ContentTree.AUDIO_ID, title, creator, album, new PersonWithRole(creator, "Performer"), res); audioContainer.addItem(musicTrack); audioContainer .setChildCount(audioContainer.getChildCount() + 1); ContentTree.addNode(id, new ContentNode(id, musicTrack, filePath)); //Log.i(TAG, "added audio item " + title + "from " + filePath); } } dosearch(); break; case UPDATE_PIC: if(mbstarted==true){ List<File> files=(List<File>) msg.obj; ContentNode rootNode = ContentTree.getRootNode(); // Image Container Container imageContainer = new Container(ContentTree.IMAGE_ID, ContentTree.ROOT_ID, "Images", "GNaP MediaServer", new DIDLObject.Class("object.container"), 0); imageContainer.setRestricted(true); imageContainer.setWriteStatus(WriteStatus.NOT_WRITABLE); rootNode.getContainer().addContainer(imageContainer); rootNode.getContainer().setChildCount( rootNode.getContainer().getChildCount() + 1); ContentTree.addNode(ContentTree.IMAGE_ID, new ContentNode( ContentTree.IMAGE_ID, imageContainer)); for(int i=0;i<files.size();i++){ String id = ContentTree.IMAGE_PREFIX+i; String title = files.get(i).getName(); String creator ="system"; String filePath =files.get(i).getPath()+""; String mimeType = IOHelper.getMIMEType(title); long size = 50*1024*1024; Res res = new Res(new MimeType(mimeType.substring(0, mimeType.indexOf('/')), mimeType.substring(mimeType .indexOf('/') + 1)), size, "http://" + mediaServer.getAddress() + "/" + id); ImageItem imageItem = new ImageItem(id, ContentTree.IMAGE_ID, title, creator, res); imageContainer.addItem(imageItem); imageContainer .setChildCount(imageContainer.getChildCount() + 1); ContentTree.addNode(id, new ContentNode(id, imageItem, filePath)); //Log.i(TAG, "added image item " + title + "from " + filePath); } } dosearch(); break; case UPDATE_FILE: if(mbstarted==true){ List<File> files=(List<File>) msg.obj; ContentNode rootNode = ContentTree.getRootNode(); // doc Container Container docContainer = new Container(ContentTree.FILE_ID, ContentTree.ROOT_ID, "document", "GNaP MediaServer", new DIDLObject.Class("object.container"), 0); docContainer.setRestricted(true); docContainer.setWriteStatus(WriteStatus.NOT_WRITABLE); rootNode.getContainer().addContainer(docContainer); rootNode.getContainer().setChildCount( rootNode.getContainer().getChildCount() + 1); ContentTree.addNode(ContentTree.FILE_ID, new ContentNode( ContentTree.FILE_ID, docContainer)); for(int i=0;i<files.size();i++){ String id = ContentTree.FILE_PREFIX+i; String title = files.get(i).getName(); String creator ="system"; String filePath =files.get(i).getPath()+""; String mimeType = IOHelper.getMIMEType(title); long size = 50*1024*1024; Res res = new Res(new MimeType(mimeType.substring(0, mimeType.indexOf('/')), mimeType.substring(mimeType .indexOf('/') + 1)), size, "http://" + mediaServer.getAddress() + "/" + id); TextItem textItem = new TextItem(id, ContentTree.FILE_ID, title, creator, res); docContainer.addItem(textItem); docContainer .setChildCount(docContainer.getChildCount() + 1); ContentTree.addNode(id, new ContentNode(id, textItem, filePath)); //Log.i(TAG, "added doc item " + title + "from " + filePath); } } dosearch(); break; default: break; } } }; } private IShareService.Stub mBinder = new IShareService.Stub(){ @Override public void start() throws RemoteException { mbstarted = true; try { if(upnpService==null){ final Intent intent = new Intent(ShareService.this,WireUpnpService.class); getApplicationContext().bindService(intent,serviceConnection,Context.BIND_AUTO_CREATE); }else { startupnpService(); } } catch (Exception e1) { e1.printStackTrace(); } } @Override public void stop() throws RemoteException { cleanService(); mbstarted = false; } @Override public void restart() throws RemoteException { stop(); start(); } @Override public boolean isStarted() throws RemoteException { return mbstarted; } @Override public void updateconfig(String devname,boolean bsharevideo,boolean bsharemusic,boolean bsharepicture,boolean sharedoc) throws RemoteException { mbsharevideo=bsharevideo; mbsharemusic=bsharemusic; mbsharepicture=bsharepicture; mbsharedoc=sharedoc; mdevicename=devname; } @Override public String getCurDevName() throws RemoteException { return mdevicename; } @Override public boolean getbsharevideo() throws RemoteException { return mbsharevideo; } @Override public boolean getbsharemusic() throws RemoteException { return mbsharemusic; } @Override public boolean getbsharepicture() throws RemoteException { return mbsharepicture; } @Override public boolean getbsharedoc() throws RemoteException { return mbsharedoc; } }; @Override public void onDestroy() { mbstarted = false; cleanService(); if(upnpService!=null){ getApplicationContext().unbindService(serviceConnection); } super.onDestroy(); } private void startupnpService() { Log.i(TAG, "startupnpService upnpService="+upnpService); if(upnpService==null){ final Intent intent = new Intent(this,WireUpnpService.class); getApplicationContext().bindService(intent,serviceConnection,Context.BIND_AUTO_CREATE); }else { cleanService(); try { mediaServer = new MediaServer(getLocalIpAddress(),mdevicename); upnpService.getRegistry() .addDevice(mediaServer.getDevice()); autoNotifyDevices(); prepareMediaServer(); } catch (Exception ex) { return; } } } private void cleanService() { if(upnpService!=null){ if (mediaServer != null) { upnpService.getRegistry().removeDevice(mediaServer.getDevice()); mediaServer.stopHttpServer(); clearMediaServer(); mediaServer=null; } } } private ServiceConnection serviceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { upnpService = (AndroidUpnpService) service; Log.i(TAG, "Connected to UPnP Service"); startupnpService(); } public void onServiceDisconnected(ComponentName className) { upnpService = null; } }; private void prepareMediaServer() { if (serverPrepared) return; startsearch(); serverPrepared = true; } private void clearMediaServer() { if (serverPrepared==false) return; // stop handle stopsearch(); ContentTree.resetRootNode(); serverPrepared = false; } // FIXME: now only can get wifi address private InetAddress getLocalIpAddress() throws UnknownHostException { WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE); WifiInfo wifiInfo = wifiManager.getConnectionInfo(); int ipAddress = wifiInfo.getIpAddress(); return InetAddress.getByName(String.format("%d.%d.%d.%d", (ipAddress & 0xff), (ipAddress >> 8 & 0xff), (ipAddress >> 16 & 0xff), (ipAddress >> 24 & 0xff))); } private void searchVideo() { new Thread(){ public void run(){ List<File> files = FileFilterUtil.getFiles(Environment .getExternalStorageDirectory().getPath(), new String[] { "flv","mkv","mp4","3gp","wmv"}); Message msg = new Message(); msg.what = UPDATE_VIDEO; msg.obj = files; handler.sendMessage(msg); } }.start(); } private void searchMusic() { new Thread(){ public void run(){ List<File> files = FileFilterUtil.getFiles(Environment .getExternalStorageDirectory().getPath(), new String[] { "mp3"}); Message msg = new Message(); msg.what = UPDATE_MUISC; msg.obj = files; handler.sendMessage(msg); } }.start(); } private void searchPic() { new Thread(){ public void run(){ List<File> files = FileFilterUtil.getFiles(Environment .getExternalStorageDirectory().getPath(), new String[] { "jpg"}); Message msg = new Message(); msg.what = UPDATE_PIC; msg.obj = files; handler.sendMessage(msg); } }.start(); } private void searchFile() { new Thread(){ public void run(){ List<File> files = FileFilterUtil.getFiles(Environment .getExternalStorageDirectory().getPath(), new String[] { "doc","pdf","txt","xls","xlsx","docx"}); Message msg = new Message(); msg.what = UPDATE_FILE; msg.obj = files; handler.sendMessage(msg); } }.start(); } private void dosearch() { Log.i(TAG,"dosearch loadstep ="+ mloadstep+ ";bstarted="+mbstarted); if(mbstarted ==false) { mloadstep=LOADSTEP_IDLE; return; } if(mloadstep==LOADSTEP_IDLE) { return; } if(mloadstep==LOADSTEP_STOPPENDING) { mloadstep=LOADSTEP_BEGIN; //continue } if(mloadstep==LOADSTEP_BEGIN) { if(mbsharevideo==true) { mloadstep=LOADSTEP_VIDEO; searchVideo(); return ; }else { //next step continue mloadstep=LOADSTEP_VIDEO; } } if(mloadstep==LOADSTEP_VIDEO) { if(mbsharemusic==true) { mloadstep=LOADSTEP_MUISC; searchMusic(); return ; }else { //next step continue mloadstep=LOADSTEP_MUISC; } } if(mloadstep==LOADSTEP_MUISC) { if(mbsharepicture==true) { mloadstep=LOADSTEP_PIC; searchPic(); return ; }else { //next step continue mloadstep=LOADSTEP_PIC; } } if(mloadstep==LOADSTEP_PIC) { if(mbsharedoc==true) { mloadstep=LOADSTEP_FILE; searchFile(); return ; }else { //next step continue mloadstep=LOADSTEP_FILE; } } if(mloadstep==LOADSTEP_FILE) { mloadstep=LOADSTEP_IDLE; return; } return; } private void startsearch() { Log.i(TAG,"startsearch loadstep ="+ mloadstep); if(mloadstep==LOADSTEP_IDLE) { mloadstep=LOADSTEP_BEGIN; }else if (mloadstep==LOADSTEP_STOPPENDING) { return; } dosearch(); return; } private void stopsearch() { Log.i(TAG,"stopsearch loadstep ="+ mloadstep); if(mloadstep!=LOADSTEP_IDLE) { mloadstep=LOADSTEP_STOPPENDING; } } private final Runnable mautoNotifyDevicesRunnable = new Runnable() { public void run() { if(mbstarted==true){ if(upnpService!=null){ if (mediaServer != null) { upnpService.getRegistry().removeDevice(mediaServer.getDevice()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } upnpService.getRegistry().addDevice(mediaServer.getDevice()); } } handler.postDelayed(mautoNotifyDevicesRunnable,60*1000); } } }; private void autoNotifyDevices() { Log.i(TAG,"autoNotifyDevices"); handler.removeCallbacks(mautoNotifyDevicesRunnable); if(mbstarted==true){ handler.postDelayed(mautoNotifyDevicesRunnable,60*1000); } } }