FileDocCategorySizeDatePackage
FileListingService.javaAPI DocAndroid 1.5 API27022Wed May 06 22:41:08 BST 2009com.android.ddmlib

FileListingService

public final class FileListingService extends Object
Provides {@link Device} side file listing service.

To get an instance for a known {@link Device}, call {@link Device#getFileListingService()}.

Fields Summary
private static final Pattern
sApkPattern
Pattern to find filenames that match "*.apk"
private static final String
PM_FULL_LISTING
private static final Pattern
sPmPattern
Pattern to parse the output of the 'pm -lf' command.
The output format looks like:
/data/app/myapp.apk=com.mypackage.myapp
public static final String
DIRECTORY_DATA
Top level data folder.
public static final String
DIRECTORY_SDCARD
Top level sdcard folder.
public static final String
DIRECTORY_SYSTEM
Top level system folder.
public static final String
DIRECTORY_TEMP
Top level temp folder.
public static final String
DIRECTORY_APP
Application folder.
private static final String[]
sRootLevelApprovedItems
public static final long
REFRESH_RATE
static final long
REFRESH_TEST
Refresh test has to be slightly lower for precision issue.
public static final int
TYPE_FILE
Entry type: File
public static final int
TYPE_DIRECTORY
Entry type: Directory
public static final int
TYPE_DIRECTORY_LINK
Entry type: Directory Link
public static final int
TYPE_BLOCK
Entry type: Block
public static final int
TYPE_CHARACTER
Entry type: Character
public static final int
TYPE_LINK
Entry type: Link
public static final int
TYPE_SOCKET
Entry type: Socket
public static final int
TYPE_FIFO
Entry type: FIFO
public static final int
TYPE_OTHER
Entry type: Other
public static final String
FILE_SEPARATOR
Device side file separator.
private static final String
FILE_ROOT
private static Pattern
sLsPattern
Regexp pattern to parse the result from ls.
private Device
mDevice
private FileEntry
mRoot
private ArrayList
mThreadList
Constructors Summary
FileListingService(Device device)
Creates a File Listing Service for a specified {@link Device}.

param
device The Device the service is connected to.

        mDevice = device;
    
Methods Summary
private voiddoLs(com.android.ddmlib.FileListingService$FileEntry entry)

        // create a list that will receive the list of the entries
        ArrayList<FileEntry> entryList = new ArrayList<FileEntry>();

        // create a list that will receive the link to compute post ls;
        ArrayList<String> linkList = new ArrayList<String>();

        try {
            // create the command
            String command = "ls -l " + entry.getFullPath(); //$NON-NLS-1$

            // create the receiver object that will parse the result from ls
            LsReceiver receiver = new LsReceiver(entry, entryList, linkList);

            // call ls.
            mDevice.executeShellCommand(command, receiver);

            // finish the process of the receiver to handle links
            receiver.finishLinks();
        } catch (IOException e) {
        }


        // at this point we need to refresh the viewer
        entry.fetchTime = System.currentTimeMillis();

        // sort the children and set them as the new children
        Collections.sort(entryList, FileEntry.sEntryComparator);
        entry.setChildren(entryList);
    
public com.android.ddmlib.FileListingService$FileEntry[]getChildren(com.android.ddmlib.FileListingService$FileEntry entry, boolean useCache, com.android.ddmlib.FileListingService$IListingReceiver receiver)
Returns the children of a {@link FileEntry}.

This method supports a cache mechanism and synchronous and asynchronous modes.

If receiver is null, the device side ls command is done synchronously, and the method will return upon completion of the command.
If receiver is non null, the command is launched is a separate thread and upon completion, the receiver will be notified of the result.

The result for each ls command is cached in the parent FileEntry. useCache allows usage of this cache, but only if the cache is valid. The cache is valid only for {@link FileListingService#REFRESH_RATE} ms. After that a new ls command is always executed.

If the cache is valid and useCache == true, the method will always simply return the value of the cache, whether a {@link IListingReceiver} has been provided or not.

param
entry The parent entry.
param
useCache A flag to use the cache or to force a new ls command.
param
receiver A receiver for asynchronous calls.
return
The list of children or null for asynchronous calls.
see
FileEntry#getCachedChildren()

        // first thing we do is check the cache, and if we already have a recent
        // enough children list, we just return that.
        if (useCache && entry.needFetch() == false) {
            return entry.getCachedChildren();
        }

        // if there's no receiver, then this is a synchronous call, and we
        // return the result of ls
        if (receiver == null) {
            doLs(entry);
            return entry.getCachedChildren();
        }

        // this is a asynchronous call.
        // we launch a thread that will do ls and give the listing
        // to the receiver
        Thread t = new Thread("ls " + entry.getFullPath()) { //$NON-NLS-1$
            @Override
            public void run() {
                doLs(entry);

                receiver.setChildren(entry, entry.getCachedChildren());

                final FileEntry[] children = entry.getCachedChildren();
                if (children.length > 0 && children[0].isApplicationPackage()) {
                    final HashMap<String, FileEntry> map = new HashMap<String, FileEntry>();

                    for (FileEntry child : children) {
                        String path = child.getFullPath();
                        map.put(path, child);
                    }

                    // call pm.
                    String command = PM_FULL_LISTING;
                    try {
                        mDevice.executeShellCommand(command, new MultiLineReceiver() {
                            @Override
                            public void processNewLines(String[] lines) {
                                for (String line : lines) {
                                    if (line.length() > 0) {
                                        // get the filepath and package from the line
                                        Matcher m = sPmPattern.matcher(line);
                                        if (m.matches()) {
                                            // get the children with that path
                                            FileEntry entry = map.get(m.group(1));
                                            if (entry != null) {
                                                entry.info = m.group(2);
                                                receiver.refreshEntry(entry);
                                            }
                                        }
                                    }
                                }
                            }
                            public boolean isCancelled() {
                                return false;
                            }
                        });
                    } catch (IOException e) {
                        // adb failed somehow, we do nothing.
                    }
                }


                // if another thread is pending, launch it
                synchronized (mThreadList) {
                    // first remove ourselves from the list
                    mThreadList.remove(this);

                    // then launch the next one if applicable.
                    if (mThreadList.size() > 0) {
                        Thread t = mThreadList.get(0);
                        t.start();
                    }
                }
            }
        };

        // we don't want to run multiple ls on the device at the same time, so we
        // store the thread in a list and launch it only if there's no other thread running.
        // the thread will launch the next one once it's done.
        synchronized (mThreadList) {
            // add to the list
            mThreadList.add(t);

            // if it's the only one, launch it.
            if (mThreadList.size() == 1) {
                t.start();
            }
        }

        // and we return null.
        return null;
    
public com.android.ddmlib.FileListingService$FileEntrygetRoot()
Returns the root element.

return
the {@link FileEntry} object representing the root element or null if the device is invalid.

        if (mDevice != null) {
            if (mRoot == null) {
                mRoot = new FileEntry(null /* parent */, "" /* name */, TYPE_DIRECTORY,
                        true /* isRoot */);
            }

            return mRoot;
        }

        return null;