Commit 91eda9e8 authored by Gang Wu's avatar Gang Wu Committed by Commit Bot

Fix image search from search activity

SearchActivity did not handle image search data since image search need
post data, so the fix is add the post data into intent to pass to chrome.

Bug: 1078773
Change-Id: I04efdad0bba315508e0b05d3d9e444d8c1a5d955
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2187191
Commit-Queue: Gang Wu <gangwu@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarEnder <ender@google.com>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#772335}
parent 8f6be972
......@@ -186,6 +186,17 @@ public class IntentHandler {
*/
public static final String EXTRA_INCOGNITO_MODE = "org.chromium.chrome.browser.incognito_mode";
/**
* Byte array for the POST data when load a url, only Intents sent by Chrome can use this.
*/
public static final String EXTRA_POST_DATA = "com.android.chrome.post_data";
/**
* The type of the POST data, need to be added to the HTTP request header, only Intents sent by
* Chrome can use this.
*/
public static final String EXTRA_POST_DATA_TYPE = "com.android.chrome.post_data_type";
/**
* Fake ComponentName used in constructing TRUSTED_APPLICATION_CODE_EXTRA.
*/
......
......@@ -46,6 +46,7 @@ import org.chromium.ui.ViewProvider;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modelutil.LazyConstructionPropertyMcp;
import org.chromium.ui.modelutil.MVCListAdapter;
import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
import org.chromium.ui.modelutil.PropertyModel;
import java.util.ArrayList;
......@@ -336,6 +337,11 @@ public class AutocompleteCoordinatorImpl implements AutocompleteCoordinator {
return mMediator;
}
@VisibleForTesting
ModelList getSuggestionModelList() {
return mMediator.getSuggestionModelList();
}
private void onTileSelected(QueryTile queryTile) {
mMediator.onQueryTileSelected(queryTile);
}
......
......@@ -14,6 +14,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.app.ActivityOptionsCompat;
......@@ -102,6 +103,8 @@ public class SearchActivity extends AsyncInitializationActivity
/** Input submitted before before the native library was loaded. */
private String mQueuedUrl;
private String mQueuedPostDataType;
private byte[] mQueuedPostData;
/** The View that represents the search box. */
private SearchActivityLocationBarLayout mSearchBox;
......@@ -273,7 +276,7 @@ public class SearchActivity extends AsyncInitializationActivity
assert !mIsActivityUsable
: "finishDeferredInitialization() incorrectly called multiple times";
mIsActivityUsable = true;
if (mQueuedUrl != null) loadUrl(mQueuedUrl);
if (mQueuedUrl != null) loadUrl(mQueuedUrl, mQueuedPostDataType, mQueuedPostData);
// TODO(tedchoc): Warmup triggers the CustomTab layout to be inflated, but this widget
// will navigate to Tabbed mode. Investigate whether this can inflate
......@@ -327,29 +330,53 @@ public class SearchActivity extends AsyncInitializationActivity
}
@Override
public void loadUrl(String url) {
public void loadUrl(String url, @Nullable String postDataType, @Nullable byte[] postData) {
// Wait until native has loaded.
if (!mIsActivityUsable) {
mQueuedUrl = url;
mQueuedPostDataType = postDataType;
mQueuedPostData = postData;
return;
}
Intent intent = createIntentForStartActivity(url, postDataType, postData);
if (intent == null) return;
IntentUtils.safeStartActivity(this, intent,
ActivityOptionsCompat
.makeCustomAnimation(this, android.R.anim.fade_in, android.R.anim.fade_out)
.toBundle());
RecordUserAction.record("SearchWidget.SearchMade");
finish();
}
/**
* Creates an intent that will be used to launch Chrome.
*
* @param url The URL to be loaded.
* @param postDataType postData type.
* @param postData Post-data to include in the tab URL's request body, ex. bitmap when
* image search.
* @return the intent will be passed to ChromeLauncherActivity, null if input was emprty.
*/
private Intent createIntentForStartActivity(
String url, @Nullable String postDataType, @Nullable byte[] postData) {
// Don't do anything if the input was empty. This is done after the native check to prevent
// resending a queued query after the user deleted it.
if (TextUtils.isEmpty(url)) return;
if (TextUtils.isEmpty(url)) return null;
// Fix up the URL and send it to the full browser.
GURL fixedUrl = UrlFormatter.fixupUrl(url);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(fixedUrl.getValidSpecOrEmpty()));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
intent.setClass(this, ChromeLauncherActivity.class);
if (!TextUtils.isEmpty(postDataType) && postData != null && postData.length != 0) {
intent.putExtra(IntentHandler.EXTRA_POST_DATA_TYPE, postDataType);
intent.putExtra(IntentHandler.EXTRA_POST_DATA, postData);
}
IntentHandler.addTrustedIntentExtras(intent);
IntentUtils.safeStartActivity(this, intent,
ActivityOptionsCompat
.makeCustomAnimation(this, android.R.anim.fade_in, android.R.anim.fade_out)
.toBundle());
RecordUserAction.record("SearchWidget.SearchMade");
finish();
return intent;
}
private ViewGroup createContentView() {
......
......@@ -28,7 +28,7 @@ public class SearchActivityLocationBarLayout extends LocationBarLayout {
/** Delegates calls out to the containing Activity. */
public static interface Delegate {
/** Load a URL in the associated tab. */
void loadUrl(String url);
void loadUrl(String url, @Nullable String postDataType, @Nullable byte[] postData);
/** The user hit the back button. */
void backKeyPressed();
......@@ -56,8 +56,9 @@ public class SearchActivityLocationBarLayout extends LocationBarLayout {
}
@Override
public void loadUrl(String url, int transition, long inputStart) {
mDelegate.loadUrl(url);
public void loadUrlWithPostData(String url, int transition, long inputStart,
@Nullable String postDataType, @Nullable byte[] postData) {
mDelegate.loadUrl(url, postDataType, postData);
LocaleManager.getInstance().recordLocaleBasedSearchMetrics(true, url, transition);
}
......
......@@ -33,6 +33,7 @@ import org.chromium.components.url_formatter.UrlFormatter;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.common.Referrer;
import org.chromium.content_public.common.ResourceRequestBody;
import org.chromium.ui.base.PageTransition;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.url.GURL;
......@@ -298,8 +299,9 @@ public class ChromeTabCreator extends TabCreatorManager.TabCreator {
* @param intentTimestamp the time the intent was received.
* @return the tab the URL was opened in, could be a new tab or a reused one.
*/
public Tab launchUrlFromExternalApp(String url, String referer, String headers,
String appId, boolean forceNewTab, Intent intent, long intentTimestamp) {
// TODO(crbug.com/1081924): Clean up the launches from SearchActivity/Chrome.
public Tab launchUrlFromExternalApp(String url, String referer, String headers, String appId,
boolean forceNewTab, Intent intent, long intentTimestamp) {
assert !mIncognito;
boolean isLaunchedFromChrome = TextUtils.equals(appId, mActivity.getPackageName());
......@@ -309,11 +311,26 @@ public class ChromeTabCreator extends TabCreatorManager.TabCreator {
// reused either.
LoadUrlParams loadUrlParams = new LoadUrlParams(url);
loadUrlParams.setIntentReceivedTimestamp(intentTimestamp);
loadUrlParams.setVerbatimHeaders(headers);
if (referer != null) {
loadUrlParams.setReferrer(
new Referrer(referer, IntentHandler.getReferrerPolicyFromIntent(intent)));
}
// Handle post data case.
if (IntentHandler.wasIntentSenderChrome(intent)) {
String postDataType =
IntentUtils.safeGetStringExtra(intent, IntentHandler.EXTRA_POST_DATA_TYPE);
byte[] postData =
IntentUtils.safeGetByteArrayExtra(intent, IntentHandler.EXTRA_POST_DATA);
if (!TextUtils.isEmpty(postDataType) && postData != null && postData.length != 0) {
StringBuilder appendToHeader = new StringBuilder();
if (!TextUtils.isEmpty(headers)) appendToHeader.append("\r\n");
appendToHeader.append("Content-Type: ");
appendToHeader.append(postDataType);
headers = headers + appendToHeader.toString();
loadUrlParams.setPostData(ResourceRequestBody.createFromBytes(postData));
}
}
loadUrlParams.setVerbatimHeaders(headers);
return createNewTab(loadUrlParams, TabLaunchType.FROM_EXTERNAL_APP, null, intent);
}
......
......@@ -2,6 +2,7 @@ include_rules = [
"+chrome/app",
"+chrome/browser/android/lifecycle",
"+chrome/browser/profiles/android/java",
"+chrome/browser/share/android/java",
"+chrome/browser/tab/java",
"+chrome/browser/thumbnail/generator/android/java",
"+chrome/browser/ui/android/appmenu",
......
......@@ -326,6 +326,8 @@ public abstract class ChromeFeatureList {
public static final String OMNIBOX_ASSISTANT_VOICE_SEARCH = "OmniboxAssistantVoiceSearch";
public static final String OMNIBOX_COMPACT_SUGGESTIONS = "OmniboxCompactSuggestions";
public static final String OMNIBOX_DEFERRED_KEYBOARD_POPUP = "OmniboxDeferredKeyboardPopup";
public static final String OMNIBOX_ENABLE_CLIPBOARD_PROVIDER_IMAGE_SUGGESTIONS =
"OmniboxEnableClipboardProviderImageSuggestions";
public static final String OMNIBOX_HIDE_SCHEME_IN_STEADY_STATE =
"OmniboxUIExperimentHideSteadyStateUrlScheme";
public static final String OMNIBOX_HIDE_TRIVIAL_SUBDOMAINS_IN_STEADY_STATE =
......
......@@ -4,6 +4,9 @@
package org.chromium.chrome.browser.omnibox.suggestions;
import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteMediator.DropdownItemViewInfo;
import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
/**
* Utility methods providing access to package-private methods in {@link AutocompleteCoordinator}
* for tests.
......@@ -34,4 +37,28 @@ public class AutocompleteCoordinatorTestUtils {
AutocompleteCoordinator coordinator) {
return ((AutocompleteCoordinatorImpl) coordinator).getSuggestionsDropdown();
}
/**
* @return The {@link OmniboxSuggestion} at the specified index.
*/
public static OmniboxSuggestion getOmniboxSuggestionAt(
AutocompleteCoordinator coordinator, int index) {
return coordinator.getSuggestionAt(index);
}
/**
* @return The index of the first suggestion which is |type|.
*/
public static int getIndexForFirstSuggestionOfType(
AutocompleteCoordinator coordinator, @OmniboxSuggestionUiType int type) {
ModelList currentModels =
((AutocompleteCoordinatorImpl) coordinator).getSuggestionModelList();
for (int i = 0; i < currentModels.size(); i++) {
DropdownItemViewInfo info = (DropdownItemViewInfo) currentModels.get(i);
if (info.type == type) {
return i;
}
}
return -1;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment