OSDN Git Service

Made NavigationView reliant on FileObserver to keep up to date.
authorherriojr <jherriott@cyngn.com>
Tue, 28 Jul 2015 21:52:47 +0000 (14:52 -0700)
committerherriojr <jherriott@cyngn.com>
Fri, 31 Jul 2015 18:25:41 +0000 (11:25 -0700)
We no longer deal with having to refresh a directory upon reentering.
Instead we now just listen on the directory for changes and update as
necessary.  This will make it much more difficult to get out of sync
with the file system in pretty much all situations.

Changed per comments on patch to no longer do refreshes for the list
when items change as the FileObserver handles all of this.

Change-Id: I28a6af965708ce76107a09d6b931f4c7bafb8365
Ticket: QRDL-932

src/com/cyanogenmod/filemanager/activities/NavigationActivity.java
src/com/cyanogenmod/filemanager/model/Directory.java
src/com/cyanogenmod/filemanager/model/FileSystemObject.java
src/com/cyanogenmod/filemanager/model/RegularFile.java
src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java
src/com/cyanogenmod/filemanager/util/FileHelper.java

index d65568f..ac4c9b2 100755 (executable)
@@ -297,20 +297,6 @@ public class NavigationActivity extends Activity
                     }
 
                 } else if (intent.getAction().compareTo(
-                        FileManagerSettings.INTENT_FILE_CHANGED) == 0) {
-                    // Retrieve the file that was changed
-                    String file =
-                            intent.getStringExtra(FileManagerSettings.EXTRA_FILE_CHANGED_KEY);
-                    try {
-                        FileSystemObject fso = CommandHelper.getFileInfo(context, file, null);
-                        if (fso != null) {
-                            getCurrentNavigationView().refresh(fso);
-                        }
-                    } catch (Exception e) {
-                        ExceptionUtil.translateException(context, e, true, false);
-                    }
-
-                } else if (intent.getAction().compareTo(
                         FileManagerSettings.INTENT_THEME_CHANGED) == 0) {
                     applyTheme();
 
@@ -644,7 +630,6 @@ public class NavigationActivity extends Activity
         if (curDir != null) {
             VirtualMountPointConsole vc = VirtualMountPointConsole.getVirtualConsoleForPath(
                     mNavigationViews[mCurrentNavigationView].getCurrentDir());
-            getCurrentNavigationView().refresh(true);
             if (vc != null && !vc.isMounted()) {
                 onRequestBookmarksRefresh();
                 removeUnmountedHistory();
@@ -1942,10 +1927,6 @@ public class NavigationActivity extends Activity
                         if (searchInfo != null && searchInfo.isSuccessNavigation()) {
                             //Navigate to previous history
                             back();
-                        } else {
-                            // I don't know is the search view was changed, so try to do a refresh
-                            // of the navigation view
-                            getCurrentNavigationView().refresh(true);
                         }
                     }
                     // reset bookmarks list to default as the user could have set a
@@ -1982,13 +1963,6 @@ public class NavigationActivity extends Activity
      */
     @Override
     public void onRequestRefresh(Object o, boolean clearSelection) {
-        if (o instanceof FileSystemObject) {
-            // Refresh only the item
-            this.getCurrentNavigationView().refresh((FileSystemObject)o);
-        } else if (o == null) {
-            // Refresh all
-            getCurrentNavigationView().refresh();
-        }
         if (clearSelection) {
             this.getCurrentNavigationView().onDeselectAll();
         }
@@ -2008,13 +1982,8 @@ public class NavigationActivity extends Activity
     @Override
     public void onRequestRemove(Object o, boolean clearSelection) {
         if (o instanceof FileSystemObject) {
-            // Remove from view
-            this.getCurrentNavigationView().removeItem((FileSystemObject)o);
-
             //Remove from history
             removeFromHistory((FileSystemObject)o);
-        } else {
-            onRequestRefresh(null, clearSelection);
         }
         if (clearSelection) {
             this.getCurrentNavigationView().onDeselectAll();
@@ -2367,19 +2336,8 @@ public class NavigationActivity extends Activity
             }
 
         } catch (Exception e) {
-            // Notify the user
+            // Do nothing, objects should be removed by the FileObserver in NavigationView
             ExceptionUtil.translateException(this, e);
-
-            // Remove the object
-            if (e instanceof FileNotFoundException || e instanceof NoSuchFileOrDirectory) {
-                // If have a FileSystemObject reference then there is no need to search
-                // the path (less resources used)
-                if (item instanceof FileSystemObject) {
-                    getCurrentNavigationView().removeItem((FileSystemObject)item);
-                } else {
-                    getCurrentNavigationView().removeItem((String)item);
-                }
-            }
             return;
         }
 
index 77b1208..47e53e2 100644 (file)
@@ -37,6 +37,12 @@ public class Directory extends FileSystemObject {
     public static final char UNIX_ID = 'd';
 
     /**
+     * Normally, you shouldn't call this, however, this is in to be able
+     * to further abstract some calls in FileHelper.
+     **/
+    public Directory() {}
+
+    /**
      * Constructor of <code>Directory</code>.
      *
      * @param name The name of the object
index 578ea32..f82ff0b 100644 (file)
@@ -54,6 +54,12 @@ public abstract class FileSystemObject implements Serializable, Comparable<FileS
     private boolean mIsRemote;
 
     /**
+     * Normally, you shouldn't call this, however, this is in to be able
+     * to further abstract some calls in FileHelper.
+     **/
+    public FileSystemObject() {}
+
+    /**
      * Constructor of <code>FileSystemObject</code>.
      *
      * @param name The name of the object
index 49c9fd7..cd8b886 100644 (file)
@@ -32,6 +32,12 @@ public class RegularFile extends FileSystemObject {
     public static final char UNIX_ID = '-';
 
     /**
+     * Normally, you shouldn't call this, however, this is in to be able
+     * to further abstract some calls in FileHelper.
+     **/
+    public RegularFile() {}
+
+    /**
      * Constructor of <code>RegularFile</code>.
      *
      * @param name The name of the object
index 3510f2c..d947bb8 100755 (executable)
@@ -21,6 +21,7 @@ import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.res.TypedArray;
 import android.os.AsyncTask;
+import android.os.FileObserver;
 import android.os.storage.StorageVolume;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -438,6 +439,8 @@ BreadcrumbListener, OnSelectionChangedListener, OnSelectionListener, OnRequestRe
     // Restrictions
     private Map<DisplayRestrictions, Object> mRestrictions;
 
+    private FileObserver mCurrentDirObserver;
+
     /**
      * @hide
      */
@@ -828,6 +831,7 @@ BreadcrumbListener, OnSelectionChangedListener, OnSelectionListener, OnRequestRe
     public void recycle() {
         if (this.mAdapter != null) {
             this.mAdapter.dispose();
+            this.mCurrentDirObserver.stopWatching();
         }
     }
 
@@ -941,38 +945,6 @@ BreadcrumbListener, OnSelectionChangedListener, OnSelectionListener, OnRequestRe
     }
 
     /**
-     * Method that removes a {@link FileSystemObject} from the view
-     *
-     * @param fso The file system object
-     */
-    public void removeItem(FileSystemObject fso) {
-        // Delete also from internal list
-        if (fso != null) {
-            int cc = this.mFiles.size()-1;
-            for (int i = cc; i >= 0; i--) {
-                FileSystemObject f = this.mFiles.get(i);
-                if (f != null && f.compareTo(fso) == 0) {
-                    this.mFiles.remove(i);
-                    break;
-                }
-            }
-        }
-        this.mAdapter.remove(fso);
-    }
-
-    /**
-     * Method that removes a file system object from his path from the view
-     *
-     * @param path The file system object path
-     */
-    public void removeItem(String path) {
-        FileSystemObject fso = this.mAdapter.getItem(path);
-        if (fso != null) {
-            this.mAdapter.remove(fso);
-        }
-    }
-
-    /**
      * Method that returns the current directory.
      *
      * @return String The current directory
@@ -1024,6 +996,10 @@ BreadcrumbListener, OnSelectionChangedListener, OnSelectionListener, OnRequestRe
             final String newDir, final boolean addToHistory,
             final boolean reload, final boolean useCurrent,
             final SearchInfoParcelable searchInfo, final FileSystemObject scrollTo) {
+        if (mCurrentDirObserver != null) {
+            mCurrentDirObserver.stopWatching();
+            mCurrentDirObserver = null;
+        }
         NavigationTask task = new NavigationTask(useCurrent, addToHistory, reload,
                 searchInfo, scrollTo, mRestrictions, mChRooted);
         task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, newDir);
@@ -1066,7 +1042,7 @@ BreadcrumbListener, OnSelectionChangedListener, OnSelectionListener, OnRequestRe
     void onPostExecuteTask(
             List<FileSystemObject> files, boolean addToHistory, boolean isNewHistory,
             boolean hasChanged, SearchInfoParcelable searchInfo,
-            String newDir, final FileSystemObject scrollTo) {
+            final String newDir, final FileSystemObject scrollTo) {
         try {
             //Check that there is not errors and have some data
             if (files == null) {
@@ -1105,6 +1081,66 @@ BreadcrumbListener, OnSelectionChangedListener, OnSelectionListener, OnRequestRe
 
             //The current directory is now the "newDir"
             this.mCurrentDir = newDir;
+            mCurrentDirObserver = new FileObserver(newDir) {
+                @Override
+                public void onEvent(int event, final String path) {
+                    Runnable runnable = null;
+                    final String fullPath = newDir + '/' + path;
+                    // This is done because the implementation doesn't match the documentation
+                    // for FileObserver and we are given undocumented flags.
+                    event &= FileObserver.ALL_EVENTS;
+
+                    switch (event) {
+                        case FileObserver.CREATE:
+                        case FileObserver.MOVED_TO: {
+                            final FileSystemObject fso = FileHelper.createFileSystemObject(
+                                    new File(fullPath));
+
+                            if (FileHelper.shouldShow(fso, mRestrictions, mChRooted)) {
+                                runnable = new Runnable() {
+                                    @Override
+                                            public void run() {
+                                        mAdapter.add(fso);
+                                        // TODO: refactor to move this off of UI thread
+                                        mAdapter.sort(FileHelper.getSortComparator());
+                                    }
+                                };
+                                break;
+                            }
+                        } case FileObserver.DELETE:
+                          case FileObserver.MOVED_FROM: {
+                              runnable = new Runnable() {
+                                  @Override
+                                  public void run() {
+                                      mAdapter.remove(mAdapter.getItem(fullPath));
+                                  }
+                              };
+                            break;
+                        } case FileObserver.DELETE_SELF: {
+                            // TODO: Actually handle this
+                            break;
+
+                        } case FileObserver.MODIFY: {
+                            runnable = new Runnable() {
+                                @Override
+                                public void run() {
+                                    FileHelper.updateFileSystemObject(mAdapter.getItem(fullPath));
+                                    mAdapter.notifyDataSetChanged();
+                                }
+                            };
+                            break;
+                        }
+                        default:
+                            Log.w(TAG, "Unknown event " + event + " for " + fullPath);
+                    }
+
+                    if (runnable != null) {
+                        post(runnable);
+                    }
+                }
+            };
+            mCurrentDirObserver.startWatching();
+
             if (this.mOnDirectoryChangedListener != null) {
                 FileSystemObject dir = FileHelper.createFileSystemObject(new File(newDir));
                 this.mOnDirectoryChangedListener.onDirectoryChanged(dir);
@@ -1240,11 +1276,6 @@ BreadcrumbListener, OnSelectionChangedListener, OnSelectionListener, OnRequestRe
      */
     @Override
     public void onRequestRefresh(Object o, boolean clearSelection) {
-        if (o instanceof FileSystemObject) {
-            refresh((FileSystemObject)o);
-        } else if (o == null) {
-            refresh();
-        }
         if (clearSelection) {
             onDeselectAll();
         }
@@ -1263,11 +1294,6 @@ BreadcrumbListener, OnSelectionChangedListener, OnSelectionListener, OnRequestRe
      */
     @Override
     public void onRequestRemove(Object o, boolean clearSelection) {
-        if (o != null && o instanceof FileSystemObject) {
-            removeItem((FileSystemObject)o);
-        } else {
-            onRequestRefresh(null, clearSelection);
-        }
         if (clearSelection) {
             onDeselectAll();
         }
index 501092a..b2389a9 100644 (file)
@@ -515,6 +515,103 @@ public final class FileHelper {
         return fso;
     }
 
+
+    public static boolean shouldShow(FileSystemObject file,
+                                     Map<DisplayRestrictions, Object> restrictions,
+                                     boolean chRooted) {
+        //Retrieve user preferences
+        SharedPreferences prefs = Preferences.getSharedPreferences();
+        FileManagerSettings showHiddenPref = FileManagerSettings.SETTINGS_SHOW_HIDDEN;
+        FileManagerSettings showSystemPref = FileManagerSettings.SETTINGS_SHOW_SYSTEM;
+        FileManagerSettings showSymlinksPref = FileManagerSettings.SETTINGS_SHOW_SYMLINKS;
+
+        //Hidden files
+        if (!prefs.getBoolean(
+                showHiddenPref.getId(),
+                ((Boolean)showHiddenPref.getDefaultValue()).booleanValue()) || chRooted) {
+            if (file.isHidden()) {
+                return false;
+            }
+        }
+
+        //System files
+        if (!prefs.getBoolean(
+                showSystemPref.getId(),
+                ((Boolean)showSystemPref.getDefaultValue()).booleanValue()) || chRooted) {
+            if (file instanceof SystemFile) {
+                return false;
+            }
+        }
+
+        //Symlinks files
+        if (!prefs.getBoolean(
+                showSymlinksPref.getId(),
+                ((Boolean)showSymlinksPref.getDefaultValue()).booleanValue()) || chRooted) {
+            if (file instanceof Symlink) {
+                return false;
+            }
+        }
+
+        // Restrictions (only apply to files)
+        if (restrictions != null) {
+            if (!isDirectory(file)) {
+                if (!isDisplayAllowed(file, restrictions)) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    public static Comparator<FileSystemObject> getSortComparator() {
+
+        //Retrieve user preferences
+        SharedPreferences prefs = Preferences.getSharedPreferences();
+        FileManagerSettings sortModePref = FileManagerSettings.SETTINGS_SORT_MODE;
+        FileManagerSettings showDirsFirstPref = FileManagerSettings.SETTINGS_SHOW_DIRS_FIRST;
+
+        final boolean showDirsFirst =
+                prefs.getBoolean(
+                        showDirsFirstPref.getId(),
+                        ((Boolean)showDirsFirstPref.getDefaultValue()).booleanValue());
+        final NavigationSortMode sortMode =
+                NavigationSortMode.fromId(
+                        prefs.getInt(sortModePref.getId(),
+                                ((ObjectIdentifier) sortModePref.getDefaultValue()).getId()));
+
+        return new Comparator<FileSystemObject>() {
+            @Override
+            public int compare(FileSystemObject lhs, FileSystemObject rhs) {
+                //Parent directory always goes first
+                boolean isLhsParentDirectory = lhs instanceof ParentDirectory;
+                boolean isRhsParentDirectory = rhs instanceof ParentDirectory;
+                if (isLhsParentDirectory || isRhsParentDirectory) {
+                    if (isLhsParentDirectory && isRhsParentDirectory) {
+                        return 0;
+                    }
+                    return (isLhsParentDirectory) ? -1 : 1;
+                }
+
+                //Need to sort directory first?
+                if (showDirsFirst) {
+                    boolean isLhsDirectory = FileHelper.isDirectory(lhs);
+                    boolean isRhsDirectory = FileHelper.isDirectory(rhs);
+                    if (isLhsDirectory || isRhsDirectory) {
+                        if (isLhsDirectory && isRhsDirectory) {
+                            //Apply sort mode
+                            return FileHelper.doCompare(lhs, rhs, sortMode);
+                        }
+                        return (isLhsDirectory) ? -1 : 1;
+                    }
+                }
+
+                //Apply sort mode
+                return FileHelper.doCompare(lhs, rhs, sortMode);
+            }
+        };
+    }
+
     /**
      * Method that applies the configuration modes to the listed files
      * (sort mode, hidden files, ...).
@@ -543,101 +640,18 @@ public final class FileHelper {
     public static List<FileSystemObject> applyUserPreferences(
             List<FileSystemObject> files, Map<DisplayRestrictions, Object> restrictions,
             boolean noSort, boolean chRooted) {
-        //Retrieve user preferences
-        SharedPreferences prefs = Preferences.getSharedPreferences();
-        FileManagerSettings sortModePref = FileManagerSettings.SETTINGS_SORT_MODE;
-        FileManagerSettings showDirsFirstPref = FileManagerSettings.SETTINGS_SHOW_DIRS_FIRST;
-        FileManagerSettings showHiddenPref = FileManagerSettings.SETTINGS_SHOW_HIDDEN;
-        FileManagerSettings showSystemPref = FileManagerSettings.SETTINGS_SHOW_SYSTEM;
-        FileManagerSettings showSymlinksPref = FileManagerSettings.SETTINGS_SHOW_SYMLINKS;
 
         //Remove all unnecessary files (no required by the user)
         int cc = files.size();
         for (int i = cc - 1; i >= 0; i--) {
-            FileSystemObject file = files.get(i);
-
-            //Hidden files
-            if (!prefs.getBoolean(
-                    showHiddenPref.getId(),
-                    ((Boolean)showHiddenPref.getDefaultValue()).booleanValue()) || chRooted) {
-                if (file.isHidden()) {
-                    files.remove(i);
-                    continue;
-                }
-            }
-
-            //System files
-            if (!prefs.getBoolean(
-                    showSystemPref.getId(),
-                    ((Boolean)showSystemPref.getDefaultValue()).booleanValue()) || chRooted) {
-                if (file instanceof SystemFile) {
-                    files.remove(i);
-                    continue;
-                }
-            }
-
-            //Symlinks files
-            if (!prefs.getBoolean(
-                    showSymlinksPref.getId(),
-                    ((Boolean)showSymlinksPref.getDefaultValue()).booleanValue()) || chRooted) {
-                if (file instanceof Symlink) {
-                    files.remove(i);
-                    continue;
-                }
-            }
-
-            // Restrictions (only apply to files)
-            if (restrictions != null) {
-                if (!isDirectory(file)) {
-                    if (!isDisplayAllowed(file, restrictions)) {
-                        files.remove(i);
-                        continue;
-                    }
-                }
+            if (!shouldShow(files.get(i), restrictions, chRooted)) {
+                files.remove(i);
             }
         }
 
         //Apply sort mode
         if (!noSort) {
-            final boolean showDirsFirst =
-                    prefs.getBoolean(
-                            showDirsFirstPref.getId(),
-                        ((Boolean)showDirsFirstPref.getDefaultValue()).booleanValue());
-            final NavigationSortMode sortMode =
-                    NavigationSortMode.fromId(
-                            prefs.getInt(sortModePref.getId(),
-                            ((ObjectIdentifier)sortModePref.getDefaultValue()).getId()));
-            Collections.sort(files, new Comparator<FileSystemObject>() {
-                @Override
-                public int compare(FileSystemObject lhs, FileSystemObject rhs) {
-                    //Parent directory always goes first
-                    boolean isLhsParentDirectory = lhs instanceof ParentDirectory;
-                    boolean isRhsParentDirectory = rhs instanceof ParentDirectory;
-                    if (isLhsParentDirectory || isRhsParentDirectory) {
-                        if (isLhsParentDirectory && isRhsParentDirectory) {
-                            return 0;
-                        }
-                        return (isLhsParentDirectory) ? -1 : 1;
-                    }
-
-                    //Need to sort directory first?
-                    if (showDirsFirst) {
-                        boolean isLhsDirectory = FileHelper.isDirectory(lhs);
-                        boolean isRhsDirectory = FileHelper.isDirectory(rhs);
-                        if (isLhsDirectory || isRhsDirectory) {
-                            if (isLhsDirectory && isRhsDirectory) {
-                                //Apply sort mode
-                                return FileHelper.doCompare(lhs, rhs, sortMode);
-                            }
-                            return (isLhsDirectory) ? -1 : 1;
-                        }
-                    }
-
-                    //Apply sort mode
-                    return FileHelper.doCompare(lhs, rhs, sortMode);
-                }
-
-            });
+            Collections.sort(files, getSortComparator());
         }
 
         //Return the files
@@ -1053,6 +1067,35 @@ public final class FileHelper {
         return relative.toString() + s1.substring(s2.length());
     }
 
+    private static void applyFileToFileSystemObject(File file, FileSystemObject fso) {
+        // The user and group name of the files. Use the defaults one for sdcards
+        final String USER = "root"; //$NON-NLS-1$
+        final String GROUP = "sdcard_r"; //$NON-NLS-1$
+
+        // The user and group name of the files. In ChRoot, aosp give restrict access to
+        // this user and group. This applies for permission also. This has no really much
+        // interest if we not allow to change the permissions
+        AID userAID = AIDHelper.getAIDFromName(USER);
+        AID groupAID = AIDHelper.getAIDFromName(GROUP);
+        User user = new User(userAID.getId(), userAID.getName());
+        Group group = new Group(groupAID.getId(), groupAID.getName());
+        Permissions perm = file.isDirectory()
+                ? Permissions.createDefaultFolderPermissions()
+                : Permissions.createDefaultFilePermissions();
+
+        // Build a directory?
+        Date lastModified = new Date(file.lastModified());
+
+        fso.setName(file.getName());
+        fso.setParent(file.getParent());
+        fso.setUser(user);
+        fso.setGroup(group);
+        fso.setPermissions(perm);
+        fso.setLastModifiedTime(lastModified);
+        fso.setLastAccessedTime(lastModified);
+        fso.setLastChangedTime(lastModified);
+    }
+
     /**
      * Method that creates a {@link FileSystemObject} from a {@link File}
      *
@@ -1061,46 +1104,29 @@ public final class FileHelper {
      */
     public static FileSystemObject createFileSystemObject(File file) {
         try {
-            // The user and group name of the files. Use the defaults one for sdcards
-            final String USER = "root"; //$NON-NLS-1$
-            final String GROUP = "sdcard_r"; //$NON-NLS-1$
-
-            // The user and group name of the files. In ChRoot, aosp give restrict access to
-            // this user and group. This applies for permission also. This has no really much
-            // interest if we not allow to change the permissions
-            AID userAID = AIDHelper.getAIDFromName(USER);
-            AID groupAID = AIDHelper.getAIDFromName(GROUP);
-            User user = new User(userAID.getId(), userAID.getName());
-            Group group = new Group(groupAID.getId(), groupAID.getName());
-            Permissions perm = file.isDirectory()
-                    ? Permissions.createDefaultFolderPermissions()
-                    : Permissions.createDefaultFilePermissions();
-
-            // Build a directory?
-            Date lastModified = new Date(file.lastModified());
-            if (file.isDirectory()) {
-                return
-                    new Directory(
-                            file.getName(),
-                            file.getParent(),
-                            user, group, perm,
-                            lastModified, lastModified, lastModified); // The only date we have
-            }
-
-            // Build a regular file
-            return
-                new RegularFile(
-                        file.getName(),
-                        file.getParent(),
-                        user, group, perm,
-                        file.length(),
-                        lastModified, lastModified, lastModified); // The only date we have
+            FileSystemObject fso = file.isDirectory() ? new Directory() : new RegularFile();
+            applyFileToFileSystemObject(file, fso);
+            return fso;
         } catch (Exception e) {
             Log.e(TAG, "Exception retrieving the fso", e); //$NON-NLS-1$
         }
         return null;
     }
 
+
+    /**
+     * Method that updates a {@link FileSystemObject}
+     *
+     * @param fso The {@link FileSystemObject} to update
+     */
+    public static void updateFileSystemObject(FileSystemObject fso) {
+        try {
+            applyFileToFileSystemObject(new File(fso.getFullPath()), fso);
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to apply changes to " + fso.getFullPath(), e);
+        }
+    }
+
     /**
      * Method that copies recursively to the destination
      *