OSDN Git Service

CM File Manager - Make AsyncResultExecutable's cancel() and end() innocuous
[android-x86/packages-apps-CMFileManager.git] / src / com / cyanogenmod / filemanager / commands / secure / FindCommand.java
1 /*
2  * Copyright (C) 2012 The CyanogenMod Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.cyanogenmod.filemanager.commands.secure;
18
19 import android.util.Log;
20
21 import com.cyanogenmod.filemanager.commands.AsyncResultListener;
22 import com.cyanogenmod.filemanager.commands.ConcurrentAsyncResultListener;
23 import com.cyanogenmod.filemanager.commands.FindExecutable;
24 import com.cyanogenmod.filemanager.console.ExecutionException;
25 import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory;
26 import com.cyanogenmod.filemanager.console.secure.SecureConsole;
27 import com.cyanogenmod.filemanager.model.FileSystemObject;
28 import com.cyanogenmod.filemanager.model.Query;
29 import com.cyanogenmod.filemanager.util.FileHelper;
30 import com.cyanogenmod.filemanager.util.SearchHelper;
31
32 import de.schlichtherle.truezip.file.TFile;
33
34 import java.util.Arrays;
35
36 /**
37  * A class for search files.
38  */
39 public class FindCommand extends Program implements FindExecutable {
40
41     private static final String TAG = "FindCommand"; //$NON-NLS-1$
42
43     private final String mDirectory;
44     private final String[] mQueryRegExp;
45     private final ConcurrentAsyncResultListener mAsyncResultListener;
46
47     private volatile boolean mCancelled;
48     private volatile boolean mEnded;
49     private final Object mSync = new Object();
50
51     /**
52      * Constructor of <code>FindCommand</code>.
53      *
54      * @param console The secure console
55      * @param directory The absolute directory where start the search
56      * @param query The terms to be searched
57      * @param asyncResultListener The partial result listener
58      */
59     public FindCommand(SecureConsole console, String directory, Query query,
60             ConcurrentAsyncResultListener asyncResultListener) {
61         super(console);
62         // This command should start the search in the root directory or in a descendent folder
63         if (!getConsole().isSecureStorageResource(directory)) {
64             this.mDirectory = getConsole().getVirtualMountPoint().getAbsolutePath();
65         } else {
66             this.mDirectory = directory;
67         }
68         this.mQueryRegExp = createRegexp(directory, query);
69         this.mAsyncResultListener = asyncResultListener;
70         if (mAsyncResultListener instanceof ConcurrentAsyncResultListener) {
71             ((ConcurrentAsyncResultListener) mAsyncResultListener).onRegister();
72         }
73         this.mCancelled = false;
74         this.mEnded = false;
75     }
76
77     /**
78      * {@inheritDoc}
79      */
80     @Override
81     public boolean isAsynchronous() {
82         return true;
83     }
84
85     /**
86      * {@inheritDoc}
87      */
88     @Override
89     public void execute() throws NoSuchFileOrDirectory, ExecutionException {
90         if (isTrace()) {
91             Log.v(TAG,
92                     String.format("Finding in %s the query %s", //$NON-NLS-1$
93                             this.mDirectory, Arrays.toString(this.mQueryRegExp)));
94         }
95         if (this.mAsyncResultListener != null) {
96             this.mAsyncResultListener.onAsyncStart();
97         }
98
99         TFile f = getConsole().buildRealFile(mDirectory);
100         if (!f.exists()) {
101             if (isTrace()) {
102                 Log.v(TAG, "Result: FAIL. NoSuchFileOrDirectory"); //$NON-NLS-1$
103             }
104             if (this.mAsyncResultListener != null) {
105                 this.mAsyncResultListener.onException(new NoSuchFileOrDirectory(this.mDirectory));
106             }
107         }
108         if (!f.isDirectory()) {
109             if (isTrace()) {
110                 Log.v(TAG, "Result: FAIL. NoSuchFileOrDirectory"); //$NON-NLS-1$
111             }
112             if (this.mAsyncResultListener != null) {
113                 this.mAsyncResultListener.onException(
114                         new ExecutionException("path exists but it's not a folder")); //$NON-NLS-1$
115             }
116         }
117
118         // Find the data
119         findRecursive(f);
120
121         // record program's execution termination
122         synchronized (mSync) {
123             mEnded = true;
124             // account for the delay between the end of findRecursive and setting program
125             // termination flag (mEnded)
126             // notify again in case a thread entered wait state since
127             mSync.notify();
128         }
129
130         if (this.mAsyncResultListener != null) {
131             this.mAsyncResultListener.onAsyncEnd(this.mCancelled);
132         }
133         if (this.mAsyncResultListener != null) {
134             this.mAsyncResultListener.onAsyncExitCode(0);
135         }
136
137         if (isTrace()) {
138             Log.v(TAG, "Result: OK"); //$NON-NLS-1$
139         }
140     }
141
142     /**
143      * Method that search files recursively
144      *
145      * @param folder The folder where to start the search
146      */
147     private void findRecursive(TFile folder) {
148         // Obtains the files and folders of the folders
149         TFile[] files = folder.listFiles();
150         if (files != null) {
151             int cc = files.length;
152             for (int i = 0; i < cc; i++) {
153                 if (files[i].isDirectory()) {
154                     findRecursive(files[i]);
155                 }
156
157                 // Check if the file or folder matches the regexp
158                 try {
159                     int ccc = this.mQueryRegExp.length;
160                     for (int j = 0; j < ccc; j++) {
161                         if (files[i].getName().matches(this.mQueryRegExp[j])) {
162                             FileSystemObject fso = FileHelper.createFileSystemObject(files[i]);
163                             if (fso != null) {
164                                 // Convert to virtual
165                                 fso.setParent(getConsole().buildVirtualPath(
166                                         files[i].getParentFile()));
167                                 fso.setSecure(true);
168
169                                 if (isTrace()) {
170                                     Log.v(TAG, String.valueOf(fso));
171                                 }
172                                 if (this.mAsyncResultListener != null) {
173                                     this.mAsyncResultListener.onPartialResult(fso);
174                                 }
175                             }
176                         }
177                     }
178                 } catch (Exception e) {/**NON-BLOCK**/}
179
180                 // Check if the process was cancelled
181                 try {
182                     synchronized (this.mSync) {
183                         if (this.mCancelled  || this.mEnded || (mAsyncResultListener != null
184                                 && mAsyncResultListener.isCancelled())) {
185                             this.mSync.notify();
186                             break;
187                         }
188                     }
189                 } catch (Exception e) {/**NON BLOCK**/}
190             }
191         }
192     }
193
194     /**
195      * {@inheritDoc}
196      */
197     @Override
198     public boolean isCancelled() {
199         synchronized (this.mSync) {
200             return this.mCancelled;
201         }
202     }
203
204     /**
205      * {@inheritDoc}
206      */
207     @Override
208     public boolean cancel() {
209         try {
210             // ensure the program is running before attempting to cancel
211             // there won't be a corresponding lock.notify() otherwise
212             if (!mEnded) {
213                 this.mCancelled = true;
214                 this.mSync.wait(5000L);
215             }
216         } catch (Exception e) {/**NON BLOCK**/}
217         return true;
218     }
219
220     /**
221      * {@inheritDoc}
222      */
223     @Override
224     public boolean end() {
225         try {
226             // ensure the program is running before attempting to terminate
227             if (!mEnded) {
228                 this.mEnded = true;
229                 this.mSync.wait(5000L);
230             }
231         } catch (Exception e) {/**NON BLOCK**/}
232         return true;
233     }
234
235     /**
236      * {@inheritDoc}
237      */
238     @Override
239     public void setOnEndListener(OnEndListener onEndListener) {
240         //Ignore. secure console don't use this
241     }
242
243     /**
244      * {@inheritDoc}
245      */
246     @Override
247     public void setOnCancelListener(OnCancelListener onCancelListener) {
248         //Ignore. secure console don't use this
249     }
250
251     /**
252      * {@inheritDoc}
253      */
254     @Override
255     public boolean isCancellable() {
256         return true;
257     }
258
259     /**
260      * {@inheritDoc}
261      */
262     @Override
263     public AsyncResultListener getAsyncResultListener() {
264         return this.mAsyncResultListener;
265     }
266
267     /**
268      * Method that create the regexp of this command, using the directory and
269      * arguments and creating the regular expressions of the search.
270      *
271      * @param directory The directory where to search
272      * @param query The query make for user
273      * @return String[] The regexp for filtering files
274      */
275     private static String[] createRegexp(String directory, Query query) {
276         String[] args = new String[query.getSlotsCount()];
277         int cc = query.getSlotsCount();
278         for (int i = 0; i < cc; i++) {
279             args[i] = SearchHelper.toIgnoreCaseRegExp(query.getSlot(i), true);
280         }
281         return args;
282     }
283 }