Commit c659cb51 authored by Jun Cai's avatar Jun Cai Committed by Commit Bot

[sms] Dismiss soft input keyboard when sms arrives

If the soft input keyboard is open and focused on the OTP/code field
when the SMS arrives, the keyboard is dismissed.

Bug: 997025
Change-Id: Ibadd3febb4696ccfd600971538926ed667ce1bd8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1768995Reviewed-by: default avatarMichael Thiessen <mthiesse@chromium.org>
Reviewed-by: default avatarAyu Ishii <ayui@chromium.org>
Commit-Queue: Jun Cai <juncai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#690924}
parent f1a4234e
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
package org.chromium.chrome.browser.sms; package org.chromium.chrome.browser.sms;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.view.View;
import org.chromium.base.Log; import org.chromium.base.Log;
import org.chromium.base.VisibleForTesting; import org.chromium.base.VisibleForTesting;
...@@ -14,6 +16,8 @@ import org.chromium.chrome.browser.ResourceId; ...@@ -14,6 +16,8 @@ import org.chromium.chrome.browser.ResourceId;
import org.chromium.chrome.browser.infobar.ConfirmInfoBar; import org.chromium.chrome.browser.infobar.ConfirmInfoBar;
import org.chromium.chrome.browser.infobar.InfoBarControlLayout; import org.chromium.chrome.browser.infobar.InfoBarControlLayout;
import org.chromium.chrome.browser.infobar.InfoBarLayout; import org.chromium.chrome.browser.infobar.InfoBarLayout;
import org.chromium.ui.KeyboardVisibilityDelegate;
import org.chromium.ui.base.WindowAndroid;
/** /**
* An InfoBar that asks for the user's permission to share the SMS with the page. * An InfoBar that asks for the user's permission to share the SMS with the page.
...@@ -22,26 +26,41 @@ public class SmsReceiverInfoBar extends ConfirmInfoBar { ...@@ -22,26 +26,41 @@ public class SmsReceiverInfoBar extends ConfirmInfoBar {
private static final String TAG = "SmsReceiverInfoBar"; private static final String TAG = "SmsReceiverInfoBar";
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
private String mMessage; private String mMessage;
private WindowAndroid mWindowAndroid;
@VisibleForTesting @VisibleForTesting
@CalledByNative @CalledByNative
static SmsReceiverInfoBar create( static SmsReceiverInfoBar create(WindowAndroid windowAndroid, int enumeratedIconId,
int enumeratedIconId, String title, String message, String okButtonLabel) { String title, String message, String okButtonLabel) {
if (DEBUG) Log.d(TAG, "SmsReceiverInfoBar.create()"); if (DEBUG) Log.d(TAG, "SmsReceiverInfoBar.create()");
return new SmsReceiverInfoBar(enumeratedIconId, title, message, okButtonLabel); return new SmsReceiverInfoBar(
windowAndroid, enumeratedIconId, title, message, okButtonLabel);
} }
private SmsReceiverInfoBar( private SmsReceiverInfoBar(WindowAndroid windowAndroid, int enumeratedIconId, String title,
int enumeratedIconId, String title, String message, String okButtonLabel) { String message, String okButtonLabel) {
super(ResourceId.mapToDrawableId(enumeratedIconId), R.color.infobar_icon_drawable_color, super(ResourceId.mapToDrawableId(enumeratedIconId), R.color.infobar_icon_drawable_color,
/*iconBitmap=*/null, /*message=*/title, /*linkText=*/null, okButtonLabel, /*iconBitmap=*/null, /*message=*/title, /*linkText=*/null, okButtonLabel,
/*secondaryButtonText=*/null); /*secondaryButtonText=*/null);
mMessage = message; mMessage = message;
mWindowAndroid = windowAndroid;
} }
@Override @Override
public void createContent(InfoBarLayout layout) { public void createContent(InfoBarLayout layout) {
super.createContent(layout); super.createContent(layout);
Activity activity = mWindowAndroid.getActivity().get();
if (activity != null) {
View focusedView = activity.getCurrentFocus();
KeyboardVisibilityDelegate keyboardVisibilityDelegate =
KeyboardVisibilityDelegate.getInstance();
if (focusedView != null
&& keyboardVisibilityDelegate.isKeyboardShowing(activity, focusedView)) {
keyboardVisibilityDelegate.hideKeyboard(focusedView);
}
}
Context context = layout.getContext(); Context context = layout.getContext();
InfoBarControlLayout control = layout.addControlLayout(); InfoBarControlLayout control = layout.addControlLayout();
control.addDescription(mMessage); control.addDescription(mMessage);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.sms; package org.chromium.chrome.browser.sms;
import android.support.test.filters.MediumTest; import android.support.test.filters.MediumTest;
import android.widget.EditText;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
...@@ -21,7 +22,11 @@ import org.chromium.chrome.browser.tab.Tab; ...@@ -21,7 +22,11 @@ import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.util.InfoBarUtil; import org.chromium.chrome.test.util.InfoBarUtil;
import org.chromium.content_public.browser.test.util.Criteria;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.KeyboardVisibilityDelegate;
import org.chromium.ui.base.ActivityWindowAndroid;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
...@@ -35,20 +40,30 @@ public class SmsReceiverInfoBarTest { ...@@ -35,20 +40,30 @@ public class SmsReceiverInfoBarTest {
public ChromeActivityTestRule<ChromeActivity> mActivityTestRule = public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
new ChromeActivityTestRule<>(ChromeActivity.class); new ChromeActivityTestRule<>(ChromeActivity.class);
private ChromeActivity mActivity;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
mActivityTestRule.startMainActivityOnBlankPage(); mActivityTestRule.startMainActivityOnBlankPage();
mActivity = mActivityTestRule.getActivity();
}
private SmsReceiverInfoBar createInfoBar() {
return TestThreadUtils.runOnUiThreadBlockingNoException(() -> {
Tab tab = mActivity.getActivityTab();
ActivityWindowAndroid windowAndroid = new ActivityWindowAndroid(mActivity);
SmsReceiverInfoBar infoBar = SmsReceiverInfoBar.create(
windowAndroid, /*enumeratedIconId=*/0, "title", "message", "ok");
InfoBarContainer.get(tab).addInfoBarForTesting(infoBar);
return infoBar;
});
} }
@Test @Test
@MediumTest @MediumTest
@Feature({"InfoBars", "UiCatalogue"}) @Feature({"InfoBars", "UiCatalogue"})
public void testSmsInfoBarOk() throws TimeoutException, InterruptedException { public void testSmsInfoBarOk() throws TimeoutException, InterruptedException {
Tab tab = mActivityTestRule.getActivity().getActivityTab(); SmsReceiverInfoBar infoBar = createInfoBar();
SmsReceiverInfoBar infoBar =
SmsReceiverInfoBar.create(/*enumeratedIconId=*/0, "title", "message", "ok");
TestThreadUtils.runOnUiThreadBlocking(
() -> InfoBarContainer.get(tab).addInfoBarForTesting(infoBar));
Assert.assertFalse(InfoBarUtil.hasSecondaryButton(infoBar)); Assert.assertFalse(InfoBarUtil.hasSecondaryButton(infoBar));
...@@ -60,15 +75,36 @@ public class SmsReceiverInfoBarTest { ...@@ -60,15 +75,36 @@ public class SmsReceiverInfoBarTest {
@MediumTest @MediumTest
@Feature({"InfoBars", "UiCatalogue"}) @Feature({"InfoBars", "UiCatalogue"})
public void testSmsInfoBarClose() throws TimeoutException, InterruptedException { public void testSmsInfoBarClose() throws TimeoutException, InterruptedException {
Tab tab = mActivityTestRule.getActivity().getActivityTab(); SmsReceiverInfoBar infoBar = createInfoBar();
SmsReceiverInfoBar infoBar =
SmsReceiverInfoBar.create(/*enumeratedIconId=*/0, "title", "message", "ok");
TestThreadUtils.runOnUiThreadBlocking(
() -> InfoBarContainer.get(tab).addInfoBarForTesting(infoBar));
Assert.assertFalse(InfoBarUtil.hasSecondaryButton(infoBar)); Assert.assertFalse(InfoBarUtil.hasSecondaryButton(infoBar));
// Close infobar. // Close infobar.
Assert.assertTrue(InfoBarUtil.clickCloseButton(infoBar)); Assert.assertTrue(InfoBarUtil.clickCloseButton(infoBar));
} }
@Test
@MediumTest
@Feature({"InfoBars", "UiCatalogue"})
public void testHideKeyboardWhenInfoBarIsShown() {
KeyboardVisibilityDelegate keyboardVisibilityDelegate =
mActivityTestRule.getKeyboardDelegate();
EditText editText = new EditText(mActivity);
TestThreadUtils.runOnUiThreadBlocking(() -> {
mActivity.setContentView(editText);
editText.requestFocus();
keyboardVisibilityDelegate.showKeyboard(editText);
});
// Wait until the keyboard is showing.
CriteriaHelper.pollUiThread(Criteria.equals(
true, () -> keyboardVisibilityDelegate.isKeyboardShowing(mActivity, editText)));
SmsReceiverInfoBar infoBar = createInfoBar();
// Keyboard is hidden after info bar is created and shown.
CriteriaHelper.pollUiThread(Criteria.equals(
false, () -> keyboardVisibilityDelegate.isKeyboardShowing(mActivity, editText)));
}
} }
...@@ -168,8 +168,7 @@ void TabWebContentsDelegateAndroid::CreateSmsPrompt( ...@@ -168,8 +168,7 @@ void TabWebContentsDelegateAndroid::CreateSmsPrompt(
base::OnceClosure on_confirm, base::OnceClosure on_confirm,
base::OnceClosure on_cancel) { base::OnceClosure on_cancel) {
auto* web_contents = content::WebContents::FromRenderFrameHost(host); auto* web_contents = content::WebContents::FromRenderFrameHost(host);
auto* infobar_service = InfoBarService::FromWebContents(web_contents); SmsInfoBar::Create(web_contents, origin, std::move(on_confirm),
SmsInfoBar::Create(infobar_service, origin, std::move(on_confirm),
std::move(on_cancel)); std::move(on_cancel));
} }
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include "chrome/android/chrome_jni_headers/SmsReceiverInfoBar_jni.h" #include "chrome/android/chrome_jni_headers/SmsReceiverInfoBar_jni.h"
#include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/ui/android/sms/sms_infobar_delegate.h" #include "chrome/browser/ui/android/sms/sms_infobar_delegate.h"
#include "content/public/browser/web_contents.h"
#include "ui/android/window_android.h"
#include "url/origin.h" #include "url/origin.h"
using base::android::ConvertUTF16ToJavaString; using base::android::ConvertUTF16ToJavaString;
...@@ -15,18 +17,21 @@ using base::android::ScopedJavaLocalRef; ...@@ -15,18 +17,21 @@ using base::android::ScopedJavaLocalRef;
using infobars::InfoBarDelegate; using infobars::InfoBarDelegate;
// static // static
void SmsInfoBar::Create(InfoBarService* infobar_service, void SmsInfoBar::Create(content::WebContents* web_contents,
const url::Origin& origin, const url::Origin& origin,
base::OnceClosure on_confirm, base::OnceClosure on_confirm,
base::OnceClosure on_cancel) { base::OnceClosure on_cancel) {
auto delegate = std::make_unique<SmsInfoBarDelegate>( auto delegate = std::make_unique<SmsInfoBarDelegate>(
origin, std::move(on_confirm), std::move(on_cancel)); origin, std::move(on_confirm), std::move(on_cancel));
auto infobar = std::make_unique<SmsInfoBar>(std::move(delegate)); auto infobar =
std::make_unique<SmsInfoBar>(web_contents, std::move(delegate));
auto* infobar_service = InfoBarService::FromWebContents(web_contents);
infobar_service->AddInfoBar(std::move(infobar)); infobar_service->AddInfoBar(std::move(infobar));
} }
SmsInfoBar::SmsInfoBar(std::unique_ptr<SmsInfoBarDelegate> delegate) SmsInfoBar::SmsInfoBar(content::WebContents* web_contents,
: ConfirmInfoBar(std::move(delegate)) {} std::unique_ptr<SmsInfoBarDelegate> delegate)
: ConfirmInfoBar(std::move(delegate)), web_contents_(web_contents) {}
SmsInfoBar::~SmsInfoBar() = default; SmsInfoBar::~SmsInfoBar() = default;
...@@ -39,6 +44,9 @@ ScopedJavaLocalRef<jobject> SmsInfoBar::CreateRenderInfoBar(JNIEnv* env) { ...@@ -39,6 +44,9 @@ ScopedJavaLocalRef<jobject> SmsInfoBar::CreateRenderInfoBar(JNIEnv* env) {
auto button = ConvertUTF16ToJavaString( auto button = ConvertUTF16ToJavaString(
env, GetTextFor(ConfirmInfoBarDelegate::BUTTON_OK)); env, GetTextFor(ConfirmInfoBarDelegate::BUTTON_OK));
return Java_SmsReceiverInfoBar_create(env, GetEnumeratedIconId(), title, base::android::ScopedJavaLocalRef<jobject> window_android =
message, button); web_contents_->GetNativeView()->GetWindowAndroid()->GetJavaObject();
return Java_SmsReceiverInfoBar_create(
env, window_android, GetEnumeratedIconId(), title, message, button);
} }
...@@ -10,21 +10,25 @@ ...@@ -10,21 +10,25 @@
#include "base/macros.h" #include "base/macros.h"
#include "chrome/browser/ui/android/infobars/confirm_infobar.h" #include "chrome/browser/ui/android/infobars/confirm_infobar.h"
namespace content {
class WebContents;
} // namespace content
namespace url { namespace url {
class Origin; class Origin;
} // namespace url } // namespace url
class SmsInfoBarDelegate; class SmsInfoBarDelegate;
class InfoBarService;
class SmsInfoBar : public ConfirmInfoBar { class SmsInfoBar : public ConfirmInfoBar {
public: public:
explicit SmsInfoBar(std::unique_ptr<SmsInfoBarDelegate> delegate); SmsInfoBar(content::WebContents* web_contents,
std::unique_ptr<SmsInfoBarDelegate> delegate);
~SmsInfoBar() override; ~SmsInfoBar() override;
// Creates an SMS receiver infobar and delegate and adds it to // Creates an SMS receiver infobar and delegate and adds it to
// |infobar_service|. // |infobar_service|.
static void Create(InfoBarService* infobar_service, static void Create(content::WebContents* web_contents,
const url::Origin& origin, const url::Origin& origin,
base::OnceCallback<void()> on_confirm, base::OnceCallback<void()> on_confirm,
base::OnceCallback<void()> on_cancel); base::OnceCallback<void()> on_cancel);
...@@ -34,6 +38,8 @@ class SmsInfoBar : public ConfirmInfoBar { ...@@ -34,6 +38,8 @@ class SmsInfoBar : public ConfirmInfoBar {
base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar( base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
JNIEnv* env) override; JNIEnv* env) override;
content::WebContents* web_contents_;
DISALLOW_COPY_AND_ASSIGN(SmsInfoBar); DISALLOW_COPY_AND_ASSIGN(SmsInfoBar);
}; };
......
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