2 * Copyright (C) 2012 The CyanogenMod Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.cyanogenmod.filemanager.commands.secure;
19 import android.util.Log;
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;
32 import de.schlichtherle.truezip.file.TFile;
34 import java.util.Arrays;
37 * A class for search files.
39 public class FindCommand extends Program implements FindExecutable {
41 private static final String TAG = "FindCommand"; //$NON-NLS-1$
43 private final String mDirectory;
44 private final String[] mQueryRegExp;
45 private final ConcurrentAsyncResultListener mAsyncResultListener;
47 private volatile boolean mCancelled;
48 private volatile boolean mEnded;
49 private final Object mSync = new Object();
52 * Constructor of <code>FindCommand</code>.
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
59 public FindCommand(SecureConsole console, String directory, Query query,
60 ConcurrentAsyncResultListener asyncResultListener) {
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();
66 this.mDirectory = directory;
68 this.mQueryRegExp = createRegexp(directory, query);
69 this.mAsyncResultListener = asyncResultListener;
70 if (mAsyncResultListener instanceof ConcurrentAsyncResultListener) {
71 ((ConcurrentAsyncResultListener) mAsyncResultListener).onRegister();
73 this.mCancelled = false;
81 public boolean isAsynchronous() {
89 public void execute() throws NoSuchFileOrDirectory, ExecutionException {
92 String.format("Finding in %s the query %s", //$NON-NLS-1$
93 this.mDirectory, Arrays.toString(this.mQueryRegExp)));
95 if (this.mAsyncResultListener != null) {
96 this.mAsyncResultListener.onAsyncStart();
99 TFile f = getConsole().buildRealFile(mDirectory);
102 Log.v(TAG, "Result: FAIL. NoSuchFileOrDirectory"); //$NON-NLS-1$
104 if (this.mAsyncResultListener != null) {
105 this.mAsyncResultListener.onException(new NoSuchFileOrDirectory(this.mDirectory));
108 if (!f.isDirectory()) {
110 Log.v(TAG, "Result: FAIL. NoSuchFileOrDirectory"); //$NON-NLS-1$
112 if (this.mAsyncResultListener != null) {
113 this.mAsyncResultListener.onException(
114 new ExecutionException("path exists but it's not a folder")); //$NON-NLS-1$
121 // record program's execution termination
122 synchronized (mSync) {
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
130 if (this.mAsyncResultListener != null) {
131 this.mAsyncResultListener.onAsyncEnd(this.mCancelled);
133 if (this.mAsyncResultListener != null) {
134 this.mAsyncResultListener.onAsyncExitCode(0);
138 Log.v(TAG, "Result: OK"); //$NON-NLS-1$
143 * Method that search files recursively
145 * @param folder The folder where to start the search
147 private void findRecursive(TFile folder) {
148 // Obtains the files and folders of the folders
149 TFile[] files = folder.listFiles();
151 int cc = files.length;
152 for (int i = 0; i < cc; i++) {
153 if (files[i].isDirectory()) {
154 findRecursive(files[i]);
157 // Check if the file or folder matches the regexp
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]);
164 // Convert to virtual
165 fso.setParent(getConsole().buildVirtualPath(
166 files[i].getParentFile()));
170 Log.v(TAG, String.valueOf(fso));
172 if (this.mAsyncResultListener != null) {
173 this.mAsyncResultListener.onPartialResult(fso);
178 } catch (Exception e) {/**NON-BLOCK**/}
180 // Check if the process was cancelled
182 synchronized (this.mSync) {
183 if (this.mCancelled || this.mEnded || (mAsyncResultListener != null
184 && mAsyncResultListener.isCancelled())) {
189 } catch (Exception e) {/**NON BLOCK**/}
198 public boolean isCancelled() {
199 synchronized (this.mSync) {
200 return this.mCancelled;
208 public boolean cancel() {
210 // ensure the program is running before attempting to cancel
211 // there won't be a corresponding lock.notify() otherwise
213 this.mCancelled = true;
214 this.mSync.wait(5000L);
216 } catch (Exception e) {/**NON BLOCK**/}
224 public boolean end() {
226 // ensure the program is running before attempting to terminate
229 this.mSync.wait(5000L);
231 } catch (Exception e) {/**NON BLOCK**/}
239 public void setOnEndListener(OnEndListener onEndListener) {
240 //Ignore. secure console don't use this
247 public void setOnCancelListener(OnCancelListener onCancelListener) {
248 //Ignore. secure console don't use this
255 public boolean isCancellable() {
263 public AsyncResultListener getAsyncResultListener() {
264 return this.mAsyncResultListener;
268 * Method that create the regexp of this command, using the directory and
269 * arguments and creating the regular expressions of the search.
271 * @param directory The directory where to search
272 * @param query The query make for user
273 * @return String[] The regexp for filtering files
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);