Merge "Add RemoteInput auth bypass flow" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
174eb3ef2e
@@ -76,8 +76,8 @@ android_library {
|
|||||||
"androidx.dynamicanimation_dynamicanimation",
|
"androidx.dynamicanimation_dynamicanimation",
|
||||||
"androidx-constraintlayout_constraintlayout",
|
"androidx-constraintlayout_constraintlayout",
|
||||||
"androidx.exifinterface_exifinterface",
|
"androidx.exifinterface_exifinterface",
|
||||||
"kotlinx-coroutines-android",
|
"kotlinx_coroutines_android",
|
||||||
"kotlinx-coroutines-core",
|
"kotlinx_coroutines",
|
||||||
"iconloader_base",
|
"iconloader_base",
|
||||||
"SystemUI-tags",
|
"SystemUI-tags",
|
||||||
"SystemUI-proto",
|
"SystemUI-proto",
|
||||||
|
|||||||
@@ -388,7 +388,28 @@ public class NotificationRemoteInputManager implements Dumpable {
|
|||||||
*/
|
*/
|
||||||
public boolean activateRemoteInput(View view, RemoteInput[] inputs, RemoteInput input,
|
public boolean activateRemoteInput(View view, RemoteInput[] inputs, RemoteInput input,
|
||||||
PendingIntent pendingIntent, @Nullable EditedSuggestionInfo editedSuggestionInfo) {
|
PendingIntent pendingIntent, @Nullable EditedSuggestionInfo editedSuggestionInfo) {
|
||||||
|
return activateRemoteInput(view, inputs, input, pendingIntent, editedSuggestionInfo,
|
||||||
|
null /* userMessageContent */, null /* authBypassCheck */);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activates a given {@link RemoteInput}
|
||||||
|
*
|
||||||
|
* @param view The view of the action button or suggestion chip that was tapped.
|
||||||
|
* @param inputs The remote inputs that need to be sent to the app.
|
||||||
|
* @param input The remote input that needs to be activated.
|
||||||
|
* @param pendingIntent The pending intent to be sent to the app.
|
||||||
|
* @param editedSuggestionInfo The smart reply that should be inserted in the remote input, or
|
||||||
|
* {@code null} if the user is not editing a smart reply.
|
||||||
|
* @param userMessageContent User-entered text with which to initialize the remote input view.
|
||||||
|
* @param authBypassCheck Optional auth bypass check associated with this remote input
|
||||||
|
* activation. If {@code null}, we never bypass.
|
||||||
|
* @return Whether the {@link RemoteInput} was activated.
|
||||||
|
*/
|
||||||
|
public boolean activateRemoteInput(View view, RemoteInput[] inputs, RemoteInput input,
|
||||||
|
PendingIntent pendingIntent, @Nullable EditedSuggestionInfo editedSuggestionInfo,
|
||||||
|
@Nullable String userMessageContent,
|
||||||
|
@Nullable AuthBypassPredicate authBypassCheck) {
|
||||||
ViewParent p = view.getParent();
|
ViewParent p = view.getParent();
|
||||||
RemoteInputView riv = null;
|
RemoteInputView riv = null;
|
||||||
ExpandableNotificationRow row = null;
|
ExpandableNotificationRow row = null;
|
||||||
@@ -410,40 +431,9 @@ public class NotificationRemoteInputManager implements Dumpable {
|
|||||||
|
|
||||||
row.setUserExpanded(true);
|
row.setUserExpanded(true);
|
||||||
|
|
||||||
if (!mLockscreenUserManager.shouldAllowLockscreenRemoteInput()) {
|
final boolean deferBouncer = authBypassCheck != null;
|
||||||
final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
|
if (!deferBouncer && showBouncerForRemoteInput(view, pendingIntent, row)) {
|
||||||
|
return true;
|
||||||
final boolean isLockedManagedProfile =
|
|
||||||
mUserManager.getUserInfo(userId).isManagedProfile()
|
|
||||||
&& mKeyguardManager.isDeviceLocked(userId);
|
|
||||||
|
|
||||||
final boolean isParentUserLocked;
|
|
||||||
if (isLockedManagedProfile) {
|
|
||||||
final UserInfo profileParent = mUserManager.getProfileParent(userId);
|
|
||||||
isParentUserLocked = (profileParent != null)
|
|
||||||
&& mKeyguardManager.isDeviceLocked(profileParent.id);
|
|
||||||
} else {
|
|
||||||
isParentUserLocked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mLockscreenUserManager.isLockscreenPublicMode(userId)
|
|
||||||
|| mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
|
|
||||||
// If the parent user is no longer locked, and the user to which the remote input
|
|
||||||
// is destined is a locked, managed profile, then onLockedWorkRemoteInput should be
|
|
||||||
// called to unlock it.
|
|
||||||
if (isLockedManagedProfile && !isParentUserLocked) {
|
|
||||||
mCallback.onLockedWorkRemoteInput(userId, row, view);
|
|
||||||
} else {
|
|
||||||
// Even if we don't have security we should go through this flow, otherwise
|
|
||||||
// we won't go to the shade.
|
|
||||||
mCallback.onLockedRemoteInput(row, view);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (isLockedManagedProfile) {
|
|
||||||
mCallback.onLockedWorkRemoteInput(userId, row, view);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (riv != null && !riv.isAttachedToWindow()) {
|
if (riv != null && !riv.isAttachedToWindow()) {
|
||||||
@@ -461,7 +451,10 @@ public class NotificationRemoteInputManager implements Dumpable {
|
|||||||
&& !row.getPrivateLayout().getExpandedChild().isShown()) {
|
&& !row.getPrivateLayout().getExpandedChild().isShown()) {
|
||||||
// The expanded layout is selected, but it's not shown yet, let's wait on it to
|
// The expanded layout is selected, but it's not shown yet, let's wait on it to
|
||||||
// show before we do the animation.
|
// show before we do the animation.
|
||||||
mCallback.onMakeExpandedVisibleForRemoteInput(row, view);
|
mCallback.onMakeExpandedVisibleForRemoteInput(row, view, deferBouncer, () -> {
|
||||||
|
activateRemoteInput(view, inputs, input, pendingIntent, editedSuggestionInfo,
|
||||||
|
userMessageContent, authBypassCheck);
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,10 +484,62 @@ public class NotificationRemoteInputManager implements Dumpable {
|
|||||||
riv.setPendingIntent(pendingIntent);
|
riv.setPendingIntent(pendingIntent);
|
||||||
riv.setRemoteInput(inputs, input, editedSuggestionInfo);
|
riv.setRemoteInput(inputs, input, editedSuggestionInfo);
|
||||||
riv.focusAnimated();
|
riv.focusAnimated();
|
||||||
|
if (userMessageContent != null) {
|
||||||
|
riv.setEditTextContent(userMessageContent);
|
||||||
|
}
|
||||||
|
if (deferBouncer) {
|
||||||
|
final ExpandableNotificationRow finalRow = row;
|
||||||
|
riv.setBouncerChecker(() -> !authBypassCheck.canSendRemoteInputWithoutBouncer()
|
||||||
|
&& showBouncerForRemoteInput(view, pendingIntent, finalRow));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean showBouncerForRemoteInput(View view, PendingIntent pendingIntent,
|
||||||
|
ExpandableNotificationRow row) {
|
||||||
|
if (mLockscreenUserManager.shouldAllowLockscreenRemoteInput()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
|
||||||
|
|
||||||
|
final boolean isLockedManagedProfile =
|
||||||
|
mUserManager.getUserInfo(userId).isManagedProfile()
|
||||||
|
&& mKeyguardManager.isDeviceLocked(userId);
|
||||||
|
|
||||||
|
final boolean isParentUserLocked;
|
||||||
|
if (isLockedManagedProfile) {
|
||||||
|
final UserInfo profileParent = mUserManager.getProfileParent(userId);
|
||||||
|
isParentUserLocked = (profileParent != null)
|
||||||
|
&& mKeyguardManager.isDeviceLocked(profileParent.id);
|
||||||
|
} else {
|
||||||
|
isParentUserLocked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mLockscreenUserManager.isLockscreenPublicMode(userId)
|
||||||
|
|| mStatusBarStateController.getState() == StatusBarState.KEYGUARD)) {
|
||||||
|
// If the parent user is no longer locked, and the user to which the remote
|
||||||
|
// input
|
||||||
|
// is destined is a locked, managed profile, then onLockedWorkRemoteInput
|
||||||
|
// should be
|
||||||
|
// called to unlock it.
|
||||||
|
if (isLockedManagedProfile && !isParentUserLocked) {
|
||||||
|
mCallback.onLockedWorkRemoteInput(userId, row, view);
|
||||||
|
} else {
|
||||||
|
// Even if we don't have security we should go through this flow, otherwise
|
||||||
|
// we won't go to the shade.
|
||||||
|
mCallback.onLockedRemoteInput(row, view);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (isLockedManagedProfile) {
|
||||||
|
mCallback.onLockedWorkRemoteInput(userId, row, view);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private RemoteInputView findRemoteInputView(View v) {
|
private RemoteInputView findRemoteInputView(View v) {
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -807,8 +852,11 @@ public class NotificationRemoteInputManager implements Dumpable {
|
|||||||
*
|
*
|
||||||
* @param row
|
* @param row
|
||||||
* @param clickedView
|
* @param clickedView
|
||||||
|
* @param deferBouncer
|
||||||
|
* @param runnable
|
||||||
*/
|
*/
|
||||||
void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row, View clickedView);
|
void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row, View clickedView,
|
||||||
|
boolean deferBouncer, Runnable runnable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether or not remote input should be handled for this view.
|
* Return whether or not remote input should be handled for this view.
|
||||||
@@ -845,4 +893,28 @@ public class NotificationRemoteInputManager implements Dumpable {
|
|||||||
*/
|
*/
|
||||||
boolean handleClick();
|
boolean handleClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate that is associated with a specific {@link #activateRemoteInput(View, RemoteInput[],
|
||||||
|
* RemoteInput, PendingIntent, EditedSuggestionInfo, String, AuthBypassPredicate)}
|
||||||
|
* invocation that determines whether or not the bouncer can be bypassed when sending the
|
||||||
|
* RemoteInput.
|
||||||
|
*/
|
||||||
|
public interface AuthBypassPredicate {
|
||||||
|
/**
|
||||||
|
* Determines if the RemoteInput can be sent without the bouncer. Should be checked the
|
||||||
|
* same frame that the RemoteInput is to be sent.
|
||||||
|
*/
|
||||||
|
boolean canSendRemoteInputWithoutBouncer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Shows the bouncer if necessary */
|
||||||
|
public interface BouncerChecker {
|
||||||
|
/**
|
||||||
|
* Shows the bouncer if necessary in order to send a RemoteInput.
|
||||||
|
*
|
||||||
|
* @return {@code true} if the bouncer was shown, {@code false} otherwise
|
||||||
|
*/
|
||||||
|
boolean showBouncerIfNecessary();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,8 +180,8 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
|
public void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
|
||||||
View clickedView) {
|
View clickedView, boolean deferBouncer, Runnable runnable) {
|
||||||
if (mKeyguardStateController.isShowing()) {
|
if (!deferBouncer && mKeyguardStateController.isShowing()) {
|
||||||
onLockedRemoteInput(row, clickedView);
|
onLockedRemoteInput(row, clickedView);
|
||||||
} else {
|
} else {
|
||||||
if (row.isChildInGroup() && !row.areChildrenExpanded()) {
|
if (row.isChildInGroup() && !row.areChildrenExpanded()) {
|
||||||
@@ -189,7 +189,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
|
|||||||
mGroupExpansionManager.toggleGroupExpansion(row.getEntry());
|
mGroupExpansionManager.toggleGroupExpansion(row.getEntry());
|
||||||
}
|
}
|
||||||
row.setUserExpanded(true);
|
row.setUserExpanded(true);
|
||||||
row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick);
|
row.getPrivateLayout().setOnExpandedVisibleListener(runnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ import com.android.internal.statusbar.IStatusBarService;
|
|||||||
import com.android.systemui.Dependency;
|
import com.android.systemui.Dependency;
|
||||||
import com.android.systemui.Interpolators;
|
import com.android.systemui.Interpolators;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
|
import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
||||||
import com.android.systemui.statusbar.RemoteInputController;
|
import com.android.systemui.statusbar.RemoteInputController;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
|
||||||
@@ -80,6 +81,7 @@ import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewW
|
|||||||
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
|
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
|
||||||
import com.android.systemui.statusbar.phone.LightBarController;
|
import com.android.systemui.statusbar.phone.LightBarController;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -99,6 +101,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
|
|||||||
|
|
||||||
private final SendButtonTextWatcher mTextWatcher;
|
private final SendButtonTextWatcher mTextWatcher;
|
||||||
private final TextView.OnEditorActionListener mEditorActionHandler;
|
private final TextView.OnEditorActionListener mEditorActionHandler;
|
||||||
|
private final NotificationRemoteInputManager mRemoteInputManager;
|
||||||
|
private final List<OnFocusChangeListener> mEditTextFocusChangeListeners = new ArrayList<>();
|
||||||
private RemoteEditText mEditText;
|
private RemoteEditText mEditText;
|
||||||
private ImageButton mSendButton;
|
private ImageButton mSendButton;
|
||||||
private ProgressBar mProgressBar;
|
private ProgressBar mProgressBar;
|
||||||
@@ -121,12 +125,14 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
|
|||||||
private boolean mResetting;
|
private boolean mResetting;
|
||||||
private NotificationViewWrapper mWrapper;
|
private NotificationViewWrapper mWrapper;
|
||||||
private Consumer<Boolean> mOnVisibilityChangedListener;
|
private Consumer<Boolean> mOnVisibilityChangedListener;
|
||||||
|
private NotificationRemoteInputManager.BouncerChecker mBouncerChecker;
|
||||||
|
|
||||||
public RemoteInputView(Context context, AttributeSet attrs) {
|
public RemoteInputView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
mTextWatcher = new SendButtonTextWatcher();
|
mTextWatcher = new SendButtonTextWatcher();
|
||||||
mEditorActionHandler = new EditorActionHandler();
|
mEditorActionHandler = new EditorActionHandler();
|
||||||
mRemoteInputQuickSettingsDisabler = Dependency.get(RemoteInputQuickSettingsDisabler.class);
|
mRemoteInputQuickSettingsDisabler = Dependency.get(RemoteInputQuickSettingsDisabler.class);
|
||||||
|
mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
|
||||||
mStatusBarManagerService = IStatusBarService.Stub.asInterface(
|
mStatusBarManagerService = IStatusBarService.Stub.asInterface(
|
||||||
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
|
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
|
||||||
}
|
}
|
||||||
@@ -200,6 +206,11 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendRemoteInput(Intent intent) {
|
private void sendRemoteInput(Intent intent) {
|
||||||
|
if (mBouncerChecker != null && mBouncerChecker.showBouncerIfNecessary()) {
|
||||||
|
mEditText.hideIme();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mEditText.setEnabled(false);
|
mEditText.setEnabled(false);
|
||||||
mSendButton.setVisibility(INVISIBLE);
|
mSendButton.setVisibility(INVISIBLE);
|
||||||
mProgressBar.setVisibility(VISIBLE);
|
mProgressBar.setVisibility(VISIBLE);
|
||||||
@@ -351,6 +362,11 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Populates the text field of the remote input with the given content. */
|
||||||
|
public void setEditTextContent(@Nullable CharSequence editTextContent) {
|
||||||
|
mEditText.setText(editTextContent);
|
||||||
|
}
|
||||||
|
|
||||||
public void focusAnimated() {
|
public void focusAnimated() {
|
||||||
if (getVisibility() != VISIBLE) {
|
if (getVisibility() != VISIBLE) {
|
||||||
Animator animator = ViewAnimationUtils.createCircularReveal(
|
Animator animator = ViewAnimationUtils.createCircularReveal(
|
||||||
@@ -552,6 +568,37 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
|
|||||||
return getVisibility() == VISIBLE && mController.isSpinning(mEntry.getKey(), mToken);
|
return getVisibility() == VISIBLE && mController.isSpinning(mEntry.getKey(), mToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a {@link com.android.systemui.statusbar.NotificationRemoteInputManager.BouncerChecker}
|
||||||
|
* that will be used to determine if the device needs to be unlocked before sending the
|
||||||
|
* RemoteInput.
|
||||||
|
*/
|
||||||
|
public void setBouncerChecker(
|
||||||
|
@Nullable NotificationRemoteInputManager.BouncerChecker bouncerChecker) {
|
||||||
|
mBouncerChecker = bouncerChecker;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Registers a listener for focus-change events on the EditText */
|
||||||
|
public void addOnEditTextFocusChangedListener(View.OnFocusChangeListener listener) {
|
||||||
|
mEditTextFocusChangeListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a previously-added listener for focus-change events on the EditText */
|
||||||
|
public void removeOnEditTextFocusChangedListener(View.OnFocusChangeListener listener) {
|
||||||
|
mEditTextFocusChangeListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Determines if the EditText has focus. */
|
||||||
|
public boolean editTextHasFocus() {
|
||||||
|
return mEditText != null && mEditText.hasFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onEditTextFocusChanged(RemoteEditText remoteEditText, boolean focused) {
|
||||||
|
for (View.OnFocusChangeListener listener : mEditTextFocusChangeListeners) {
|
||||||
|
listener.onFocusChange(remoteEditText, focused);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Handler for button click on send action in IME. */
|
/** Handler for button click on send action in IME. */
|
||||||
private class EditorActionHandler implements TextView.OnEditorActionListener {
|
private class EditorActionHandler implements TextView.OnEditorActionListener {
|
||||||
|
|
||||||
@@ -603,6 +650,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
|
|||||||
private RemoteInputView mRemoteInputView;
|
private RemoteInputView mRemoteInputView;
|
||||||
boolean mShowImeOnInputConnection;
|
boolean mShowImeOnInputConnection;
|
||||||
private LightBarController mLightBarController;
|
private LightBarController mLightBarController;
|
||||||
|
private InputMethodManager mInputMethodManager;
|
||||||
UserHandle mUser;
|
UserHandle mUser;
|
||||||
|
|
||||||
public RemoteEditText(Context context, AttributeSet attrs) {
|
public RemoteEditText(Context context, AttributeSet attrs) {
|
||||||
@@ -621,6 +669,12 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
|
|||||||
setOnReceiveContentListener(types, listener);
|
setOnReceiveContentListener(types, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void hideIme() {
|
||||||
|
if (mInputMethodManager != null) {
|
||||||
|
mInputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void defocusIfNeeded(boolean animate) {
|
private void defocusIfNeeded(boolean animate) {
|
||||||
if (mRemoteInputView != null && mRemoteInputView.mEntry.getRow().isChangingPosition()
|
if (mRemoteInputView != null && mRemoteInputView.mEntry.getRow().isChangingPosition()
|
||||||
|| isTemporarilyDetached()) {
|
|| isTemporarilyDetached()) {
|
||||||
@@ -654,6 +708,9 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
|
|||||||
@Override
|
@Override
|
||||||
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
|
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
|
||||||
super.onFocusChanged(focused, direction, previouslyFocusedRect);
|
super.onFocusChanged(focused, direction, previouslyFocusedRect);
|
||||||
|
if (mRemoteInputView != null) {
|
||||||
|
mRemoteInputView.onEditTextFocusChanged(this, focused);
|
||||||
|
}
|
||||||
if (!focused) {
|
if (!focused) {
|
||||||
defocusIfNeeded(true /* animate */);
|
defocusIfNeeded(true /* animate */);
|
||||||
}
|
}
|
||||||
@@ -724,17 +781,16 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
|
|||||||
|
|
||||||
if (mShowImeOnInputConnection && ic != null) {
|
if (mShowImeOnInputConnection && ic != null) {
|
||||||
Context targetContext = userContext != null ? userContext : getContext();
|
Context targetContext = userContext != null ? userContext : getContext();
|
||||||
final InputMethodManager imm =
|
mInputMethodManager = targetContext.getSystemService(InputMethodManager.class);
|
||||||
targetContext.getSystemService(InputMethodManager.class);
|
if (mInputMethodManager != null) {
|
||||||
if (imm != null) {
|
|
||||||
// onCreateInputConnection is called by InputMethodManager in the middle of
|
// onCreateInputConnection is called by InputMethodManager in the middle of
|
||||||
// setting up the connection to the IME; wait with requesting the IME until that
|
// setting up the connection to the IME; wait with requesting the IME until that
|
||||||
// work has completed.
|
// work has completed.
|
||||||
post(new Runnable() {
|
post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
imm.viewClicked(RemoteEditText.this);
|
mInputMethodManager.viewClicked(RemoteEditText.this);
|
||||||
imm.showSoftInput(RemoteEditText.this, 0);
|
mInputMethodManager.showSoftInput(RemoteEditText.this, 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user