Secure the pendingIntent in SearchWidgetProvider. am: ae2c873754 am: a51a669fe6 am: 1367aef11c am: 78a2c7633d am: e0fcc36980 am: 11b29ba771 am: f8c478e0a5

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/QuickSearchBox/+/15806296

Change-Id: I978db8ebd83c9f859c7b2850886a2c58a96815a3
diff --git a/Android.bp b/Android.bp
index 4546c8c..d21d8d6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -33,7 +33,7 @@
 
 android_app {
     name: "QuickSearchBox",
-    sdk_version: "14",
+    sdk_version: "current",
     static_libs: [
         "guava",
         "android-common",
@@ -42,7 +42,6 @@
         "src/**/*.java",
         "src/**/*.logtags",
     ],
-    optional_uses_libs: ["org.apache.http.legacy"],
     certificate: "shared",
     product_specific: true,
     resource_dirs: ["res"],
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8b83023..7120537 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -19,7 +19,7 @@
 
     <original-package android:name="com.android.quicksearchbox" />
 
-    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="29" />
+    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="30" />
 
     <uses-permission android:name="android.permission.GLOBAL_SEARCH" />
 
@@ -39,7 +39,6 @@
                  android:name=".QsbApplicationWrapper"
                  android:theme="@style/Theme.QuickSearchBox"
                  android:hardwareAccelerated="true">
-        <uses-library android:name="org.apache.http.legacy" android:required="false" />
 
         <activity android:name=".SearchActivity"
                   android:label="@string/app_name"
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..d4d3090
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,23 @@
+load("@rules_android//rules:rules.bzl", "android_binary")
+load("//build/make/tools:event_log_tags.bzl", "event_log_tags")
+
+event_log_tags(
+    name = "genlogtags",
+    srcs = glob(["src/**/*.logtags"]),
+)
+
+android_binary(
+    name = "QuickSearchBox",
+    srcs = glob(["src/**/*.java"]),
+    custom_package = "com.android.quicksearchbox",
+    javacopts = ["-Xep:ArrayToString:OFF"],
+    manifest = "AndroidManifest.xml",
+    # TODO(182591919): uncomment the below once android rules are integrated with r8.
+    # proguard_specs = ["proguard.flags"],
+    resource_files = glob(["res/**"]),
+    deps = [
+        ":genlogtags",
+        "//external/guava:guava-android-host",
+        "//frameworks/ex/common:android-common",
+    ],
+)
diff --git a/proguard.flags b/proguard.flags
index 8390f5b..922c2ba 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -1,3 +1,11 @@
 -keep class com.android.quicksearchbox.preferences.DeviceSearchFragment
 
 -keep class com.android.quicksearchbox.preferences.SearchableItemsFragment
+
+-keep class com.android.quicksearchbox.util.CachedLater {
+  *;
+}
+
+-keep class com.android.quicksearchbox.util.PerNameExecutor {
+  *;
+}
diff --git a/src/com/android/quicksearchbox/google/GoogleSuggestClient.java b/src/com/android/quicksearchbox/google/GoogleSuggestClient.java
index 5381acb..51c5129 100644
--- a/src/com/android/quicksearchbox/google/GoogleSuggestClient.java
+++ b/src/com/android/quicksearchbox/google/GoogleSuggestClient.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
-import android.net.http.AndroidHttpClient;
 import android.os.Build;
 import android.os.Handler;
 import android.text.TextUtils;
@@ -33,16 +32,17 @@
 import com.android.quicksearchbox.SuggestionCursor;
 import com.android.quicksearchbox.util.NamedTaskExecutor;
 
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.params.HttpParams;
-import org.apache.http.util.EntityUtils;
 import org.json.JSONArray;
 import org.json.JSONException;
 
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
 import java.net.URLEncoder;
 import java.util.Locale;
 
@@ -60,15 +60,13 @@
     // TODO: this should be defined somewhere
     private static final String HTTP_TIMEOUT = "http.conn-manager.timeout";
 
-    private final HttpClient mHttpClient;
+    private final int mConnectTimeout;
 
     public GoogleSuggestClient(Context context, Handler uiThread,
             NamedTaskExecutor iconLoader, Config config) {
         super(context, uiThread, iconLoader);
-        mHttpClient = AndroidHttpClient.newInstance(USER_AGENT, context);
-        HttpParams params = mHttpClient.getParams();
-        params.setLongParameter(HTTP_TIMEOUT, config.getHttpConnectTimeout());
 
+        mConnectTimeout = config.getHttpConnectTimeout();
         // NOTE:  Do not look up the resource here;  Localization changes may not have completed
         // yet (e.g. we may still be reading the SIM card).
         mSuggestUri = null;
@@ -101,33 +99,48 @@
             Log.i(LOG_TAG, "Not connected to network.");
             return null;
         }
+        HttpURLConnection connection = null;
         try {
             String encodedQuery = URLEncoder.encode(query, "UTF-8");
             if (mSuggestUri == null) {
                 Locale l = Locale.getDefault();
                 String language = GoogleSearch.getLanguage(l);
                 mSuggestUri = getContext().getResources().getString(R.string.google_suggest_base,
-                                                                    language);
+                    language);
             }
 
             String suggestUri = mSuggestUri + encodedQuery;
             if (DBG) Log.d(LOG_TAG, "Sending request: " + suggestUri);
-            HttpGet method = new HttpGet(suggestUri);
-            HttpResponse response = mHttpClient.execute(method);
-            if (response.getStatusLine().getStatusCode() == 200) {
+            URL url = URI.create(suggestUri).toURL();
+            connection = (HttpURLConnection) url.openConnection();
+            connection.setConnectTimeout(mConnectTimeout);
+            connection.setRequestProperty("User-Agent", USER_AGENT);
+            connection.setRequestMethod("GET");
+            connection.setDoInput(true);
+            connection.connect();
+            InputStream inputStream = connection.getInputStream();
+            if (connection.getResponseCode() == 200) {
 
                 /* Goto http://www.google.com/complete/search?json=true&q=foo
                  * to see what the data format looks like. It's basically a json
                  * array containing 4 other arrays. We only care about the middle
                  * 2 which contain the suggestions and their popularity.
                  */
-                JSONArray results = new JSONArray(EntityUtils.toString(response.getEntity()));
+                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+                StringBuilder sb = new StringBuilder();
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    sb.append(line).append("\n");
+                }
+                reader.close();
+                JSONArray results = new JSONArray(sb.toString());
                 JSONArray suggestions = results.getJSONArray(1);
                 JSONArray popularity = results.getJSONArray(2);
                 if (DBG) Log.d(LOG_TAG, "Got " + suggestions.length() + " results");
                 return new GoogleSuggestCursor(this, query, suggestions, popularity);
             } else {
-                if (DBG) Log.d(LOG_TAG, "Request failed " + response.getStatusLine());
+                if (DBG)
+                    Log.d(LOG_TAG, "Request failed " + connection.getResponseMessage());
             }
         } catch (UnsupportedEncodingException e) {
             Log.w(LOG_TAG, "Error", e);
@@ -135,6 +148,8 @@
             Log.w(LOG_TAG, "Error", e);
         } catch (JSONException e) {
             Log.w(LOG_TAG, "Error", e);
+        } finally {
+            if (connection != null) connection.disconnect();
         }
         return null;
     }