1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
package cgeo.geocaching.loaders;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.connector.gc.GCConstants;
import cgeo.geocaching.connector.gc.RecaptchaHandler;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.TextUtils;
import org.apache.commons.lang3.StringUtils;
import android.content.Context;
import android.os.Handler;
import android.support.v4.content.AsyncTaskLoader;
import java.util.concurrent.CountDownLatch;
public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult> implements RecaptchaReceiver {
public enum CacheListLoaderType {
OFFLINE,
POCKET,
HISTORY,
NEAREST,
COORDINATE,
KEYWORD,
ADDRESS,
FINDER,
OWNER,
MAP,
NEXT_PAGE;
public int getLoaderId() {
return ordinal();
}
}
private Handler recaptchaHandler = null;
private String recaptchaChallenge = null;
private String recaptchaKey = null;
private String recaptchaText = null;
private SearchResult search;
private boolean loading;
private final CountDownLatch latch = new CountDownLatch(1);
public AbstractSearchLoader(final Context context) {
super(context);
}
public abstract SearchResult runSearch();
public boolean isLoading() {
return loading;
}
@Override
public SearchResult loadInBackground() {
loading = true;
try {
if (search == null) {
search = runSearch();
} else {
// Unless we make a new Search the Loader framework won't deliver results. It does't do equals only identity
search = new SearchResult(search);
}
} catch (final Exception e) {
Log.e("Error in Loader ", e);
}
loading = false;
if (search == null) {
search = new SearchResult();
}
return search;
}
@Override
protected void onStartLoading() {
forceLoad();
}
public void setRecaptchaHandler(final Handler recaptchaHandler) {
this.recaptchaHandler = recaptchaHandler;
}
@Override
public void notifyNeed() {
if (recaptchaHandler != null) {
recaptchaHandler.sendEmptyMessage(RecaptchaHandler.SHOW_CAPTCHA);
}
}
@Override
public void waitForUser() {
try {
latch.await();
} catch (final InterruptedException ignored) {
Log.w("searchThread is not waiting for user…");
}
}
@Override
public void setKey(final String key) {
recaptchaKey = key;
}
@Override
public void fetchChallenge() {
recaptchaChallenge = null;
if (StringUtils.isNotEmpty(recaptchaKey)) {
final Parameters params = new Parameters("k", recaptchaKey);
final String recaptchaJs = Network.getResponseData(Network.getRequest("http://www.google.com/recaptcha/api/challenge", params));
if (StringUtils.isNotBlank(recaptchaJs)) {
recaptchaChallenge = TextUtils.getMatch(recaptchaJs, GCConstants.PATTERN_SEARCH_RECAPTCHACHALLENGE, true, 1, null, true);
}
}
}
@Override
public String getChallenge() {
return recaptchaChallenge;
}
@Override
public void setText(final String text) {
recaptchaText = text;
latch.countDown();
}
@Override
public String getText() {
return recaptchaText;
}
@Override
public void reset() {
super.reset();
search = null;
}
}
|