Skip to content

Commit e96a0dc

Browse files
committed
Reverse image search is finally working :3 TODO: Add default application activity and settings
1 parent b33fc8a commit e96a0dc

File tree

5 files changed

+109
-71
lines changed

5 files changed

+109
-71
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
*.iml
22
.gradle
33
/local.properties
4-
/.idea
4+
/.idea/
55
.DS_Store
66
/build
77
/captures

app/build.gradle

+5-1
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ dependencies {
3434
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
3535
implementation 'com.android.support:appcompat-v7:28.0.0'
3636
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
37-
implementation 'com.android.volley:volley:1.1.1'
37+
// implementation 'com.android.volley:volley:1.1.1'
38+
implementation 'com.loopj.android:android-async-http:1.4.9'
3839
implementation 'org.jsoup:jsoup:1.7.2'
3940
implementation group: 'commons-io', name: 'commons-io', version: '2.4'
41+
// implementation 'com.squareup.retrofit2:retrofit:2.1.0'
42+
// implementation 'com.google.code.gson:gson:2.8.2'
43+
// implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
4044
testImplementation 'junit:junit:4.12'
4145
androidTestImplementation 'com.android.support.test:runner:1.0.2'
4246
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

app/src/main/java/eu/dasancti/reversee/MainActivity.java

+66-67
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,117 @@
11
package eu.dasancti.reversee;
22

33
import android.Manifest;
4-
import android.content.ContentProviderClient;
54
import android.content.Intent;
65
import android.content.pm.PackageManager;
76
import android.net.Uri;
87
import android.os.Bundle;
98
import android.support.v4.content.ContextCompat;
109
import android.support.v7.app.AppCompatActivity;
1110
import android.util.Log;
12-
import android.util.Xml;
11+
import android.widget.TextView;
1312
import android.widget.Toast;
14-
import com.android.volley.Request;
15-
import com.android.volley.RequestQueue;
16-
import com.android.volley.Response;
17-
import com.android.volley.VolleyError;
18-
import com.android.volley.toolbox.StringRequest;
19-
import com.android.volley.toolbox.Volley;
20-
import org.apache.commons.io.IOUtils;
13+
import com.loopj.android.http.AsyncHttpClient;
14+
import com.loopj.android.http.AsyncHttpResponseHandler;
15+
import com.loopj.android.http.RequestHandle;
16+
import com.loopj.android.http.RequestParams;
17+
import cz.msebera.android.httpclient.Header;
2118
import org.jsoup.Jsoup;
2219
import org.jsoup.nodes.Document;
2320
import org.jsoup.nodes.Element;
2421
import org.jsoup.select.Elements;
2522

26-
import java.io.*;
27-
import java.util.HashMap;
28-
import java.util.Map;
23+
import java.io.FileNotFoundException;
24+
import java.util.Arrays;
2925
import java.util.Objects;
3026
import java.util.concurrent.atomic.AtomicReference;
3127

3228
public class MainActivity extends AppCompatActivity {
3329

3430
private static final String GOOGLE_REVERSE_IMAGE_SEARCH_URL = "https://www.google.com/searchbyimage/upload";
3531
private static final String FAKE_USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11";
32+
private static final String API_SCH_KEY = "sch";
33+
private static final String API_SCH_VALUE = "sch";
34+
private static final String API_ENCODED_IMAGE_KEY = "encoded_image";
35+
private static final String API_USER_AGENT_KEY = "User-Agent";
36+
37+
private TextView progressStatus;
3638

3739
@Override
3840
protected void onCreate(Bundle savedInstanceState) {
3941
super.onCreate(savedInstanceState);
4042
setContentView(R.layout.activity_main);
4143

44+
progressStatus = findViewById(R.id.progressStatus);
45+
4246
Intent intent = getIntent();
4347
String action = intent.getAction();
4448
if (isPermissionGranted()) {
4549
if (action.equals(Intent.ACTION_SEND)) {
46-
handleImageSearch(intent);
50+
progressStatus.setText(getString(R.string.progress_status_recieved_intent));
51+
try {
52+
handleImageSearch(intent);
53+
} catch (FileNotFoundException e) {
54+
String err = "Failed to handle Share image intent:"+e.getMessage();
55+
Log.e("INTENT_HANDLE",err);
56+
Toast.makeText(getApplicationContext(), err, Toast.LENGTH_SHORT).show();
57+
}
4758
}
4859
} else {
4960
Toast.makeText(this, "The app wasn't allowed permissions to manage files.", Toast.LENGTH_LONG).show();
5061
}
5162
}
5263

53-
private void handleImageSearch(Intent intent) {
64+
private void handleImageSearch(Intent intent) throws FileNotFoundException {
5465
Uri imageUri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
55-
Toast.makeText(this, "Received image URI:"+imageUri.getPath(), Toast.LENGTH_SHORT).show();
56-
AtomicReference<String> imageData = new AtomicReference<>();
57-
try {
58-
imageData.set(IOUtils.toString(Objects.requireNonNull(getContentResolver().openInputStream(imageUri))));
59-
} catch (FileNotFoundException e) {
60-
String err = "Couldn't open the shared image as an input stream.";
61-
Toast.makeText(this, err, Toast.LENGTH_LONG).show();
62-
Log.e("GET_IMAGE_FILE", err);
63-
this.finish();
64-
return;
65-
} catch (IOException e) {
66-
String err = "Couldn't read input stream of image.";
67-
Toast.makeText(this, err, Toast.LENGTH_LONG).show();
68-
Log.e("GET_IMAGE_FILE", err);
69-
this.finish();
70-
return;
71-
}
72-
Intent searchIntent = new Intent();
73-
searchIntent.setAction(Intent.ACTION_VIEW);
74-
//TODO: Implement browser intent with POST method
75-
RequestQueue requestQueue = Volley.newRequestQueue(this);
76-
final AtomicReference<String> browserRedirect = new AtomicReference<>();
77-
StringRequest getGoogleRedirectUrl = new StringRequest(
78-
Request.Method.POST,
79-
GOOGLE_REVERSE_IMAGE_SEARCH_URL,
80-
response -> {
81-
Document doc = Jsoup.parse(response);
82-
Element content = doc.getElementById("content");
83-
Elements redirects = content.getElementsByTag("meta");
66+
progressStatus.setText(getString(R.string.progress_status_handling_image));
67+
AtomicReference<String> reverseSearchRedirectURL = new AtomicReference<>();
68+
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
69+
asyncHttpClient.addHeader(API_USER_AGENT_KEY, FAKE_USER_AGENT);
70+
RequestParams requestParams = new RequestParams();
71+
requestParams.put(API_SCH_KEY, API_SCH_VALUE);
72+
requestParams.put(API_ENCODED_IMAGE_KEY, Objects.requireNonNull(getContentResolver().openInputStream(imageUri)));
73+
RequestHandle requestHandle = asyncHttpClient.post(getApplicationContext(),GOOGLE_REVERSE_IMAGE_SEARCH_URL, requestParams, new AsyncHttpResponseHandler() {
74+
@Override
75+
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
76+
Log.e("UNEXPECTED", "Based on the stupendous behavior of this async library, we should never be able to get here. 3xx HTML codes are considered a failure.");
77+
MainActivity.this.finish();
78+
}
79+
80+
@Override
81+
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
82+
if (statusCode == 302) {
83+
progressStatus.setText(getString(R.string.progress_status_response_success));
84+
Log.i("RESPONSE_SUCCESS", "Recieved 302 redirect, processing HTML response.");
85+
String responseString = new String(responseBody);
86+
Document doc = Jsoup.parse(responseString);
87+
Elements redirects = doc.getElementsByTag("a");
8488
for (Element redirect : redirects) {
85-
String redirectUrl = redirect.attr("url");
89+
String redirectUrl = redirect.attr("href");
8690
if (redirectUrl.contains("/search?tbs=sbi:")) {
87-
browserRedirect.set(redirectUrl);
91+
reverseSearchRedirectURL.set(redirectUrl);
92+
progressStatus.setText(getString(R.string.progress_status_redirect_found));
8893
break;
8994
}
9095
}
91-
if (browserRedirect.get().isEmpty()) {
92-
Toast.makeText(this, "Failed to get redirect URL", Toast.LENGTH_LONG).show();
96+
if (reverseSearchRedirectURL.get().isEmpty()) {
97+
Toast.makeText(MainActivity.this, "Failed to get redirect URL", Toast.LENGTH_LONG).show();
9398
} else {
94-
//TODO: Launch browser intent with the redirect
95-
Toast.makeText(this, "Found redirect URL for reverse search.", Toast.LENGTH_SHORT).show();
96-
Log.i("REVERSE_SEARCH_URL", browserRedirect.get());
99+
Toast.makeText(MainActivity.this, "Found redirect URL for reverse search, opening browser.", Toast.LENGTH_SHORT).show();
100+
Log.i("REVERSE_SEARCH_URL", reverseSearchRedirectURL.get());
101+
Intent searchIntent = new Intent();
102+
searchIntent.setAction(Intent.ACTION_VIEW);
103+
searchIntent.setData(Uri.parse(reverseSearchRedirectURL.get()));
104+
startActivity(searchIntent);
105+
MainActivity.this.finish();
97106
}
98-
},
99-
error -> Toast.makeText(this, "POST call to reverse search failed: "+error.getMessage(), Toast.LENGTH_LONG).show()
100-
) {
101-
protected Map<String, String> getParams() {
102-
Map<String, String> params = new HashMap<>();
103-
params.put("sch", "sch");
104-
params.put("encoded_image", imageData.get());
105-
return params;
106-
}
107-
public Map<String, String> getHeaders() {
108-
Map<String, String> headers = new HashMap<>();
109-
headers.put("User-Agent", FAKE_USER_AGENT);
110-
return headers;
107+
} else {
108+
String err = "POST call to reverse search failed [" + statusCode + "] error message: " + error.getMessage() + "\n body:" + Arrays.toString(responseBody);
109+
Log.e("POST_CALL_FAILED", err);
110+
Toast.makeText(MainActivity.this, err, Toast.LENGTH_LONG).show();
111+
}
111112
}
112-
};
113-
requestQueue.add(getGoogleRedirectUrl);
114-
Toast.makeText(this, "Handling google reverse image search.", Toast.LENGTH_LONG).show();
115-
this.finish();
113+
});
114+
// TODO: Display spinner until requestHandle.isFinished() is true
116115
}
117116

118117
private boolean isPermissionGranted() {

app/src/main/res/layout/activity_main.xml

+33-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,41 @@
1010
<TextView
1111
android:layout_width="wrap_content"
1212
android:layout_height="wrap_content"
13-
android:text="Hello World!"
13+
android:text="Please be patient"
1414
app:layout_constraintBottom_toBottomOf="parent"
1515
app:layout_constraintLeft_toLeftOf="parent"
1616
app:layout_constraintRight_toRightOf="parent"
17-
app:layout_constraintTop_toTopOf="parent"/>
17+
app:layout_constraintTop_toTopOf="parent"
18+
app:layout_constraintVertical_bias="0.351"
19+
tools:ignore="HardcodedText"/>
20+
<TextView
21+
android:layout_width="wrap_content"
22+
android:layout_height="wrap_content"
23+
android:text="We are processing your queue."
24+
app:layout_constraintBottom_toBottomOf="parent"
25+
app:layout_constraintLeft_toLeftOf="parent"
26+
app:layout_constraintRight_toRightOf="parent"
27+
app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.39"
28+
android:id="@+id/textView"
29+
tools:ignore="HardcodedText"/>
30+
<ProgressBar
31+
style="?android:attr/progressBarStyle"
32+
app:layout_constraintBottom_toBottomOf="parent"
33+
app:layout_constraintLeft_toLeftOf="parent"
34+
app:layout_constraintRight_toRightOf="parent"
35+
app:layout_constraintTop_toTopOf="parent"
36+
app:layout_constraintVertical_bias="0.5"
37+
android:layout_width="wrap_content"
38+
android:layout_height="wrap_content"
39+
tools:layout_editor_absoluteY="230dp" tools:layout_editor_absoluteX="167dp" android:id="@+id/progressBar" />
40+
<TextView
41+
app:layout_constraintTop_toBottomOf="@id/progressBar"
42+
app:layout_constraintLeft_toLeftOf="parent"
43+
app:layout_constraintRight_toRightOf="parent"
44+
android:text="..."
45+
android:layout_width="wrap_content"
46+
android:layout_height="wrap_content" tools:layout_editor_absoluteY="280dp"
47+
tools:layout_editor_absoluteX="187dp" android:id="@+id/progressStatus" android:paddingTop="42dp"
48+
tools:ignore="HardcodedText"/>
1849

1950
</android.support.constraint.ConstraintLayout>

app/src/main/res/values/strings.xml

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
<resources>
22
<string name="app_name">Reversee</string>
3+
<string name="progress_status_recieved_intent">Recieved intent data (image share)</string>
4+
<string name="progress_status_handling_image">Handling google reverse image search.</string>
5+
<string name="progress_status_response_success">Google request successful.</string>
6+
<string name="progress_status_redirect_found">Found redirect URL, opening browser intent.</string>
37
</resources>

0 commit comments

Comments
 (0)