Thursday, June 24, 2010

Working with the SyncService

I have gotten a few more key parts of the Managed Android Debug Bridge done. The SyncService has some important methods completed. I have been able to successfully pull a single file from a device, and push a single file to a device. Still not working is the ability to push and pull multiple files, but that is next.

Even though this is a port of the DDMS library, I have taken it upon myself to make some needed changes to some components. For example, when pulling a file, here is the original ddmslib code:

public SyncResult pullFile(String remoteFilepath, String localFilename, ISyncProgressMonitor monitor) {
monitor.start(0);
//TODO: use the {@link FileListingService} to get the file size.

SyncResult result = doPullFile(remoteFilepath, localFilename, monitor);
monitor.stop();
return result;
}


Notice the “TODO”, this means that when this method is used to pull a file, there is no “notifications” to the ISyncProgressMonitor since the total bytes is set to 0 in the monitor.start. I took the 5 minutes to actually write the method in the FileListingService that can take a string path, and find the FileEntry object, or it will throw a FileNotFoundException. Once we have the FileEntry, we can determine how much data is going to be transfered. Here is the same method, but in MADB.



public SyncResult PullFile ( String remoteFilepath, String localFilename, ISyncProgressMonitor monitor ) {
if ( monitor == null ) {
throw new ArgumentNullException ( "monitor", "Monitor cannot be null" );
}

long totalWork = 0;
try {
FileListingService fls = new FileListingService ( this.Device );
FileEntry remoteFileEntry = fls.FindEntry ( remoteFilepath );
totalWork = remoteFileEntry.Size;
} catch ( FileNotFoundException ffe ) {
Console.WriteLine ( ffe.ToString ( ) );
Log.w ( "ddms", ffe );
}
monitor.Start ( totalWork );

SyncResult result = DoPullFile ( remoteFilepath, localFilename, monitor );

monitor.Stop ( );
return result;
}


If it fails to find the FileEntry, then it continues on just like the original does. Here is the FindFileEntry method in the FileListingService.



public FileEntry FindFileEntry ( String path ) {
String[] entriesString = path.Split ( new char[] { LinuxPath.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries );
FileEntry current = this.Root;
foreach ( var pathItem in entriesString ) {
FileEntry[] entries = GetChildren ( current, true, null );
foreach ( var e in entries ) {
if ( String.Compare ( e.Name, pathItem, false ) == 0 ) {
current = e;
continue;
}
}
}
if ( String.Compare ( current.FullPath, path, false ) == 0 ) {
Console.WriteLine ( "returning: {0}", current.FullPath );
return current;
} else {
throw new FileNotFoundException ( String.Format ( "Unable to locate {0}", path ) );
}
}


Another thing that I thought should be modified was the Regex used for the FileListingService. In the original version, it only supports the stock Android ls command. I have modified it to support the stock ls, plus it supports busybox ls as well. This was a selfish act, since it helps me closer to my goal of not requiring busybox in order for Droid Explorer to work.

Working with the SyncService

I have gotten a few more key parts of the Managed Android Debug Bridge done. The SyncService has some important methods completed. I have been able to successfully pull a single file from a device, and push a single file to a device. Still not working is the ability to push and pull multiple files, but that is next.

Even though this is a port of the DDMS library, I have taken it upon myself to make some needed changes to some components. For example, when pulling a file, here is the original ddmslib code:

public SyncResult pullFile(String remoteFilepath, String localFilename, ISyncProgressMonitor monitor) {
monitor.start(0);
//TODO: use the {@link FileListingService} to get the file size.

SyncResult result = doPullFile(remoteFilepath, localFilename, monitor);
monitor.stop();
return result;
}


Notice the “TODO”, this means that when this method is used to pull a file, there is no “notifications” to the ISyncProgressMonitor since the total bytes is set to 0 in the monitor.start. I took the 5 minutes to actually write the method in the FileListingService that can take a string path, and find the FileEntry object, or it will throw a FileNotFoundException. Once we have the FileEntry, we can determine how much data is going to be transfered. Here is the same method, but in MADB.



public SyncResult PullFile ( String remoteFilepath, String localFilename, ISyncProgressMonitor monitor ) {
if ( monitor == null ) {
throw new ArgumentNullException ( "monitor", "Monitor cannot be null" );
}

long totalWork = 0;
try {
FileListingService fls = new FileListingService ( this.Device );
FileEntry remoteFileEntry = fls.FindEntry ( remoteFilepath );
totalWork = remoteFileEntry.Size;
} catch ( FileNotFoundException ffe ) {
Console.WriteLine ( ffe.ToString ( ) );
Log.w ( "ddms", ffe );
}
monitor.Start ( totalWork );

SyncResult result = DoPullFile ( remoteFilepath, localFilename, monitor );

monitor.Stop ( );
return result;
}


If it fails to find the FileEntry, then it continues on just like the original does. Here is the FindFileEntry method in the FileListingService.



public FileEntry FindFileEntry ( String path ) {
String[] entriesString = path.Split ( new char[] { LinuxPath.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries );
FileEntry current = this.Root;
foreach ( var pathItem in entriesString ) {
FileEntry[] entries = GetChildren ( current, true, null );
foreach ( var e in entries ) {
if ( String.Compare ( e.Name, pathItem, false ) == 0 ) {
current = e;
continue;
}
}
}
if ( String.Compare ( current.FullPath, path, false ) == 0 ) {
Console.WriteLine ( "returning: {0}", current.FullPath );
return current;
} else {
throw new FileNotFoundException ( String.Format ( "Unable to locate {0}", path ) );
}
}


Another thing that I thought should be modified was the Regex used for the FileListingService. In the original version, it only supports the stock Android ls command. I have modified it to support the stock ls, plus it supports busybox ls as well. This was a selfish act, since it helps me closer to my goal of not requiring busybox in order for Droid Explorer to work.