();
+ }
+ }
+
+ /**
+ * Searches for matches in the contents of multiple files
+ *
+ * For example, a search with the term "Foo" and the constrainValues {"/Bar", "/Stool"}
+ * will return pages with contents related to "Foo" only from the directories or
+ * subdirectories or "/Bar" and "/Stool"
+ *
+ * @param term The search term for choosing and ranking results
+ * @param field The field to search, i.e. "contents"
+ * @param constrainValues The paths to which to constrain the search
+ * @param constrainField The field used to constrain searches
+ * @param maxResults The maximum number of results that will be returned
+ * @param set The set number, e.g., searching set 0 returns the first n results,
+ * searching set 1 returns the 2nd n results
+ * @param type The type of the search, one of QUERY_BOOLEAN or QUERY_STANDARD
+ * @return A list of PageResult containing all of the results the searcher found,
+ * sorted by relevance
+ */
+ public PageResult[] findInFiles(String term, String field, List constrainValues,
+ String constrainField, int maxResults, int set, int type) {
+ Query qry = this.getQuery(term, field, type);
+ if(qry != null){
+ Filter filter = this.getFilter(constrainField, constrainValues);
+ ScoreDoc[] hits = null;
+ try {
+ hits = indexSearcher.search(qry, filter, maxResults * set + maxResults).scoreDocs;
+ } catch(IOException e) {
+ Log.e(TAG, "Error ", e);
+ }
+ if(this.interrupt) {
+ this.interrupt = true;
+ return null;
+ }
+ List docs = this.getDocs(maxResults, set, hits);
+ Log.i(TAG, "Found instance of term in " + docs.size() + " documents");
+ return this.getHighlightedResults(docs, qry, type, term, maxResults);
+ } else {
+ Log.e(TAG, "Query Type: " + type + " not recognised");
+ return new PageResult[0];
+ }
+ }
+
+ /**
+ * Searches for matches in the contents of multiple files
+ *
+ * For example, a search with the term "Foo" and the constrainValue "/Bar.txt"
+ * will return pages with contents related to "Foo" only from inside the file "/Bar.txt"
+ *
+ * @param term The search term for choosing and ranking results
+ * @param field The field to search, i.e. "contents"
+ * @param constrainValue The path to which to constrain the search
+ * @param constrainField The field used to constrain searches
+ * @param maxResults The maximum number of results that will be returned
+ * @param set The set number, e.g., searching set 0 returns the first n results,
+ * searching set 1 returns the 2nd n results
+ * @param type The type of the search, one of QUERY_BOOLEAN or QUERY_STANDARD
+ * @return A list of PageResult containing all of the results the searcher found,
+ * sorted by relevance
+ */
+ public PageResult[] findInFile(String term, String field, String constrainValue,
+ String constrainField, int maxResults, int set, int type,
+ final int page) {
+ Query qry = this.getQuery(term, field, type);
+ if(qry != null){
+ String[] values = {constrainValue};
+ Filter filter = this.getFilter(constrainField, Arrays.asList(values));
+ ScoreDoc[] hits = null;
+ try {
+ Log.i(TAG, "Searching...");
+ hits = indexSearcher.search(qry, filter, maxResults * set + maxResults,
+ this.getPagedSort(page)).scoreDocs;
+ } catch(IOException e) {
+ Log.e(TAG, "Error ", e);
+ }
+ if(this.interrupt) {
+ this.interrupt = true;
+ return null;
+ }
+
+ Log.i(TAG, "Found instance of term in " + hits.length + " documents");
+ return this.getHighlightedResults(this.getDocs(maxResults, set, hits), qry, type,
+ term, maxResults);
+ } else {
+ Log.e(TAG, "Query Type: " + type + " not recognised");
+ return new PageResult[0];
+ }
+ }
+
+ /**
+ * Creates a query based on the given term field and type
+ * @param term Search Term for the query
+ * @param field Document Field for the Query which the term is matched against
+ * @param type The type of query to be created, either QUERY_BOOLEAN, or QUERY_STANDARD,
+ * @return a query for the given field and term using either a BooleanQuery with a
+ * WildcardQuery for the term or a Query built from a QueryParser and SimpleAnalyzer
+ */
+ private Query getQuery(String term, String field, int type) {
+ if(this.interrupt) {
+ this.interrupt = false;
+ return null;
+ }
+ Query qry = null;
+ if(type == FileSearcher.QUERY_BOOLEAN) {
+ String[] terms = term.split(" ");
+ qry = new BooleanQuery();
+ ((BooleanQuery) qry).add(new WildcardQuery(new Term(field, "*" + term + "*")),
+ BooleanClause.Occur.MUST);
+ } else if(type == FileSearcher.QUERY_STANDARD) {
+ try {
+ qry = new QueryParser(Version.LUCENE_47, field,
+ new SimpleAnalyzer(Version.LUCENE_47)).parse(term);
+ } catch(ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ if(this.interrupt) {
+ this.interrupt = false;
+ return null;
+ }
+ return qry;
+ }
+
+ /**
+ * Creates a directory filter
+ * @param constrainField The field that contains the directory info
+ * @param constrainValues The directories to which the filters shold limit
+ * @return The created filter
+ */
+ private Filter getFilter(String constrainField, List constrainValues){
+ BooleanQuery cqry = new BooleanQuery();
+ for(String s : constrainValues) {
+ cqry.add(new TermQuery(new Term(constrainField, s)),
+ BooleanClause.Occur.SHOULD);
+ }
+ return new QueryWrapperFilter(cqry);
+ }
+
+ /**
+ * Takes a list of Documents and highlights information relevant to a given Query
+ * @param docs The documents to highlight
+ * @param qry The query used to highlight the documents
+ * @param type The type of the search, one of QUERY_BOOLEAN,
+ * which just notes the page on which the term exists or QUERY_STANDARD,
+ * which gives highlighted fragments and the page on which they exist.
+ * @param term The term that created the query
+ * @param maxResults The maximum number of results that will be returned
+ * @return An array containing a PageResult entry for each result
+ */
+ private PageResult[] getHighlightedResults(List docs, Query qry, int type,
+ String term, int maxResults){
+ try {
+ int numResults = 0;
+ PageResult[] results = new PageResult[docs.size()];
+ for(int i = 0; i < docs.size() && numResults < maxResults; i++) {
+ if(this.interrupt) {
+ this.interrupt = false;
+ return null;
+ }
+ Document d = docs.get(i);
+ int docPage = Integer.parseInt(d.get("page"));
+ String name = d.get("path");
+ if(type != FileSearcher.QUERY_BOOLEAN) {
+ String contents = d.get("text");
+ Highlighter highlighter = new Highlighter(new QueryScorer(qry));
+
+ String[] frag = null;
+ try {
+ frag = highlighter.getBestFragments(new SimpleAnalyzer(Version.LUCENE_47), "text", contents, maxResults - numResults);
+ numResults += frag.length;
+ } catch(IOException e) {
+ Log.e(TAG, "Error while reading index", e);
+ } catch(InvalidTokenOffsetsException e) {
+ Log.e(TAG, "Error while highlighting", e);
+ }
+ Log.i(TAG, "Frags: " + frag.length + " " + frag + " " + frag[0]);
+ ArrayList tmpList = new ArrayList(Arrays
+ .asList(frag != null ? frag : new String[0]));
+ Log.i(TAG, "list " + tmpList.getClass().getName());
+ results[i] = (new PageResult(tmpList, docPage, name));
+ Log.i(TAG, "" + results[i]);
+ } else {
+ ArrayList tmp = new ArrayList();
+ tmp.add(term);
+ results[i] = (new PageResult(tmp, docPage, name));
+ }
+
+ }
+ Log.i(TAG, "" + results.length);
+ if(this.interrupt) {
+ this.interrupt = false;
+ return null;
+ }
+ return results;
+ } catch(Exception e) {
+ Log.e("TAG", "Error while Highlighting", e);
+ return null;
+ }
+ }
+
+ /**
+ * Takes an array of ScoreDoc and turns it into the relevant number of Documents
+ * @param maxResults The maximum number of documents that will be parsed
+ * @param set The set number, e.g., searching set 0 returns the first n results,
+ * searching set 1 returns the 2nd n results
+ * @param hits The ScoreDoc to be parsed
+ * @return The list of documents that is maxResults long and skips set*maxResults results
+ */
+ private List getDocs(int maxResults, int set, ScoreDoc[] hits){
+ ArrayList docs = new ArrayList();
+ for(int i = maxResults * set; i < hits.length && i < (maxResults * set + maxResults);
+ i++) {
+ try {
+ Document tmp = indexSearcher.doc(hits[i].doc);
+ docs.add(tmp);
+ } catch(IOException e) {
+ Log.e(TAG, "Error ", e);
+ }
+ }
+ return docs;
+ }
+
+ /**
+ * Takes an array of ScoreDoc and turns it into the relevant number of Document paths
+ * @param maxResults The maximum number of paths that will be parsed
+ * @param set The set number, e.g., searching set 0 returns the first n results,
+ * searching set 1 returns the 2nd n results
+ * @param hits The ScoreDoc to be parsed
+ * @return The list of paths that is maxResults long and skips set*maxResults results
+ */
+ private List getDocPaths(int maxResults, int set, ScoreDoc[] hits){
+ ArrayList docs = new ArrayList();
+ for(int i = maxResults * set; i < hits.length && i < maxResults * set + maxResults; i++) {
+ try{
+ Document tmp = indexSearcher.doc(hits[i].doc);
+ docs.add(tmp.get("path"));
+ } catch(IOException e) {
+ Log.e(TAG, "Error ", e);
+ }
+ }
+ return docs;
+ }
+
+ /**
+ * Calls for the any current searches to be inturrupted
+ * @return false if the interrupt flag was already set; otherwise true
+ */
+ public boolean interrupt() {
+ // TODO - Must become path dependent so that interrupt calls do not interrupt searches
+ // from other applications
+ boolean tmp = this.interrupt;
+ this.interrupt = true;
+ return !tmp;
+ }
+
+ /**
+ * Creates a sort that splits results around a given page
+ * @param page The page that will show first in the results,
+ * @return A Sort object that splits results around the given page
+ */
+ private Sort getPagedSort(final int page){
+ return new Sort(new SortField("page", new FieldComparatorSource() {
+ @Override
+ public FieldComparator> newComparator(String fieldname, int numhits,
+ int sortpos,
+ boolean reversed) throws
+ IOException {
+ return new PagedIntComparator(numhits, fieldname, null,
+ null) {
+ public int compare(int slot1, int slot2) {
+ final int v1 = this.values[slot1];
+ final int v2 = this.values[slot2];
+ if(v1 < page && v2 >= page) {
+ return 1;
+ } else if(v1 >= page && v2 < page) {
+ return -1;
+ } else {
+ if(v1 > v2) {
+ return 1;
+ } else if(v1 < v2) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ @Override
+ public int compareBottom(int doc) {
+ int v2 = this.currentReaderValues.get(doc);
+ if(docsWithField != null && v2 == 0 && !docsWithField.get(doc)) {
+ v2 = missingValue;
+ }
+ if(v2 < page) {
+ return -1;
+ }
+ if(this.bottom > v2) {
+ return 1;
+ } else if(this.bottom < v2) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public int compareTop(int doc) {
+ int docValue = this.currentReaderValues.get(doc);
+ if(docsWithField != null && docValue == 0 && !docsWithField.get(doc)) {
+ docValue = missingValue;
+ }
+ if(this.topValue < page && docValue > page) {
+ return 1;
+ }
+ if(this.topValue < docValue) {
+ return -1;
+ } else if(this.topValue > docValue) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ };
+ }
+ }));
+ }
+
+ /**
+ * Adapted from Lucene 4.7 IntComparator
+ *
+ * Identical but intended for sorting pages of a document starting at a certain page.
+ * Previous pages are added to the end of the list
+ *
+ * @since v0.4
+ */
public abstract class PagedIntComparator extends NumericComparator {
protected final int[] values;
private final IntParser parser;
@@ -347,7 +526,7 @@ public abstract class PagedIntComparator extends NumericComparator {
protected int topValue;
PagedIntComparator(int numHits, String field, FieldCache.Parser parser,
- Integer missingValue) {
+ Integer missingValue) {
super(field, missingValue);
values = new int[numHits];
this.parser = (IntParser) parser;
@@ -358,7 +537,7 @@ public void copy(int slot, int doc) {
int v2 = currentReaderValues.get(doc);
// Test for v2 == 0 to save Bits.get method call for
// the common case (doc has value and value is non-zero):
- if (docsWithField != null && v2 == 0 && !docsWithField.get(doc)) {
+ if(docsWithField != null && v2 == 0 && !docsWithField.get(doc)) {
v2 = missingValue;
}
@@ -388,204 +567,4 @@ public Integer value(int slot) {
return Integer.valueOf(values[slot]);
}
}
-
- // TODO - Boolean Search returns a huge number of results for simple queries, maxResults must be implemented
- public PageResult[] find(String term, String field, String constrainValue,
- String constrainField, int maxResults, int set, int type,
- final int page) {
- if(this.interrupt) {
- this.interrupt = false;
- return null;
- }
- Query qry = null;
- if (type == FileSearcher.QUERY_BOOLEAN) {
- String[] terms = term.split(" ");
- qry = new BooleanQuery();
- ((BooleanQuery) qry).add(new WildcardQuery(new Term(field, "*" + term +"*")),
- BooleanClause.Occur.MUST);
- } else if (type == FileSearcher.QUERY_STANDARD) {
- try {
- qry = new QueryParser(Version.LUCENE_47, field,
- new SimpleAnalyzer(Version.LUCENE_47)).parse(term);
- } catch (ParseException e) {
- e.printStackTrace();
- }
- // qry.add(new Query(field, value));
- }
- if(this.interrupt){
- this.interrupt = false;
- return null;
- }
- if (qry != null) {
- BooleanQuery cqry = new BooleanQuery();
- cqry.add(new TermQuery(new Term(constrainField, constrainValue)),
- BooleanClause.Occur.MUST);
- Filter filter = new QueryWrapperFilter(cqry);
- ScoreDoc[] hits = null;
- try {
- Log.i(TAG, "Searching...");
- hits = indexSearcher.search(qry, filter, maxResults * set + maxResults,
- new Sort(new SortField("page",new FieldComparatorSource() {
- @Override
- public FieldComparator> newComparator(String fieldname, int numhits,
- int sortpos,
- boolean reversed) throws
- IOException {
- return new PagedIntComparator(numhits, fieldname, null,
- null){
- public int compare(int slot1, int slot2){
- // TODO: there are sneaky non-branch ways to compute
- // -1/+1/0 sign
- // Cannot return values[slot1] - values[slot2] because that
- // may overflow
- final int v1 = this.values[slot1];
- final int v2 = this.values[slot2];
- if(v1 < page && v2 >= page) {
- return 1;
- } else if (v1 >= page && v2 < page){
- return -1;
- } else{
- if(v1 > v2) {
- return 1;
- } else if(v1 < v2) {
- return -1;
- } else {
- return 0;
- }
- }
- }
-
- @Override
- public int compareBottom(int doc) {
- // TODO: there are sneaky non-branch ways to compute
- // -1/+1/0 sign
- // Cannot return bottom - values[slot2] because that
- // may overflow
- int v2 = this.currentReaderValues.get(doc);
- // Test for v2 == 0 to save Bits.get method call for
- // the common case (doc has value and value is non-zero):
- if(docsWithField != null && v2 == 0 && !docsWithField.get(doc)) {
- v2 = missingValue;
- }
- if(v2 < page){
- return -1;
- }
- if(this.bottom > v2) {
- return 1;
- } else if(this.bottom < v2) {
- return -1;
- } else {
- return 0;
- }
- }
-
- @Override
- public int compareTop(int doc){
- int docValue = this.currentReaderValues.get(doc);
- // Test for docValue == 0 to save Bits.get method call for
- // the common case (doc has value and value is non-zero):
- if(docsWithField != null && docValue == 0 && !docsWithField.get(doc)) {
- docValue = missingValue;
- }
- // Cannot use Integer.compare (it's java 7)
- if(this.topValue < page && docValue > page){
- return 1;
- }
- if(this.topValue < docValue) {
- return -1;
- } else if(this.topValue > docValue) {
- return 1;
- } else {
- return 0;
- }
- }
- };
- }
- }))).scoreDocs;
- } catch (IOException e) {
- Log.e(TAG, "Error ", e);
- }
- if(this.interrupt){
- this.interrupt = true;
- return null;
- }
-
- Log.i(TAG, "Sorted " + hits.length);
- ArrayList docs = new ArrayList();
- for (int i = maxResults*set; i < hits.length || i < (maxResults * set + maxResults);
- i++) {
- try {
- Document tmp = indexSearcher.doc(hits[i].doc);
- int docPage = Integer.parseInt(tmp.get("page"));
- docs.add(tmp);
- } catch (IOException e) {
- Log.e(TAG, "Error ", e);
- }
- }
- if(this.interrupt){
- this.interrupt = false;
- return null;
- }
- Log.i(TAG, "Found instance of term in " + hits.length + " documents");
- /**
- * TODO - Add Highlighter Code to retrieve the generated phrase here (In progress)
- **/
- try {
- int numResults = 0;
- ArrayList results = new ArrayList();
- for (int i = 0; i < docs.size(); i++) {
- if(this.interrupt){
- this.interrupt = false;
- return null;
- }
- Document d = docs.get(i);
- int docPage = Integer.parseInt(d.get("page"));
- if(type != FileSearcher.QUERY_BOOLEAN) {
- String contents = d.get("text");
- Highlighter highlighter = new Highlighter(new QueryScorer(qry));
-
- String[] frag = null;
- try {
- frag = highlighter.getBestFragments(new SimpleAnalyzer(Version.LUCENE_47), "text", contents, maxResults - numResults);
- numResults += frag.length;
- } catch (IOException e) {
- Log.e(TAG, "Error while reading index", e);
- } catch (InvalidTokenOffsetsException e) {
- Log.e(TAG, "Error while highlighting", e);
- }
- Log.i(TAG, "Frags: " + frag.length + " " + frag + " " + frag[0]);
- ArrayList tmpList = new ArrayList(Arrays
- .asList(frag != null ? frag : new String[0]));
- Log.i(TAG, "list " + tmpList.getClass().getName());
- results.add(new PageResult(tmpList, docPage, constrainValue));
- Log.i(TAG, "" + results.get(i));
- }
- else {
- ArrayList tmp = new ArrayList();
- tmp.add(term);
- results.add(new PageResult(tmp, docPage, constrainValue));
- }
-
- }
- Log.i(TAG, "" +results.size());
- if(this.interrupt){
- this.interrupt = false;
- return null;
- }
- return results.toArray(new PageResult[0]);
- }catch(Exception e){
- Log.e("TAG", "Error while Highlighting", e);
- return null;
- }
- } else {
- Log.e(TAG, "Query Type: " + type + " not recognised");
- return new PageResult[0];
- }
- }
-
- public boolean interrupt(){
- boolean tmp = this.interrupt;
- this.interrupt = true;
- return tmp;
- }
}
diff --git a/src/ca/dracode/ais/indexinfo/FileChangeListener.java b/src/ca/dracode/ais/indexinfo/FileChangeListener.java
deleted file mode 100644
index 3d6b111..0000000
--- a/src/ca/dracode/ais/indexinfo/FileChangeListener.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*******************************************************************************
- * Copyright 2014 Benjamin Winger.
- *
- * This file is part of Android Indexing Service.
- *
- * Android Indexing Service is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Android Indexing Service is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Android Indexing Service. If not, see .
- ******************************************************************************/
-
-package ca.dracode.ais.indexinfo;
-
-import java.io.File;
-
-public interface FileChangeListener {
- public void onFileChanged(File newFile);
-}
diff --git a/src/ca/dracode/ais/indexinfo/IndexComm.aidl b/src/ca/dracode/ais/indexinfo/IndexComm.aidl
index 3e43f8e..b2616c7 100644
--- a/src/ca/dracode/ais/indexinfo/IndexComm.aidl
+++ b/src/ca/dracode/ais/indexinfo/IndexComm.aidl
@@ -21,20 +21,18 @@ package ca.dracode.ais.indexinfo;
interface IndexComm {
void stopIndexer();
- /*
+ /**
Get Current State of the Indexer
@return true if the indexer is running, false otherwise
*/
boolean isIndexerRunning();
- /*
- Sets the file change listener
- @param a listener that will be notified whenever the indexer starts indexing a
- new file
+ /**
+ Gets the path of the directory currently being indexed
*/
- void setFileChangeListener(out FileChangeListener listener);
+ String getCurrentIndexPath();
- /*
+ /**
Gets the number of documents in the index
@return the number of documents in the index
*/
diff --git a/src/ca/dracode/ais/indexinfo/IndexInfo.java b/src/ca/dracode/ais/indexinfo/IndexInfo.java
index e0f0853..bfd80bd 100644
--- a/src/ca/dracode/ais/indexinfo/IndexInfo.java
+++ b/src/ca/dracode/ais/indexinfo/IndexInfo.java
@@ -24,9 +24,8 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
-import android.util.Log;
-
import android.os.RemoteException;
+import android.util.Log;
import ca.dracode.ais.alarm.Alarm;
import ca.dracode.ais.service.FileListener;
@@ -34,58 +33,7 @@
public class IndexInfo {
private static final String TAG = "ca.dracode.ais.indexinfo";
private boolean enabled = true;
- /*
- Get Current State of the Indexer
- @return true if the indexer is running, false otherwise
- */
- public boolean isIndexerRunning() {
- return false;
- }
-
- /*
- Sets the file change listener
- @param a listener that will be notified whenever the indexer starts indexing a
- new file
- */
- public void setFileChangeListener(FileChangeListener listener) {
-
- }
-
- /*
- Gets the number of documents in the index
- @return the number of documents in the index
- */
- public int getNumDocumentsInIndex() {
- return 0;
- }
-
- /*
- Manually stops the indexer
- @precondition the indexer is running
- @postcondition the indexer will no longer be running
- */
- public void stopIndexer(Context context) {
- Alarm.CancelAlarm(context);
- try {
- mService.stopIndexer();
- } catch(RemoteException e){
- Log.e(TAG, "Error", e);
- }
- }
-
- /*
- Manually starts the indexer
- @precondition the indexer is not running
- @postcondition the indexer will be running
- */
- public void startIndexer(Context context) {
- Alarm.SetAlarm(context);
- Intent serviceIntent = new Intent(context, FileListener.class);
- context.startService(serviceIntent);
- }
-
private IndexComm mService;
-
private ServiceConnection mConnection = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
@@ -98,4 +46,56 @@ public void onServiceDisconnected(ComponentName className) {
mService = null;
}
};
+
+ /**
+ * Get Current State of the Indexer
+ * @return true if the indexer is running, false otherwise
+ */
+ public boolean isIndexerRunning() {
+ return false;
+ }
+
+ /**
+ * Sets the file change listener
+ * @return The path that the indexer is currently indexing
+ */
+ public String getCurrentIndexPath(){
+ try {
+ return mService.getCurrentIndexPath();
+ } catch(RemoteException e){
+ Log.e(TAG, "Error", e);
+ }
+ return "Error connecting to the service!";
+ }
+
+ /**
+ * Gets the number of documents in the index
+ * @return the number of documents in the index
+ */
+ public int getNumDocumentsInIndex() {
+ return 0;
+ }
+
+ /**
+ * Manually stops the indexer
+ * @param context
+ */
+ public void stopIndexer(Context context) {
+ Alarm.CancelAlarm(context);
+ try {
+ mService.stopIndexer();
+ } catch(RemoteException e) {
+ Log.e(TAG, "Error", e);
+ }
+ }
+
+ /**
+ * Manually starts the indexer
+ * @param context
+ */
+ public void startIndexer(Context context) {
+ Alarm.SetAlarm(context);
+ Intent serviceIntent = new Intent(context, FileListener.class);
+ context.startService(serviceIntent);
+ }
}
diff --git a/src/ca/dracode/ais/service/BSearchService1_0.aidl b/src/ca/dracode/ais/service/BSearchService1_0.aidl
index 195e801..0ce60d0 100644
--- a/src/ca/dracode/ais/service/BSearchService1_0.aidl
+++ b/src/ca/dracode/ais/service/BSearchService1_0.aidl
@@ -56,7 +56,7 @@ interface BSearchService1_0 {
/**
* Used to search for file names
- * @param dir - the root directory for the search.
+ * @param docs - the root directory for the search.
* type - allows the client to specify how to filter the files
* text - the search term
* numHits - the maximum number of results to return, a value of -1 means no limit
diff --git a/src/ca/dracode/ais/service/FileListener.java b/src/ca/dracode/ais/service/FileListener.java
index cede3df..d1e8b01 100644
--- a/src/ca/dracode/ais/service/FileListener.java
+++ b/src/ca/dracode/ais/service/FileListener.java
@@ -36,20 +36,12 @@
public class FileListener extends Service {
private static final String TAG = "ca.dracode.ais.service.FileListener";
+ private static final int DELAY = 2000;
+ Handler timerHandler = new Handler();
private AISObserver listener;
private IBinder mLocalBinder = new LocalBinder();
private Timer timeSinceLastChange;
- private static final int DELAY = 2000;
-
- @Override
- public void onCreate(){
- this.timeSinceLastChange = new Timer();
- this.listener = new AISObserver(Environment.getExternalStorageDirectory().getPath());
- Log.i(TAG, "Starting listener on " + Environment.getExternalStorageDirectory().getPath());
- this.listener.startWatching();
- }
-
- Handler timerHandler = new Handler();
+ private IndexService mBoundService;
Runnable timerRunnable = new Runnable() {
@Override
public void run() {
@@ -61,30 +53,77 @@ public void run() {
}
}
};
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ mBoundService = ((IndexService.LocalBinder) service).getService();
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ mBoundService = null;
+ }
+ };
+ private boolean mIsBound = false;
- public void stopListener(){
+ @Override
+ public void onCreate() {
+ this.timeSinceLastChange = new Timer();
+ this.listener = new AISObserver(Environment.getExternalStorageDirectory().getPath());
+ Log.i(TAG, "Starting listener on " + Environment.getExternalStorageDirectory().getPath());
+ this.listener.startWatching();
+ }
+
+ /**
+ * Tells the listener to stop watching the filesystem and close
+ */
+ public void stopListener() {
this.listener.stopWatching();
+ this.doUnbindService();
this.stopSelf();
}
- private class AISObserver extends FileObserver{
- public AISObserver(String path){
+ public IBinder onBind(Intent intent) {
+ return mLocalBinder;
+ }
+
+ private void doBindService() {
+ bindService(new Intent(FileListener.this,
+ IndexService.class), mConnection, Context.BIND_AUTO_CREATE);
+ mIsBound = true;
+ }
+
+ private void doUnbindService() {
+ if(mIsBound) {
+ // Detach our existing connection.
+ unbindService(mConnection);
+ mIsBound = false;
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ doUnbindService();
+ }
+
+ private class AISObserver extends FileObserver {
+ public AISObserver(String path) {
super(path);
}
- public void onEvent(int event, String path){
+ @Override
+ public void onEvent(int event, String path) {
if(path != null) {
if(path.contains("Android/data/ca.dracode.ais")) {
return;
}
if(event == FileObserver.MODIFY || event
== FileObserver.MOVED_TO || event == FileObserver.CREATE) {
- if(mBoundService == null){
+ if(mBoundService == null) {
doBindService();
- while(mBoundService == null){
- try{
+ while(mBoundService == null) {
+ try {
Thread.sleep(10);
- } catch(InterruptedException e){
+ } catch(InterruptedException e) {
Log.e(TAG, "Error ", e);
}
}
@@ -95,12 +134,12 @@ public void onEvent(int event, String path){
timerHandler.postDelayed(timerRunnable, DELAY);
Log.i(TAG, "File changed: " + path);
} else if(event == FileObserver.DELETE || event == FileObserver.MOVED_FROM) {
- if(mBoundService == null){
+ if(mBoundService == null) {
doBindService();
- while(mBoundService == null){
- try{
+ while(mBoundService == null) {
+ try {
Thread.sleep(10);
- } catch(InterruptedException e){
+ } catch(InterruptedException e) {
Log.e(TAG, "Error ", e);
}
}
@@ -120,55 +159,4 @@ public FileListener getService() {
return FileListener.this;
}
}
-
- public IBinder onBind(Intent intent){
- return mLocalBinder;
- }
-
-
- private IndexService mBoundService;
- private boolean mIsBound = false;
-
- private ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- // This is called when the connection with the service has been
- // established, giving us the service object we can use to
- // interact with the service. Because we have bound to a explicit
- // service that we know is running in our own process, we can
- // cast its IBinder to a concrete class and directly access it.
- mBoundService = ((IndexService.LocalBinder)service).getService();
- }
-
- public void onServiceDisconnected(ComponentName className) {
- // This is called when the connection with the service has been
- // unexpectedly disconnected -- that is, its process crashed.
- // Because it is running in our same process, we should never
- // see this happen.
- mBoundService = null;
- }
- };
-
- void doBindService() {
- // Establish a connection with the service. We use an explicit
- // class name because we want a specific service implementation that
- // we know will be running in our own process (and thus won't be
- // supporting component replacement by other applications).
- bindService(new Intent(FileListener.this,
- IndexService.class), mConnection, Context.BIND_AUTO_CREATE);
- mIsBound = true;
- }
-
- void doUnbindService() {
- if (mIsBound) {
- // Detach our existing connection.
- unbindService(mConnection);
- mIsBound = false;
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- doUnbindService();
- }
}
\ No newline at end of file
diff --git a/src/ca/dracode/ais/service/IndexService.java b/src/ca/dracode/ais/service/IndexService.java
index 0cd909d..e73e677 100644
--- a/src/ca/dracode/ais/service/IndexService.java
+++ b/src/ca/dracode/ais/service/IndexService.java
@@ -40,6 +40,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
+import java.util.List;
import java.util.Queue;
import ca.dracode.ais.R;
@@ -60,23 +61,70 @@
*/
public class IndexService extends Service {
- private static String TAG = "ca.dracode.ais.service.IndexService";
- private final IBinder mBinder = new LocalBinder();
- protected boolean interrupt;
- private NotificationManager nm;
- private int mIsBound = 0;
- private boolean doneCrawling;
- private boolean canStop = false;
- private ArrayList services;
- private Queue pIndexes;
- private FileIndexer indexer;
+ private static String TAG = "ca.dracode.ais.service.IndexService";
+ private final IBinder mBinder = new LocalBinder();
private final int maxTasks = 30;
+ protected boolean interrupt;
+ private NotificationManager nm;
+ private int mIsBound = 0;
+ private boolean doneCrawling;
+ private boolean canStop = false;
+ private ArrayList services;
+ private Queue pIndexes;
+ private FileIndexer indexer;
private int tasks = 0;
private boolean crawl = false;
- public int onStartCommand (Intent intent, int flags, int startId){
+ /**
+ * Retrieves service information from files found in the directory passed and all of its
+ * subdirectories
+ * @param directory directory to be searched
+ * @param services The list to store the given services
+ */
+ private static void getServices(File directory, List services) {
+ File[] contents = directory.listFiles();
+ for(File content : contents) {
+ if(content.canRead()) {
+ if(content.isFile()) {
+ if(content.getName().toLowerCase().endsWith(".is")) {
+ BufferedReader br = null;
+ try {
+ br = new BufferedReader(new FileReader(
+ content.getAbsolutePath()));
+ } catch(FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ if(br != null) {
+ try {
+ String name = br.readLine();
+ Log.i(TAG, "Found service of name: " + name);
+ ArrayList tmpExt = new ArrayList();
+ if(name != null) {
+ String tmp;
+ while((tmp = br.readLine()) != null) {
+ tmpExt.add(tmp);
+ Log.i(TAG, "Found Extension: " + tmp);
+ }
+ }
+ br.close();
+ services.add(new ParserService(name,
+ tmpExt));
+ } catch(IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ } else {
+ IndexService.getServices(content, services);
+ }
+ }
+ }
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
this.crawl = intent.getBooleanExtra("crawl", false);
- if(this.crawl){
+ if(this.crawl) {
canStop = true;
doneCrawling = false;
this.crawl();
@@ -88,364 +136,347 @@ public int onStartCommand (Intent intent, int flags, int startId){
return START_STICKY;
}
- @Override
- public void onCreate() {
- this.services = new ArrayList();
- nm = (NotificationManager) this
- .getSystemService(NOTIFICATION_SERVICE);
- IndexService.this.notifyPersistent(
- getText(R.string.notification_indexer_started), 1);
- boolean mExternalStorageAvailable;
- boolean mExternalStorageWriteable;
- String state = Environment.getExternalStorageState();
- if (Environment.MEDIA_MOUNTED.equals(state)) {
- // We can read and write the media
- mExternalStorageAvailable = mExternalStorageWriteable = true;
- } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
- // We can only read the media
- mExternalStorageAvailable = true;
- mExternalStorageWriteable = false;
- } else {
- mExternalStorageAvailable = mExternalStorageWriteable = false;
- }
+ @Override
+ public void onCreate() {
+ this.services = new ArrayList();
+ nm = (NotificationManager) this
+ .getSystemService(NOTIFICATION_SERVICE);
+ IndexService.this.notifyPersistent(
+ getText(R.string.notification_indexer_started), 1);
+ boolean mExternalStorageAvailable;
+ boolean mExternalStorageWriteable;
+ String state = Environment.getExternalStorageState();
+ if(Environment.MEDIA_MOUNTED.equals(state)) {
+ // We can read and write the media
+ mExternalStorageAvailable = mExternalStorageWriteable = true;
+ } else if(Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+ // We can only read the media
+ mExternalStorageAvailable = true;
+ mExternalStorageWriteable = false;
+ } else {
+ mExternalStorageAvailable = mExternalStorageWriteable = false;
+ }
- if (mExternalStorageAvailable && mExternalStorageWriteable) {
- this.getServices(new File(Environment
- .getExternalStorageDirectory() + "/Android/data"), this.services);
- } else {
- notify("Error: External Storage not mounted", 2);
- return;
- }
- Log.i(TAG, "Creating Indexer");
- this.indexer = new FileIndexer();
+ if(mExternalStorageAvailable && mExternalStorageWriteable) {
+ IndexService.getServices(new File(Environment
+ .getExternalStorageDirectory() + "/Android/data"), this.services);
+ } else {
+ notify("Error: External Storage not mounted", 2);
+ return;
+ }
+ Log.i(TAG, "Creating Indexer");
+ this.indexer = new FileIndexer();
Log.i(TAG, "Created Indexer");
- this.pIndexes = new LinkedList();
- this.doneCrawling = true;
- new Thread(new Runnable() {
- public void run() {
- //Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- while (true) {
- try {
- Thread.sleep(1);
- } catch (InterruptedException e1) {
- e1.printStackTrace();
- }
- Indexable tmp = pIndexes.poll();
- if (tmp != null) {
- Log.i(TAG, "Indexing: " + tmp.file.getAbsolutePath());
- if (tmp.tmpData == null || tmp.tmpData.size() == 0) {
- indexer.buildIndex(tmp.file.getAbsolutePath());
+ this.pIndexes = new LinkedList();
+ this.doneCrawling = true;
+ new Thread(new Runnable() {
+ public void run() {
+ //Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ while(true) {
+ try {
+ Thread.sleep(1);
+ } catch(InterruptedException e1) {
+ e1.printStackTrace();
+ }
+ Indexable tmp = pIndexes.poll();
+ if(tmp != null) {
+ Log.i(TAG, "Indexing: " + tmp.file.getAbsolutePath());
+ if(tmp.tmpData == null || tmp.tmpData.size() == 0) {
+ indexer.buildIndex(tmp.file.getAbsolutePath(), -1);
+ tasks--;
+ } else {
+ try {
+ indexer.buildIndex(tmp.tmpData,
+ tmp.file);
tasks--;
- } else {
- try {
- indexer.buildIndex(tmp.tmpData,
- tmp.file);
- tasks--;
- } catch (Exception e) {
- Log.e(TAG, "Error ", e);
- }
- }
- }
- if (doneCrawling && mIsBound == 0
- && pIndexes.size() == 0 && canStop) {
- Log.i(TAG, "Done Indexing, Closing... ");
- indexer.close();
- doneCrawling = false;
- NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.cancel(1);
- IndexService.this.stopSelf();
- break;
- }
- }
- }
- }).start();
- }
+ } catch(Exception e) {
+ Log.e(TAG, "Error ", e);
+ }
+ }
+ }
+ if(doneCrawling && mIsBound == 0
+ && pIndexes.size() == 0 && canStop) {
+ Log.i(TAG, "Done Indexing, Closing... ");
+ indexer.close();
+ doneCrawling = false;
+ NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.cancel(1);
+ IndexService.this.stopSelf();
+ break;
+ }
+ }
+ }
+ }).start();
+ }
- public void stopWhenReady(){
+ /**
+ * Tells the service to stop itself once it is finished its queued tasks
+ */
+ public void stopWhenReady() {
canStop = true;
}
- public static void getServices(File directory, ArrayList services) {
- File[] contents = directory.listFiles();
- for (File content : contents) {
- if (content.canRead()) {
- if (content.isFile()) {
- if (content.getName().toLowerCase().endsWith(".is")) {
- BufferedReader br = null;
- try {
- br = new BufferedReader(new FileReader(
- content.getAbsolutePath()));
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- }
- if (br != null) {
- try {
- String name = br.readLine();
- Log.i(TAG, "Found service of name: " + name);
- ArrayList tmpExt = new ArrayList();
- if (name != null) {
- String tmp;
- while ((tmp = br.readLine()) != null) {
- tmpExt.add(tmp);
- Log.i(TAG, "Found Extension: " + tmp);
- }
- }
- br.close();
- services.add(new ParserService(name,
- tmpExt));
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- } else {
- getServices(content, services);
- }
- }
- }
- }
-
- public void onDestroy() {
- nm.cancel(1);
- }
+ @Override
+ public void onDestroy() {
+ nm.cancel(1);
+ }
- public void crawl(){
- new Thread(new Runnable(){
- public void run(){
+ /**
+ * Starts indexing the external storage directory
+ */
+ public void crawl() {
+ new Thread(new Runnable() {
+ public void run() {
//Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
try {
crawl(Environment.getExternalStorageDirectory());
doneCrawling = true;
- } catch(IOException e){
+ } catch(IOException e) {
Log.e(TAG, "Error", e);
}
}
}).start();
}
- public void crawl(File directory) throws IOException {
- // Log.i(TAG, "Indexing directory " + directory.getAbsolutePath());
- File[] contents = directory.listFiles();
+ /**
+ * Indexes the directory passed and calls itself on all subdirectories
+ * @param directory The directory that will be indexed
+ * @throws IOException
+ */
+ public void crawl(File directory) throws IOException {
+ // TODO Implement breadth search, indexing important directories such as ~/Documents first
+ File[] contents = directory.listFiles();
Log.i(TAG, "Indexer Entered Directory " + directory.getAbsolutePath());
- if (contents != null) {
- for (File content : contents) {
- if(content.getAbsolutePath().contains("Android/data/ca.dracode.ais")){
+ if(contents != null) {
+ for(File content : contents) {
+ if(content.getAbsolutePath().contains("Android/data/ca.dracode.ais")) {
return;
}
- while(tasks > maxTasks){
+ while(tasks > maxTasks) {
try {
Thread.sleep(10);
- } catch(InterruptedException e){
+ } catch(InterruptedException e) {
Log.e(TAG, "Error", e);
}
}
- if (content.canRead()) {
- createIndex(content);
- }
- }
- for (File content : contents) {
- if (content.canRead()) {
- if (content.isDirectory()
- && content.getAbsolutePath().equals(
- content.getCanonicalPath())) {
- this.crawl(content);
- }
- }
- }
- }
- }
-
-
+ if(content.canRead()) {
+ createIndex(content);
+ }
+ }
+ for(File content : contents) {
+ if(content.canRead()) {
+ if(content.isDirectory()
+ && content.getAbsolutePath().equals(
+ content.getCanonicalPath())) {
+ this.crawl(content);
+ }
+ }
+ }
+ }
+ }
- public void createIndex(File content){
+ /**
+ * calls for an index to be created for the given file
+ * @param content The file to be stored in the index
+ */
+ public void createIndex(File content) {
String serviceName = null;
- if (content.isFile()) {
+ if(content.isFile()) {
int size = services.size();
- for (int j = 0; j < size; j++) {
+ for(int j = 0; j < size; j++) {
int mLoc = content.getName().lastIndexOf(".") + 1;
- if (mLoc != 0) {
+ if(mLoc != 0) {
boolean found = services.get(j).checkExtension(
content.getName().substring(mLoc)
.toLowerCase()
);
- if (found) {
+ if(found) {
serviceName = services.get(j).getName();
}
}
}
}
- try {
- int state =indexer.checkForIndex("id",
- content.getAbsolutePath() + ":meta", content.lastModified());
- if (state == 0) {
- Log.i(TAG, "Found index for " + content.getName() + "; skipping.");
- } else if(state == 1) {
+ try {
+ int state = indexer.checkForIndex(content.getAbsolutePath() + ":meta", content.lastModified());
+ if(state == 0) {
+ Log.i(TAG, "Found index for " + content.getName() + "; skipping.");
+ } else if(state == 1) {
Log.i(TAG, "Index for " + content.getName() + " out of date, building index");
try {
new RemoteBuilder(
content,
serviceName);
tasks++;
- } catch (Exception e) {
+ } catch(Exception e) {
Log.e(TAG, "" + e.getMessage());
}
- }
- else if(state == -1){
- Log.i(TAG, "Index for " + content.getName() + " not found, building index");
- try {
- new RemoteBuilder(
- content,
- serviceName);
+ } else if(state == -1) {
+ Log.i(TAG, "Index for " + content.getName() + " not found, building index");
+ try {
+ new RemoteBuilder(
+ content,
+ serviceName);
tasks++;
- } catch (Exception e) {
- Log.e(TAG, "" + e.getMessage());
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public void removeIndex(String path){
-
+ } catch(Exception e) {
+ Log.e(TAG, "" + e.getMessage());
+ }
+ }
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
}
- public void notify(CharSequence c, int id) {
- Notification notification = new Notification(R.drawable.file_icon, c,
- System.currentTimeMillis());
- Intent intent = new Intent(getApplicationContext(), IndexService.class);
- PendingIntent pendingIntent = PendingIntent.getActivity(
- getApplicationContext(), 0, intent, 0);
- notification.setLatestEventInfo(this, c, c, pendingIntent);
- nm.notify(id, notification);
- }
-
- public void notifyPersistent(CharSequence c, int id) {
- Notification not = new Notification(R.drawable.file_icon, c,
- System.currentTimeMillis());
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
- new Intent(this, IndexService.class),
- Notification.FLAG_ONGOING_EVENT);
- not.flags = Notification.FLAG_ONGOING_EVENT;
- not.setLatestEventInfo(this, "AIS", "Indexing...", contentIntent);
- nm.notify(1, not);
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
+ /**
+ * calls for the index matching path to be removed from the index
+ * @param path the path of the index to be removed
+ */
+ public void removeIndex(String path) {
+ this.indexer.removeIndex(path);
+ }
- private class Indexable {
- private ArrayList tmpData;
- private File file;
- private IBinder mService;
- private String serviceName = null;
- private RemoteBuilder builder;
+ /**
+ * Creates a notification with the given text
+ * @param text The text that will appear in the notification
+ * @param id The id that can be used to stop the notification
+ */
+ private void notify(CharSequence text, int id) {
+ Notification notification = new Notification(R.drawable.file_icon, text,
+ System.currentTimeMillis());
+ Intent intent = new Intent(getApplicationContext(), IndexService.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ getApplicationContext(), 0, intent, 0);
+ notification.setLatestEventInfo(this, text, text, pendingIntent);
+ nm.notify(id, notification);
+ }
- public Indexable(ArrayList tmpData, File file,
- IBinder mService, String serviceName, RemoteBuilder builder) {
- super();
- this.tmpData = tmpData;
- this.file = file;
- this.mService = mService;
- this.serviceName = serviceName;
- this.builder = builder;
- }
+ /**
+ * Creates the persistent notification showing that the indexer is running
+ * @param text The text that will appear in the notification
+ * @param id The id that can be used to stop the notification
+ */
+ private void notifyPersistent(CharSequence text, int id) {
+ Notification not = new Notification(R.drawable.file_icon, text,
+ System.currentTimeMillis());
+ PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
+ new Intent(this, IndexService.class),
+ Notification.FLAG_ONGOING_EVENT);
+ not.flags = Notification.FLAG_ONGOING_EVENT;
+ not.setLatestEventInfo(this, "AIS", "Indexing...", contentIntent);
+ nm.notify(1, not);
+ }
- }
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
- private class RemoteBuilder {
- private ArrayList tmpData;
- private File file;
- private IBinder mService;
- private String serviceName = null;
+ private class Indexable {
+ private ArrayList tmpData;
+ private File file;
+ private IBinder mService;
+ private String serviceName = null;
+ private RemoteBuilder builder;
+
+ public Indexable(ArrayList tmpData, File file,
+ IBinder mService, String serviceName, RemoteBuilder builder) {
+ super();
+ this.tmpData = tmpData;
+ this.file = file;
+ this.mService = mService;
+ this.serviceName = serviceName;
+ this.builder = builder;
+ }
- public RemoteBuilder(File file, String serviceName) {
- this.file = file;
- this.serviceName = serviceName;
- if(serviceName != null) {
- this.doBindService(getApplicationContext());
- } else{
- pIndexes.add(new Indexable(null, file, null,
- null, RemoteBuilder.this));
- }
- }
+ }
- void doBindService(Context c) {
- // Establish a connection with the service. We use an explicit
- // class name because we want a specific service implementation that
- // we know will be running in our own process (and thus won't be
- // supporting component replacement by other applications).
- Log.i(TAG, "Binding to service...");
+ private class RemoteBuilder {
+ private ArrayList tmpData;
+ private File file;
+ private IBinder mService;
+ private String serviceName = null;
+
+ public RemoteBuilder(File file, String serviceName) {
+ this.file = file;
+ this.serviceName = serviceName;
+ if(serviceName != null) {
+ this.doBindService(getApplicationContext());
+ } else {
+ pIndexes.add(new Indexable(null, file, null,
+ null, RemoteBuilder.this));
+ }
+ }
- if (serviceName == null) {
- return;
- }
- /*
- * while(mIsBound > 0){ try { Thread.sleep(1); } catch
- * (InterruptedException e) { e.printStackTrace(); } }
- */
- if (c.bindService(new Intent(serviceName), mConnection,
- Context.BIND_AUTO_CREATE)) {
- mIsBound++;
- }
- Log.i(TAG, "Service is bound = " + mIsBound);
- }
+ /**
+ * Binds the builders service to the given context
+ * @param context
+ */
+ void doBindService(Context context) {
+ // Establish a connection with the service. We use an explicit
+ // class name because we want a specific service implementation that
+ // we know will be running in our own process (and thus won't be
+ // supporting component replacement by other applications).
+ Log.i(TAG, "Binding to service...");
+
+ if(serviceName == null) {
+ return;
+ }
+ if(context.bindService(new Intent(serviceName), mConnection,
+ Context.BIND_AUTO_CREATE)) {
+ mIsBound++;
+ }
+ Log.i(TAG, "Service is bound = " + mIsBound);
+ }
- public void doUnbindService(Context c) {
- if (mIsBound > 0) {
- // Detach our existing connection.
- c.unbindService(mConnection);
- mIsBound--;
- /*
- * if (mIsBound == 0) { nm.cancel(1); stopSelf(); }
- */
- }
- }
+ /**
+ * Unbinds the service from the context
+ * @param context
+ */
+ public void doUnbindService(Context context) {
+ if(mIsBound > 0) {
+ // Detach our existing connection.
+ context.unbindService(mConnection);
+ mIsBound--;
+ }
+ }
- private ServiceConnection mConnection = new ServiceConnection() {
- // Called when the connection with the service is established
- public void onServiceConnected(ComponentName className,
- IBinder service) {
- // Following the example above for an AIDL interface,
- // this gets an instance of the IRemoteInterface, which we can
- // use
- // to call on the service
- mService = service;
- Log.i(TAG, "Service: " + mService);
- try {
- MClientService tmp = MClientService.Stub
- .asInterface(mService);
- tmp.loadFile(file.getAbsolutePath());
- tmpData = new ArrayList();
- int pages = tmp.getPageCount();
- for (int i = 0; i < pages; i++) {
- tmpData.add(tmp.getWordsForPage(i));
- }
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- // build();
- pIndexes.add(new Indexable(tmpData, file, mService,
- serviceName, RemoteBuilder.this));
- doUnbindService(getApplicationContext());
- }
+ private ServiceConnection mConnection = new ServiceConnection() {
+ // Called when the connection with the service is established
+ public void onServiceConnected(ComponentName className,
+ IBinder service) {
+ mService = service;
+ Log.i(TAG, "Service: " + mService);
+ try {
+ MClientService tmp = MClientService.Stub
+ .asInterface(mService);
+ tmp.loadFile(file.getAbsolutePath());
+ tmpData = new ArrayList();
+ int pages = tmp.getPageCount();
+ for(int i = 0; i < pages; i++) {
+ tmpData.add(tmp.getWordsForPage(i));
+ }
+ } catch(RemoteException e) {
+ e.printStackTrace();
+ }
+ // build();
+ pIndexes.add(new Indexable(tmpData, file, mService,
+ serviceName, RemoteBuilder.this));
+ doUnbindService(getApplicationContext());
+ }
- // Called when the connection with the service disconnects
- // unexpectedly
- public void onServiceDisconnected(ComponentName className) {
- Log.e(TAG, "Service has unexpectedly disconnected");
- mService = null;
- mIsBound--;
- }
- };
- }
+ // Called when the connection with the service disconnects
+ // unexpectedly
+ public void onServiceDisconnected(ComponentName className) {
+ Log.e(TAG, "Service has unexpectedly disconnected");
+ mService = null;
+ mIsBound--;
+ }
+ };
+ }
- public class LocalBinder extends Binder {
- IndexService getService() {
- return IndexService.this;
- }
- }
+ public class LocalBinder extends Binder {
+ IndexService getService() {
+ return IndexService.this;
+ }
+ }
}
diff --git a/src/ca/dracode/ais/service/InfoProxy.java b/src/ca/dracode/ais/service/InfoProxy.java
index 4a256aa..a3c183d 100644
--- a/src/ca/dracode/ais/service/InfoProxy.java
+++ b/src/ca/dracode/ais/service/InfoProxy.java
@@ -26,7 +26,6 @@
import android.content.ServiceConnection;
import android.os.IBinder;
-import ca.dracode.ais.indexinfo.FileChangeListener;
import ca.dracode.ais.indexinfo.IndexComm;
public class InfoProxy extends Service {
@@ -43,9 +42,7 @@ public boolean isIndexerRunning(){
return false;
}
- public void setFileChangeListener(FileChangeListener listener){
-
- }
+ public String getCurrentIndexPath(){ return "/sdcard";}
};
@Override
@@ -58,28 +55,15 @@ public IBinder onBind(Intent intent) {
private ServiceConnection mListenerConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
- // This is called when the connection with the service has been
- // established, giving us the service object we can use to
- // interact with the service. Because we have bound to a explicit
- // service that we know is running in our own process, we can
- // cast its IBinder to a concrete class and directly access it.
mListenerService = ((FileListener.LocalBinder)service).getService();
}
public void onServiceDisconnected(ComponentName className) {
- // This is called when the connection with the service has been
- // unexpectedly disconnected -- that is, its process crashed.
- // Because it is running in our same process, we should never
- // see this happen.
mListenerService = null;
}
};
void doBindService() {
- // Establish a connection with the service. We use an explicit
- // class name because we want a specific service implementation that
- // we know will be running in our own process (and thus won't be
- // supporting component replacement by other applications).
bindService(new Intent(InfoProxy.this,
FileListener.class), mListenerConnection, Context.BIND_AUTO_CREATE);
mIsListenerBound = true;
@@ -87,7 +71,6 @@ void doBindService() {
void doUnbindService() {
if (mIsListenerBound) {
- // Detach our existing connection.
unbindService(mListenerConnection);
mIsListenerBound = false;
}
diff --git a/src/ca/dracode/ais/service/ParserService.java b/src/ca/dracode/ais/service/ParserService.java
index 6cc4896..294ccc9 100644
--- a/src/ca/dracode/ais/service/ParserService.java
+++ b/src/ca/dracode/ais/service/ParserService.java
@@ -45,6 +45,11 @@ public String getName() {
return name;
}
+ /**
+ * Checks to see if this ParserService can handle the given extension
+ * @param ext The extension that needs to be parsed
+ * @return true if the ParserService can handle the given extension; false otherwise
+ */
public boolean checkExtension(String ext) {
return this.extensions.contains(ext);
}
diff --git a/src/ca/dracode/ais/service/SearchData.java b/src/ca/dracode/ais/service/SearchData.java
index da759c5..e700945 100644
--- a/src/ca/dracode/ais/service/SearchData.java
+++ b/src/ca/dracode/ais/service/SearchData.java
@@ -1,34 +1,30 @@
-/*******************************************************************************
+/*
* Copyright 2014 Benjamin Winger.
*
- * This file is part of Android Indexing Service.
+ * This file is part of AIS.
*
- * Android Indexing Service is free software: you can redistribute it and/or modify
+ * AIS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
- * Android Indexing Service is distributed in the hope that it will be useful,
+ * AIS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with Android Indexing Service. If not, see .
- ******************************************************************************/
-
+ * along with AIS. If not, see .
+ */
package ca.dracode.ais.service;
-
import java.util.ArrayList;
-
/*
- * SearchData.java
- *
- * Some container - must verify
- * I think it is deprecated code that was replaced with PageResut
- */
-
+* SearchData.java
+*
+* Some container - must verify
+* I think it is deprecated code that was replaced with PageResut
+*/
public class SearchData {
- int pages;
- ArrayList text = new ArrayList();
-}
+ int pages;
+ ArrayList text = new ArrayList();
+}
\ No newline at end of file
diff --git a/src/ca/dracode/ais/service/SearchService.java b/src/ca/dracode/ais/service/SearchService.java
index 7e71306..26b6d25 100644
--- a/src/ca/dracode/ais/service/SearchService.java
+++ b/src/ca/dracode/ais/service/SearchService.java
@@ -35,98 +35,47 @@
import ca.dracode.ais.indexer.FileIndexer;
import ca.dracode.ais.indexer.FileSearcher;
-/*
+/**
* SearchService.java
*
* Service accessed by the client library with functions to search through the index
- *
- * Make the indexer search from disk for multi-file searches and search from memory
- * for single file searches (load file into memory in load function).
*/
+// TODO - Make the indexer search from disk for multi-file searches and search from memory
+// for single file searches (create new index in RAMDirectory and add appropriate documents in
+// the load function).
+
public class SearchService extends Service {
private static final String TAG = "ca.dracode.ais.service.SearchService";
private final BSearchService1_0.Stub mBinder = new BSearchService1_0.Stub() {
- public PageResult[] find(String doc, int type, String text, int numHits, int set, int page){
- return sm.find(text, doc, numHits, type, set, page);
- }
-
- /**
- * Used to search the contents of multiple files
- * @param docs - A list containing the names of the documents that should be searched. This allows metadata
- * for multiple files to be in the search service's memory at once. An empty list will
- * cause the search service to search all files on the device
- * Directories can also be included for search of their contents
- * type - allows the client to specify what type of results it wants to receive
- * text - the search term
- * numHits - the maximum number of results to return per file, a value of -1 means no limit
- * @return a list containing the terms found that matched the query and what page of the document they appear on.
- */
- public PageResult[] findIn(List docs, int type, String text, int numHits, int set){
- return sm.findIn(text, docs, numHits, set, type);
- }
-
- /**
- * Used to search for file names
- * @param docs - the root directory for the search.
- * type - allows the client to specify how to filter the files
- * text - the search term
- * numHits - the maximum number of results to return
- */
- public List findName(List docs, int type, String text, int numHits,
- int set){
- return sm.findName(text, docs, numHits, set, type);
- }
-
- /**
- * used to send file contents to the indexing service. Because of the limitations of
- * the service communicsation system the information may have to be sent in chunks as
- * there can only be a maximum of about 1MB in the buffer at a time (which is shared
- * among all applications). The client class sends data in chunks that do not exceed 256KB,
- * currently pages cannot exceed 256KB as the data transfer will fail
- * @param filePath - the location of the file to be built; used by the indexer to identify the file
- * text - the text to be added to the index
- * page - the page upon which the chunk of the file that is being transferred starts.
- * It is a double to allow the transfer of parts of a single page if the page is too large
- * maxPage - the total number of pages in the entire file
- * @return 0 if index was built successfully;
- * 1 if the file lock was in place due to another build operation being in progress;
- * 2 if the Service is still waiting for the rest of the pages
- * -1 on error
- */
- public int buildIndex(String filePath, List text, double page, int maxPage){
- return SearchService.this.buildIndex(filePath, text, page, maxPage);
- }
-
- /**
- * Tells the indexer to load a file's metadata into memory for use in searches.
- * The function can be called multiple times to load several files. Files remain loaded until the unload
- * function is called. Please make sure to call unload when you are finished with the document.
- * @param filePath - the location of the file to prepare; is also the identifier for the file's data in the index
- * @return 0 if the file exists in the index and was not already loaded;
- * 1 if the file was already loaded;
- * 2 if the file was not loaded and does not exist in the index;
- * -1 if there was an error
- */
- public int load(String filePath){
- return SearchService.this.load(filePath);
- }
-
- /**
- * Tells the indexer to unload a file's metadata from memory as it will not be used in future searches.
- * @param filePath - the location of the file; used to identify which file should be unloaded
- * @return true if the file exists in the index; false otherwise
- */
- public boolean unload(String filePath){
- return SearchService.this.unload(filePath);
- }
-
- /**
- * Tells the search service to cancel any searches that are currently running
- */
- public boolean interrupt(){
- return sm.interrupt();
- }
+ public PageResult[] find(String doc, int type, String text, int numHits, int set, int page) {
+ return sm.find(text, doc, numHits, type, set, page);
+ }
+
+ public PageResult[] findIn(List docs, int type, String text, int numHits, int set) {
+ return sm.findIn(text, docs, numHits, set, type);
+ }
+
+ public List findName(List docs, int type, String text, int numHits,
+ int set) {
+ return sm.findName(text, docs, numHits, set, type);
+ }
+
+ public int buildIndex(String filePath, List text, double page, int maxPage) {
+ return SearchService.this.buildIndex(filePath, text, page, maxPage);
+ }
+
+ public int load(String filePath) {
+ return SearchService.this.load(filePath);
+ }
+
+ public boolean unload(String filePath) {
+ return SearchService.this.unload(filePath);
+ }
+
+ public boolean interrupt() {
+ return sm.interrupt();
+ }
};
private SearchManager sm;
@@ -145,29 +94,46 @@ public void onCreate() {
this.data = new HashMap();
}
+ /**
+ * used to send file contents to the indexing service. Because of the limitations of
+ * the service communicsation system the information may have to be sent in chunks as
+ * there can only be a maximum of about 1MB in the buffer at a time (which is shared
+ * among all applications). The client class sends data in chunks that do not exceed 256KB,
+ * currently pages cannot exceed 256KB as the data transfer will fail
+ * @param filePath - the location of the file to be built; used by the indexer to identify the file
+ * @param text - the text to be added to the index
+ * @param page - the page upon which the chunk of the file that is being transferred
+ * starts.
+ * It is a double to allow the transfer of parts of a single page if the page is too large
+ * maxPage - the total number of pages in the entire file
+ * @return 0 if index was built successfully;
+ * 1 if the file lock was in place due to another build operation being in progress;
+ * 2 if the Service is still waiting for the rest of the pages
+ * -1 on error
+ */
public int buildIndex(String filePath, List text, double page,
int maxPage) {
File indexDirFile = new File(FileIndexer.getRootStorageDir());
File[] dirContents = indexDirFile.listFiles();
- if (dirContents != null) {
- for (File dirContent : dirContents) {
- if (dirContent.getName().equals("write.lock")) {
+ if(dirContents != null) {
+ for(File dirContent : dirContents) {
+ if(dirContent.getName().equals("write.lock")) {
return 1;
}
}
}
FileIndexer indexer = new FileIndexer();
SearchData tmpData = this.data.get(filePath);
- if (page == 0) {
+ if(page == 0) {
tmpData.text.clear();
}
- if (page + text.size() != maxPage) {
+ if(page + text.size() != maxPage) {
tmpData.text.addAll(text);
} else {
tmpData.text.addAll(text);
try {
indexer.buildIndex(tmpData.text, new File(filePath));
- } catch (Exception ex) {
+ } catch(Exception ex) {
Log.v("PDFIndex", "" + ex.getMessage());
ex.printStackTrace();
} finally {
@@ -178,27 +144,37 @@ public int buildIndex(String filePath, List text, double page,
return 2;
}
+ /**
+ * Tells the indexer to load a file's metadata into memory for use in searches.
+ * The function can be called multiple times to load several files. Files remain loaded until the unload
+ * function is called. Please make sure to call unload when you are finished with the document.
+ * @param filePath - the location of the file to prepare; is also the identifier for the file's data in the index
+ * @return 0 if the file exists in the index and was not already loaded;
+ * 1 if the file was already loaded;
+ * 2 if the file was not loaded and does not exist in the index;
+ * -1 if there was an error
+ */
public int load(final String filePath) {
- if (this.data.containsKey(filePath)) {
+ if(this.data.containsKey(filePath)) {
return 1;
}
SearchData tmpData = new SearchData();
Document tmp;
- if (SearchService.this.sm.searcher == null) {
+ if(SearchService.this.sm.searcher == null) {
Log.e(TAG, "Searcher is null");
return -1;
}
- if ((tmp = this.sm.searcher.getMetaFile(filePath)) != null) {
+ if((tmp = this.sm.searcher.getMetaFile(filePath)) != null) {
try {
IndexableField f = tmp.getField("pages");
- if (f == null) {
+ if(f == null) {
Log.e(TAG,
"Cannot find pages in metafile: " + tmp.toString());
return -1;
} else {
tmpData.pages = f.numericValue().intValue();
}
- } catch (Exception e) {
+ } catch(Exception e) {
Log.e(TAG, "Error", e);
return -1;
}
@@ -210,6 +186,11 @@ public int load(final String filePath) {
}
+ /**
+ * Tells the indexer to unload a file's metadata from memory as it will not be used in future searches.
+ * @param path - the location of the file; used to identify which file should be unloaded
+ * @return true if the file exists in the index; false otherwise
+ */
public boolean unload(String path) {
return this.data.remove(path) != null;
}
@@ -217,33 +198,55 @@ public boolean unload(String path) {
private class SearchManager {
boolean found;
boolean finishedLoading = false;
- private FileSearcher searcher;
+ private FileSearcher searcher;
public SearchManager() {
- this.searcher = new FileSearcher();
+ this.searcher = new FileSearcher();
}
- private boolean interrupt(){
- return searcher.interrupt();
- }
+ /**
+ * Tells the search service to cancel any searches that are currently running
+ */
+ private boolean interrupt() {
+ return searcher.interrupt();
+ }
- private List findName(String term, List directory, int numHits, int set,
- int type){
- return this.searcher.findName(term, "path", directory, "path", numHits, set, type);
- }
+ /**
+ * Used to search for file names
+ * @param directory - A list containing directories to search
+ * type - allows the client to specify how to filter the files
+ * text - the search term
+ * numHits - the maximum number of results to return
+ */
+ private List findName(String term, List directory, int numHits, int set,
+ int type) {
+ return this.searcher.findName(term, "path", directory, "path", numHits, set, type);
+ }
- private PageResult[] findIn(String term, List documents, int numHits, int set,
- int type){
- return this.searcher.findIn(term, "text", documents, "path", numHits, set, type);
- }
+ /**
+ * Used to search the contents of multiple files
+ * @param documents - A list containing the names of the documents that should be
+ * searched. This allows metadata
+ * for multiple files to be in the search service's memory at once. An empty list will
+ * cause the search service to search all files on the device
+ * Directories can also be included for search of their contents
+ * type - allows the client to specify what type of results it wants to receive
+ * text - the search term
+ * numHits - the maximum number of results to return per file, a value of -1 means no limit
+ * @return a list containing the terms found that matched the query and what page of the document they appear on.
+ */
+ private PageResult[] findIn(String term, List documents, int numHits, int set,
+ int type) {
+ return this.searcher.findInFiles(term, "text", documents, "path", numHits, set, type);
+ }
private PageResult[] find(String term, String constrainValue, int maxResults, int set,
int type, int page) {
/**
* TODO - Preload information about the index in the load function for use here
* **/
- Log.i(TAG, "Received request to search for: " + term);
- return this.searcher.find(term, "text",
+ Log.i(TAG, "Received request to search for: " + term);
+ return this.searcher.findInFile(term, "text",
constrainValue, "path", maxResults, set, type, page);
}
}
diff --git a/src/ca/dracode/ais/ui/AISApplication.java b/src/ca/dracode/ais/ui/AISApplication.java
index adb706d..e2d28f9 100644
--- a/src/ca/dracode/ais/ui/AISApplication.java
+++ b/src/ca/dracode/ais/ui/AISApplication.java
@@ -22,8 +22,6 @@
import android.app.Application;
import android.util.Log;
-import org.apache.lucene.search.IndexSearcher;
-
/*
* AISApplication.java
*
@@ -36,7 +34,6 @@
public class AISApplication extends Application {
private final static String TAG = "ca.dracode.ais.ais";
- protected IndexSearcher indexSearcher; // TODO - Use this as a global searcher for whenever the aplication is running (is this necessary?)
public void onCreate() {
super.onCreate();
diff --git a/src/ca/dracode/ais/ui/AISPreferences.java b/src/ca/dracode/ais/ui/AISPreferences.java
index 4f53dff..dcb358b 100644
--- a/src/ca/dracode/ais/ui/AISPreferences.java
+++ b/src/ca/dracode/ais/ui/AISPreferences.java
@@ -28,27 +28,22 @@
import ca.dracode.ais.indexinfo.IndexInfo;
public class AISPreferences extends PreferenceActivity {
- private boolean enabled;
private final IndexInfo indexInfo = new IndexInfo();
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.prefs);
SwitchPreference mEnableWifi = (SwitchPreference) findPreference("enabled");
mEnableWifi.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
-
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- if (preference.isEnabled() != newValue) {
- if(!((Boolean)newValue)){
+ if(!((Boolean) newValue)) {
indexInfo.stopIndexer(getApplicationContext());
} else {
indexInfo.startIndexer(getApplicationContext());
}
return true;
- } else {
- return false;
- }
}
});
}
diff --git a/src/ca/dracode/ais/ui/MainActivity.java b/src/ca/dracode/ais/ui/MainActivity.java
index 772b12c..7472a64 100644
--- a/src/ca/dracode/ais/ui/MainActivity.java
+++ b/src/ca/dracode/ais/ui/MainActivity.java
@@ -33,29 +33,31 @@
public class MainActivity extends Activity {
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- this.setContentView(R.layout.activity_main);
- TextView t = (TextView)findViewById(R.id.textView1);
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.setContentView(R.layout.activity_main);
+ TextView t = (TextView) findViewById(R.id.textView1);
+
+ // TODO Remove testing code
Intent serviceIntent = new Intent(this, IndexService.class);
serviceIntent.putExtra("crawl", true);
this.startService(serviceIntent);
Intent serviceIntent2 = new Intent(this, FileListener.class);
this.startService(serviceIntent2);
Alarm.SetAlarm(this);
- }
+ }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.main, menu);
- return true;
- }
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
@Override
- public boolean onOptionsItemSelected(MenuItem item){
+ public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
- if (id == R.id.action_settings) {
+ if(id == R.id.action_settings) {
Intent i = new Intent(this, AISPreferences.class);
startActivity(i);
return true;